Andre Poenitz wrote:
On Tue, Jul 31, 2007 at 03:00:34PM -0400, Richard Heck wrote:
Index: src/Buffer.h
===================================================================
--- src/Buffer.h        (revision 19264)
+++ 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"
Why that? Including stuff from frontends/ in src/ is wrong in theory.
Yes, I agree. This is needed, IIRC (I did this a while ago), for certain constants, e.g.: static const docstring TheBibliographyRef(from_ascii("TheBibliographyRef")); which was in frontends/controllers/frontend_helpers.cpp and which I've moved (in effect) to the header.

There is a lot of BibTeX-related stuff in frontends/controllers/. I think most of that should be elsewhere. I think the whole biblio namespace should be moved, probably into src/Biblio.{h,cpp}, or something similar. But I guess I thought I should address this first within the existing structure and save the clean-up for later. If you think I should just do that now, I can do that.
[...]
@@ -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);
No space before [
Thanks.
[...]
-docstring const parseBibTeX(docstring data, std::string const & findkey);
+docstring const getValueForKey(KeyValMap data, std::string const & findkey);
Passing a  std::map<docstring, docstring>  by value seems wrong.
Yes. Made it const &. This required a const_cast, but that seems ok.
        void fillWithBibKeys(Buffer const & buffer,
-               std::vector<std::pair<std::string, docstring> > & keys) const;
+               std::map<std::string, std::map<docstring, docstring> > & keys) 
const;

Maybe a typedef would make this clearer, too.
Done.

Thanks again. Glad someone reads these patches....

Updated patch attached.

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 19264)
+++ 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 19264)
+++ 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 19264)
+++ src/frontends/controllers/frontend_helpers.h	(working copy)
@@ -28,8 +28,18 @@
 
 /** 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"));
+static const docstring TheEntryType(from_ascii("@BibTeXEntryType"));
+
 enum CiteEngine {
 	ENGINE_BASIC,
 	ENGINE_NATBIB_AUTHORYEAR,
@@ -69,34 +79,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 const & 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 +112,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 +152,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 +169,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 19264)
+++ src/frontends/controllers/frontend_helpers.cpp	(working copy)
@@ -5,6 +5,7 @@
  *
  * \author Angus Leeming
  * \author Herbert Voß
+ * \author Richard Heck (improvements of BibTeX stuff)
  *
  * Full author contact details are available in file CREDITS.
  */
@@ -26,9 +27,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 +121,6 @@
 	return str;
 }
 
-
-static const docstring TheBibliographyRef(from_ascii("TheBibliographyRef"));
-
 } // namespace anon
 
 
@@ -200,38 +195,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 +239,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 +277,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,72 +291,69 @@
 }
 
 
-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");
+	//FIXME FIXME FIXME
+	//This could be made alot better using the biblio::TheEntryType
+	//field to customize the output based upon entry type.
+	
+	//Search for all possible "required" fields
+	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");
-	if (media.empty())
-		media = parseBibTeX(data, "publisher");
-	if (media.empty())
-		media = parseBibTeX(data, "school");
-	if (media.empty())
-		media = parseBibTeX(data, "institution");
+	docstring year      = getValueForKey(data, "year");
+	docstring title     = getValueForKey(data, "title");
+	docstring docLoc    = getValueForKey(data, "pages");
+	if (docLoc.empty()) {
+		docLoc = getValueForKey(data, "chapter");
+		if (!docLoc.empty())
+			docLoc = from_ascii("Ch. ") + docLoc;
+	}	else 
+		docLoc = from_ascii("pp. ") + docLoc;
+	docstring media     = getValueForKey(data, "journal");
+	if (media.empty()) {
+		media = getValueForKey(data, "publisher");
+		if (media.empty()) {
+			media = getValueForKey(data, "school");
+			if (media.empty())
+				media = getValueForKey(data, "institution");
+		}
+	}
+	docstring volume = getValueForKey(data, "volume");
 
 	odocstringstream result;
 	if (!author.empty())
 		result << author << ", ";
 	if (!title.empty())
 		result << title;
-	if (!booktitle.empty())
-		result << ", in " << booktitle;
-	if (!chapter.empty())
-		result << ", Ch. " << chapter;
 	if (!media.empty())
 		result << ", " << media;
