Jürgen Spitzmüller wrote:
Jürgen Spitzmüller wrote:
It looks rather complicated, so I'd like to have others review it first.
I had a look at it again. I think this is rather something for 1.5.2. It needs very good testing.
OK. I did a good bit of testing earlier and saw no problems, but I haven't tested it since updating it to current trunk. It's actually less complex than it seems. The improvement lies in our storing the data for the individual BibTeX fields in a std::map rather than one massive string which we then have to parse over and over---this is all in the parser in InsetBibtex.cpp. As a result, though, the signature of certain function calls changes, so there are a lot of very minor changes to function calls. And we can then simplify a lot else, removing the complicated code that attempted to recover the year, author, etc, from the massive string.

In any event, here's an up-to-date patch. Should I commit to trunk at some point so it can be tested there? Once I've done a little more testing here?

Richard

--
==================================================================
Richard G Heck, Jr
Professor of Philosophy
Brown University
http://frege.brown.edu/heck/
==================================================================
Get my public key from http://sks.keyserver.penguin.de
Hash: 0x1DE91F1E66FFBDEC
Learn how to sign your email using Thunderbird and GnuPG at:
http://dudu.dyn.2-h.org/nist/gpg-enigmail-howto

Index: src/Buffer.h
===================================================================
--- src/Buffer.h	(revision 19245)
+++ src/Buffer.h	(working copy)
@@ -13,7 +13,11 @@
 #define BUFFER_H
 
 #include "DocIterator.h"
+#include "ErrorList.h"
+#include "InsetList.h"
 
+#include "frontends/controllers/frontend_helpers.h"
+
 #include "support/FileName.h"
 #include "support/limited_stack.h"
 #include "support/types.h"
@@ -283,7 +287,7 @@
 	void validate(LaTeXFeatures &) const;
 
 	/// return all bibkeys from buffer and its childs
-	void fillWithBibKeys(std::vector<std::pair<std::string, docstring> > & keys) const;
+	void fillWithBibKeys(biblio::BibKeyList & keys) const;
 	/// Update the cache with all bibfiles in use (including bibfiles
 	/// of loaded child documents).
 	void updateBibfilesCache();
Index: src/Buffer.cpp
===================================================================
--- src/Buffer.cpp	(revision 19245)
+++ src/Buffer.cpp	(working copy)
@@ -1333,7 +1333,7 @@
 
 
 // This is also a buffer property (ale)
-void Buffer::fillWithBibKeys(vector<pair<string, docstring> > & keys)
+void Buffer::fillWithBibKeys(biblio::BibKeyList & keys)
 	const
 {
 	/// if this is a child document and the parent is already loaded
@@ -1359,11 +1359,12 @@
 				static_cast<InsetBibitem const &>(*it);
 			// FIXME UNICODE
 			string const key = to_utf8(inset.getParam("key"));
-			docstring const label = inset.getParam("label");
+			biblio::KeyValMap keyvalmap;
+			keyvalmap[from_ascii("label")] = inset.getParam("label");
 			DocIterator doc_it(it); doc_it.forwardPos();
-			docstring const ref = doc_it.paragraph().asString(*this, false);
-			docstring const info = label + "TheBibliographyRef" + ref;
-			keys.push_back(pair<string, docstring>(key, info));
+			keyvalmap [from_ascii("ref")] = doc_it.paragraph().asString(*this, false);
+			keyvalmap[biblio::TheBibliographyRef] = biblio::TheBibliographyRef;
+			keys[key] = keyvalmap;
 		}
 	}
 }
