LCOV - lcov.info - ept/debtags/maint/vocabularymerger.cc

LTP GCOV extension - code coverage report
Current view: | directory - ept/debtags/maint - vocabularymerger.cc
Test: | lcov.info
Date: | 2008-08-14 |  | Instrumented lines: | 181
Code covered: | 81.2 % |  | Executed lines: | 147

           1                 : /*
           2                 :  * Merge different vocabularies together and create the tag and facet indexes
           3                 :  *
           4                 :  * Copyright (C) 2003-2006  Enrico Zini <enrico@debian.org>
           5                 :  *
           6                 :  * This program is free software; you can redistribute it and/or modify
           7                 :  * it under the terms of the GNU General Public License as published by
           8                 :  * the Free Software Foundation; either version 2 of the License, or
           9                 :  * (at your option) any later version.
          10                 :  *
          11                 :  * This program is distributed in the hope that it will be useful,
          12                 :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
          13                 :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
          14                 :  * GNU General Public License for more details.
          15                 :  *
          16                 :  * You should have received a copy of the GNU General Public License
          17                 :  * along with this program; if not, write to the Free Software
          18                 :  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
          19                 :  */
          20                 :
          21                 :
          22                 : #include <ept/debtags/maint/vocabularymerger.h>
          23                 : #include <ept/debtags/maint/debdbparser.h>
          24                 :
          25                 : #include <cassert>
          26                 : #include <cstring>
          27                 :
          28                 : using namespace std;
          29                 : using namespace tagcoll;
          30                 :
          31                 : namespace ept {
          32                 : namespace debtags {
          33                 :
          34            1432 : static void writeDebStyleField(FILE* out, const string& name, const string& val) throw ()
          35                 : {
          36            1432 :         fprintf(out, "%s: ", name.c_str());
          37                 :
          38                 :         // Properly escape newlines
          39            1432 :         bool was_nl = false;
          40           56225 :         for (string::const_iterator s = val.begin(); s != val.end(); s++)
          41           54793 :                 if (was_nl)
          42                 :                         // \n\n -> \n .\n
          43             738 :                         if (*s == '\n')
          44                 :                         {
          45             120 :                                 fputc(' ', out);
          46             120 :                                 fputc('.', out);
          47             120 :                                 fputc(*s, out);
          48                 :                         }
          49                 :                         // \n([^ \t]) -> \n \1
          50             618 :                         else if (*s != ' ' && *s != '\t')
          51                 :                         {
          52             618 :                                 fputc(' ', out);
          53             618 :                                 fputc(*s, out);
          54             618 :                                 was_nl = false;
          55                 :                         }
          56                 :                         // \n[ \t] goes unchanged
          57                 :                         else
          58                 :                         {
          59               0 :                                 fputc(*s, out);
          60               0 :                                 was_nl = false;
          61                 :                         }
          62                 :                 else
          63           54055 :                         if (*s == '\n')
          64                 :                         {
          65             618 :                                 fputc(*s, out);
          66             618 :                                 was_nl = true;
          67                 :                         }
          68                 :                         else
          69           53437 :                                 fputc(*s, out);
          70                 :
          71            1432 :         fputc('\n', out);
          72            1432 : }
          73                 :
          74            1865 : VocabularyMerger::TagData& VocabularyMerger::FacetData::obtainTag(const std::string& name)
          75                 : {
          76            1865 :         std::map<std::string, TagData>::iterator i = tags.find(name);
          77            1865 :         if (i == tags.end())
          78                 :         {
          79                 :                 // Create the tag if it's missing
          80            1245 :                 pair<std::map<std::string, TagData>::iterator, bool> res = tags.insert(make_pair<std::string, TagData>(name, TagData()));
          81            1245 :                 i = res.first;
          82            1245 :                 i->second.name = name;
          83                 :         }
          84            1865 :         return i->second;
          85                 : }
          86                 :
          87            1953 : VocabularyMerger::FacetData& VocabularyMerger::obtainFacet(const std::string& name)
          88                 : {
          89            1953 :         std::map<std::string, FacetData>::iterator i = facets.find(name);
          90            1953 :         if (i == facets.end())
          91                 :         {
          92                 :                 // Create the facet if it's missing
          93              62 :                 pair<std::map<std::string, FacetData>::iterator, bool> res = facets.insert(make_pair<std::string, FacetData>(name, FacetData()));
          94              62 :                 i = res.first;
          95              62 :                 i->second.name = name;
          96                 :         }
          97            1953 :         return i->second;
          98                 : }
          99                 :
         100            1865 : VocabularyMerger::TagData& VocabularyMerger::obtainTag(const std::string& fullname)
         101                 : {
         102            1865 :         size_t p = fullname.find("::");
         103            1865 :         if (p == string::npos)
         104                 :         {
         105              28 :                 FacetData& facet = obtainFacet("legacy");
         106              28 :                 return facet.obtainTag(fullname);
         107                 :         } else {
         108            1837 :                 FacetData& facet = obtainFacet(fullname.substr(0, p));
         109            3674 :                 return facet.obtainTag(fullname.substr(p + 2));
         110                 :         }
         111                 : }
         112                 :
         113                 :
         114               7 : void VocabularyMerger::read(tagcoll::input::Input& input)
         115                 : {
         116               7 :         DebDBParser parser(input);
         117               7 :         DebDBParser::Record record;
         118                 :
         119            1967 :         while (parser.nextRecord(record))
         120                 :         {
         121            1953 :                 DebDBParser::Record::const_iterator fi = record.find("Facet");
         122            3906 :                 DebDBParser::Record::const_iterator ti = record.find("Tag");
         123            3906 :                 if (fi != record.end())
         124                 :                 {
         125                 :                         // Get the facet record
         126              88 :                         FacetData& facet = obtainFacet(fi->second);
         127                 :                         //fprintf(stderr, "Read facet@%d %.*s\n", parser.lineNumber(), PFSTR(facet.name));
         128              88 :                         assert(facet.name == fi->second);
         129                 :
         130                 :                         // Merge the data
         131             416 :                         for (DebDBParser::Record::const_iterator i = record.begin();
         132                 :                                         i != record.end(); i++)
         133             328 :                                 if (i->first != "Facet")
         134             240 :                                         facet[i->first] = i->second;
         135                 :                 }
         136            1865 :                 else if (ti != record.end())
         137                 :                 {
         138                 :                         // Get the tag record
         139            1865 :                         TagData& tag = obtainTag(ti->second);
         140                 :                         //fprintf(stderr, "Read tag@%d %.*s\n", parser.lineNumber(), PFSTR(tag.name));
         141                 :                         //assert(tag.name == ti->second);
         142                 :
         143                 :                         // Merge the data
         144            5796 :                         for (DebDBParser::Record::const_iterator i = record.begin();
         145                 :                                         i != record.end(); i++)
         146            3931 :                                 if (i->first != "Tag")
         147            2066 :                                         tag[i->first] = i->second;
         148                 :                 }
         149                 :                 else
         150                 :                 {
         151                 :                         fprintf(stderr, "%s:%d: Skipping record without Tag or Facet field\n",
         152               0 :                                         input.fileName().c_str(), input.lineNumber());
         153                 :                 }
         154               7 :         }
         155               7 : }
         156                 :
         157               0 : bool VocabularyMerger::hasTag(const std::string& fullname) const
         158                 : {
         159               0 :         size_t p = fullname.find("::");
         160               0 :         std::string facetName;
         161               0 :         std::string tagName;
         162               0 :         if (p == string::npos)
         163                 :         {
         164               0 :                 facetName = "legacy";
         165               0 :                 tagName = fullname;
         166                 :         } else {
         167               0 :                 facetName = fullname.substr(0, p);
         168               0 :                 tagName = fullname.substr(p + 2);
         169                 :         }
         170                 :
         171               0 :         std::map<std::string, FacetData>::const_iterator i = facets.find(facetName);
         172               0 :         if (i == facets.end())
         173               0 :                 return false;
         174               0 :         return i->second.tags.find(tagName) != i->second.tags.end();
         175                 : }
         176                 :
         177               0 : int VocabularyMerger::tagID(const std::string& fullname) const
         178                 : {
         179               0 :         size_t p = fullname.find("::");
         180               0 :         std::string facetName;
         181               0 :         std::string tagName;
         182               0 :         if (p == string::npos)
         183                 :         {
         184               0 :                 facetName = "legacy";
         185               0 :                 tagName = fullname;
         186                 :         } else {
         187               0 :                 facetName = fullname.substr(0, p);
         188               0 :                 tagName = fullname.substr(p + 2);
         189                 :         }
         190                 :
         191               0 :         std::map<std::string, FacetData>::const_iterator i = facets.find(facetName);
         192               0 :         if (i == facets.end())
         193               0 :                 return -1;
         194               0 :         std::map<std::string, TagData>::const_iterator j = i->second.tags.find(tagName);
         195               0 :         if (j == i->second.tags.end())
         196               0 :                 return -1;
         197               0 :         return j->second.id;
         198                 : }
         199                 :
         200               1 : std::set<std::string> VocabularyMerger::tagNames() const
         201                 : {
         202               1 :         set<string> res;
         203              30 :         for (std::map<std::string, FacetData>::const_iterator f = facets.begin(); f != facets.end(); f++)
         204             649 :                 for (std::map<std::string, TagData>::const_iterator t = f->second.tags.begin();
         205                 :                                 t != f->second.tags.end(); t++)
         206             620 :                         res.insert(f->first + "::" + t->first);
         207               0 :         return res;
         208                 : }
         209                 :
         210               4 : void VocabularyMerger::write(const std::string& fname)
         211                 : {
         212               4 :         FILE* out = fopen(fname.c_str(), "wt");
         213               4 :         if (!out)
         214               0 :                 throw wibble::exception::File(fname, "cept_debtags_vocabularymerger:reating file ");
         215               4 :         write(out);
         216               4 :         fclose(out);
         217               4 : }
         218                 :
         219               4 : void VocabularyMerger::write(FILE* out)
         220                 : {
         221               4 :         long start_ofs = ftell(out);
         222               4 :         int facetid = 0;
         223               4 :         int tagid = 0;
         224                 :
         225                 :         //fprintf(stderr, "Write\n");
         226              37 :         for (std::map<std::string, FacetData>::iterator f = facets.begin(); f != facets.end(); f++)
         227                 :         {
         228              33 :                 f->second.id = facetid++;
         229                 :                 //fprintf(stderr, "Writing facet %.*s\n", PFSTR(f->first));
         230              33 :                 f->second.ofs = ftell(out) - start_ofs;
         231              33 :                 writeDebStyleField(out, "Facet", f->first);
         232             115 :                 for (std::map<std::string, std::string>::const_iterator j = f->second.begin();
         233                 :                                 j != f->second.end(); j++)
         234              82 :                         writeDebStyleField(out, j->first, j->second);
         235              33 :                 fputc('\n', out);
         236              33 :                 f->second.len = ftell(out) - f->second.ofs;
         237                 :
         238             658 :                 for (std::map<std::string, TagData>::iterator t = f->second.tags.begin();
         239                 :                                 t != f->second.tags.end(); t++)
         240                 :                 {
         241             625 :                         t->second.id = tagid++;
         242                 :                         //fprintf(stderr, "Writing tag %.*s\n", PFSTR(t->first));
         243             625 :                         t->second.ofs = ftell(out) - start_ofs;
         244             625 :                         writeDebStyleField(out, "Tag", f->first + "::" + t->first);
         245            1317 :                         for (std::map<std::string, std::string>::const_iterator j = t->second.begin();
         246                 :                                         j != t->second.end(); j++)
         247             692 :                                 writeDebStyleField(out, j->first, j->second);
         248             625 :                         fputc('\n', out);
         249             625 :                         t->second.len = ftell(out) - t->second.ofs;
         250                 :                 }
         251                 :         }
         252                 :
         253               4 :         tagCount = tagid;
         254               4 : }
         255                 :
         256                 :
         257               4 : int VocabularyMerger::FacetIndexer::encodedSize() const
         258                 : {
         259                 :         // First the main offset table
         260               4 :         int size = vm.facets.size() * sizeof(int);
         261                 :
         262              37 :         for (std::map<std::string, FacetData>::const_iterator f = vm.facets.begin(); f != vm.facets.end(); f++)
         263                 :         {
         264                 :                 // offset of record in vocabulary
         265                 :                 // size of record in vocabulary
         266                 :                 // id of first tag
         267                 :                 // id of last tag
         268                 :                 // name (0-terminated)
         269              33 :                 size += 4 * sizeof(int) + f->first.size() + 1;
         270                 :
         271                 :                 // Align to int boundaries
         272              33 :                 if ((size % sizeof(int)) != 0)
         273              25 :                         size = (size + sizeof(int)) / sizeof(int) * sizeof(int);
         274                 :         }
         275                 :
         276               4 :         return tagcoll::diskindex::MMap::align(size);
         277                 : }
         278                 :
         279               4 : void VocabularyMerger::FacetIndexer::encode(char* buf) const
         280                 : {
         281               4 :         int pos = vm.facets.size() * sizeof(int);
         282                 :
         283              37 :         for (std::map<std::string, FacetData>::const_iterator f = vm.facets.begin(); f != vm.facets.end(); f++)
         284                 :         {
         285              33 :                 ((int*)buf)[f->second.id] = pos;
         286                 :
         287                 :                 // offset of record in vocabulary
         288              33 :                 *(int*)(buf+pos) = f->second.ofs;
         289              33 :                 pos += sizeof(int);
         290                 :
         291                 :                 // size of record in vocabulary
         292              33 :                 *(int*)(buf+pos) = f->second.len;
         293              33 :                 pos += sizeof(int);
         294                 :
         295              33 :                 if (f->second.tags.empty())
         296                 :                 {
         297                 :                         // id of first tag
         298               1 :                         *(int*)(buf+pos) = -1;
         299               1 :                         pos += sizeof(int);
         300                 :
         301                 :                         // id of last tag
         302               1 :                         *(int*)(buf+pos) = -1;
         303               1 :                         pos += sizeof(int);
         304                 :                 } else {
         305                 :                         // id of first tag
         306              32 :                         *(int*)(buf+pos) = f->second.tags.begin()->second.id;
         307              32 :                         pos += sizeof(int);
         308                 :
         309                 :                         // id of last tag
         310              32 :                         *(int*)(buf+pos) = f->second.tags.rbegin()->second.id;
         311              32 :                         pos += sizeof(int);
         312                 :                 }
         313                 :
         314                 :                 // name (0-terminated)
         315              33 :                 memcpy(buf + pos, f->first.c_str(), f->first.size() + 1);
         316              33 :                 pos += f->first.size() + 1;
         317                 :
         318                 :                 // Align to int boundaries
         319              33 :                 if ((pos % sizeof(int)) != 0)
         320              25 :                         pos = (pos + sizeof(int)) / sizeof(int) * sizeof(int);
         321                 :         }
         322               4 : }
         323                 :
         324               4 : int VocabularyMerger::TagIndexer::encodedSize() const
         325                 : {
         326                 :         // First the main offset table
         327               4 :         int size = vm.tagCount * sizeof(int);
         328                 :
         329              37 :         for (std::map<std::string, FacetData>::const_iterator f = vm.facets.begin(); f != vm.facets.end(); f++)
         330                 :         {
         331             658 :                 for (std::map<std::string, TagData>::const_iterator t = f->second.tags.begin();
         332                 :                                 t != f->second.tags.end(); t++)
         333                 :                 {
         334                 :                         // offset of record in vocabulary
         335                 :                         // size of record in vocabulary
         336                 :                         // id of facet
         337                 :                         // name (0-terminated)
         338             625 :                         size += 3 * sizeof(int) + f->first.size() + t->first.size() + 3;
         339                 :
         340                 :                         // Align to int boundaries
         341             625 :                         if ((size % sizeof(int)) != 0)
         342             479 :                                 size = (size + sizeof(int)) / sizeof(int) * sizeof(int);
         343                 :                 }
         344                 :         }
         345               4 :         return tagcoll::diskindex::MMap::align(size);
         346                 : }
         347                 :
         348               4 : void VocabularyMerger::TagIndexer::encode(char* buf) const
         349                 : {
         350               4 :         int pos = vm.tagCount * sizeof(int);
         351                 :
         352              37 :         for (std::map<std::string, FacetData>::const_iterator f = vm.facets.begin(); f != vm.facets.end(); f++)
         353                 :         {
         354             658 :                 for (std::map<std::string, TagData>::const_iterator t = f->second.tags.begin();
         355                 :                                 t != f->second.tags.end(); t++)
         356                 :                 {
         357             625 :                         ((int*)buf)[t->second.id] = pos;
         358                 :
         359                 :                         // offset of record in vocabulary
         360             625 :                         *(int*)(buf+pos) = t->second.ofs;
         361             625 :                         pos += sizeof(int);
         362                 :
         363                 :                         // size of record in vocabulary
         364             625 :                         *(int*)(buf+pos) = t->second.len;
         365             625 :                         pos += sizeof(int);
         366                 :
         367                 :                         // id of facet
         368             625 :                         *(int*)(buf+pos) = f->second.id;
         369             625 :                         pos += sizeof(int);
         370                 :
         371                 :                         // name (0-terminated)
         372             625 :                         string name = f->first + "::" + t->first;
         373             625 :                         memcpy(buf + pos, name.c_str(), name.size() + 1);
         374             625 :                         pos += name.size() + 1;
         375                 :
         376                 :                         // Align to int boundaries
         377             625 :                         if ((pos % sizeof(int)) != 0)
         378             479 :                                 pos = (pos + sizeof(int)) / sizeof(int) * sizeof(int);
         379                 :                 }
         380                 :         }
         381               4 : }
         382                 :
         383                 : }
         384               6 : }
         385                 :
         386                 : // vim:set ts=4 sw=4:

Generated by: LTP GCOV extension version 1.6