-	if (!volume.empty())
-		result << ", vol. " << volume;
-	if (!number.empty())
-		result << ", no. " << number;
-	if (!pages.empty())
-		result << ", pp. " << pages;
 	if (!year.empty())
 		result << ", " << year;
-	if (!annote.empty())
-		result << "\n\n" << annote;
+	if (!docLoc.empty())
+		result << ", " << docLoc;
 
 	docstring const result_str = rtrim(result.str());
 	if (!result_str.empty())
 		return result_str;
 
 	// This should never happen (or at least be very unusual!)
-	return data;
+	return docstring();
 }
 
 
@@ -420,24 +390,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 +419,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 +466,14 @@
 }
 
 
-docstring const parseBibTeX(docstring data, string const & findkey)
+docstring const getValueForKey(KeyValMap const & 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);
-			}
-		}
-	}
+	KeyValMap & data2 = const_cast<KeyValMap &>(data);
+	return data2[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 19264)
+++ 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 19264)
+++ 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 19264)
+++ 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 19264)
+++ src/insets/InsetBibtex.cpp	(working copy)
@@ -4,6 +4,7 @@
  * Licence details can be found in the file COPYING.
  *
  * \author Alejandro Aguilar Sierra
+ * \author Richard Heck (BibTeX parser improvements)
  *
  * Full author contact details are available in file CREDITS.
  */
@@ -34,7 +35,6 @@
 
 #include <boost/tokenizer.hpp>
 
-
 namespace lyx {
 
 using support::absolutePath;
@@ -415,13 +415,13 @@
 		bool legalChar = true;
 		while (ifs && !isSpace(ch) && 
 			   delimChars.find(ch) == docstring::npos &&
-			   (legalChar = illegalChars.find(ch) == docstring::npos)
-			   ) {
-			if (chCase == makeLowerCase) {
+			   (legalChar = (illegalChars.find(ch) == docstring::npos))
+			   ) 
+		{
+			if (chCase == makeLowerCase)
 				val += lowercase(ch);
-			} else {
+			else
 				val += ch;
-			}
 			ifs.get(ch);
 		}
 		
@@ -478,19 +478,41 @@
 					return false;
 
 			} else if (ch == '"' || ch == '{') {
+				// set end delimiter
+				char_type delim = ch == '"' ? '"': '}';
 
-				// read delimited text - set end delimiter
-				char_type delim = ch == '"'? '"': '}';
-
+				//Skip whitespace
+				do {
+					ifs.get(ch);
+				} while (ifs && isSpace(ch));
+				
+				if (!ifs)
+					return false;
+				
+				//We now have the first non-whitespace character
+				//We'll collapse adjacent whitespace.
+				bool lastWasWhiteSpace = false;
+				
 				// inside this delimited text braces must match.
 				// Thus we can have a closing delimiter only
 				// when nestLevel == 0
 				int nestLevel = 0;
 
-				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 '{':
@@ -503,7 +525,7 @@
 					}
 
 					ifs.get(ch);
-				}
+				} //end while loop
 
 				if (!ifs)
 					return false;
@@ -554,9 +576,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 +593,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 +601,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());
@@ -658,24 +672,29 @@
 					continue;
 
 			} 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;
+				keyvalmap[biblio::TheEntryType] = entryType;
+				
 				bool readNext = removeWSAndComma(ifs);
 
 				while (ifs && readNext) {
@@ -698,23 +717,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 19264)
+++ 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 19264)
+++ src/insets/InsetInclude.h	(working copy)
@@ -18,6 +18,8 @@
 #include "MailInset.h"
 #include "Counters.h"
 
+#include "frontends/controllers/frontend_helpers.h"
+
 #include "support/FileName.h"
 
 #include <boost/scoped_ptr.hpp>
@@ -57,10 +59,9 @@
 			  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.
-	 */
-	void fillWithBibKeys(Buffer const & buffer,
-		std::vector<std::pair<std::string, docstring> > & keys) const;
+	 *  \param keys the map of bibkeys in the child buffer.
+	 */	
+	void fillWithBibKeys(Buffer const & buffer, biblio::BibKeyList & 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 19264)
+++ 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