@@ -1725,10 +1726,10 @@
 	vector<docstring> labels;
 
 	if (code == Inset::CITE_CODE) {
-		vector<pair<string, docstring> > keys;
+		biblio::BibKeyList keys;
 		fillWithBibKeys(keys);
-		vector<pair<string, docstring> >::const_iterator bit  = keys.begin();
-		vector<pair<string, docstring> >::const_iterator bend = keys.end();
+		biblio::BibKeyList::const_iterator bit  = keys.begin();
+		biblio::BibKeyList::const_iterator bend = keys.end();
 
 		for (; bit != bend; ++bit)
 			// FIXME UNICODE
Index: src/frontends/controllers/frontend_helpers.h
===================================================================
--- src/frontends/controllers/frontend_helpers.h	(revision 19245)
+++ src/frontends/controllers/frontend_helpers.h	(working copy)
@@ -28,8 +28,17 @@
 
 /** Functions of use to citation and bibtex GUI controllers and views */
 namespace lyx {
+	
 namespace biblio {
+	
+/// First entry is field, second is value
+typedef std::map<docstring, docstring> KeyValMap;
+/// First entry is the bibliography key, second the data
+typedef std::map<std::string, std::map<docstring, docstring> > BibKeyList;
 
+static const docstring TheBibliographyRef(from_ascii("@LyXInfo"));
+static const docstring TheDataString(from_ascii("@BibTeXData"));
+
 enum CiteEngine {
 	ENGINE_BASIC,
 	ENGINE_NATBIB_AUTHORYEAR,
@@ -69,34 +78,31 @@
 std::string const asValidLatexCommand(std::string const & input,
 				      CiteEngine const engine);
 
-/// First entry is the bibliography key, second the data
-typedef std::map<std::string, docstring> InfoMap;
-
 /// Returns a vector of bibliography keys
-std::vector<std::string> const getKeys(InfoMap const &);
+std::vector<std::string> const getKeys(BibKeyList const &);
 
 /** Returns the BibTeX data associated with a given key.
-    Empty if no info exists. */
-docstring const getInfo(InfoMap const &, std::string const & key);
+    Empty if the key was not defined in the BibTeX record. */
+docstring const getInfo(BibKeyList const &, std::string const & key);
 
 /// return the year from the bibtex data record
-docstring const getYear(InfoMap const & map, std::string const & key);
+docstring const getYear(BibKeyList const & map, std::string const & key);
 
 /// return the short form of an authorlist
-docstring const getAbbreviatedAuthor(InfoMap const & map, std::string const & key);
+docstring const getAbbreviatedAuthor(BibKeyList const & map, std::string const & key);
 
 // return only the family name
 docstring const familyName(docstring const & name);
 
 /** Search a BibTeX info field for the given key and return the
     associated field. */
-docstring const parseBibTeX(docstring data, std::string const & findkey);
+docstring const getValueForKey(KeyValMap data, std::string const & findkey);
 
 /** Returns an iterator to the first key that meets the search
     criterion, or end() if unsuccessful.
 
     User supplies :
-    the InfoMap of bibkeys info,
+    the BibKeyList of bibkeys info,
     the vector of keys to be searched,
     the search criterion,
     an iterator defining the starting point of the search,
@@ -105,7 +111,7 @@
 */
 
 std::vector<std::string>::const_iterator
-searchKeys(InfoMap const & map,
+searchKeys(BibKeyList const & map,
 	   std::vector<std::string> const & keys_to_search,
 	   docstring const & search_expression,
 	   std::vector<std::string>::const_iterator start,
@@ -145,12 +151,12 @@
 
    User supplies :
    the key,
-   the InfoMap of bibkeys info,
+   the BibKeyList of bibkeys info,
    the available citation styles
 */
 std::vector<docstring> const
 getNumericalStrings(std::string const & key,
-		    InfoMap const & map,
+		    BibKeyList const & map,
 		    std::vector<CiteStyle> const & styles);
 
 /**
@@ -162,12 +168,12 @@
 
    User supplies :
    the key,
-   the InfoMap of bibkeys info,
+   the BibKeyList of bibkeys info,
    the available citation styles
 */
 std::vector<docstring> const
 getAuthorYearStrings(std::string const & key,
-		     InfoMap const & map,
+		     BibKeyList const & map,
 		     std::vector<CiteStyle> const & styles);
 
 } // namespace biblio
Index: src/frontends/controllers/frontend_helpers.cpp
===================================================================
--- src/frontends/controllers/frontend_helpers.cpp	(revision 19245)
+++ src/frontends/controllers/frontend_helpers.cpp	(working copy)
@@ -26,9 +26,6 @@
 
 #include "support/filetools.h"
 #include "support/lstrings.h"
-#include "support/Package.h"
-#include "support/filetools.h"
-#include "support/lstrings.h"
 #include "support/lyxalgo.h"
 #include "support/os.h"
 #include "support/Package.h"
@@ -123,9 +120,6 @@
 	return str;
 }
 
-
-static const docstring TheBibliographyRef(from_ascii("TheBibliographyRef"));
-
 } // namespace anon
 
 
@@ -200,38 +194,29 @@
 }
 
 
-docstring const getAbbreviatedAuthor(InfoMap const & map, string const & key)
+docstring const getAbbreviatedAuthor(BibKeyList const & map, string const & key)
 {
 	BOOST_ASSERT(!map.empty());
 
-	InfoMap::const_iterator it = map.find(key);
+	BibKeyList::const_iterator it = map.find(key);
 	if (it == map.end())
 		return docstring();
-	docstring const & data = it->second;
+	KeyValMap const & data = it->second;
 
 	// Is the entry a BibTeX one or one from lyx-layout "bibliography"?
-	docstring::size_type const pos = data.find(TheBibliographyRef);
-	if (pos != docstring::npos) {
-		if (pos <= 2) {
-			return docstring();
-		}
+	KeyValMap::const_iterator it2 = data.find(TheBibliographyRef);
+	if (it2 != data.end()) 
+		// We don't have any way to tell how the author names might have
+		// been formatted.
+		return docstring();
 
-		docstring const opt = trim(data.substr(0, pos - 1));
-		if (opt.empty())
-			return docstring();
+	docstring author = getValueForKey(data, "author");
 
-		docstring authors;
-		split(opt, authors, '(');
-		return authors;
-	}
-
-	docstring author = parseBibTeX(data, "author");
-
 	if (author.empty())
-		author = parseBibTeX(data, "editor");
+		author = getValueForKey(data, "editor");
 
 	if (author.empty()) {
-		author = parseBibTeX(data, "key");
+		author = getValueForKey(data, "key");
 		if (author.empty())
 			// FIXME UNICODE
 			return from_utf8(key);
@@ -253,36 +238,23 @@
 }
 
 
-docstring const getYear(InfoMap const & map, string const & key)
+docstring const getYear(BibKeyList const & map, string const & key)
 {
 	BOOST_ASSERT(!map.empty());
 
-	InfoMap::const_iterator it = map.find(key);
+	BibKeyList::const_iterator it = map.find(key);
 	if (it == map.end())
 		return docstring();
-	docstring const & data = it->second;
+	KeyValMap const & data = it->second;
 
 	// Is the entry a BibTeX one or one from lyx-layout "bibliography"?
-	docstring::size_type const pos = data.find(TheBibliographyRef);
-	if (pos != docstring::npos) {
-		if (pos <= 2) {
-			return docstring();
-		}
+	KeyValMap::const_iterator it2 = data.find(TheBibliographyRef);
+	if (it2 != data.end()) 
+		// We don't have any way to tell how the entry might have
+		// been formatted.
+		return docstring();
 
-		docstring const opt =
-			trim(data.substr(0, pos - 1));
-		if (opt.empty())
-			return docstring();
-
-		docstring authors;
-		docstring const tmp = split(opt, authors, '(');
-		docstring year;
-		split(tmp, year, ')');
-		return year;
-
-	}
-
-	docstring year = parseBibTeX(data, "year");
+	docstring year = getValueForKey(data, "year");
 	if (year.empty())
 		year = _("No year");
 
@@ -304,11 +276,11 @@
 } // namespace anon
 
 
-vector<string> const getKeys(InfoMap const & map)
+vector<string> const getKeys(BibKeyList const & map)
 {
 	vector<string> bibkeys;
-	InfoMap::const_iterator it  = map.begin();
-	InfoMap::const_iterator end = map.end();
+	BibKeyList::const_iterator it  = map.begin();
+	BibKeyList::const_iterator end = map.end();
 	for (; it != end; ++it) {
 		bibkeys.push_back(it->first);
 	}
@@ -318,43 +290,42 @@
 }
 
 
-docstring const getInfo(InfoMap const & map, string const & key)
+docstring const getInfo(BibKeyList const & map, string const & key)
 {
 	BOOST_ASSERT(!map.empty());
 
-	InfoMap::const_iterator it = map.find(key);
+	BibKeyList::const_iterator it = map.find(key);
 	if (it == map.end())
 		return docstring();
-	docstring const & data = it->second;
+	KeyValMap const & data = it->second;
 
-	// is the entry a BibTeX one or one from lyx-layout "bibliography"?
-	docstring::size_type const pos = data.find(TheBibliographyRef);
-	if (pos != docstring::npos) {
-		docstring::size_type const pos2 = pos + TheBibliographyRef.size();
-		docstring const info = trim(data.substr(pos2));
-		return info;
+	// Is the entry a BibTeX one or one from lyx-layout "bibliography"?
+	KeyValMap::const_iterator it2 = data.find(TheBibliographyRef);
+	if (it2 != data.end()) {
+		KeyValMap::const_iterator it3 = data.find(from_ascii("ref"));
+		return it3->second;
 	}
 
 	// Search for all possible "required" keys
-	docstring author = parseBibTeX(data, "author");
+	docstring author = getValueForKey(data, "author");
 	if (author.empty())
-		author = parseBibTeX(data, "editor");
+		author = getValueForKey(data, "editor");
 
-	docstring year      = parseBibTeX(data, "year");
-	docstring title     = parseBibTeX(data, "title");
-	docstring booktitle = parseBibTeX(data, "booktitle");
-	docstring chapter   = parseBibTeX(data, "chapter");
-	docstring number    = parseBibTeX(data, "number");
-	docstring volume    = parseBibTeX(data, "volume");
-	docstring pages     = parseBibTeX(data, "pages");
-	docstring annote    = parseBibTeX(data, "annote");
-	docstring media     = parseBibTeX(data, "journal");
+	docstring year      = getValueForKey(data, "year");
+	docstring title     = getValueForKey(data, "title");
+	docstring booktitle = getValueForKey(data, "booktitle");
+	docstring chapter   = getValueForKey(data, "chapter");
+	docstring number    = getValueForKey(data, "number");
+	docstring volume    = getValueForKey(data, "volume");
+	docstring pages     = getValueForKey(data, "pages");
+	docstring annote    = getValueForKey(data, "annote");
+	docstring media     = getValueForKey(data, "journal");
 	if (media.empty())
-		media = parseBibTeX(data, "publisher");
+		media = getValueForKey(data, "publisher");
 	if (media.empty())
-		media = parseBibTeX(data, "school");
+		media = getValueForKey(data, "school");
 	if (media.empty())
-		media = parseBibTeX(data, "institution");
+		media = getValueForKey(data, "institution");
 
 	odocstringstream result;
 	if (!author.empty())
@@ -383,7 +354,7 @@
 		return result_str;
 
 	// This should never happen (or at least be very unusual!)
-	return data;
+	return docstring();
 }
 
 
@@ -420,24 +391,28 @@
 public:
 	// re and icase are used to construct an instance of boost::RegEx.
 	// if icase is true, then matching is insensitive to case
-	RegexMatch(InfoMap const & m, string const & re, bool icase)
+	RegexMatch(BibKeyList const & m, string const & re, bool icase)
 		: map_(m), regex_(re, icase) {}
 
+	//FIXME This should probably be restored to its earlier behavior
 	bool operator()(string const & key) const {
-		// the data searched is the key + its associated BibTeX/biblio
-		// fields
-		string data = key;
-		InfoMap::const_iterator info = map_.find(key);
-		if (info != map_.end())
+		BibKeyList::const_iterator info = map_.find(key);
+ 		if (info == map_.end())
+ 			return false;
+ 
+ 		string data = key;
+		//The machinations here are required because map::operator[] 
+		//has no const version.
+		KeyValMap const kvm = info->second;
+		KeyValMap::const_iterator it = kvm.find(TheDataString);
+		if (it != kvm.end())
 			// FIXME UNICODE
-			data += ' ' + to_utf8(info->second);
-
-		// Attempts to find a match for the current RE
-		// somewhere in data.
+			data += ' ' + to_utf8(it->second);
+ 
 		return boost::regex_search(data, regex_);
 	}
 private:
-	InfoMap const map_;
+	BibKeyList const map_;
 	mutable boost::regex regex_;
 };
 
@@ -445,7 +420,7 @@
 
 
 vector<string>::const_iterator
-searchKeys(InfoMap const & theMap,
+searchKeys(BibKeyList const & theMap,
 	   vector<string> const & keys,
 	   string const & search_expr,
 	   vector<string>::const_iterator start,
@@ -492,142 +467,13 @@
 }
 
 
-docstring const parseBibTeX(docstring data, string const & findkey)
+docstring const getValueForKey(KeyValMap data, string const & findkey)
 {
-	// at first we delete all characters right of '%' and
-	// replace tabs through a space and remove leading spaces
-	// we read the data line by line so that the \n are
-	// ignored, too.
-	docstring data_;
-	int Entries = 0;
-	docstring dummy = token(data,'\n', Entries);
-	while (!dummy.empty()) {
-		// no tabs
-		dummy = subst(dummy, '\t', ' ');
-		// no leading spaces
-		dummy = ltrim(dummy);
-		// ignore lines with a beginning '%' or ignore all right of %
-		docstring::size_type const idx =
-			dummy.empty() ? docstring::npos : dummy.find('%');
-		if (idx != docstring::npos)
-			// Check if this is really a comment or just "\%"
-			if (idx == 0 || dummy[idx - 1] != '\\')
-				dummy.erase(idx, docstring::npos);
-			else
-				//  This is "\%", so just erase the '\'
-				dummy.erase(idx - 1, 1);
-		// do we have a new token or a new line of
-		// the same one? In the first case we ignore
-		// the \n and in the second we replace it
-		// with a space
-		if (!dummy.empty()) {
-			if (!contains(dummy, '='))
-				data_ += ' ' + dummy;
-			else
-				data_ += dummy;
-		}
-		dummy = token(data, '\n', ++Entries);
-	}
-
-	// replace double commas with "" for easy scanning
-	data = subst(data_, from_ascii(",,"), from_ascii("\"\""));
-
-	// unlikely!
-	if (data.empty())
+	docstring key = from_ascii(findkey);
+	KeyValMap::const_iterator it = data.find(key);
+	if (it == data.end())
 		return docstring();
-
-	// now get only the important line of the bibtex entry.
-	// all entries are devided by ',' except the last one.
-	data += ',';
-	// now we have same behaviour for all entries because the last one
-	// is "blah ... }"
-	Entries = 0;
-	bool found = false;
-	// parsing of title and booktitle is different from the
-	// others, because booktitle contains title
-	do {
-		dummy = token(data, ',', Entries++);
-		if (!dummy.empty()) {
-			found = contains(ascii_lowercase(dummy), from_ascii(findkey));
-			if (findkey == "title" &&
-			    contains(ascii_lowercase(dummy), from_ascii("booktitle")))
-				found = false;
-		}
-	} while (!found && !dummy.empty());
-	if (dummy.empty())
-		// no such keyword
-		return docstring();
-
-	// we are not sure, if we get all, because "key= "blah, blah" is
-	// allowed.
-	// Therefore we read all until the next "=" character, which follows a
-	// new keyword
-	docstring keyvalue = dummy;
-	dummy = token(data, ',', Entries++);
-	while (!contains(dummy, '=') && !dummy.empty()) {
-		keyvalue += ',' + dummy;
-		dummy = token(data, ',', Entries++);
-	}
-
-	// replace double "" with originals ,, (two commas)
-	// leaving us with the all-important line
-	data = subst(keyvalue, from_ascii("\"\""), from_ascii(",,"));
-
-	// Clean-up.
-	// 1. Spaces
-	data = rtrim(data);
-	// 2. if there is no opening '{' then a closing '{' is probably cruft.
-	if (!contains(data, '{'))
-		data = rtrim(data, "}");
-	// happens, when last keyword
-	docstring::size_type const idx =
-		!data.empty() ? data.find('=') : docstring::npos;
-
-	if (idx == docstring::npos)
-		return docstring();
-
-	data = trim(data.substr(idx));
-
-	// a valid entry?
-	if (data.length() < 2 || data[0] != '=')
-		return docstring();
-	else {
-		// delete '=' and the following spaces
-		data = ltrim(data, " =");
-		if (data.length() < 2) {
-			// not long enough to find delimiters
-			return data;
-		} else {
-			docstring::size_type keypos = 1;
-			char_type enclosing;
-			if (data[0] == '{') {
-				enclosing = '}';
-			} else if (data[0] == '"') {
-				enclosing = '"';
-			} else {
-				// no {} and no "", pure data but with a
-				// possible ',' at the end
-				return rtrim(data, ",");
-			}
-			docstring tmp = data.substr(keypos);
-			while (tmp.find('{') != docstring::npos &&
-			       tmp.find('}') != docstring::npos &&
-			       tmp.find('{') < tmp.find('}') &&
-			       tmp.find('{') < tmp.find(enclosing)) {
-
-				keypos += tmp.find('{') + 1;
-				tmp = data.substr(keypos);
-				keypos += tmp.find('}') + 1;
-				tmp = data.substr(keypos);
-			}
-			if (tmp.find(enclosing) == docstring::npos)
-				return data;
-			else {
-				keypos += tmp.find(enclosing);
-				return data.substr(1, keypos - 1);
-			}
-		}
-	}
+	return data[key];
 }
 
 
@@ -745,7 +591,7 @@
 
 vector<docstring> const
 getNumericalStrings(string const & key,
-		    InfoMap const & map, vector<CiteStyle> const & styles)
+		    BibKeyList const & map, vector<CiteStyle> const & styles)
 {
 	if (map.empty())
 		return vector<docstring>();
@@ -799,7 +645,7 @@
 
 vector<docstring> const
 getAuthorYearStrings(string const & key,
-		    InfoMap const & map, vector<CiteStyle> const & styles)
+		    BibKeyList const & map, vector<CiteStyle> const & styles)
 {
 	if (map.empty())
 		return vector<docstring>();
Index: src/frontends/controllers/ControlCitation.h
===================================================================
--- src/frontends/controllers/ControlCitation.h	(revision 19245)
+++ src/frontends/controllers/ControlCitation.h	(working copy)
@@ -63,7 +63,7 @@
 	}
 private:
 	/// The info associated with each key
-	biblio::InfoMap bibkeysInfo_;
+	biblio::BibKeyList bibkeysInfo_;
 
 	///
 	static std::vector<biblio::CiteStyle> citeStyles_;
Index: src/frontends/controllers/ControlCitation.cpp
===================================================================
--- src/frontends/controllers/ControlCitation.cpp	(revision 19245)
+++ src/frontends/controllers/ControlCitation.cpp	(working copy)
@@ -12,6 +12,7 @@
 #include <config.h>
 
 #include "ControlCitation.h"
+#include "frontend_helpers.h"
 
 #include "Buffer.h"
 #include "BufferParams.h"
@@ -48,12 +49,8 @@
 
 	bool use_styles = engine != biblio::ENGINE_BASIC;
 
-	vector<pair<string, docstring> > blist;
-	kernel().buffer().fillWithBibKeys(blist);
-	bibkeysInfo_.clear();
-	for (size_t i = 0; i < blist.size(); ++i)
-		bibkeysInfo_[blist[i].first] = blist[i].second;
-
+	kernel().buffer().fillWithBibKeys(bibkeysInfo_);
+	
 	if (citeStyles_.empty())
 		citeStyles_ = biblio::getCiteStyles(engine);
 	else {
@@ -137,23 +134,21 @@
 		// it is treated as a simple string by boost::regex.
 		expr = escape_special_chars(expr);
 
-	boost::regex reg_exp(to_utf8(expr), case_sensitive?
+	boost::regex reg_exp(to_utf8(expr), case_sensitive ?
 		boost::regex_constants::normal : boost::regex_constants::icase);
 
 	vector<string>::const_iterator it = keys_to_search.begin();
 	vector<string>::const_iterator end = keys_to_search.end();
 	for (; it != end; ++it ) {
-		biblio::InfoMap::const_iterator info = bibkeysInfo_.find(*it);
+		biblio::BibKeyList::iterator info = bibkeysInfo_.find(*it);
 		if (info == bibkeysInfo_.end())
 			continue;
 
 		string data = *it;
 		// FIXME UNICODE
-		data += ' ' + to_utf8(info->second);
+		data += ' ' + to_utf8((info->second)[biblio::TheDataString]);
 
 		try {
-			// Attempts to find a match for the current RE
-			// somewhere in data.
 			if (boost::regex_search(data, reg_exp))
 				foundKeys.push_back(*it);
 		}
Index: src/insets/InsetBibtex.h
===================================================================
--- src/insets/InsetBibtex.h	(revision 19245)
+++ src/insets/InsetBibtex.h	(working copy)
@@ -13,8 +13,9 @@
 #define INSET_BIBTEX_H
 
 
-#include <vector>
+#include <map>
 #include "InsetCommand.h"
+#include "frontends/controllers/frontend_helpers.h"
 
 #include "support/FileName.h"
 
@@ -38,8 +39,7 @@
 	///
 	int latex(Buffer const &, odocstream &, OutputParams const &) const;
 	///
-	void fillWithBibKeys(Buffer const & buffer,
-		std::vector<std::pair<std::string, docstring> > & keys) const;
+	void fillWithBibKeys(Buffer const & buffer, biblio::BibKeyList & keys) const;
 	///
 	std::vector<support::FileName> const getFiles(Buffer const &) const;
 	///
Index: src/insets/InsetBibtex.cpp
===================================================================
--- src/insets/InsetBibtex.cpp	(revision 19245)
+++ src/insets/InsetBibtex.cpp	(working copy)
@@ -34,7 +34,6 @@
 
 #include <boost/tokenizer.hpp>
 
-
 namespace lyx {
 
 using support::absolutePath;
@@ -478,6 +477,9 @@
 					return false;
 
 			} else if (ch == '"' || ch == '{') {
+				//Skip whitespace?
+				//while (ifs && isSpace(ch)) 
+				//	ifs.get(ch);
 
 				// read delimited text - set end delimiter
 				char_type delim = ch == '"'? '"': '}';
@@ -487,10 +489,25 @@
 				// when nestLevel == 0
 				int nestLevel = 0;
 
+				//We'll collapse adjacent whitespace.
+				bool lastWasWhiteSpace = isSpace(ch);
+				
 				ifs.get(ch);
 				while (ifs && (nestLevel > 0 || ch != delim)) {
+					if (isSpace(ch)) {
+						lastWasWhiteSpace = true;
+						ifs.get(ch);
+						continue;
+					} 
+					//We output the space only after we stop getting 
+					//whitespace so as not to output any whitespace
+					//at the end of the value.
+					if (lastWasWhiteSpace) {
+						lastWasWhiteSpace = false;
+						val += ' ';
+					}
+					
 					val += ch;
-
 					// update nesting level
 					switch (ch) {
 						case '{':
@@ -554,9 +571,9 @@
 }
 
 
-// This method returns a comma separated list of Bibtex entries
+// This method returns a map of Bibtex entries
 void InsetBibtex::fillWithBibKeys(Buffer const & buffer,
-		std::vector<std::pair<string, docstring> > & keys) const
+		biblio::BibKeyList & keys) const
 {
 	vector<FileName> const files = getFiles(buffer);
 	for (vector<FileName>::const_iterator it = files.begin();
@@ -571,15 +588,6 @@
 		//   field values.
 		// - it accepts more characters in keys or value names than
 		//   bibtex does.
-		//
-		// TODOS:
-		// - the entries are split into name = value pairs by the
-		//   parser. These have to be merged again because of the
-		//   way lyx treats the entries ( pair<...>(...) ). The citation
-		//   mechanism in lyx should be changed such that it can use
-		//   the split entries.
-		// - messages on parsing errors can be generated.
-		//
 
 		// Officially bibtex does only support ASCII, but in practice
 		// you can use the encoding of the main document as long as
@@ -588,6 +596,7 @@
 		// We don't restrict keys to ASCII in LyX, since our own
 		// InsetBibitem can generate non-ASCII keys, and nonstandard
 		// 8bit clean bibtex forks exist.
+		
 		idocfstream ifs(it->toFilesystemEncoding().c_str(),
 				std::ios_base::in,
 				buffer.params().encoding().iconvName());
@@ -659,23 +668,28 @@
 
 			} else {
 
-				// Citation entry. Read the key and all name = value pairs
+				// Citation entry. Try to read the key.
 				docstring key;
-				docstring fields;
-				docstring name;
-				docstring value;
-				docstring commaNewline;
 
 				if (!readTypeOrKey(key, ifs, from_ascii(","), 
 				                   from_ascii("}"), keepCase) || !ifs)
 					continue;
 
-				// now we have a key, so we will add an entry
+				/////////////////////////////////////////////
+				// now we have a key, so we will add an entry 
 				// (even if it's empty, as bibtex does)
 				//
+				// we now read the field = value pairs.
 				// all items must be separated by a comma. If
 				// it is missing the scanning of this entry is
 				// stopped and the next is searched.
+				docstring fields;
+				docstring name;
+				docstring value;
+				docstring commaNewline;
+				docstring data;
+				biblio::KeyValMap keyvalmap;
+				
 				bool readNext = removeWSAndComma(ifs);
 
 				while (ifs && readNext) {
@@ -698,23 +712,15 @@
 					if (!readValue(value, ifs, strings))
 						break;
 
-					// append field to the total entry string.
-					//
-					// TODO: Here is where the fields can be put in
-					//       a more intelligent structure that preserves
-					//	     the already known parts.
-					fields += commaNewline;
-					fields += name + from_ascii(" = {") + value + '}';
-
-					if (!commaNewline.length())
-						commaNewline = from_ascii(",\n");
-
+					keyvalmap[name] = value;
+					data += "\n\n" + value;
+					
 					readNext = removeWSAndComma(ifs);
 				}
 
 				// add the new entry
-				keys.push_back(pair<string, docstring>(
-				to_utf8(key), fields));
+				keyvalmap[biblio::TheDataString] = data;
+				keys[to_utf8(key)] = keyvalmap;
 			}
 
 		} //< searching '@'
Index: src/insets/InsetCitation.cpp
===================================================================
--- src/insets/InsetCitation.cpp	(revision 19245)
+++ src/insets/InsetCitation.cpp	(working copy)
@@ -65,13 +65,13 @@
 		return docstring();
 
 	// Cache the labels
-	typedef std::map<Buffer const *, biblio::InfoMap> CachedMap;
+	typedef std::map<Buffer const *, biblio::BibKeyList> CachedMap;
 	static CachedMap cached_keys;
 
 	// and cache the timestamp of the bibliography files.
 	static std::map<FileName, time_t> bibfileStatus;
 
-	biblio::InfoMap infomap;
+	biblio::BibKeyList infomap;
 
 	vector<FileName> const & bibfilesCache = buffer.getBibfilesCache();
 	// compare the cached timestamps with the actual ones.
@@ -97,16 +97,7 @@
 
 	// build the keylist only if the bibfiles have been changed
 	if (cached_keys[&buffer].empty() || bibfileStatus.empty() || changed) {
-		typedef vector<std::pair<string, docstring> > InfoType;
-		InfoType bibkeys;
-		buffer.fillWithBibKeys(bibkeys);
-
-		InfoType::const_iterator bit  = bibkeys.begin();
-		InfoType::const_iterator bend = bibkeys.end();
-
-		for (; bit != bend; ++bit)
-			infomap[bit->first] = bit->second;
-
+		buffer.fillWithBibKeys(infomap);
 		cached_keys[&buffer] = infomap;
 	} else
 		// use the cached keys
Index: src/insets/InsetInclude.h
===================================================================
--- src/insets/InsetInclude.h	(revision 19245)
+++ src/insets/InsetInclude.h	(working copy)
@@ -57,10 +57,11 @@
 			  std::vector<docstring> & list) const;
 	/** Fills \c keys
 	 *  \param buffer the Buffer containing this inset.
-	 *  \param keys the list of bibkeys in the child buffer.
-	 */
+	 *  \param keys the map of bibkeys in the child buffer.
+	 */	
+
 	void fillWithBibKeys(Buffer const & buffer,
-		std::vector<std::pair<std::string, docstring> > & keys) const;
+		std::map<std::string, std::map<docstring, docstring> > & keys) const;
 	/** Update the cache with all bibfiles in use of the child buffer
 	 *  (including bibfiles of grandchild documents).
 	 *  Does nothing if the child document is not loaded to prevent
Index: src/insets/InsetInclude.cpp
===================================================================
--- src/insets/InsetInclude.cpp	(revision 19245)
+++ src/insets/InsetInclude.cpp	(working copy)
@@ -736,7 +736,7 @@
 
 
 void InsetInclude::fillWithBibKeys(Buffer const & buffer,
-		std::vector<std::pair<string, docstring> > & keys) const
+		std::map<std::string, std::map<docstring, docstring> > & keys) const
 {
 	if (loadIfNeeded(buffer, params_)) {
 		string const included_file = includedFilename(buffer, params_).absFilename();

Reply via email to