From 820a7e8172284983f5f6378c4c7b93b2e1d1a3f1 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Mon, 2 Dec 2019 22:03:07 +0100 Subject: [PATCH 01/18] Modernize code of TestVM --- src/main/java/org/jabref/logic/bst/VM.java | 6 +- .../java/org/jabref/logic/bst/TestVM.java | 195 ++++++++---------- 2 files changed, 82 insertions(+), 119 deletions(-) diff --git a/src/main/java/org/jabref/logic/bst/VM.java b/src/main/java/org/jabref/logic/bst/VM.java index 79a745761a1..b9349a4a0ae 100644 --- a/src/main/java/org/jabref/logic/bst/VM.java +++ b/src/main/java/org/jabref/logic/bst/VM.java @@ -32,14 +32,13 @@ /** * - * A Bibtex Virtual machine that can execute .bst files. + * A BibTeX Virtual machine that can execute .bst files. * * Documentation can be found in the original bibtex distribution: * * https://www.ctan.org/pkg/bibtex * */ - public class VM implements Warn { public static final Integer FALSE = 0; @@ -74,7 +73,6 @@ public static class Identifier { public final String name; - public Identifier(String name) { this.name = name; } @@ -88,7 +86,6 @@ public static class Variable { public final String name; - public Variable(String name) { this.name = name; } @@ -103,7 +100,6 @@ public interface BstFunction { void execute(BstEntry context); } - public VM(File f) throws RecognitionException, IOException { this(new ANTLRFileStream(f.getPath())); this.file = f; diff --git a/src/test/java/org/jabref/logic/bst/TestVM.java b/src/test/java/org/jabref/logic/bst/TestVM.java index 54bf2f0b7c1..35d42d7e217 100644 --- a/src/test/java/org/jabref/logic/bst/TestVM.java +++ b/src/test/java/org/jabref/logic/bst/TestVM.java @@ -3,8 +3,8 @@ import java.io.File; import java.io.IOException; import java.io.StringReader; -import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Optional; @@ -21,8 +21,8 @@ import org.mockito.Answers; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.Mockito.mock; public class TestVM { @@ -30,8 +30,7 @@ public class TestVM { @Test public void testAbbrv() throws RecognitionException, IOException { VM vm = new VM(new File("src/test/resources/org/jabref/logic/bst/abbrv.bst")); - List v = new ArrayList<>(); - v.add(t1BibtexEntry()); + List v = List.of(t1BibtexEntry()); String expected = "\\begin{thebibliography}{1}\\bibitem{canh05}K.~Crowston, H.~Annabi, J.~Howison, and C.~Masango.\\newblock Effective work practices for floss development: A model and propositions.\\newblock In {\\em Hawaii International Conference On System Sciences (HICSS)}, 2005.\\end{thebibliography}"; @@ -48,8 +47,7 @@ public void testVMSimple() throws RecognitionException, IOException { + " #1 'mid.sentence := #2 'after.sentence := #3 'after.block := } " + "STRINGS { s t } " + "READ"); - List v = new ArrayList<>(); - v.add(t1BibtexEntry()); + List v = List.of(t1BibtexEntry()); vm.run(v); @@ -62,13 +60,11 @@ public void testVMSimple() throws RecognitionException, IOException { @Test public void testLabel() throws RecognitionException, IOException { - VM vm = new VM("ENTRY { title } {} { label } " + "FUNCTION { test } { label #0 = title 'label := #5 label #6 pop$ } " + "READ " + "ITERATE { test }"); - List v = new ArrayList<>(); - v.add(t1BibtexEntry()); + List v = List.of(t1BibtexEntry()); vm.run(v); @@ -79,22 +75,17 @@ public void testLabel() throws RecognitionException, IOException { @Test public void testQuote() throws RecognitionException { - VM vm = new VM("FUNCTION {a}{ quote$ quote$ * } EXECUTE {a}"); - List v = new ArrayList<>(); - vm.run(v); - + vm.run(Collections.emptyList()); assertEquals("\"\"", vm.getStack().pop()); } @Test public void testVMFunction1() throws RecognitionException { - VM vm = new VM("FUNCTION {init.state.consts}{ #0 'before.all := } "); - List v = new ArrayList<>(); - vm.run(v); + vm.run(Collections.emptyList()); assertEquals(38, vm.getFunctions().size()); @@ -109,8 +100,8 @@ public void testVMExecuteSimple() throws RecognitionException { VM vm = new VM("INTEGERS { variable.a } " + "FUNCTION {init.state.consts}{ #5 'variable.a := } " + "EXECUTE {init.state.consts}"); - List v = new ArrayList<>(); - vm.run(v); + vm.run(Collections.emptyList()); + assertEquals(Integer.valueOf(5), vm.getIntegers().get("variable.a")); } @@ -120,8 +111,7 @@ public void testVMExecuteSimple2() throws RecognitionException { + "#4 #4 < " + "#3 #4 > " + "#4 #3 > " + "#4 #4 > " + "\"H\" \"H\" = " + "\"H\" \"Ha\" = } " + "EXECUTE {a}"); - List v = new ArrayList<>(); - vm.run(v); + vm.run(Collections.emptyList()); assertEquals(VM.FALSE, vm.getStack().pop()); assertEquals(VM.TRUE, vm.getStack().pop()); @@ -144,8 +134,8 @@ public void testVMIfSkipPop() throws RecognitionException { + "#1 #1 and #0 #1 and #1 #0 and #0 #0 and " + "#0 not #1 not " + "#1 #1 or #0 #1 or #1 #0 or #0 #0 or }" + "EXECUTE {test}"); - List v = new ArrayList<>(); - vm.run(v); + vm.run(Collections.emptyList()); + assertEquals(VM.FALSE, vm.getStack().pop()); assertEquals(VM.TRUE, vm.getStack().pop()); assertEquals(VM.TRUE, vm.getStack().pop()); @@ -161,11 +151,10 @@ public void testVMIfSkipPop() throws RecognitionException { @Test public void testVMArithmetic() throws RecognitionException { - VM vm = new VM("FUNCTION {test} { " + "#1 #1 + #5 #2 - }" + "EXECUTE {test}"); - List v = new ArrayList<>(); - vm.run(v); + vm.run(Collections.emptyList()); + assertEquals(3, vm.getStack().pop()); assertEquals(2, vm.getStack().pop()); assertEquals(0, vm.getStack().size()); @@ -174,23 +163,15 @@ public void testVMArithmetic() throws RecognitionException { @Test public void testVMArithmetic2() throws RecognitionException { VM vm = new VM("FUNCTION {test} { " + "#1 \"HELLO\" + #5 #2 - }" + "EXECUTE {test}"); - - List v = new ArrayList<>(); - - try { - vm.run(v); - fail("fail"); - } catch (VMException ignored) { - // Ignored - } + assertThrows(VMException.class, () -> vm.run(Collections.emptyList())); } @Test public void testNumNames() throws RecognitionException { VM vm = new VM("FUNCTION {test} { \"Johnny Foo and Mary Bar\" num.names$ }" + "EXECUTE {test}"); - List v = new ArrayList<>(); - vm.run(v); + vm.run(Collections.emptyList()); + assertEquals(2, vm.getStack().pop()); assertEquals(0, vm.getStack().size()); } @@ -200,8 +181,8 @@ public void testNumNames2() throws RecognitionException { VM vm = new VM("FUNCTION {test} { \"Johnny Foo { and } Mary Bar\" num.names$ }" + "EXECUTE {test}"); - List v = new ArrayList<>(); - vm.run(v); + vm.run(Collections.emptyList()); + assertEquals(1, vm.getStack().pop()); assertEquals(0, vm.getStack().size()); } @@ -214,8 +195,8 @@ public void testVMStringOps1() throws RecognitionException { + "\"Johnny!}\" add.period$ \"Johnny?}\" add.period$ \"Johnny.}\" add.period$ }" + "EXECUTE {test}"); - List v = new ArrayList<>(); - vm.run(v); + vm.run(Collections.emptyList()); + assertEquals("Johnny.}", vm.getStack().pop()); assertEquals("Johnny?}", vm.getStack().pop()); assertEquals("Johnny!}", vm.getStack().pop()); @@ -243,8 +224,8 @@ public void testSubstring() throws RecognitionException { "} EXECUTE {test} "); - List v = new ArrayList<>(); - vm.run(v); + vm.run(Collections.emptyList()); + assertEquals("78", vm.getStack().pop()); assertEquals("789", vm.getStack().pop()); assertEquals("9", vm.getStack().pop()); @@ -266,8 +247,7 @@ public void testEmpty() throws RecognitionException, IOException { " title empty$ " + // FALSE " \" HALLO \" empty$ } ITERATE {test} "); - List v = new ArrayList<>(); - v.add(TestVM.bibtexString2BibtexEntry("@article{a, author=\"AAA\"}")); + List v = List.of(TestVM.bibtexString2BibtexEntry("@article{a, author=\"AAA\"}")); vm.run(v); assertEquals(VM.FALSE, vm.getStack().pop()); assertEquals(VM.TRUE, vm.getStack().pop()); @@ -283,8 +263,8 @@ public void testDuplicateEmptyPopSwapIf() throws RecognitionException { + " { \"{\\em \" swap$ * \"}\" * } " + " if$ " + "} " + "FUNCTION {test} {" + " \"\" emphasize " + " \"Hello\" emphasize " + "}" + "EXECUTE {test} "); - List v = new ArrayList<>(); - vm.run(v); + vm.run(Collections.emptyList()); + assertEquals("{\\em Hello}", vm.getStack().pop()); assertEquals("", vm.getStack().pop()); assertEquals(0, vm.getStack().size()); @@ -308,8 +288,8 @@ public void testChangeCase() throws RecognitionException { + " \"{A}{D}/{C}ycle: {I}{B}{M}'s {F}ramework for {A}pplication {D}evelopment and {C}ase\" \"u\" change.case$ format.title " + "}" + "EXECUTE {test} "); - List v = new ArrayList<>(); - vm.run(v); + vm.run(Collections.emptyList()); + assertEquals( "{A}{D}/{C}ycle: {I}{B}{M}'s {F}ramework for {A}pplication {D}evelopment and {C}ase", vm.getStack().pop()); @@ -329,8 +309,8 @@ public void testTextLength() throws RecognitionException { + " \"{\\And this too\" text.length$ " + " \"These are {\\11}\" text.length$ " + "} " + "EXECUTE {test} "); - List v = new ArrayList<>(); - vm.run(v); + vm.run(Collections.emptyList()); + assertEquals(11, vm.getStack().pop()); assertEquals(1, vm.getStack().pop()); assertEquals(1, vm.getStack().pop()); @@ -346,8 +326,8 @@ public void testTextLength() throws RecognitionException { public void testVMIntToStr() throws RecognitionException { VM vm = new VM("FUNCTION {test} { #3 int.to.str$ #9999 int.to.str$}" + "EXECUTE {test}"); - List v = new ArrayList<>(); - vm.run(v); + vm.run(Collections.emptyList()); + assertEquals("9999", vm.getStack().pop()); assertEquals("3", vm.getStack().pop()); assertEquals(0, vm.getStack().size()); @@ -357,8 +337,8 @@ public void testVMIntToStr() throws RecognitionException { public void testVMChrToInt() throws RecognitionException { VM vm = new VM("FUNCTION {test} { \"H\" chr.to.int$ }" + "EXECUTE {test}"); - List v = new ArrayList<>(); - vm.run(v); + vm.run(Collections.emptyList()); + assertEquals(72, vm.getStack().pop()); assertEquals(0, vm.getStack().size()); } @@ -367,23 +347,22 @@ public void testVMChrToInt() throws RecognitionException { public void testVMChrToIntIntToChr() throws RecognitionException { VM vm = new VM("FUNCTION {test} { \"H\" chr.to.int$ int.to.chr$ }" + "EXECUTE {test}"); - List v = new ArrayList<>(); - vm.run(v); + vm.run(Collections.emptyList()); + assertEquals("H", vm.getStack().pop()); assertEquals(0, vm.getStack().size()); } @Test public void testSort() throws RecognitionException, IOException { - VM vm = new VM("ENTRY { title } { } { label }" + "FUNCTION {presort} { cite$ 'sort.key$ := } ITERATE { presort } SORT"); - List v = new ArrayList<>(); - v.add(TestVM.bibtexString2BibtexEntry("@article{a, author=\"AAA\"}")); - v.add(TestVM.bibtexString2BibtexEntry("@article{b, author=\"BBB\"}")); - v.add(TestVM.bibtexString2BibtexEntry("@article{d, author=\"DDD\"}")); - v.add(TestVM.bibtexString2BibtexEntry("@article{c, author=\"CCC\"}")); + List v = List.of( + TestVM.bibtexString2BibtexEntry("@article{a, author=\"AAA\"}"), + TestVM.bibtexString2BibtexEntry("@article{b, author=\"BBB\"}"), + TestVM.bibtexString2BibtexEntry("@article{d, author=\"DDD\"}"), + TestVM.bibtexString2BibtexEntry("@article{c, author=\"CCC\"}")); vm.run(v); List v2 = vm.getEntries(); @@ -397,8 +376,7 @@ public void testSort() throws RecognitionException, IOException { public void testBuildIn() throws RecognitionException { VM vm = new VM("EXECUTE {global.max$}"); - List v = new ArrayList<>(); - vm.run(v); + vm.run(Collections.emptyList()); assertEquals(Integer.MAX_VALUE, vm.getStack().pop()); assertTrue(vm.getStack().empty()); @@ -406,20 +384,18 @@ public void testBuildIn() throws RecognitionException { @Test public void testVariables() throws RecognitionException { - VM vm = new VM(" STRINGS { t } " + " FUNCTION {not} { { #0 } { #1 } if$ } " + " FUNCTION {n.dashify} { \"HELLO-WORLD\" 't := t empty$ not } " + " EXECUTE {n.dashify} "); - vm.run(new ArrayList<>()); + vm.run(Collections.emptyList()); assertEquals(VM.TRUE, vm.getStack().pop()); } @Test public void testWhile() throws RecognitionException { - VM vm = new VM( "STRINGS { t } " + "FUNCTION {not} { " @@ -451,7 +427,7 @@ public void testWhile() throws RecognitionException { + " } " + " EXECUTE {n.dashify} "); - List v = new ArrayList<>(); + List v = Collections.emptyList(); vm.run(v); assertEquals(1, vm.getStack().size()); @@ -460,15 +436,14 @@ public void testWhile() throws RecognitionException { @Test public void testType() throws RecognitionException, IOException { - VM vm = new VM("ENTRY { title } { } { label }" + "FUNCTION {presort} { cite$ 'sort.key$ := } ITERATE { presort } SORT FUNCTION {test} { type$ } ITERATE { test }"); - List v = new ArrayList<>(); - v.add(TestVM.bibtexString2BibtexEntry("@article{a, author=\"AAA\"}")); - v.add(TestVM.bibtexString2BibtexEntry("@book{b, author=\"BBB\"}")); - v.add(TestVM.bibtexString2BibtexEntry("@misc{c, author=\"CCC\"}")); - v.add(TestVM.bibtexString2BibtexEntry("@inproceedings{d, author=\"DDD\"}")); + List v = List.of( + TestVM.bibtexString2BibtexEntry("@article{a, author=\"AAA\"}"), + TestVM.bibtexString2BibtexEntry("@book{b, author=\"BBB\"}"), + TestVM.bibtexString2BibtexEntry("@misc{c, author=\"CCC\"}"), + TestVM.bibtexString2BibtexEntry("@inproceedings{d, author=\"DDD\"}")); vm.run(v); assertEquals(4, vm.getStack().size()); @@ -480,18 +455,17 @@ public void testType() throws RecognitionException, IOException { @Test public void testMissing() throws RecognitionException, IOException { - - VM vm = new VM( // - "ENTRY { title } { } { label } " + // - "FUNCTION {presort} { cite$ 'sort.key$ := } " + // - "ITERATE {presort} " + // - "READ SORT " + // - "FUNCTION {test}{ title missing$ cite$ } " + // + VM vm = new VM( + "ENTRY { title } { } { label } " + + "FUNCTION {presort} { cite$ 'sort.key$ := } " + + "ITERATE {presort} " + + "READ SORT " + + "FUNCTION {test}{ title missing$ cite$ } " + "ITERATE { test }"); - List v = new ArrayList<>(); - v.add(t1BibtexEntry()); - v.add(TestVM.bibtexString2BibtexEntry("@article{test, author=\"No title\"}")); + List v = List.of( + t1BibtexEntry(), + TestVM.bibtexString2BibtexEntry("@article{test, author=\"No title\"}")); vm.run(v); assertEquals(4, vm.getStack().size()); @@ -508,7 +482,7 @@ public void testFormatName() throws RecognitionException { "FUNCTION {format}{ \"Charles Louis Xavier Joseph de la Vall{\\'e}e Poussin\" #1 \"{vv~}{ll}{, jj}{, f}?\" format.name$ }" + "EXECUTE {format}"); - List v = new ArrayList<>(); + List v = Collections.emptyList(); vm.run(v); assertEquals("de~la Vall{\\'e}e~Poussin, C.~L. X.~J?", vm.getStack().pop()); assertEquals(0, vm.getStack().size()); @@ -520,10 +494,10 @@ public void testFormatName2() throws RecognitionException, IOException { + "ITERATE { presort } " + "READ " + "SORT " + "FUNCTION {format}{ author #2 \"{vv~}{ll}{, jj}{, f}?\" format.name$ }" + "ITERATE {format}"); - List v = new ArrayList<>(); - v.add(t1BibtexEntry()); - v.add(TestVM.bibtexString2BibtexEntry( - "@book{test, author=\"Jonathan Meyer and Charles Louis Xavier Joseph de la Vall{\\'e}e Poussin\"}")); + List v = List.of( + t1BibtexEntry(), + TestVM.bibtexString2BibtexEntry( + "@book{test, author=\"Jonathan Meyer and Charles Louis Xavier Joseph de la Vall{\\'e}e Poussin\"}")); vm.run(v); assertEquals("de~la Vall{\\'e}e~Poussin, C.~L. X.~J?", vm.getStack().pop()); assertEquals("Annabi, H?", vm.getStack().pop()); @@ -532,15 +506,15 @@ public void testFormatName2() throws RecognitionException, IOException { @Test public void testCallType() throws RecognitionException, IOException { - VM vm = new VM( "ENTRY { title } { } { label } FUNCTION {presort} { cite$ 'sort.key$ := } ITERATE { presort } READ SORT " + "FUNCTION {inproceedings}{ \"InProceedings called on \" title * } " + "FUNCTION {book}{ \"Book called on \" title * } " + " ITERATE { call.type$ }"); - List v = new ArrayList<>(); - v.add(t1BibtexEntry()); - v.add(TestVM.bibtexString2BibtexEntry("@book{test, title=\"Test\"}")); + List v = List.of( + t1BibtexEntry(), + TestVM.bibtexString2BibtexEntry("@book{test, title=\"Test\"}")); + vm.run(v); assertEquals(2, vm.getStack().size()); @@ -554,14 +528,12 @@ public void testCallType() throws RecognitionException, IOException { @Test public void testIterate() throws RecognitionException, IOException { - VM vm = new VM("ENTRY { " + " address " + " author " + " title " + " type " + "} {} { label } " + "FUNCTION {test}{ cite$ } " + "READ " + "ITERATE { test }"); - List v = new ArrayList<>(); - v.add(t1BibtexEntry()); - - v.add(TestVM.bibtexString2BibtexEntry("@article{test, title=\"BLA\"}")); + List v = List.of( + t1BibtexEntry(), + TestVM.bibtexString2BibtexEntry("@article{test, title=\"BLA\"}")); vm.run(v); @@ -580,7 +552,6 @@ public void testIterate() throws RecognitionException, IOException { @Test public void testWidth() throws RecognitionException, IOException { - VM vm = new VM("ENTRY { " + " address " + " author " + " title " + " type " + "} {} { label } " + // "STRINGS { longest.label } " + // @@ -614,8 +585,7 @@ public void testWidth() throws RecognitionException, IOException { "}" + // "EXECUTE {begin.bib}");// - List v = new ArrayList<>(); - v.add(t1BibtexEntry()); + List v = List.of(t1BibtexEntry()); vm.run(v); @@ -625,10 +595,9 @@ public void testWidth() throws RecognitionException, IOException { @Test public void testVMSwap() throws RecognitionException { - VM vm = new VM("FUNCTION {a}{ #3 \"Hallo\" swap$ } EXECUTE { a }"); - List v = new ArrayList<>(); + List v = Collections.emptyList(); vm.run(v); assertEquals(2, vm.getStack().size()); @@ -636,6 +605,13 @@ public void testVMSwap() throws RecognitionException { assertEquals("Hallo", vm.getStack().pop()); } + @Test + public void testHypthenatedName() throws RecognitionException, IOException { + VM vm = new VM(new File("src/test/resources/org/jabref/logic/bst/abbrv.bst")); + List v = List.of(TestVM.bibtexString2BibtexEntry("@article{canh05, author = \"Jean-Paul Sartre\" }")); + assertTrue(vm.run(v).contains("J.-P. Sartre")); + } + private static BibEntry bibtexString2BibtexEntry(String s) throws IOException { ParserResult result = new BibtexParser(mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS), new DummyFileUpdateMonitor()).parse(new StringReader(s)); Collection c = result.getDatabase().getEntries(); @@ -643,8 +619,7 @@ private static BibEntry bibtexString2BibtexEntry(String s) throws IOException { return c.iterator().next(); } - /* TEST DATA */ - private String t1BibtexString() { + private static String t1BibtexString() { return "@inproceedings{canh05,\n" + " author = {Crowston, K. and Annabi, H. and Howison, J. and Masango, C.},\n" + " title = {Effective work practices for floss development: A model and propositions},\n" @@ -653,15 +628,7 @@ private String t1BibtexString() { + " url = {http://james.howison.name/publications.html}}\n"; } - @Test - public void testHypthenatedName() throws RecognitionException, IOException { - VM vm = new VM(new File("src/test/resources/org/jabref/logic/bst/abbrv.bst")); - List v = new ArrayList<>(); - v.add(TestVM.bibtexString2BibtexEntry("@article{canh05, author = \"Jean-Paul Sartre\" }")); - assertTrue(vm.run(v).contains("J.-P. Sartre")); - } - - private BibEntry t1BibtexEntry() throws IOException { + private static BibEntry t1BibtexEntry() throws IOException { return TestVM.bibtexString2BibtexEntry(t1BibtexString()); } } From 046928cc0306982d681626735a8afcf3d9dd64e3 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Mon, 2 Dec 2019 22:03:31 +0100 Subject: [PATCH 02/18] Add IEEEtran.bst --- external-libraries.txt | 6 + src/main/resources/bst/IEEEtran.bst | 2409 +++++++++++++++++++++++++++ 2 files changed, 2415 insertions(+) create mode 100644 src/main/resources/bst/IEEEtran.bst diff --git a/external-libraries.txt b/external-libraries.txt index 1f4e0433d78..c43bc7873df 100644 --- a/external-libraries.txt +++ b/external-libraries.txt @@ -13,6 +13,12 @@ In case you add a library, please use these identifiers. For instance, "BSD" is not exact enough, there are numerous variants out there: BSD-2-Clause, BSD-3-Clause-No-Nuclear-Warranty, ... Note that the SPDX license identifiers are different from the ones used by debian. See https://wiki.debian.org/Proposals/CopyrightFormat for more information. +# bst files + +Project: IEEEtran +Path: src/main/resources/bst/IEEEtran.bst +URL: https://www.ctan.org/tex-archive/macros/latex/contrib/IEEEtran/bibtex +License: LPPL-1.3 # Fonts and Icons diff --git a/src/main/resources/bst/IEEEtran.bst b/src/main/resources/bst/IEEEtran.bst new file mode 100644 index 00000000000..f9c03d79f4f --- /dev/null +++ b/src/main/resources/bst/IEEEtran.bst @@ -0,0 +1,2409 @@ +%% +%% IEEEtran.bst +%% BibTeX Bibliography Style file for IEEE Journals and Conferences (unsorted) +%% Version 1.14 (2015/08/26) +%% +%% Copyright (c) 2003-2015 Michael Shell +%% +%% Original starting code base and algorithms obtained from the output of +%% Patrick W. Daly's makebst package as well as from prior versions of +%% IEEE BibTeX styles: +%% +%% 1. Howard Trickey and Oren Patashnik's ieeetr.bst (1985/1988) +%% 2. Silvano Balemi and Richard H. Roy's IEEEbib.bst (1993) +%% +%% Support sites: +%% http://www.michaelshell.org/tex/ieeetran/ +%% http://www.ctan.org/pkg/ieeetran +%% and/or +%% http://www.ieee.org/ +%% +%% For use with BibTeX version 0.99a or later +%% +%% This is a numerical citation style. +%% +%%************************************************************************* +%% Legal Notice: +%% This code is offered as-is without any warranty either expressed or +%% implied; without even the implied warranty of MERCHANTABILITY or +%% FITNESS FOR A PARTICULAR PURPOSE! +%% User assumes all risk. +%% In no event shall the IEEE or any contributor to this code be liable for +%% any damages or losses, including, but not limited to, incidental, +%% consequential, or any other damages, resulting from the use or misuse +%% of any information contained here. +%% +%% All comments are the opinions of their respective authors and are not +%% necessarily endorsed by the IEEE. +%% +%% This work is distributed under the LaTeX Project Public License (LPPL) +%% ( http://www.latex-project.org/ ) version 1.3, and may be freely used, +%% distributed and modified. A copy of the LPPL, version 1.3, is included +%% in the base LaTeX documentation of all distributions of LaTeX released +%% 2003/12/01 or later. +%% Retain all contribution notices and credits. +%% ** Modified files should be clearly indicated as such, including ** +%% ** renaming them and changing author support contact information. ** +%%************************************************************************* + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% DEFAULTS FOR THE CONTROLS OF THE BST STYLE %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% These are the defaults for the user adjustable controls. The values used +% here can be overridden by the user via IEEEtranBSTCTL entry type. + +% NOTE: The recommended LaTeX command to invoke a control entry type is: +% +%\makeatletter +%\def\bstctlcite{\@ifnextchar[{\@bstctlcite}{\@bstctlcite[@auxout]}} +%\def\@bstctlcite[#1]#2{\@bsphack +% \@for\@citeb:=#2\do{% +% \edef\@citeb{\expandafter\@firstofone\@citeb}% +% \if@filesw\immediate\write\csname #1\endcsname{\string\citation{\@citeb}}\fi}% +% \@esphack} +%\makeatother +% +% It is called at the start of the document, before the first \cite, like: +% \bstctlcite{IEEEexample:BSTcontrol} +% +% IEEEtran.cls V1.6 and later does provide this command. + + + +% #0 turns off the display of the number for articles. +% #1 enables +FUNCTION {default.is.use.number.for.article} { #1 } + + +% #0 turns off the display of the paper and type fields in @inproceedings. +% #1 enables +FUNCTION {default.is.use.paper} { #1 } + + +% #0 turns off the display of urls +% #1 enables +FUNCTION {default.is.use.url} { #1 } + + +% #0 turns off the forced use of "et al." +% #1 enables +FUNCTION {default.is.forced.et.al} { #0 } + + +% The maximum number of names that can be present beyond which an "et al." +% usage is forced. Be sure that num.names.shown.with.forced.et.al (below) +% is not greater than this value! +% Note: There are many instances of references in IEEE journals which have +% a very large number of authors as well as instances in which "et al." is +% used profusely. +FUNCTION {default.max.num.names.before.forced.et.al} { #10 } + + +% The number of names that will be shown with a forced "et al.". +% Must be less than or equal to max.num.names.before.forced.et.al +FUNCTION {default.num.names.shown.with.forced.et.al} { #1 } + + +% #0 turns off the alternate interword spacing for entries with URLs. +% #1 enables +FUNCTION {default.is.use.alt.interword.spacing} { #1 } + + +% If alternate interword spacing for entries with URLs is enabled, this is +% the interword spacing stretch factor that will be used. For example, the +% default "4" here means that the interword spacing in entries with URLs can +% stretch to four times normal. Does not have to be an integer. Note that +% the value specified here can be overridden by the user in their LaTeX +% code via a command such as: +% "\providecommand\BIBentryALTinterwordstretchfactor{1.5}" in addition to +% that via the IEEEtranBSTCTL entry type. +FUNCTION {default.ALTinterwordstretchfactor} { "4" } + + +% #0 turns off the "dashification" of repeated (i.e., identical to those +% of the previous entry) names. The IEEE normally does this. +% #1 enables +FUNCTION {default.is.dash.repeated.names} { #1 } + + +% The default name format control string. +FUNCTION {default.name.format.string}{ "{f.~}{vv~}{ll}{, jj}" } + + +% The default LaTeX font command for the names. +FUNCTION {default.name.latex.cmd}{ "" } + + +% The default URL prefix. +FUNCTION {default.name.url.prefix}{ "[Online]. Available:" } + + +% Other controls that cannot be accessed via IEEEtranBSTCTL entry type. + +% #0 turns off the terminal startup banner/completed message so as to +% operate more quietly. +% #1 enables +FUNCTION {is.print.banners.to.terminal} { #1 } + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% FILE VERSION AND BANNER %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +FUNCTION{bst.file.version} { "1.14" } +FUNCTION{bst.file.date} { "2015/08/26" } +FUNCTION{bst.file.website} { "http://www.michaelshell.org/tex/ieeetran/bibtex/" } + +FUNCTION {banner.message} +{ is.print.banners.to.terminal + { "-- IEEEtran.bst version" " " * bst.file.version * + " (" * bst.file.date * ") " * "by Michael Shell." * + top$ + "-- " bst.file.website * + top$ + "-- See the " quote$ * "IEEEtran_bst_HOWTO.pdf" * quote$ * " manual for usage information." * + top$ + } + { skip$ } + if$ +} + +FUNCTION {completed.message} +{ is.print.banners.to.terminal + { "" + top$ + "Done." + top$ + } + { skip$ } + if$ +} + + + + +%%%%%%%%%%%%%%%%%%%%%% +%% STRING CONSTANTS %% +%%%%%%%%%%%%%%%%%%%%%% + +FUNCTION {bbl.and}{ "and" } +FUNCTION {bbl.etal}{ "et~al." } +FUNCTION {bbl.editors}{ "eds." } +FUNCTION {bbl.editor}{ "ed." } +FUNCTION {bbl.edition}{ "ed." } +FUNCTION {bbl.volume}{ "vol." } +FUNCTION {bbl.of}{ "of" } +FUNCTION {bbl.number}{ "no." } +FUNCTION {bbl.in}{ "in" } +FUNCTION {bbl.pages}{ "pp." } +FUNCTION {bbl.page}{ "p." } +FUNCTION {bbl.chapter}{ "ch." } +FUNCTION {bbl.paper}{ "paper" } +FUNCTION {bbl.part}{ "pt." } +FUNCTION {bbl.patent}{ "Patent" } +FUNCTION {bbl.patentUS}{ "U.S." } +FUNCTION {bbl.revision}{ "Rev." } +FUNCTION {bbl.series}{ "ser." } +FUNCTION {bbl.standard}{ "Std." } +FUNCTION {bbl.techrep}{ "Tech. Rep." } +FUNCTION {bbl.mthesis}{ "Master's thesis" } +FUNCTION {bbl.phdthesis}{ "Ph.D. dissertation" } +FUNCTION {bbl.st}{ "st" } +FUNCTION {bbl.nd}{ "nd" } +FUNCTION {bbl.rd}{ "rd" } +FUNCTION {bbl.th}{ "th" } + + +% This is the LaTeX spacer that is used when a larger than normal space +% is called for (such as just before the address:publisher). +FUNCTION {large.space} { "\hskip 1em plus 0.5em minus 0.4em\relax " } + +% The LaTeX code for dashes that are used to represent repeated names. +% Note: Some older IEEE journals used something like +% "\rule{0.275in}{0.5pt}\," which is fairly thick and runs right along +% the baseline. However, the IEEE now uses a thinner, above baseline, +% six dash long sequence. +FUNCTION {repeated.name.dashes} { "------" } + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% PREDEFINED STRING MACROS %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +MACRO {jan} {"Jan."} +MACRO {feb} {"Feb."} +MACRO {mar} {"Mar."} +MACRO {apr} {"Apr."} +MACRO {may} {"May"} +MACRO {jun} {"Jun."} +MACRO {jul} {"Jul."} +MACRO {aug} {"Aug."} +MACRO {sep} {"Sep."} +MACRO {oct} {"Oct."} +MACRO {nov} {"Nov."} +MACRO {dec} {"Dec."} + + + +%%%%%%%%%%%%%%%%%% +%% ENTRY FIELDS %% +%%%%%%%%%%%%%%%%%% + +ENTRY + { address + assignee + author + booktitle + chapter + day + dayfiled + edition + editor + howpublished + institution + intype + journal + key + language + month + monthfiled + nationality + note + number + organization + pages + paper + publisher + school + series + revision + title + type + url + volume + year + yearfiled + CTLuse_article_number + CTLuse_paper + CTLuse_url + CTLuse_forced_etal + CTLmax_names_forced_etal + CTLnames_show_etal + CTLuse_alt_spacing + CTLalt_stretch_factor + CTLdash_repeated_names + CTLname_format_string + CTLname_latex_cmd + CTLname_url_prefix + } + {} + { label } + + + + +%%%%%%%%%%%%%%%%%%%%%%% +%% INTEGER VARIABLES %% +%%%%%%%%%%%%%%%%%%%%%%% + +INTEGERS { prev.status.punct this.status.punct punct.std + punct.no punct.comma punct.period + prev.status.space this.status.space space.std + space.no space.normal space.large + prev.status.quote this.status.quote quote.std + quote.no quote.close + prev.status.nline this.status.nline nline.std + nline.no nline.newblock + status.cap cap.std + cap.no cap.yes} + +INTEGERS { longest.label.width multiresult nameptr namesleft number.label numnames } + +INTEGERS { is.use.number.for.article + is.use.paper + is.use.url + is.forced.et.al + max.num.names.before.forced.et.al + num.names.shown.with.forced.et.al + is.use.alt.interword.spacing + is.dash.repeated.names} + + +%%%%%%%%%%%%%%%%%%%%%% +%% STRING VARIABLES %% +%%%%%%%%%%%%%%%%%%%%%% + +STRINGS { bibinfo + longest.label + oldname + s + t + ALTinterwordstretchfactor + name.format.string + name.latex.cmd + name.url.prefix} + + + + +%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOW LEVEL FUNCTIONS %% +%%%%%%%%%%%%%%%%%%%%%%%%% + +FUNCTION {initialize.controls} +{ default.is.use.number.for.article 'is.use.number.for.article := + default.is.use.paper 'is.use.paper := + default.is.use.url 'is.use.url := + default.is.forced.et.al 'is.forced.et.al := + default.max.num.names.before.forced.et.al 'max.num.names.before.forced.et.al := + default.num.names.shown.with.forced.et.al 'num.names.shown.with.forced.et.al := + default.is.use.alt.interword.spacing 'is.use.alt.interword.spacing := + default.is.dash.repeated.names 'is.dash.repeated.names := + default.ALTinterwordstretchfactor 'ALTinterwordstretchfactor := + default.name.format.string 'name.format.string := + default.name.latex.cmd 'name.latex.cmd := + default.name.url.prefix 'name.url.prefix := +} + + +% This IEEEtran.bst features a very powerful and flexible mechanism for +% controlling the capitalization, punctuation, spacing, quotation, and +% newlines of the formatted entry fields. (Note: IEEEtran.bst does not need +% or use the newline/newblock feature, but it has been implemented for +% possible future use.) The output states of IEEEtran.bst consist of +% multiple independent attributes and, as such, can be thought of as being +% vectors, rather than the simple scalar values ("before.all", +% "mid.sentence", etc.) used in most other .bst files. +% +% The more flexible and complex design used here was motivated in part by +% the IEEE's rather unusual bibliography style. For example, the IEEE ends the +% previous field item with a period and large space prior to the publisher +% address; the @electronic entry types use periods as inter-item punctuation +% rather than the commas used by the other entry types; and URLs are never +% followed by periods even though they are the last item in the entry. +% Although it is possible to accommodate these features with the conventional +% output state system, the seemingly endless exceptions make for convoluted, +% unreliable and difficult to maintain code. +% +% IEEEtran.bst's output state system can be easily understood via a simple +% illustration of two most recently formatted entry fields (on the stack): +% +% CURRENT_ITEM +% "PREVIOUS_ITEM +% +% which, in this example, is to eventually appear in the bibliography as: +% +% "PREVIOUS_ITEM," CURRENT_ITEM +% +% It is the job of the output routine to take the previous item off of the +% stack (while leaving the current item at the top of the stack), apply its +% trailing punctuation (including closing quote marks) and spacing, and then +% to write the result to BibTeX's output buffer: +% +% "PREVIOUS_ITEM," +% +% Punctuation (and spacing) between items is often determined by both of the +% items rather than just the first one. The presence of quotation marks +% further complicates the situation because, in standard English, trailing +% punctuation marks are supposed to be contained within the quotes. +% +% IEEEtran.bst maintains two output state (aka "status") vectors which +% correspond to the previous and current (aka "this") items. Each vector +% consists of several independent attributes which track punctuation, +% spacing, quotation, and newlines. Capitalization status is handled by a +% separate scalar because the format routines, not the output routine, +% handle capitalization and, therefore, there is no need to maintain the +% capitalization attribute for both the "previous" and "this" items. +% +% When a format routine adds a new item, it copies the current output status +% vector to the previous output status vector and (usually) resets the +% current (this) output status vector to a "standard status" vector. Using a +% "standard status" vector in this way allows us to redefine what we mean by +% "standard status" at the start of each entry handler and reuse the same +% format routines under the various inter-item separation schemes. For +% example, the standard status vector for the @book entry type may use +% commas for item separators, while the @electronic type may use periods, +% yet both entry handlers exploit many of the exact same format routines. +% +% Because format routines have write access to the output status vector of +% the previous item, they can override the punctuation choices of the +% previous format routine! Therefore, it becomes trivial to implement rules +% such as "Always use a period and a large space before the publisher." By +% pushing the generation of the closing quote mark to the output routine, we +% avoid all the problems caused by having to close a quote before having all +% the information required to determine what the punctuation should be. +% +% The IEEEtran.bst output state system can easily be expanded if needed. +% For instance, it is easy to add a "space.tie" attribute value if the +% bibliography rules mandate that two items have to be joined with an +% unbreakable space. + +FUNCTION {initialize.status.constants} +{ #0 'punct.no := + #1 'punct.comma := + #2 'punct.period := + #0 'space.no := + #1 'space.normal := + #2 'space.large := + #0 'quote.no := + #1 'quote.close := + #0 'cap.no := + #1 'cap.yes := + #0 'nline.no := + #1 'nline.newblock := +} + +FUNCTION {std.status.using.comma} +{ punct.comma 'punct.std := + space.normal 'space.std := + quote.no 'quote.std := + nline.no 'nline.std := + cap.no 'cap.std := +} + +FUNCTION {std.status.using.period} +{ punct.period 'punct.std := + space.normal 'space.std := + quote.no 'quote.std := + nline.no 'nline.std := + cap.yes 'cap.std := +} + +FUNCTION {initialize.prev.this.status} +{ punct.no 'prev.status.punct := + space.no 'prev.status.space := + quote.no 'prev.status.quote := + nline.no 'prev.status.nline := + punct.no 'this.status.punct := + space.no 'this.status.space := + quote.no 'this.status.quote := + nline.no 'this.status.nline := + cap.yes 'status.cap := +} + +FUNCTION {this.status.std} +{ punct.std 'this.status.punct := + space.std 'this.status.space := + quote.std 'this.status.quote := + nline.std 'this.status.nline := +} + +FUNCTION {cap.status.std}{ cap.std 'status.cap := } + +FUNCTION {this.to.prev.status} +{ this.status.punct 'prev.status.punct := + this.status.space 'prev.status.space := + this.status.quote 'prev.status.quote := + this.status.nline 'prev.status.nline := +} + + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} + +FUNCTION {and} +{ { skip$ } + { pop$ #0 } + if$ +} + +FUNCTION {or} +{ { pop$ #1 } + { skip$ } + if$ +} + + +% convert the strings "yes" or "no" to #1 or #0 respectively +FUNCTION {yes.no.to.int} +{ "l" change.case$ duplicate$ + "yes" = + { pop$ #1 } + { duplicate$ "no" = + { pop$ #0 } + { "unknown boolean " quote$ * swap$ * quote$ * + " in " * cite$ * warning$ + #0 + } + if$ + } + if$ +} + + +% pushes true if the single char string on the stack is in the +% range of "0" to "9" +FUNCTION {is.num} +{ chr.to.int$ + duplicate$ "0" chr.to.int$ < not + swap$ "9" chr.to.int$ > not and +} + +% multiplies the integer on the stack by a factor of 10 +FUNCTION {bump.int.mag} +{ #0 'multiresult := + { duplicate$ #0 > } + { #1 - + multiresult #10 + + 'multiresult := + } + while$ +pop$ +multiresult +} + +% converts a single character string on the stack to an integer +FUNCTION {char.to.integer} +{ duplicate$ + is.num + { chr.to.int$ "0" chr.to.int$ - } + {"noninteger character " quote$ * swap$ * quote$ * + " in integer field of " * cite$ * warning$ + #0 + } + if$ +} + +% converts a string on the stack to an integer +FUNCTION {string.to.integer} +{ duplicate$ text.length$ 'namesleft := + #1 'nameptr := + #0 'numnames := + { nameptr namesleft > not } + { duplicate$ nameptr #1 substring$ + char.to.integer numnames bump.int.mag + + 'numnames := + nameptr #1 + + 'nameptr := + } + while$ +pop$ +numnames +} + + + + +% The output routines write out the *next* to the top (previous) item on the +% stack, adding punctuation and such as needed. Since IEEEtran.bst maintains +% the output status for the top two items on the stack, these output +% routines have to consider the previous output status (which corresponds to +% the item that is being output). Full independent control of punctuation, +% closing quote marks, spacing, and newblock is provided. +% +% "output.nonnull" does not check for the presence of a previous empty +% item. +% +% "output" does check for the presence of a previous empty item and will +% remove an empty item rather than outputing it. +% +% "output.warn" is like "output", but will issue a warning if it detects +% an empty item. + +FUNCTION {output.nonnull} +{ swap$ + prev.status.punct punct.comma = + { "," * } + { skip$ } + if$ + prev.status.punct punct.period = + { add.period$ } + { skip$ } + if$ + prev.status.quote quote.close = + { "''" * } + { skip$ } + if$ + prev.status.space space.normal = + { " " * } + { skip$ } + if$ + prev.status.space space.large = + { large.space * } + { skip$ } + if$ + write$ + prev.status.nline nline.newblock = + { newline$ "\newblock " write$ } + { skip$ } + if$ +} + +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} + +FUNCTION {output.warn} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} + +% "fin.entry" is the output routine that handles the last item of the entry +% (which will be on the top of the stack when "fin.entry" is called). + +FUNCTION {fin.entry} +{ this.status.punct punct.no = + { skip$ } + { add.period$ } + if$ + this.status.quote quote.close = + { "''" * } + { skip$ } + if$ +write$ +newline$ +} + + +FUNCTION {is.last.char.not.punct} +{ duplicate$ + "}" * add.period$ + #-1 #1 substring$ "." = +} + +FUNCTION {is.multiple.pages} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} + +FUNCTION {capitalize}{ "u" change.case$ "t" change.case$ } + +FUNCTION {emphasize} +{ duplicate$ empty$ + { pop$ "" } + { "\emph{" swap$ * "}" * } + if$ +} + +FUNCTION {do.name.latex.cmd} +{ name.latex.cmd + empty$ + { skip$ } + { name.latex.cmd "{" * swap$ * "}" * } + if$ +} + +% IEEEtran.bst uses its own \BIBforeignlanguage command which directly +% invokes the TeX hyphenation patterns without the need of the Babel +% package. Babel does a lot more than switch hyphenation patterns and +% its loading can cause unintended effects in many class files (such as +% IEEEtran.cls). +FUNCTION {select.language} +{ duplicate$ empty$ 'pop$ + { language empty$ 'skip$ + { "\BIBforeignlanguage{" language * "}{" * swap$ * "}" * } + if$ + } + if$ +} + +FUNCTION {tie.or.space.prefix} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ +} + +FUNCTION {get.bbl.editor} +{ editor num.names$ #1 > 'bbl.editors 'bbl.editor if$ } + +FUNCTION {space.word}{ " " swap$ * " " * } + + +% Field Conditioners, Converters, Checkers and External Interfaces + +FUNCTION {empty.field.to.null.string} +{ duplicate$ empty$ + { pop$ "" } + { skip$ } + if$ +} + +FUNCTION {either.or.check} +{ empty$ + { pop$ } + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} + +FUNCTION {empty.entry.warn} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ url empty$ + and and and and and and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} + + +% The bibinfo system provides a way for the electronic parsing/acquisition +% of a bibliography's contents as is done by ReVTeX. For example, a field +% could be entered into the bibliography as: +% \bibinfo{volume}{2} +% Only the "2" would show up in the document, but the LaTeX \bibinfo command +% could do additional things with the information. IEEEtran.bst does provide +% a \bibinfo command via "\providecommand{\bibinfo}[2]{#2}". However, it is +% currently not used as the bogus bibinfo functions defined here output the +% entry values directly without the \bibinfo wrapper. The bibinfo functions +% themselves (and the calls to them) are retained for possible future use. +% +% bibinfo.check avoids acting on missing fields while bibinfo.warn will +% issue a warning message if a missing field is detected. Prior to calling +% the bibinfo functions, the user should push the field value and then its +% name string, in that order. + +FUNCTION {bibinfo.check} +{ swap$ duplicate$ missing$ + { pop$ pop$ "" } + { duplicate$ empty$ + { swap$ pop$ } + { swap$ pop$ } + if$ + } + if$ +} + +FUNCTION {bibinfo.warn} +{ swap$ duplicate$ missing$ + { swap$ "missing " swap$ * " in " * cite$ * warning$ pop$ "" } + { duplicate$ empty$ + { swap$ "empty " swap$ * " in " * cite$ * warning$ } + { swap$ pop$ } + if$ + } + if$ +} + + +% The IEEE separates large numbers with more than 4 digits into groups of +% three. The IEEE uses a small space to separate these number groups. +% Typical applications include patent and page numbers. + +% number of consecutive digits required to trigger the group separation. +FUNCTION {large.number.trigger}{ #5 } + +% For numbers longer than the trigger, this is the blocksize of the groups. +% The blocksize must be less than the trigger threshold, and 2 * blocksize +% must be greater than the trigger threshold (can't do more than one +% separation on the initial trigger). +FUNCTION {large.number.blocksize}{ #3 } + +% What is actually inserted between the number groups. +FUNCTION {large.number.separator}{ "\," } + +% So as to save on integer variables by reusing existing ones, numnames +% holds the current number of consecutive digits read and nameptr holds +% the number that will trigger an inserted space. +FUNCTION {large.number.separate} +{ 't := + "" + #0 'numnames := + large.number.trigger 'nameptr := + { t empty$ not } + { t #-1 #1 substring$ is.num + { numnames #1 + 'numnames := } + { #0 'numnames := + large.number.trigger 'nameptr := + } + if$ + t #-1 #1 substring$ swap$ * + t #-2 global.max$ substring$ 't := + numnames nameptr = + { duplicate$ #1 nameptr large.number.blocksize - substring$ swap$ + nameptr large.number.blocksize - #1 + global.max$ substring$ + large.number.separator swap$ * * + nameptr large.number.blocksize - 'numnames := + large.number.blocksize #1 + 'nameptr := + } + { skip$ } + if$ + } + while$ +} + +% Converts all single dashes "-" to double dashes "--". +FUNCTION {n.dashify} +{ large.number.separate + 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + + +% This function detects entries with names that are identical to that of +% the previous entry and replaces the repeated names with dashes (if the +% "is.dash.repeated.names" user control is nonzero). +FUNCTION {name.or.dash} +{ 's := + oldname empty$ + { s 'oldname := s } + { s oldname = + { is.dash.repeated.names + { repeated.name.dashes } + { s 'oldname := s } + if$ + } + { s 'oldname := s } + if$ + } + if$ +} + +% Converts the number string on the top of the stack to +% "numerical ordinal form" (e.g., "7" to "7th"). There is +% no artificial limit to the upper bound of the numbers as the +% two least significant digits determine the ordinal form. +FUNCTION {num.to.ordinal} +{ duplicate$ #-2 #1 substring$ "1" = + { bbl.th * } + { duplicate$ #-1 #1 substring$ "1" = + { bbl.st * } + { duplicate$ #-1 #1 substring$ "2" = + { bbl.nd * } + { duplicate$ #-1 #1 substring$ "3" = + { bbl.rd * } + { bbl.th * } + if$ + } + if$ + } + if$ + } + if$ +} + +% If the string on the top of the stack begins with a number, +% (e.g., 11th) then replace the string with the leading number +% it contains. Otherwise retain the string as-is. s holds the +% extracted number, t holds the part of the string that remains +% to be scanned. +FUNCTION {extract.num} +{ duplicate$ 't := + "" 's := + { t empty$ not } + { t #1 #1 substring$ + t #2 global.max$ substring$ 't := + duplicate$ is.num + { s swap$ * 's := } + { pop$ "" 't := } + if$ + } + while$ + s empty$ + 'skip$ + { pop$ s } + if$ +} + +% Converts the word number string on the top of the stack to +% Arabic string form. Will be successful up to "tenth". +FUNCTION {word.to.num} +{ duplicate$ "l" change.case$ 's := + s "first" = + { pop$ "1" } + { skip$ } + if$ + s "second" = + { pop$ "2" } + { skip$ } + if$ + s "third" = + { pop$ "3" } + { skip$ } + if$ + s "fourth" = + { pop$ "4" } + { skip$ } + if$ + s "fifth" = + { pop$ "5" } + { skip$ } + if$ + s "sixth" = + { pop$ "6" } + { skip$ } + if$ + s "seventh" = + { pop$ "7" } + { skip$ } + if$ + s "eighth" = + { pop$ "8" } + { skip$ } + if$ + s "ninth" = + { pop$ "9" } + { skip$ } + if$ + s "tenth" = + { pop$ "10" } + { skip$ } + if$ +} + + +% Converts the string on the top of the stack to numerical +% ordinal (e.g., "11th") form. +FUNCTION {convert.edition} +{ duplicate$ empty$ 'skip$ + { duplicate$ #1 #1 substring$ is.num + { extract.num + num.to.ordinal + } + { word.to.num + duplicate$ #1 #1 substring$ is.num + { num.to.ordinal } + { "edition ordinal word " quote$ * edition * quote$ * + " may be too high (or improper) for conversion" * " in " * cite$ * warning$ + } + if$ + } + if$ + } + if$ +} + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LATEX BIBLIOGRAPHY CODE %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +FUNCTION {start.entry} +{ newline$ + "\bibitem{" write$ + cite$ write$ + "}" write$ + newline$ + "" + initialize.prev.this.status +} + +% Here we write out all the LaTeX code that we will need. The most involved +% code sequences are those that control the alternate interword spacing and +% foreign language hyphenation patterns. The heavy use of \providecommand +% gives users a way to override the defaults. Special thanks to Javier Bezos, +% Johannes Braams, Robin Fairbairns, Heiko Oberdiek, Donald Arseneau and all +% the other gurus on comp.text.tex for their help and advice on the topic of +% \selectlanguage, Babel and BibTeX. +FUNCTION {begin.bib} +{ "% Generated by IEEEtran.bst, version: " bst.file.version * " (" * bst.file.date * ")" * + write$ newline$ + preamble$ empty$ 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * + write$ newline$ + "\providecommand{\url}[1]{#1}" + write$ newline$ + "\csname url@samestyle\endcsname" + write$ newline$ + "\providecommand{\newblock}{\relax}" + write$ newline$ + "\providecommand{\bibinfo}[2]{#2}" + write$ newline$ + "\providecommand{\BIBentrySTDinterwordspacing}{\spaceskip=0pt\relax}" + write$ newline$ + "\providecommand{\BIBentryALTinterwordstretchfactor}{" + ALTinterwordstretchfactor * "}" * + write$ newline$ + "\providecommand{\BIBentryALTinterwordspacing}{\spaceskip=\fontdimen2\font plus " + write$ newline$ + "\BIBentryALTinterwordstretchfactor\fontdimen3\font minus \fontdimen4\font\relax}" + write$ newline$ + "\providecommand{\BIBforeignlanguage}[2]{{%" + write$ newline$ + "\expandafter\ifx\csname l@#1\endcsname\relax" + write$ newline$ + "\typeout{** WARNING: IEEEtran.bst: No hyphenation pattern has been}%" + write$ newline$ + "\typeout{** loaded for the language `#1'. Using the pattern for}%" + write$ newline$ + "\typeout{** the default language instead.}%" + write$ newline$ + "\else" + write$ newline$ + "\language=\csname l@#1\endcsname" + write$ newline$ + "\fi" + write$ newline$ + "#2}}" + write$ newline$ + "\providecommand{\BIBdecl}{\relax}" + write$ newline$ + "\BIBdecl" + write$ newline$ +} + +FUNCTION {end.bib} +{ newline$ "\end{thebibliography}" write$ newline$ } + +FUNCTION {if.url.alt.interword.spacing} +{ is.use.alt.interword.spacing + { is.use.url + { url empty$ 'skip$ {"\BIBentryALTinterwordspacing" write$ newline$} if$ } + { skip$ } + if$ + } + { skip$ } + if$ +} + +FUNCTION {if.url.std.interword.spacing} +{ is.use.alt.interword.spacing + { is.use.url + { url empty$ 'skip$ {"\BIBentrySTDinterwordspacing" write$ newline$} if$ } + { skip$ } + if$ + } + { skip$ } + if$ +} + + + + +%%%%%%%%%%%%%%%%%%%%%%%% +%% LONGEST LABEL PASS %% +%%%%%%%%%%%%%%%%%%%%%%%% + +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} + +FUNCTION {longest.label.pass} +{ type$ "ieeetranbstctl" = + { skip$ } + { number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + { skip$ } + if$ + } + if$ +} + + + + +%%%%%%%%%%%%%%%%%%%%% +%% FORMAT HANDLERS %% +%%%%%%%%%%%%%%%%%%%%% + +%% Lower Level Formats (used by higher level formats) + +FUNCTION {format.address.org.or.pub.date} +{ 't := + "" + year empty$ + { "empty year in " cite$ * warning$ } + { skip$ } + if$ + address empty$ t empty$ and + year empty$ and month empty$ and + { skip$ } + { this.to.prev.status + this.status.std + cap.status.std + address "address" bibinfo.check * + t empty$ + { skip$ } + { punct.period 'prev.status.punct := + space.large 'prev.status.space := + address empty$ + { skip$ } + { ": " * } + if$ + t * + } + if$ + year empty$ month empty$ and + { skip$ } + { t empty$ address empty$ and + { skip$ } + { ", " * } + if$ + month empty$ + { year empty$ + { skip$ } + { year "year" bibinfo.check * } + if$ + } + { month "month" bibinfo.check * + year empty$ + { skip$ } + { " " * year "year" bibinfo.check * } + if$ + } + if$ + } + if$ + } + if$ +} + + +FUNCTION {format.names} +{ 'bibinfo := + duplicate$ empty$ 'skip$ { + this.to.prev.status + this.status.std + 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + name.format.string + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { nameptr num.names.shown.with.forced.et.al #1 + = + numnames max.num.names.before.forced.et.al > + is.forced.et.al and and + { "others" 't := + #1 'namesleft := + } + { skip$ } + if$ + namesleft #1 > + { ", " * t do.name.latex.cmd * } + { s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + t "others" = + { " " * bbl.etal emphasize * } + { numnames #2 > + { "," * } + { skip$ } + if$ + bbl.and + space.word * t do.name.latex.cmd * + } + if$ + } + if$ + } + { t do.name.latex.cmd } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + cap.status.std + } if$ +} + + + + +%% Higher Level Formats + +%% addresses/locations + +FUNCTION {format.address} +{ address duplicate$ empty$ 'skip$ + { this.to.prev.status + this.status.std + cap.status.std + } + if$ +} + + + +%% author/editor names + +FUNCTION {format.authors}{ author "author" format.names } + +FUNCTION {format.editors} +{ editor "editor" format.names duplicate$ empty$ 'skip$ + { ", " * + get.bbl.editor + capitalize + * + } + if$ +} + + + +%% date + +FUNCTION {format.date} +{ + month "month" bibinfo.check duplicate$ empty$ + year "year" bibinfo.check duplicate$ empty$ + { swap$ 'skip$ + { this.to.prev.status + this.status.std + cap.status.std + "there's a month but no year in " cite$ * warning$ } + if$ + * + } + { this.to.prev.status + this.status.std + cap.status.std + swap$ 'skip$ + { + swap$ + " " * swap$ + } + if$ + * + } + if$ +} + +FUNCTION {format.date.electronic} +{ month "month" bibinfo.check duplicate$ empty$ + year "year" bibinfo.check duplicate$ empty$ + { swap$ + { pop$ } + { "there's a month but no year in " cite$ * warning$ + pop$ ")" * "(" swap$ * + this.to.prev.status + punct.no 'this.status.punct := + space.normal 'this.status.space := + quote.no 'this.status.quote := + cap.yes 'status.cap := + } + if$ + } + { swap$ + { swap$ pop$ ")" * "(" swap$ * } + { "(" swap$ * ", " * swap$ * ")" * } + if$ + this.to.prev.status + punct.no 'this.status.punct := + space.normal 'this.status.space := + quote.no 'this.status.quote := + cap.yes 'status.cap := + } + if$ +} + + + +%% edition/title + +% Note: The IEEE considers the edition to be closely associated with +% the title of a book. So, in IEEEtran.bst the edition is normally handled +% within the formatting of the title. The format.edition function is +% retained here for possible future use. +FUNCTION {format.edition} +{ edition duplicate$ empty$ 'skip$ + { this.to.prev.status + this.status.std + convert.edition + status.cap + { "t" } + { "l" } + if$ change.case$ + "edition" bibinfo.check + "~" * bbl.edition * + cap.status.std + } + if$ +} + +% This is used to format the booktitle of a conference proceedings. +% Here we use the "intype" field to provide the user a way to +% override the word "in" (e.g., with things like "presented at") +% Use of intype stops the emphasis of the booktitle to indicate that +% we no longer mean the written conference proceedings, but the +% conference itself. +FUNCTION {format.in.booktitle} +{ booktitle "booktitle" bibinfo.check duplicate$ empty$ 'skip$ + { this.to.prev.status + this.status.std + select.language + intype missing$ + { emphasize + bbl.in " " * + } + { intype " " * } + if$ + swap$ * + cap.status.std + } + if$ +} + +% This is used to format the booktitle of collection. +% Here the "intype" field is not supported, but "edition" is. +FUNCTION {format.in.booktitle.edition} +{ booktitle "booktitle" bibinfo.check duplicate$ empty$ 'skip$ + { this.to.prev.status + this.status.std + select.language + emphasize + edition empty$ 'skip$ + { ", " * + edition + convert.edition + "l" change.case$ + * "~" * bbl.edition * + } + if$ + bbl.in " " * swap$ * + cap.status.std + } + if$ +} + +FUNCTION {format.article.title} +{ title duplicate$ empty$ 'skip$ + { this.to.prev.status + this.status.std + "t" change.case$ + } + if$ + "title" bibinfo.check + duplicate$ empty$ 'skip$ + { quote.close 'this.status.quote := + is.last.char.not.punct + { punct.std 'this.status.punct := } + { punct.no 'this.status.punct := } + if$ + select.language + "``" swap$ * + cap.status.std + } + if$ +} + +FUNCTION {format.article.title.electronic} +{ title duplicate$ empty$ 'skip$ + { this.to.prev.status + this.status.std + cap.status.std + "t" change.case$ + } + if$ + "title" bibinfo.check + duplicate$ empty$ + { skip$ } + { select.language } + if$ +} + +FUNCTION {format.book.title.edition} +{ title "title" bibinfo.check + duplicate$ empty$ + { "empty title in " cite$ * warning$ } + { this.to.prev.status + this.status.std + select.language + emphasize + edition empty$ 'skip$ + { ", " * + edition + convert.edition + status.cap + { "t" } + { "l" } + if$ + change.case$ + * "~" * bbl.edition * + } + if$ + cap.status.std + } + if$ +} + +FUNCTION {format.book.title} +{ title "title" bibinfo.check + duplicate$ empty$ 'skip$ + { this.to.prev.status + this.status.std + cap.status.std + select.language + emphasize + } + if$ +} + + + +%% journal + +FUNCTION {format.journal} +{ journal duplicate$ empty$ 'skip$ + { this.to.prev.status + this.status.std + cap.status.std + select.language + emphasize + } + if$ +} + + + +%% how published + +FUNCTION {format.howpublished} +{ howpublished duplicate$ empty$ 'skip$ + { this.to.prev.status + this.status.std + cap.status.std + } + if$ +} + + + +%% institutions/organization/publishers/school + +FUNCTION {format.institution} +{ institution duplicate$ empty$ 'skip$ + { this.to.prev.status + this.status.std + cap.status.std + } + if$ +} + +FUNCTION {format.organization} +{ organization duplicate$ empty$ 'skip$ + { this.to.prev.status + this.status.std + cap.status.std + } + if$ +} + +FUNCTION {format.address.publisher.date} +{ publisher "publisher" bibinfo.warn format.address.org.or.pub.date } + +FUNCTION {format.address.publisher.date.nowarn} +{ publisher "publisher" bibinfo.check format.address.org.or.pub.date } + +FUNCTION {format.address.organization.date} +{ organization "organization" bibinfo.check format.address.org.or.pub.date } + +FUNCTION {format.school} +{ school duplicate$ empty$ 'skip$ + { this.to.prev.status + this.status.std + cap.status.std + } + if$ +} + + + +%% volume/number/series/chapter/pages + +FUNCTION {format.volume} +{ volume empty.field.to.null.string + duplicate$ empty$ 'skip$ + { this.to.prev.status + this.status.std + bbl.volume + status.cap + { capitalize } + { skip$ } + if$ + swap$ tie.or.space.prefix + "volume" bibinfo.check + * * + cap.status.std + } + if$ +} + +FUNCTION {format.number} +{ number empty.field.to.null.string + duplicate$ empty$ 'skip$ + { this.to.prev.status + this.status.std + status.cap + { bbl.number capitalize } + { bbl.number } + if$ + swap$ tie.or.space.prefix + "number" bibinfo.check + * * + cap.status.std + } + if$ +} + +FUNCTION {format.number.if.use.for.article} +{ is.use.number.for.article + { format.number } + { "" } + if$ +} + +% The IEEE does not seem to tie the series so closely with the volume +% and number as is done in other bibliography styles. Instead the +% series is treated somewhat like an extension of the title. +FUNCTION {format.series} +{ series empty$ + { "" } + { this.to.prev.status + this.status.std + bbl.series " " * + series "series" bibinfo.check * + cap.status.std + } + if$ +} + + +FUNCTION {format.chapter} +{ chapter empty$ + { "" } + { this.to.prev.status + this.status.std + type empty$ + { bbl.chapter } + { type "l" change.case$ + "type" bibinfo.check + } + if$ + chapter tie.or.space.prefix + "chapter" bibinfo.check + * * + cap.status.std + } + if$ +} + + +% The intended use of format.paper is for paper numbers of inproceedings. +% The paper type can be overridden via the type field. +% We allow the type to be displayed even if the paper number is absent +% for things like "postdeadline paper" +FUNCTION {format.paper} +{ is.use.paper + { paper empty$ + { type empty$ + { "" } + { this.to.prev.status + this.status.std + type "type" bibinfo.check + cap.status.std + } + if$ + } + { this.to.prev.status + this.status.std + type empty$ + { bbl.paper } + { type "type" bibinfo.check } + if$ + " " * paper + "paper" bibinfo.check + * + cap.status.std + } + if$ + } + { "" } + if$ +} + + +FUNCTION {format.pages} +{ pages duplicate$ empty$ 'skip$ + { this.to.prev.status + this.status.std + duplicate$ is.multiple.pages + { + bbl.pages swap$ + n.dashify + } + { + bbl.page swap$ + } + if$ + tie.or.space.prefix + "pages" bibinfo.check + * * + cap.status.std + } + if$ +} + + + +%% technical report number + +FUNCTION {format.tech.report.number} +{ number "number" bibinfo.check + this.to.prev.status + this.status.std + cap.status.std + type duplicate$ empty$ + { pop$ + bbl.techrep + } + { skip$ } + if$ + "type" bibinfo.check + swap$ duplicate$ empty$ + { pop$ } + { tie.or.space.prefix * * } + if$ +} + + + +%% note + +FUNCTION {format.note} +{ note empty$ + { "" } + { this.to.prev.status + this.status.std + punct.period 'this.status.punct := + note #1 #1 substring$ + duplicate$ "{" = + { skip$ } + { status.cap + { "u" } + { "l" } + if$ + change.case$ + } + if$ + note #2 global.max$ substring$ * "note" bibinfo.check + cap.yes 'status.cap := + } + if$ +} + + + +%% patent + +FUNCTION {format.patent.date} +{ this.to.prev.status + this.status.std + year empty$ + { monthfiled duplicate$ empty$ + { "monthfiled" bibinfo.check pop$ "" } + { "monthfiled" bibinfo.check } + if$ + dayfiled duplicate$ empty$ + { "dayfiled" bibinfo.check pop$ "" * } + { "dayfiled" bibinfo.check + monthfiled empty$ + { "dayfiled without a monthfiled in " cite$ * warning$ + * + } + { " " swap$ * * } + if$ + } + if$ + yearfiled empty$ + { "no year or yearfiled in " cite$ * warning$ } + { yearfiled "yearfiled" bibinfo.check + swap$ + duplicate$ empty$ + { pop$ } + { ", " * swap$ * } + if$ + } + if$ + } + { month duplicate$ empty$ + { "month" bibinfo.check pop$ "" } + { "month" bibinfo.check } + if$ + day duplicate$ empty$ + { "day" bibinfo.check pop$ "" * } + { "day" bibinfo.check + month empty$ + { "day without a month in " cite$ * warning$ + * + } + { " " swap$ * * } + if$ + } + if$ + year "year" bibinfo.check + swap$ + duplicate$ empty$ + { pop$ } + { ", " * swap$ * } + if$ + } + if$ + cap.status.std +} + +FUNCTION {format.patent.nationality.type.number} +{ this.to.prev.status + this.status.std + nationality duplicate$ empty$ + { "nationality" bibinfo.warn pop$ "" } + { "nationality" bibinfo.check + duplicate$ "l" change.case$ "united states" = + { pop$ bbl.patentUS } + { skip$ } + if$ + " " * + } + if$ + type empty$ + { bbl.patent "type" bibinfo.check } + { type "type" bibinfo.check } + if$ + * + number duplicate$ empty$ + { "number" bibinfo.warn pop$ } + { "number" bibinfo.check + large.number.separate + swap$ " " * swap$ * + } + if$ + cap.status.std +} + + + +%% standard + +FUNCTION {format.organization.institution.standard.type.number} +{ this.to.prev.status + this.status.std + organization duplicate$ empty$ + { pop$ + institution duplicate$ empty$ + { "institution" bibinfo.warn } + { "institution" bibinfo.warn " " * } + if$ + } + { "organization" bibinfo.warn " " * } + if$ + type empty$ + { bbl.standard "type" bibinfo.check } + { type "type" bibinfo.check } + if$ + * + number duplicate$ empty$ + { "number" bibinfo.check pop$ } + { "number" bibinfo.check + large.number.separate + swap$ " " * swap$ * + } + if$ + cap.status.std +} + +FUNCTION {format.revision} +{ revision empty$ + { "" } + { this.to.prev.status + this.status.std + bbl.revision + revision tie.or.space.prefix + "revision" bibinfo.check + * * + cap.status.std + } + if$ +} + + +%% thesis + +FUNCTION {format.master.thesis.type} +{ this.to.prev.status + this.status.std + type empty$ + { + bbl.mthesis + } + { + type "type" bibinfo.check + } + if$ +cap.status.std +} + +FUNCTION {format.phd.thesis.type} +{ this.to.prev.status + this.status.std + type empty$ + { + bbl.phdthesis + } + { + type "type" bibinfo.check + } + if$ +cap.status.std +} + + + +%% URL + +FUNCTION {format.url} +{ is.use.url + { url empty$ + { "" } + { this.to.prev.status + this.status.std + cap.yes 'status.cap := + name.url.prefix " " * + "\url{" * url * "}" * + punct.no 'this.status.punct := + punct.period 'prev.status.punct := + space.normal 'this.status.space := + space.normal 'prev.status.space := + quote.no 'this.status.quote := + } + if$ + } + { "" } + if$ +} + + + + +%%%%%%%%%%%%%%%%%%%% +%% ENTRY HANDLERS %% +%%%%%%%%%%%%%%%%%%%% + + +% Note: In many journals, the IEEE (or the authors) tend not to show the number +% for articles, so the display of the number is controlled here by the +% switch "is.use.number.for.article" +FUNCTION {article} +{ std.status.using.comma + start.entry + if.url.alt.interword.spacing + format.authors "author" output.warn + name.or.dash + format.article.title "title" output.warn + format.journal "journal" bibinfo.check "journal" output.warn + format.volume output + format.number.if.use.for.article output + format.pages output + format.date "year" output.warn + format.note output + format.url output + fin.entry + if.url.std.interword.spacing +} + +FUNCTION {book} +{ std.status.using.comma + start.entry + if.url.alt.interword.spacing + author empty$ + { format.editors "author and editor" output.warn } + { format.authors output.nonnull } + if$ + name.or.dash + format.book.title.edition output + format.series output + author empty$ + { skip$ } + { format.editors output } + if$ + format.address.publisher.date output + format.volume output + format.number output + format.note output + format.url output + fin.entry + if.url.std.interword.spacing +} + +FUNCTION {booklet} +{ std.status.using.comma + start.entry + if.url.alt.interword.spacing + format.authors output + name.or.dash + format.article.title "title" output.warn + format.howpublished "howpublished" bibinfo.check output + format.organization "organization" bibinfo.check output + format.address "address" bibinfo.check output + format.date output + format.note output + format.url output + fin.entry + if.url.std.interword.spacing +} + +FUNCTION {electronic} +{ std.status.using.period + start.entry + if.url.alt.interword.spacing + format.authors output + name.or.dash + format.date.electronic output + format.article.title.electronic output + format.howpublished "howpublished" bibinfo.check output + format.organization "organization" bibinfo.check output + format.address "address" bibinfo.check output + format.note output + format.url output + fin.entry + empty.entry.warn + if.url.std.interword.spacing +} + +FUNCTION {inbook} +{ std.status.using.comma + start.entry + if.url.alt.interword.spacing + author empty$ + { format.editors "author and editor" output.warn } + { format.authors output.nonnull } + if$ + name.or.dash + format.book.title.edition output + format.series output + format.address.publisher.date output + format.volume output + format.number output + format.chapter output + format.pages output + format.note output + format.url output + fin.entry + if.url.std.interword.spacing +} + +FUNCTION {incollection} +{ std.status.using.comma + start.entry + if.url.alt.interword.spacing + format.authors "author" output.warn + name.or.dash + format.article.title "title" output.warn + format.in.booktitle.edition "booktitle" output.warn + format.series output + format.editors output + format.address.publisher.date.nowarn output + format.volume output + format.number output + format.chapter output + format.pages output + format.note output + format.url output + fin.entry + if.url.std.interword.spacing +} + +FUNCTION {inproceedings} +{ std.status.using.comma + start.entry + if.url.alt.interword.spacing + format.authors "author" output.warn + name.or.dash + format.article.title "title" output.warn + format.in.booktitle "booktitle" output.warn + format.series output + format.editors output + format.volume output + format.number output + publisher empty$ + { format.address.organization.date output } + { format.organization "organization" bibinfo.check output + format.address.publisher.date output + } + if$ + format.paper output + format.pages output + format.note output + format.url output + fin.entry + if.url.std.interword.spacing +} + +FUNCTION {manual} +{ std.status.using.comma + start.entry + if.url.alt.interword.spacing + format.authors output + name.or.dash + format.book.title.edition "title" output.warn + format.howpublished "howpublished" bibinfo.check output + format.organization "organization" bibinfo.check output + format.address "address" bibinfo.check output + format.date output + format.note output + format.url output + fin.entry + if.url.std.interword.spacing +} + +FUNCTION {mastersthesis} +{ std.status.using.comma + start.entry + if.url.alt.interword.spacing + format.authors "author" output.warn + name.or.dash + format.article.title "title" output.warn + format.master.thesis.type output.nonnull + format.school "school" bibinfo.warn output + format.address "address" bibinfo.check output + format.date "year" output.warn + format.note output + format.url output + fin.entry + if.url.std.interword.spacing +} + +FUNCTION {misc} +{ std.status.using.comma + start.entry + if.url.alt.interword.spacing + format.authors output + name.or.dash + format.article.title output + format.howpublished "howpublished" bibinfo.check output + format.organization "organization" bibinfo.check output + format.address "address" bibinfo.check output + format.pages output + format.date output + format.note output + format.url output + fin.entry + empty.entry.warn + if.url.std.interword.spacing +} + +FUNCTION {patent} +{ std.status.using.comma + start.entry + if.url.alt.interword.spacing + format.authors output + name.or.dash + format.article.title output + format.patent.nationality.type.number output + format.patent.date output + format.note output + format.url output + fin.entry + empty.entry.warn + if.url.std.interword.spacing +} + +FUNCTION {periodical} +{ std.status.using.comma + start.entry + if.url.alt.interword.spacing + format.editors output + name.or.dash + format.book.title "title" output.warn + format.series output + format.volume output + format.number output + format.organization "organization" bibinfo.check output + format.date "year" output.warn + format.note output + format.url output + fin.entry + if.url.std.interword.spacing +} + +FUNCTION {phdthesis} +{ std.status.using.comma + start.entry + if.url.alt.interword.spacing + format.authors "author" output.warn + name.or.dash + format.article.title "title" output.warn + format.phd.thesis.type output.nonnull + format.school "school" bibinfo.warn output + format.address "address" bibinfo.check output + format.date "year" output.warn + format.note output + format.url output + fin.entry + if.url.std.interword.spacing +} + +FUNCTION {proceedings} +{ std.status.using.comma + start.entry + if.url.alt.interword.spacing + format.editors output + name.or.dash + format.book.title "title" output.warn + format.series output + format.volume output + format.number output + publisher empty$ + { format.address.organization.date output } + { format.organization "organization" bibinfo.check output + format.address.publisher.date output + } + if$ + format.note output + format.url output + fin.entry + if.url.std.interword.spacing +} + +FUNCTION {standard} +{ std.status.using.comma + start.entry + if.url.alt.interword.spacing + format.authors output + name.or.dash + format.book.title "title" output.warn + format.howpublished "howpublished" bibinfo.check output + format.organization.institution.standard.type.number output + format.revision output + format.date output + format.note output + format.url output + fin.entry + if.url.std.interword.spacing +} + +FUNCTION {techreport} +{ std.status.using.comma + start.entry + if.url.alt.interword.spacing + format.authors "author" output.warn + name.or.dash + format.article.title "title" output.warn + format.howpublished "howpublished" bibinfo.check output + format.institution "institution" bibinfo.warn output + format.address "address" bibinfo.check output + format.tech.report.number output.nonnull + format.date "year" output.warn + format.note output + format.url output + fin.entry + if.url.std.interword.spacing +} + +FUNCTION {unpublished} +{ std.status.using.comma + start.entry + if.url.alt.interword.spacing + format.authors "author" output.warn + name.or.dash + format.article.title "title" output.warn + format.date output + format.note "note" output.warn + format.url output + fin.entry + if.url.std.interword.spacing +} + + +% The special entry type which provides the user interface to the +% BST controls +FUNCTION {IEEEtranBSTCTL} +{ is.print.banners.to.terminal + { "** IEEEtran BST control entry " quote$ * cite$ * quote$ * " detected." * + top$ + } + { skip$ } + if$ + CTLuse_article_number + empty$ + { skip$ } + { CTLuse_article_number + yes.no.to.int + 'is.use.number.for.article := + } + if$ + CTLuse_paper + empty$ + { skip$ } + { CTLuse_paper + yes.no.to.int + 'is.use.paper := + } + if$ + CTLuse_url + empty$ + { skip$ } + { CTLuse_url + yes.no.to.int + 'is.use.url := + } + if$ + CTLuse_forced_etal + empty$ + { skip$ } + { CTLuse_forced_etal + yes.no.to.int + 'is.forced.et.al := + } + if$ + CTLmax_names_forced_etal + empty$ + { skip$ } + { CTLmax_names_forced_etal + string.to.integer + 'max.num.names.before.forced.et.al := + } + if$ + CTLnames_show_etal + empty$ + { skip$ } + { CTLnames_show_etal + string.to.integer + 'num.names.shown.with.forced.et.al := + } + if$ + CTLuse_alt_spacing + empty$ + { skip$ } + { CTLuse_alt_spacing + yes.no.to.int + 'is.use.alt.interword.spacing := + } + if$ + CTLalt_stretch_factor + empty$ + { skip$ } + { CTLalt_stretch_factor + 'ALTinterwordstretchfactor := + "\renewcommand{\BIBentryALTinterwordstretchfactor}{" + ALTinterwordstretchfactor * "}" * + write$ newline$ + } + if$ + CTLdash_repeated_names + empty$ + { skip$ } + { CTLdash_repeated_names + yes.no.to.int + 'is.dash.repeated.names := + } + if$ + CTLname_format_string + empty$ + { skip$ } + { CTLname_format_string + 'name.format.string := + } + if$ + CTLname_latex_cmd + empty$ + { skip$ } + { CTLname_latex_cmd + 'name.latex.cmd := + } + if$ + CTLname_url_prefix + missing$ + { skip$ } + { CTLname_url_prefix + 'name.url.prefix := + } + if$ + + + num.names.shown.with.forced.et.al max.num.names.before.forced.et.al > + { "CTLnames_show_etal cannot be greater than CTLmax_names_forced_etal in " cite$ * warning$ + max.num.names.before.forced.et.al 'num.names.shown.with.forced.et.al := + } + { skip$ } + if$ +} + + +%%%%%%%%%%%%%%%%%%% +%% ENTRY ALIASES %% +%%%%%%%%%%%%%%%%%%% +FUNCTION {conference}{inproceedings} +FUNCTION {online}{electronic} +FUNCTION {internet}{electronic} +FUNCTION {webpage}{electronic} +FUNCTION {www}{electronic} +FUNCTION {default.type}{misc} + + + +%%%%%%%%%%%%%%%%%% +%% MAIN PROGRAM %% +%%%%%%%%%%%%%%%%%% + +READ + +EXECUTE {initialize.controls} +EXECUTE {initialize.status.constants} +EXECUTE {banner.message} + +EXECUTE {initialize.longest.label} +ITERATE {longest.label.pass} + +EXECUTE {begin.bib} +ITERATE {call.type$} +EXECUTE {end.bib} + +EXECUTE{completed.message} + + +%% That's all folks, mds. From eeb1c27a6fa0de0d2cfc83b420346f9908f68bd7 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Mon, 2 Dec 2019 22:07:14 +0100 Subject: [PATCH 03/18] Fix package for PreviewLayout and TextBasedPreviewLayout --- src/main/java/org/jabref/gui/DragAndDropDataFormats.java | 2 +- src/main/java/org/jabref/gui/maintable/RightClickMenu.java | 2 +- .../org/jabref/gui/openoffice/StyleSelectDialogView.java | 2 +- .../java/org/jabref/gui/preferences/PreviewTabView.java | 2 +- .../org/jabref/gui/preferences/PreviewTabViewModel.java | 4 ++-- .../jabref/gui/preview/CitationStyleToClipboardWorker.java | 2 +- src/main/java/org/jabref/gui/preview/PreviewPanel.java | 2 +- src/main/java/org/jabref/gui/preview/PreviewViewer.java | 2 +- src/main/java/org/jabref/gui/util/CustomLocalDragboard.java | 2 +- .../org/jabref/logic/{citationstyle => }/PreviewLayout.java | 5 ++++- .../org/jabref/logic/citationstyle/CitationStyleCache.java | 1 + .../logic/citationstyle/CitationStylePreviewLayout.java | 1 + .../{citationstyle => layout}/TextBasedPreviewLayout.java | 6 ++---- src/main/java/org/jabref/preferences/JabRefPreferences.java | 4 ++-- .../java/org/jabref/preferences/PreviewPreferences.java | 4 ++-- 15 files changed, 22 insertions(+), 19 deletions(-) rename src/main/java/org/jabref/logic/{citationstyle => }/PreviewLayout.java (59%) rename src/main/java/org/jabref/logic/{citationstyle => layout}/TextBasedPreviewLayout.java (89%) diff --git a/src/main/java/org/jabref/gui/DragAndDropDataFormats.java b/src/main/java/org/jabref/gui/DragAndDropDataFormats.java index 67aa1cefce0..913035c465d 100644 --- a/src/main/java/org/jabref/gui/DragAndDropDataFormats.java +++ b/src/main/java/org/jabref/gui/DragAndDropDataFormats.java @@ -4,7 +4,7 @@ import javafx.scene.input.DataFormat; -import org.jabref.logic.citationstyle.PreviewLayout; +import org.jabref.logic.PreviewLayout; /** * Contains all the different {@link DataFormat}s that may occur in JabRef. diff --git a/src/main/java/org/jabref/gui/maintable/RightClickMenu.java b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java index 7029810a2fa..ec676cfc530 100644 --- a/src/main/java/org/jabref/gui/maintable/RightClickMenu.java +++ b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java @@ -21,7 +21,7 @@ import org.jabref.gui.mergeentries.FetchAndMergeEntry; import org.jabref.gui.specialfields.SpecialFieldMenuItemFactory; import org.jabref.logic.citationstyle.CitationStylePreviewLayout; -import org.jabref.logic.citationstyle.PreviewLayout; +import org.jabref.logic.PreviewLayout; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.SpecialField; diff --git a/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java b/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java index 3ac1ba09e55..0fad78fc27d 100644 --- a/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java +++ b/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java @@ -18,7 +18,7 @@ import org.jabref.gui.util.BaseDialog; import org.jabref.gui.util.ValueTableCellFactory; import org.jabref.gui.util.ViewModelTableRowFactory; -import org.jabref.logic.citationstyle.TextBasedPreviewLayout; +import org.jabref.logic.layout.TextBasedPreviewLayout; import org.jabref.logic.l10n.Localization; import org.jabref.logic.openoffice.OOBibStyle; import org.jabref.logic.openoffice.StyleLoader; diff --git a/src/main/java/org/jabref/gui/preferences/PreviewTabView.java b/src/main/java/org/jabref/gui/preferences/PreviewTabView.java index 5c4678db9d3..ea1d526c30f 100644 --- a/src/main/java/org/jabref/gui/preferences/PreviewTabView.java +++ b/src/main/java/org/jabref/gui/preferences/PreviewTabView.java @@ -26,7 +26,7 @@ import org.jabref.gui.preview.PreviewViewer; import org.jabref.gui.util.IconValidationDecorator; import org.jabref.gui.util.ViewModelListCellFactory; -import org.jabref.logic.citationstyle.PreviewLayout; +import org.jabref.logic.PreviewLayout; import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.TestEntry; import org.jabref.model.database.BibDatabaseContext; diff --git a/src/main/java/org/jabref/gui/preferences/PreviewTabViewModel.java b/src/main/java/org/jabref/gui/preferences/PreviewTabViewModel.java index e25f26e4260..be0d3efc225 100644 --- a/src/main/java/org/jabref/gui/preferences/PreviewTabViewModel.java +++ b/src/main/java/org/jabref/gui/preferences/PreviewTabViewModel.java @@ -34,8 +34,8 @@ import org.jabref.gui.util.TaskExecutor; import org.jabref.logic.citationstyle.CitationStyle; import org.jabref.logic.citationstyle.CitationStylePreviewLayout; -import org.jabref.logic.citationstyle.PreviewLayout; -import org.jabref.logic.citationstyle.TextBasedPreviewLayout; +import org.jabref.logic.PreviewLayout; +import org.jabref.logic.layout.TextBasedPreviewLayout; import org.jabref.logic.l10n.Localization; import org.jabref.preferences.JabRefPreferences; import org.jabref.preferences.PreviewPreferences; diff --git a/src/main/java/org/jabref/gui/preview/CitationStyleToClipboardWorker.java b/src/main/java/org/jabref/gui/preview/CitationStyleToClipboardWorker.java index 23a4f056d36..ccc017c48f3 100644 --- a/src/main/java/org/jabref/gui/preview/CitationStyleToClipboardWorker.java +++ b/src/main/java/org/jabref/gui/preview/CitationStyleToClipboardWorker.java @@ -16,7 +16,7 @@ import org.jabref.logic.citationstyle.CitationStyleGenerator; import org.jabref.logic.citationstyle.CitationStyleOutputFormat; import org.jabref.logic.citationstyle.CitationStylePreviewLayout; -import org.jabref.logic.citationstyle.PreviewLayout; +import org.jabref.logic.PreviewLayout; import org.jabref.logic.l10n.Localization; import org.jabref.logic.layout.Layout; import org.jabref.logic.layout.LayoutFormatterPreferences; diff --git a/src/main/java/org/jabref/gui/preview/PreviewPanel.java b/src/main/java/org/jabref/gui/preview/PreviewPanel.java index 941818ae8ef..a8ec0bd69f1 100644 --- a/src/main/java/org/jabref/gui/preview/PreviewPanel.java +++ b/src/main/java/org/jabref/gui/preview/PreviewPanel.java @@ -23,7 +23,7 @@ import org.jabref.gui.icon.IconTheme; import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.keyboard.KeyBindingRepository; -import org.jabref.logic.citationstyle.PreviewLayout; +import org.jabref.logic.PreviewLayout; import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; diff --git a/src/main/java/org/jabref/gui/preview/PreviewViewer.java b/src/main/java/org/jabref/gui/preview/PreviewViewer.java index 937a16b987a..9cdff10b761 100644 --- a/src/main/java/org/jabref/gui/preview/PreviewViewer.java +++ b/src/main/java/org/jabref/gui/preview/PreviewViewer.java @@ -23,7 +23,7 @@ import org.jabref.gui.util.BackgroundTask; import org.jabref.gui.util.TaskExecutor; import org.jabref.gui.util.ThemeLoader; -import org.jabref.logic.citationstyle.PreviewLayout; +import org.jabref.logic.PreviewLayout; import org.jabref.logic.exporter.ExporterFactory; import org.jabref.logic.l10n.Localization; import org.jabref.logic.search.SearchQuery; diff --git a/src/main/java/org/jabref/gui/util/CustomLocalDragboard.java b/src/main/java/org/jabref/gui/util/CustomLocalDragboard.java index 6f25aedd8b5..98b3798934c 100644 --- a/src/main/java/org/jabref/gui/util/CustomLocalDragboard.java +++ b/src/main/java/org/jabref/gui/util/CustomLocalDragboard.java @@ -7,7 +7,7 @@ import org.jabref.gui.DragAndDropDataFormats; import org.jabref.gui.GUIGlobals; -import org.jabref.logic.citationstyle.PreviewLayout; +import org.jabref.logic.PreviewLayout; import org.jabref.model.entry.BibEntry; /** diff --git a/src/main/java/org/jabref/logic/citationstyle/PreviewLayout.java b/src/main/java/org/jabref/logic/PreviewLayout.java similarity index 59% rename from src/main/java/org/jabref/logic/citationstyle/PreviewLayout.java rename to src/main/java/org/jabref/logic/PreviewLayout.java index e47eec9f01c..0d9db028cfc 100644 --- a/src/main/java/org/jabref/logic/citationstyle/PreviewLayout.java +++ b/src/main/java/org/jabref/logic/PreviewLayout.java @@ -1,8 +1,11 @@ -package org.jabref.logic.citationstyle; +package org.jabref.logic; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; +/** + * Used for displaying a rendered entry in the UI. Due to historical reasons, "rendering" is called "layout". + */ public interface PreviewLayout { String generatePreview(BibEntry entry, BibDatabase database); diff --git a/src/main/java/org/jabref/logic/citationstyle/CitationStyleCache.java b/src/main/java/org/jabref/logic/citationstyle/CitationStyleCache.java index 0e9a546b2c3..f994bc945c1 100644 --- a/src/main/java/org/jabref/logic/citationstyle/CitationStyleCache.java +++ b/src/main/java/org/jabref/logic/citationstyle/CitationStyleCache.java @@ -2,6 +2,7 @@ import java.util.Objects; +import org.jabref.logic.PreviewLayout; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.event.EntriesRemovedEvent; import org.jabref.model.entry.BibEntry; diff --git a/src/main/java/org/jabref/logic/citationstyle/CitationStylePreviewLayout.java b/src/main/java/org/jabref/logic/citationstyle/CitationStylePreviewLayout.java index c07bce6ebfd..0055548682c 100644 --- a/src/main/java/org/jabref/logic/citationstyle/CitationStylePreviewLayout.java +++ b/src/main/java/org/jabref/logic/citationstyle/CitationStylePreviewLayout.java @@ -1,5 +1,6 @@ package org.jabref.logic.citationstyle; +import org.jabref.logic.PreviewLayout; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; diff --git a/src/main/java/org/jabref/logic/citationstyle/TextBasedPreviewLayout.java b/src/main/java/org/jabref/logic/layout/TextBasedPreviewLayout.java similarity index 89% rename from src/main/java/org/jabref/logic/citationstyle/TextBasedPreviewLayout.java rename to src/main/java/org/jabref/logic/layout/TextBasedPreviewLayout.java index 193a0fd6949..d4db4266751 100644 --- a/src/main/java/org/jabref/logic/citationstyle/TextBasedPreviewLayout.java +++ b/src/main/java/org/jabref/logic/layout/TextBasedPreviewLayout.java @@ -1,12 +1,10 @@ -package org.jabref.logic.citationstyle; +package org.jabref.logic.layout; import java.io.IOException; import java.io.StringReader; +import org.jabref.logic.PreviewLayout; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.layout.Layout; -import org.jabref.logic.layout.LayoutFormatterPreferences; -import org.jabref.logic.layout.LayoutHelper; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java index d4d40c3bf7d..527b85e6177 100644 --- a/src/main/java/org/jabref/preferences/JabRefPreferences.java +++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java @@ -60,8 +60,8 @@ import org.jabref.logic.bibtexkeypattern.BibtexKeyPatternPreferences; import org.jabref.logic.citationstyle.CitationStyle; import org.jabref.logic.citationstyle.CitationStylePreviewLayout; -import org.jabref.logic.citationstyle.PreviewLayout; -import org.jabref.logic.citationstyle.TextBasedPreviewLayout; +import org.jabref.logic.PreviewLayout; +import org.jabref.logic.layout.TextBasedPreviewLayout; import org.jabref.logic.cleanup.CleanupPreferences; import org.jabref.logic.cleanup.CleanupPreset; import org.jabref.logic.cleanup.Cleanups; diff --git a/src/main/java/org/jabref/preferences/PreviewPreferences.java b/src/main/java/org/jabref/preferences/PreviewPreferences.java index efec4035934..f58166dd334 100644 --- a/src/main/java/org/jabref/preferences/PreviewPreferences.java +++ b/src/main/java/org/jabref/preferences/PreviewPreferences.java @@ -3,8 +3,8 @@ import java.util.List; import org.jabref.Globals; -import org.jabref.logic.citationstyle.PreviewLayout; -import org.jabref.logic.citationstyle.TextBasedPreviewLayout; +import org.jabref.logic.PreviewLayout; +import org.jabref.logic.layout.TextBasedPreviewLayout; import org.jabref.logic.layout.LayoutFormatterPreferences; public class PreviewPreferences { From 2d4eb081e403ac68cac3dd325c6d048c5f3680e8 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Mon, 2 Dec 2019 23:27:55 +0100 Subject: [PATCH 04/18] Introduce BstPreviewLayout --- .../jabref/logic/bst/BstPreviewLayout.java | 80 ++++++++ src/main/java/org/jabref/logic/bst/VM.java | 187 +++++++++--------- .../logic/layout/format/RemoveWhitespace.java | 3 - .../jabref/preferences/JabRefPreferences.java | 5 +- .../logic/bst/BstPreviewLayoutTest.java | 51 +++++ .../bibtexfields/ClearFormatterTest.java | 1 - 6 files changed, 228 insertions(+), 99 deletions(-) create mode 100644 src/main/java/org/jabref/logic/bst/BstPreviewLayout.java create mode 100644 src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java diff --git a/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java b/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java new file mode 100644 index 00000000000..05170873abe --- /dev/null +++ b/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java @@ -0,0 +1,80 @@ +package org.jabref.logic.bst; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +import org.jabref.logic.PreviewLayout; +import org.jabref.logic.cleanup.ConvertToBiblatexCleanup; +import org.jabref.logic.cleanup.ConvertToBibtexCleanup; +import org.jabref.logic.formatter.bibtexfields.RemoveNewlinesFormatter; +import org.jabref.logic.l10n.Localization; +import org.jabref.logic.layout.format.RemoveLatexCommandsFormatter; +import org.jabref.logic.layout.format.RemoveTilde; +import org.jabref.logic.layout.format.RemoveWhitespace; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; + +import org.antlr.runtime.RecognitionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class BstPreviewLayout implements PreviewLayout { + + private static final Logger LOGGER = LoggerFactory.getLogger(BstPreviewLayout.class); + + private final String name; + + private VM vm; + private String error; + + public BstPreviewLayout(String filename) { + this(Paths.get(filename)); + } + + public BstPreviewLayout(Path path) { + name = path.getFileName().toString(); + if (!Files.exists(path)) { + LOGGER.error("File {} not found", path.toAbsolutePath()); + error = Localization.lang("Error opening file '%0'.", path.toString()); + return; + } + try { + vm = new VM(path.toFile()); + } catch (Exception e) { + LOGGER.error("Could not read {}.", path.toAbsolutePath(), e); + error = Localization.lang("Error opening file '%0'.", path.toString()); + } + } + + @Override + public String generatePreview(BibEntry entry, BibDatabase database) { + if (error != null) { + return error; + } + // ensure that the entry is of BibTeX format (and do not modify the original entry) + entry = (BibEntry) entry.clone(); + new ConvertToBibtexCleanup().cleanup(entry); + String result = vm.run(List.of(entry)); + result = new RemoveNewlinesFormatter().format(result); + // The RemoveLatexCommandsFormatter keeps the words inside latex environments. Therefore, we remove them manually + result = result.replace("\\begin{thebibliography}{1}", ""); + result = result.replace("\\end{thebibliography}", ""); + // The RemoveLatexCommandsFormatter keeps the word inside the latex command, but we want to remove that completely + result = result.replaceAll("\\\\bibitem[{].*[}]", ""); + // We want to replace \newblock by a space instead of completely removing it + result = result.replace("\\newblock", " "); + // Final cleanup + result = new RemoveLatexCommandsFormatter().format(result); + result = new RemoveTilde().format(result); + result = result.trim().replaceAll(" +", " "); + return result; + } + + @Override + public String getName() { + return name; + } +} diff --git a/src/main/java/org/jabref/logic/bst/VM.java b/src/main/java/org/jabref/logic/bst/VM.java index b9349a4a0ae..7e1fe99d0fa 100644 --- a/src/main/java/org/jabref/logic/bst/VM.java +++ b/src/main/java/org/jabref/logic/bst/VM.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.Objects; import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -31,13 +32,11 @@ import org.slf4j.LoggerFactory; /** - * * A BibTeX Virtual machine that can execute .bst files. - * + *

* Documentation can be found in the original bibtex distribution: - * + *

* https://www.ctan.org/pkg/bibtex - * */ public class VM implements Warn { @@ -221,7 +220,16 @@ private VM(CommonTree tree) { Object o2 = stack.pop(); Object o1 = stack.pop(); + if (o1 == null) { + o1 = ""; + } + if (o2 == null) { + o2 = ""; + } + if (!((o1 instanceof String) && (o2 instanceof String))) { + LOGGER.error("o1: {} ({})", o1, o1.getClass()); + LOGGER.error("o2: {} ({})", o2, o2.getClass()); throw new VMException("Can only concatenate two String with *"); } @@ -489,7 +497,7 @@ private VM(CommonTree tree) { * Is a no-op. */ buildInFunctions.put("skip$", context -> { - // Nothing to do! Yeah! + // Nothing to do! Yeah! }); /* @@ -609,7 +617,6 @@ public void execute(BstEntry context) { String s = (String) stack.pop(); VM.this.bbl.append(s); }); - } private void textLengthFunction() { @@ -812,7 +819,6 @@ private boolean assign(BstEntry context, Object o1, Object o2) { return true; } return false; - } if ((context != null) && context.localIntegers.containsKey(name)) { @@ -833,6 +839,15 @@ public String run(BibDatabase db) { } public String run(Collection bibtex) { + return this.run(bibtex, null); + } + + /** + * @param bibtex list of entries to convert + * @param bibDatabase (may be null) the bibDatabase used for resolving strings / crossref + */ + public String run(Collection bibtex, BibDatabase bibDatabase) { + Objects.requireNonNull(bibtex); // Reset bbl = new StringBuilder(); @@ -858,39 +873,39 @@ public String run(Collection bibtex) { for (int i = 0; i < tree.getChildCount(); i++) { Tree child = tree.getChild(i); switch (child.getType()) { - case BstParser.STRINGS: - strings(child); - break; - case BstParser.INTEGERS: - integers(child); - break; - case BstParser.FUNCTION: - function(child); - break; - case BstParser.EXECUTE: - execute(child); - break; - case BstParser.SORT: - sort(); - break; - case BstParser.ITERATE: - iterate(child); - break; - case BstParser.REVERSE: - reverse(child); - break; - case BstParser.ENTRY: - entry(child); - break; - case BstParser.READ: - read(); - break; - case BstParser.MACRO: - macro(child); - break; - default: - LOGGER.info("Unknown type: " + child.getType()); - break; + case BstParser.STRINGS: + strings(child); + break; + case BstParser.INTEGERS: + integers(child); + break; + case BstParser.FUNCTION: + function(child); + break; + case BstParser.EXECUTE: + execute(child); + break; + case BstParser.SORT: + sort(); + break; + case BstParser.ITERATE: + iterate(child); + break; + case BstParser.REVERSE: + reverse(child); + break; + case BstParser.ENTRY: + entry(child); + break; + case BstParser.READ: + read(bibDatabase); + break; + case BstParser.MACRO: + macro(child); + break; + default: + LOGGER.info("Unknown type: " + child.getType()); + break; } } @@ -898,19 +913,18 @@ public String run(Collection bibtex) { } /** - * Dredges up from the database file the field values for each entry in the - * list. It has no arguments. If a database entry doesn't have a value for a - * field (and probably no database entry will have a value for every field), - * that field variable is marked as missing for the entry. - * + * Dredges up from the database file the field values for each entry in the list. It has no arguments. If a database + * entry doesn't have a value for a field (and probably no database entry will have a value for every field), that + * field variable is marked as missing for the entry. + *

* We use null for the missing entry designator. + * @param bibDatabase */ - private void read() { + private void read(BibDatabase bibDatabase) { for (BstEntry e : entries) { for (Map.Entry mEntry : e.getFields().entrySet()) { Field field = FieldFactory.parseField(mEntry.getKey()); - String fieldValue = e.getBibtexEntry().getField(field).orElse(null); - + String fieldValue = e.getBibtexEntry().getResolvedFieldOrAlias(field, bibDatabase).orElse(null); mEntry.setValue(fieldValue); } } @@ -923,14 +937,11 @@ private void read() { } /** - * Defines a string macro. It has two arguments; the first is the macro's - * name, which is treated like any other variable or function name, and the - * second is its definition, which must be double-quote-delimited. You must - * have one for each three-letter month abbreviation; in addition, you - * should have one for common journal names. The user's database may - * override any definition you define using this command. If you want to - * define a string the user can't touch, use the FUNCTION command, which has - * a compatible syntax. + * Defines a string macro. It has two arguments; the first is the macro's name, which is treated like any other + * variable or function name, and the second is its definition, which must be double-quote-delimited. You must have + * one for each three-letter month abbreviation; in addition, you should have one for common journal names. The + * user's database may override any definition you define using this command. If you want to define a string the + * user can't touch, use the FUNCTION command, which has a compatible syntax. */ private void macro(Tree child) { String name = child.getChild(0).getText(); @@ -942,7 +953,6 @@ public class MacroFunction implements BstFunction { private final String replacement; - public MacroFunction(String replacement) { this.replacement = replacement; } @@ -954,13 +964,11 @@ public void execute(BstEntry context) { } /** - * Declares the fields and entry variables. It has three arguments, each a - * (possibly empty) list of variable names. The three lists are of: fields, - * integer entry variables, and string entry variables. There is an - * additional field that BibTEX automatically declares, crossref, used for - * cross referencing. And there is an additional string entry variable - * automatically declared, sort.key$, used by the SORT command. Each of - * these variables has a value for each entry on the list. + * Declares the fields and entry variables. It has three arguments, each a (possibly empty) list of variable names. + * The three lists are of: fields, integer entry variables, and string entry variables. There is an additional field + * that BibTEX automatically declares, crossref, used for cross referencing. And there is an additional string entry + * variable automatically declared, sort.key$, used by the SORT command. Each of these variables has a value for + * each entry on the list. */ private void entry(Tree child) { // Fields first @@ -1040,7 +1048,6 @@ public class StackFunction implements BstFunction { private final Tree localTree; - public StackFunction(Tree stack) { localTree = stack; } @@ -1058,22 +1065,22 @@ public void execute(BstEntry context) { try { switch (c.getType()) { - case BstParser.STRING: - String s = c.getText(); - push(s.substring(1, s.length() - 1)); - break; - case BstParser.INTEGER: - push(Integer.parseInt(c.getText().substring(1))); - break; - case BstParser.QUOTED: - push(new Identifier(c.getText().substring(1))); - break; - case BstParser.STACK: - push(c); - break; - default: - VM.this.execute(c.getText(), context); - break; + case BstParser.STRING: + String s = c.getText(); + push(s.substring(1, s.length() - 1)); + break; + case BstParser.INTEGER: + push(Integer.parseInt(c.getText().substring(1))); + break; + case BstParser.QUOTED: + push(new Identifier(c.getText().substring(1))); + break; + case BstParser.STACK: + push(c); + break; + default: + VM.this.execute(c.getText(), context); + break; } } catch (VMException e) { if (file == null) { @@ -1085,7 +1092,6 @@ public void execute(BstEntry context) { throw e; } } - } } @@ -1132,16 +1138,12 @@ private void function(Tree child) { String name = child.getChild(0).getText(); Tree localStack = child.getChild(1); functions.put(name, new StackFunction(localStack)); - } /** - * Declares global integer variables. It has one argument, a list of - * variable names. There are two such automatically-declared variables, - * entry.max$ and global.max$, used for limiting the lengths of string vari- - * ables. You may have any number of these commands, but a variable's - * declaration must precede its use. - * + * Declares global integer variables. It has one argument, a list of variable names. There are two such + * automatically-declared variables, entry.max$ and global.max$, used for limiting the lengths of string vari- + * ables. You may have any number of these commands, but a variable's declaration must precede its use. */ private void integers(Tree child) { Tree t = child.getChild(0); @@ -1153,9 +1155,8 @@ private void integers(Tree child) { } /** - * Declares global string variables. It has one argument, a list of variable - * names. You may have any number of these commands, but a variable's - * declaration must precede its use. + * Declares global string variables. It has one argument, a list of variable names. You may have any number of these + * commands, but a variable's declaration must precede its use. * * @param child */ @@ -1178,7 +1179,6 @@ public static class BstEntry { private final Map localIntegers = new HashMap<>(); - public BstEntry(BibEntry e) { this.entry = e; } @@ -1228,5 +1228,4 @@ public Stack getStack() { public void warn(String string) { LOGGER.warn(string); } - } diff --git a/src/main/java/org/jabref/logic/layout/format/RemoveWhitespace.java b/src/main/java/org/jabref/logic/layout/format/RemoveWhitespace.java index 747c726a880..15dc444965e 100644 --- a/src/main/java/org/jabref/logic/layout/format/RemoveWhitespace.java +++ b/src/main/java/org/jabref/logic/layout/format/RemoveWhitespace.java @@ -4,14 +4,11 @@ /** * Remove non printable character formatter. - * - * Based on the RemoveBrackets.java class (Revision 1.2) by mortenalver */ public class RemoveWhitespace implements LayoutFormatter { @Override public String format(String fieldEntry) { - if (fieldEntry == null) { return null; } diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java index 527b85e6177..f0013bd09ce 100644 --- a/src/main/java/org/jabref/preferences/JabRefPreferences.java +++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java @@ -58,6 +58,7 @@ import org.jabref.logic.bibtex.FieldContentParserPreferences; import org.jabref.logic.bibtex.LatexFieldFormatterPreferences; import org.jabref.logic.bibtexkeypattern.BibtexKeyPatternPreferences; +import org.jabref.logic.bst.BstPreviewLayout; import org.jabref.logic.citationstyle.CitationStyle; import org.jabref.logic.citationstyle.CitationStylePreviewLayout; import org.jabref.logic.PreviewLayout; @@ -733,7 +734,7 @@ private JabRefPreferences() { defaults.put(VERSION_IGNORED_UPDATE, ""); // preview - defaults.put(CYCLE_PREVIEW, "Preview;" + CitationStyle.DEFAULT); + defaults.put(CYCLE_PREVIEW, "Preview;" + "bst/IEEEtran.bst;" + CitationStyle.DEFAULT); defaults.put(CYCLE_PREVIEW_POS, 0); defaults.put(PREVIEW_PANEL_HEIGHT, 0.65); defaults.put(PREVIEW_AS_TAB, Boolean.FALSE); @@ -1613,6 +1614,8 @@ public PreviewPreferences getPreviewPreferences() { return CitationStyle.createCitationStyleFromFile(layout) .map(file -> (PreviewLayout) new CitationStylePreviewLayout(file)) .orElse(null); + } else if (layout.endsWith(".bst")) { + return new BstPreviewLayout(layout); } else { return new TextBasedPreviewLayout(style, getLayoutFormatterPreferences(Globals.journalAbbreviationLoader)); } diff --git a/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java b/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java new file mode 100644 index 00000000000..f977616fc0a --- /dev/null +++ b/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java @@ -0,0 +1,51 @@ +package org.jabref.logic.bst; + +import java.nio.file.Paths; + +import org.jabref.logic.formatter.bibtexfields.LatexCleanupFormatter; +import org.jabref.model.database.BibDatabase; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.StandardField; +import org.jabref.model.entry.types.StandardEntryType; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; + +class BstPreviewLayoutTest { + + private BstPreviewLayout bstPreviewLayout; + + @BeforeEach + public void initialize() throws Exception { + bstPreviewLayout = new BstPreviewLayout(Paths.get(BstPreviewLayoutTest.class.getResource("abbrv.bst").toURI())); + } + + @Test + public void generatePreviewForSimpleEntry() { + BibEntry entry = new BibEntry().withField(StandardField.AUTHOR, "Oliver Kopp").withField(StandardField.TITLE, "Thoughts on Development"); + BibDatabase bibDatabase = mock(BibDatabase.class); + String preview = bstPreviewLayout.generatePreview(entry, bibDatabase); + assertEquals("O. Kopp. Thoughts on development.", preview); + } + + @Test + public void generatePreviewForSliceTheoremPaper() { + BibEntry sliceTheoremPaper = new BibEntry(); + sliceTheoremPaper.setType(StandardEntryType.Article); + sliceTheoremPaper.setField(StandardField.AUTHOR, "Tobias Diez"); + sliceTheoremPaper.setField(StandardField.TITLE, "Slice theorem for Fréchet group actions and covariant symplectic field theory"); + sliceTheoremPaper.setField(StandardField.DATE, "2014-05-09"); + sliceTheoremPaper.setField(StandardField.ABSTRACT, "A general slice theorem for the action of a Fr\\'echet Lie group on a Fr\\'echet manifolds is established. The Nash-Moser theorem provides the fundamental tool to generalize the result of Palais to this infinite-dimensional setting. The presented slice theorem is illustrated by its application to gauge theories: the action of the gauge transformation group admits smooth slices at every point and thus the gauge orbit space is stratified by Fr\\'echet manifolds. Furthermore, a covariant and symplectic formulation of classical field theory is proposed and extensively discussed. At the root of this novel framework is the incorporation of field degrees of freedom F and spacetime M into the product manifold F * M. The induced bigrading of differential forms is used in order to carry over the usual symplectic theory to this new setting. The examples of the Klein-Gordon field and general Yang-Mills theory illustrate that the presented approach conveniently handles the occurring symmetries."); + sliceTheoremPaper.setField(StandardField.EPRINT, "1405.2249v1"); + sliceTheoremPaper.setField(StandardField.FILE, ":http\\://arxiv.org/pdf/1405.2249v1:PDF"); + sliceTheoremPaper.setField(StandardField.EPRINTTYPE, "arXiv"); + sliceTheoremPaper.setField(StandardField.EPRINTCLASS, "math-ph"); + sliceTheoremPaper.setField(StandardField.KEYWORDS, "math-ph, math.DG, math.MP, math.SG, 58B99, 58Z05, 58B25, 22E65, 58D19, 53D20, 53D42"); + BibDatabase bibDatabase = mock(BibDatabase.class); + String preview = bstPreviewLayout.generatePreview(sliceTheoremPaper, bibDatabase); + assertEquals("T. Diez. Slice theorem for fréchet group actions and covariant symplectic field theory. #may# 2014.", preview); + } +} diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/ClearFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/ClearFormatterTest.java index ea4f8407eb5..e1c759ac635 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/ClearFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/ClearFormatterTest.java @@ -8,7 +8,6 @@ /** * Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest} */ - public class ClearFormatterTest { private ClearFormatter formatter; From f16d690509e391a86801d57d9e6e112ba2884ec5 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Tue, 3 Dec 2019 00:04:23 +0100 Subject: [PATCH 05/18] Fix checkstyle --- src/main/java/org/jabref/gui/maintable/RightClickMenu.java | 2 +- .../java/org/jabref/gui/openoffice/StyleSelectDialogView.java | 2 +- .../java/org/jabref/gui/preferences/PreviewTabViewModel.java | 4 ++-- .../jabref/gui/preview/CitationStyleToClipboardWorker.java | 2 +- src/main/java/org/jabref/logic/bst/BstPreviewLayout.java | 4 ---- src/main/java/org/jabref/preferences/JabRefPreferences.java | 4 ++-- src/main/java/org/jabref/preferences/PreviewPreferences.java | 2 +- src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java | 1 - 8 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/jabref/gui/maintable/RightClickMenu.java b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java index ec676cfc530..08851fd5149 100644 --- a/src/main/java/org/jabref/gui/maintable/RightClickMenu.java +++ b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java @@ -20,8 +20,8 @@ import org.jabref.gui.menus.ChangeEntryTypeMenu; import org.jabref.gui.mergeentries.FetchAndMergeEntry; import org.jabref.gui.specialfields.SpecialFieldMenuItemFactory; -import org.jabref.logic.citationstyle.CitationStylePreviewLayout; import org.jabref.logic.PreviewLayout; +import org.jabref.logic.citationstyle.CitationStylePreviewLayout; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.SpecialField; diff --git a/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java b/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java index 0fad78fc27d..d4fac5b02ce 100644 --- a/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java +++ b/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java @@ -18,8 +18,8 @@ import org.jabref.gui.util.BaseDialog; import org.jabref.gui.util.ValueTableCellFactory; import org.jabref.gui.util.ViewModelTableRowFactory; -import org.jabref.logic.layout.TextBasedPreviewLayout; import org.jabref.logic.l10n.Localization; +import org.jabref.logic.layout.TextBasedPreviewLayout; import org.jabref.logic.openoffice.OOBibStyle; import org.jabref.logic.openoffice.StyleLoader; import org.jabref.logic.util.TestEntry; diff --git a/src/main/java/org/jabref/gui/preferences/PreviewTabViewModel.java b/src/main/java/org/jabref/gui/preferences/PreviewTabViewModel.java index be0d3efc225..80f3c498747 100644 --- a/src/main/java/org/jabref/gui/preferences/PreviewTabViewModel.java +++ b/src/main/java/org/jabref/gui/preferences/PreviewTabViewModel.java @@ -32,11 +32,11 @@ import org.jabref.gui.util.CustomLocalDragboard; import org.jabref.gui.util.NoSelectionModel; import org.jabref.gui.util.TaskExecutor; +import org.jabref.logic.PreviewLayout; import org.jabref.logic.citationstyle.CitationStyle; import org.jabref.logic.citationstyle.CitationStylePreviewLayout; -import org.jabref.logic.PreviewLayout; -import org.jabref.logic.layout.TextBasedPreviewLayout; import org.jabref.logic.l10n.Localization; +import org.jabref.logic.layout.TextBasedPreviewLayout; import org.jabref.preferences.JabRefPreferences; import org.jabref.preferences.PreviewPreferences; diff --git a/src/main/java/org/jabref/gui/preview/CitationStyleToClipboardWorker.java b/src/main/java/org/jabref/gui/preview/CitationStyleToClipboardWorker.java index ccc017c48f3..5dc01aa9a91 100644 --- a/src/main/java/org/jabref/gui/preview/CitationStyleToClipboardWorker.java +++ b/src/main/java/org/jabref/gui/preview/CitationStyleToClipboardWorker.java @@ -13,10 +13,10 @@ import org.jabref.gui.DialogService; import org.jabref.gui.util.BackgroundTask; import org.jabref.gui.util.TaskExecutor; +import org.jabref.logic.PreviewLayout; import org.jabref.logic.citationstyle.CitationStyleGenerator; import org.jabref.logic.citationstyle.CitationStyleOutputFormat; import org.jabref.logic.citationstyle.CitationStylePreviewLayout; -import org.jabref.logic.PreviewLayout; import org.jabref.logic.l10n.Localization; import org.jabref.logic.layout.Layout; import org.jabref.logic.layout.LayoutFormatterPreferences; diff --git a/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java b/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java index 05170873abe..f924fbfd532 100644 --- a/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java +++ b/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java @@ -1,23 +1,19 @@ package org.jabref.logic.bst; -import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import org.jabref.logic.PreviewLayout; -import org.jabref.logic.cleanup.ConvertToBiblatexCleanup; import org.jabref.logic.cleanup.ConvertToBibtexCleanup; import org.jabref.logic.formatter.bibtexfields.RemoveNewlinesFormatter; import org.jabref.logic.l10n.Localization; import org.jabref.logic.layout.format.RemoveLatexCommandsFormatter; import org.jabref.logic.layout.format.RemoveTilde; -import org.jabref.logic.layout.format.RemoveWhitespace; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; -import org.antlr.runtime.RecognitionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java index f0013bd09ce..3f49cf1bdfc 100644 --- a/src/main/java/org/jabref/preferences/JabRefPreferences.java +++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java @@ -55,14 +55,13 @@ import org.jabref.gui.push.PushToApplicationsManager; import org.jabref.gui.specialfields.SpecialFieldsPreferences; import org.jabref.gui.util.ThemeLoader; +import org.jabref.logic.PreviewLayout; import org.jabref.logic.bibtex.FieldContentParserPreferences; import org.jabref.logic.bibtex.LatexFieldFormatterPreferences; import org.jabref.logic.bibtexkeypattern.BibtexKeyPatternPreferences; import org.jabref.logic.bst.BstPreviewLayout; import org.jabref.logic.citationstyle.CitationStyle; import org.jabref.logic.citationstyle.CitationStylePreviewLayout; -import org.jabref.logic.PreviewLayout; -import org.jabref.logic.layout.TextBasedPreviewLayout; import org.jabref.logic.cleanup.CleanupPreferences; import org.jabref.logic.cleanup.CleanupPreset; import org.jabref.logic.cleanup.Cleanups; @@ -76,6 +75,7 @@ import org.jabref.logic.l10n.Language; import org.jabref.logic.l10n.Localization; import org.jabref.logic.layout.LayoutFormatterPreferences; +import org.jabref.logic.layout.TextBasedPreviewLayout; import org.jabref.logic.layout.format.FileLinkPreferences; import org.jabref.logic.layout.format.NameFormatterPreferences; import org.jabref.logic.net.ProxyPreferences; diff --git a/src/main/java/org/jabref/preferences/PreviewPreferences.java b/src/main/java/org/jabref/preferences/PreviewPreferences.java index f58166dd334..de5f74785ad 100644 --- a/src/main/java/org/jabref/preferences/PreviewPreferences.java +++ b/src/main/java/org/jabref/preferences/PreviewPreferences.java @@ -4,8 +4,8 @@ import org.jabref.Globals; import org.jabref.logic.PreviewLayout; -import org.jabref.logic.layout.TextBasedPreviewLayout; import org.jabref.logic.layout.LayoutFormatterPreferences; +import org.jabref.logic.layout.TextBasedPreviewLayout; public class PreviewPreferences { diff --git a/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java b/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java index f977616fc0a..17ca3ff527f 100644 --- a/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java +++ b/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java @@ -2,7 +2,6 @@ import java.nio.file.Paths; -import org.jabref.logic.formatter.bibtexfields.LatexCleanupFormatter; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.StandardField; From 30e0ac33af05336fd1ca27bea954d670a71de7bf Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Tue, 3 Dec 2019 06:30:07 +0100 Subject: [PATCH 06/18] Fix Bst.g to allow "_" as identifier --- src/main/antlr3/org/jabref/bst/Bst.g | 2 +- src/main/java/org/jabref/logic/bst/VM.java | 2 +- .../logic/bst/BstPreviewLayoutTest.java | 50 +++++++++++-------- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/main/antlr3/org/jabref/bst/Bst.g b/src/main/antlr3/org/jabref/bst/Bst.g index 206330ee8f4..498621ad1a1 100644 --- a/src/main/antlr3/org/jabref/bst/Bst.g +++ b/src/main/antlr3/org/jabref/bst/Bst.g @@ -73,7 +73,7 @@ QUOTED : '\'' IDENTIFIER; IDENTIFIER - : LETTER (LETTER|NUMERAL)* ; + : LETTER (LETTER|NUMERAL|'_')* ; fragment LETTER : ('a'..'z'|'A'..'Z'|'.'|'$'); diff --git a/src/main/java/org/jabref/logic/bst/VM.java b/src/main/java/org/jabref/logic/bst/VM.java index 7e1fe99d0fa..448266e9c89 100644 --- a/src/main/java/org/jabref/logic/bst/VM.java +++ b/src/main/java/org/jabref/logic/bst/VM.java @@ -904,7 +904,7 @@ public String run(Collection bibtex, BibDatabase bibDatabase) { macro(child); break; default: - LOGGER.info("Unknown type: " + child.getType()); + LOGGER.info("Unknown type: {}", child.getType()); break; } } diff --git a/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java b/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java index 17ca3ff527f..d4f7c3b7b6f 100644 --- a/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java +++ b/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java @@ -15,36 +15,42 @@ class BstPreviewLayoutTest { - private BstPreviewLayout bstPreviewLayout; - - @BeforeEach - public void initialize() throws Exception { - bstPreviewLayout = new BstPreviewLayout(Paths.get(BstPreviewLayoutTest.class.getResource("abbrv.bst").toURI())); - } + private BibDatabase bibDatabase = mock(BibDatabase.class); @Test - public void generatePreviewForSimpleEntry() { - BibEntry entry = new BibEntry().withField(StandardField.AUTHOR, "Oliver Kopp").withField(StandardField.TITLE, "Thoughts on Development"); + public void generatePreviewForSimpleEntryUsingAbbr() throws Exception { + BstPreviewLayout bstPreviewLayout = new BstPreviewLayout(Paths.get(BstPreviewLayoutTest.class.getResource("abbrv.bst").toURI())); + BibEntry entry = new BibEntry().withField(StandardField.AUTHOR, "Oliver Kopp"). + withField(StandardField.TITLE, "Thoughts on Development"); BibDatabase bibDatabase = mock(BibDatabase.class); String preview = bstPreviewLayout.generatePreview(entry, bibDatabase); assertEquals("O. Kopp. Thoughts on development.", preview); } @Test - public void generatePreviewForSliceTheoremPaper() { - BibEntry sliceTheoremPaper = new BibEntry(); - sliceTheoremPaper.setType(StandardEntryType.Article); - sliceTheoremPaper.setField(StandardField.AUTHOR, "Tobias Diez"); - sliceTheoremPaper.setField(StandardField.TITLE, "Slice theorem for Fréchet group actions and covariant symplectic field theory"); - sliceTheoremPaper.setField(StandardField.DATE, "2014-05-09"); - sliceTheoremPaper.setField(StandardField.ABSTRACT, "A general slice theorem for the action of a Fr\\'echet Lie group on a Fr\\'echet manifolds is established. The Nash-Moser theorem provides the fundamental tool to generalize the result of Palais to this infinite-dimensional setting. The presented slice theorem is illustrated by its application to gauge theories: the action of the gauge transformation group admits smooth slices at every point and thus the gauge orbit space is stratified by Fr\\'echet manifolds. Furthermore, a covariant and symplectic formulation of classical field theory is proposed and extensively discussed. At the root of this novel framework is the incorporation of field degrees of freedom F and spacetime M into the product manifold F * M. The induced bigrading of differential forms is used in order to carry over the usual symplectic theory to this new setting. The examples of the Klein-Gordon field and general Yang-Mills theory illustrate that the presented approach conveniently handles the occurring symmetries."); - sliceTheoremPaper.setField(StandardField.EPRINT, "1405.2249v1"); - sliceTheoremPaper.setField(StandardField.FILE, ":http\\://arxiv.org/pdf/1405.2249v1:PDF"); - sliceTheoremPaper.setField(StandardField.EPRINTTYPE, "arXiv"); - sliceTheoremPaper.setField(StandardField.EPRINTCLASS, "math-ph"); - sliceTheoremPaper.setField(StandardField.KEYWORDS, "math-ph, math.DG, math.MP, math.SG, 58B99, 58Z05, 58B25, 22E65, 58D19, 53D20, 53D42"); - BibDatabase bibDatabase = mock(BibDatabase.class); - String preview = bstPreviewLayout.generatePreview(sliceTheoremPaper, bibDatabase); + public void generatePreviewForSliceTheoremPaperUsingAbbr() throws Exception { + BstPreviewLayout bstPreviewLayout = new BstPreviewLayout(Paths.get(BstPreviewLayoutTest.class.getResource("abbrv.bst").toURI())); + String preview = bstPreviewLayout.generatePreview(getSliceTheoremPaper(), bibDatabase); assertEquals("T. Diez. Slice theorem for fréchet group actions and covariant symplectic field theory. #may# 2014.", preview); } + + @Test + public void generatePreviewForSliceTheoremPaperUsingIEEE() throws Exception { + BstPreviewLayout bstPreviewLayout = new BstPreviewLayout(Paths.get(ClassLoader.getSystemResource("bst/IEEEtran.bst").toURI())); + String preview = bstPreviewLayout.generatePreview(getSliceTheoremPaper(), bibDatabase); + assertEquals("T. Diez. Slice theorem for fréchet group actions and covariant symplectic field theory. #may# 2014.", preview); + } + + private static BibEntry getSliceTheoremPaper() { + return new BibEntry(StandardEntryType.Article) + .withField(StandardField.AUTHOR, "Tobias Diez") + .withField(StandardField.TITLE, "Slice theorem for Fréchet group actions and covariant symplectic field theory") + .withField(StandardField.DATE, "2014-05-09") + .withField(StandardField.ABSTRACT, "A general slice theorem for the action of a Fr\\'echet Lie group on a Fr\\'echet manifolds is established. The Nash-Moser theorem provides the fundamental tool to generalize the result of Palais to this infinite-dimensional setting. The presented slice theorem is illustrated by its application to gauge theories: the action of the gauge transformation group admits smooth slices at every point and thus the gauge orbit space is stratified by Fr\\'echet manifolds. Furthermore, a covariant and symplectic formulation of classical field theory is proposed and extensively discussed. At the root of this novel framework is the incorporation of field degrees of freedom F and spacetime M into the product manifold F * M. The induced bigrading of differential forms is used in order to carry over the usual symplectic theory to this new setting. The examples of the Klein-Gordon field and general Yang-Mills theory illustrate that the presented approach conveniently handles the occurring symmetries.") + .withField(StandardField.EPRINT, "1405.2249v1") + .withField(StandardField.FILE, ":http\\://arxiv.org/pdf/1405.2249v1:PDF") + .withField(StandardField.EPRINTTYPE, "arXiv") + .withField(StandardField.EPRINTCLASS, "math-ph") + .withField(StandardField.KEYWORDS, "math-ph, math.DG, math.MP, math.SG, 58B99, 58Z05, 58B25, 22E65, 58D19, 53D20, 53D42"); + } } From fbde17a65737f1fa3ad08aee3be5f4e56d065409 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Tue, 3 Dec 2019 07:31:06 +0100 Subject: [PATCH 07/18] Fix quotes and other output of IEEEtran.bst --- .../org/jabref/logic/bst/BstPreviewLayout.java | 14 +++++++++++++- .../org/jabref/logic/bst/BstPreviewLayoutTest.java | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java b/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java index f924fbfd532..6dc7bb0918a 100644 --- a/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java +++ b/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java @@ -9,6 +9,7 @@ import org.jabref.logic.cleanup.ConvertToBibtexCleanup; import org.jabref.logic.formatter.bibtexfields.RemoveNewlinesFormatter; import org.jabref.logic.l10n.Localization; +import org.jabref.logic.layout.format.LatexToUnicodeFormatter; import org.jabref.logic.layout.format.RemoveLatexCommandsFormatter; import org.jabref.logic.layout.format.RemoveTilde; import org.jabref.model.database.BibDatabase; @@ -54,7 +55,9 @@ public String generatePreview(BibEntry entry, BibDatabase database) { entry = (BibEntry) entry.clone(); new ConvertToBibtexCleanup().cleanup(entry); String result = vm.run(List.of(entry)); - result = new RemoveNewlinesFormatter().format(result); + // Remove all comments + result = result.replaceAll("%.*", ""); + // Remove all LaTeX comments // The RemoveLatexCommandsFormatter keeps the words inside latex environments. Therefore, we remove them manually result = result.replace("\\begin{thebibliography}{1}", ""); result = result.replace("\\end{thebibliography}", ""); @@ -62,7 +65,16 @@ public String generatePreview(BibEntry entry, BibDatabase database) { result = result.replaceAll("\\\\bibitem[{].*[}]", ""); // We want to replace \newblock by a space instead of completely removing it result = result.replace("\\newblock", " "); + // remove all latex commands statements - assumption: command in a separate line + result = result.replaceAll("(?m)^\\\\.*$", ""); + // remove some IEEEtran.bst output (resulting from a multiline \providecommand) + result = result.replace("#2}}", ""); + // Have quotes right - and more + result = new LatexToUnicodeFormatter().format(result); + result = result.replace("``", "\""); + result = result.replace("''", "\""); // Final cleanup + result = new RemoveNewlinesFormatter().format(result); result = new RemoveLatexCommandsFormatter().format(result); result = new RemoveTilde().format(result); result = result.trim().replaceAll(" +", " "); diff --git a/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java b/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java index d4f7c3b7b6f..e42bb9827a9 100644 --- a/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java +++ b/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java @@ -38,7 +38,7 @@ public void generatePreviewForSliceTheoremPaperUsingAbbr() throws Exception { public void generatePreviewForSliceTheoremPaperUsingIEEE() throws Exception { BstPreviewLayout bstPreviewLayout = new BstPreviewLayout(Paths.get(ClassLoader.getSystemResource("bst/IEEEtran.bst").toURI())); String preview = bstPreviewLayout.generatePreview(getSliceTheoremPaper(), bibDatabase); - assertEquals("T. Diez. Slice theorem for fréchet group actions and covariant symplectic field theory. #may# 2014.", preview); + assertEquals("T. Diez, \"Slice theorem for fréchet group actions and covariant symplectic field theory\" #may# 2014.", preview); } private static BibEntry getSliceTheoremPaper() { From 6865b132340de99f60da01bc3c7787abf676ae21 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 18 Jan 2020 01:15:02 +0100 Subject: [PATCH 08/18] Fix checkstyle --- src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java b/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java index e42bb9827a9..09aaa037fea 100644 --- a/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java +++ b/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java @@ -7,7 +7,6 @@ import org.jabref.model.entry.field.StandardField; import org.jabref.model.entry.types.StandardEntryType; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; From ad392c8e125c431d340fbde06fdf35e4f6c9a50f Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 21 Mar 2020 17:48:37 +0100 Subject: [PATCH 09/18] Remove calling of WIP preview functionality --- src/main/java/org/jabref/preferences/JabRefPreferences.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java index bd7f2a98aab..b27ea3e1d70 100644 --- a/src/main/java/org/jabref/preferences/JabRefPreferences.java +++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java @@ -58,7 +58,6 @@ import org.jabref.logic.bibtex.FieldContentFormatterPreferences; import org.jabref.logic.bibtex.FieldWriterPreferences; import org.jabref.logic.bibtexkeypattern.BibtexKeyPatternPreferences; -import org.jabref.logic.bst.BstPreviewLayout; import org.jabref.logic.citationstyle.CitationStyle; import org.jabref.logic.citationstyle.CitationStylePreviewLayout; import org.jabref.logic.cleanup.CleanupPreferences; @@ -652,7 +651,7 @@ private JabRefPreferences() { defaults.put(VERSION_IGNORED_UPDATE, ""); // preview - defaults.put(CYCLE_PREVIEW, "Preview;" + "bst/IEEEtran.bst;" + CitationStyle.DEFAULT); + defaults.put(CYCLE_PREVIEW, "Preview;" + CitationStyle.DEFAULT); defaults.put(CYCLE_PREVIEW_POS, 0); defaults.put(PREVIEW_PANEL_HEIGHT, 0.65); defaults.put(PREVIEW_AS_TAB, Boolean.FALSE); @@ -1493,8 +1492,6 @@ public PreviewPreferences getPreviewPreferences() { return CitationStyle.createCitationStyleFromFile(layout) .map(file -> (PreviewLayout) new CitationStylePreviewLayout(file)) .orElse(null); - } else if (layout.endsWith(".bst")) { - return new BstPreviewLayout(layout); } else { return new TextBasedPreviewLayout(style, getLayoutFormatterPreferences(Globals.journalAbbreviationLoader)); } From 62c7c76c1943032e75771674ea1baa13dcd45157 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 21 Mar 2020 18:08:03 +0100 Subject: [PATCH 10/18] Add JavaDoc on "TextBasedPreviewLayout" --- .../java/org/jabref/logic/layout/TextBasedPreviewLayout.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/jabref/logic/layout/TextBasedPreviewLayout.java b/src/main/java/org/jabref/logic/layout/TextBasedPreviewLayout.java index d4db4266751..ed8fa9f4f85 100644 --- a/src/main/java/org/jabref/logic/layout/TextBasedPreviewLayout.java +++ b/src/main/java/org/jabref/logic/layout/TextBasedPreviewLayout.java @@ -11,6 +11,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Implements the preview based JabRef's Custom export fitlters. + */ public class TextBasedPreviewLayout implements PreviewLayout { private static final Logger LOGGER = LoggerFactory.getLogger(TextBasedPreviewLayout.class); From a026538a5a44bbab480f9e4af8a56aaff5d51531 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 21 Mar 2020 19:20:10 +0100 Subject: [PATCH 11/18] Fix reuse of variable --- src/main/java/org/jabref/logic/bst/BstPreviewLayout.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java b/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java index 6dc7bb0918a..5e53fdd2bbe 100644 --- a/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java +++ b/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java @@ -5,7 +5,7 @@ import java.nio.file.Paths; import java.util.List; -import org.jabref.logic.PreviewLayout; +import org.jabref.logic.preview.PreviewLayout; import org.jabref.logic.cleanup.ConvertToBibtexCleanup; import org.jabref.logic.formatter.bibtexfields.RemoveNewlinesFormatter; import org.jabref.logic.l10n.Localization; @@ -47,12 +47,12 @@ public BstPreviewLayout(Path path) { } @Override - public String generatePreview(BibEntry entry, BibDatabase database) { + public String generatePreview(BibEntry originalEntry, BibDatabase database) { if (error != null) { return error; } // ensure that the entry is of BibTeX format (and do not modify the original entry) - entry = (BibEntry) entry.clone(); + BibEntry entry = (BibEntry) originalEntry.clone(); new ConvertToBibtexCleanup().cleanup(entry); String result = vm.run(List.of(entry)); // Remove all comments From 983aaa27ccf5d589717371f5748066dd4fac380f Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 21 Mar 2020 19:27:20 +0100 Subject: [PATCH 12/18] Move PreviewLayout to org.jabref.logic.preview --- src/main/java/org/jabref/gui/DragAndDropDataFormats.java | 2 +- src/main/java/org/jabref/gui/maintable/RightClickMenu.java | 2 +- src/main/java/org/jabref/gui/preferences/PreviewTabView.java | 2 +- .../java/org/jabref/gui/preferences/PreviewTabViewModel.java | 2 +- src/main/java/org/jabref/gui/preview/CopyCitationAction.java | 2 +- src/main/java/org/jabref/gui/preview/PreviewPanel.java | 2 +- src/main/java/org/jabref/gui/preview/PreviewViewer.java | 2 +- src/main/java/org/jabref/gui/util/CustomLocalDragboard.java | 2 +- .../java/org/jabref/logic/citationstyle/CitationStyleCache.java | 2 +- .../jabref/logic/citationstyle/CitationStylePreviewLayout.java | 2 +- .../java/org/jabref/logic/layout/TextBasedPreviewLayout.java | 2 +- src/main/java/org/jabref/logic/{ => preview}/PreviewLayout.java | 2 +- src/main/java/org/jabref/preferences/JabRefPreferences.java | 2 +- src/main/java/org/jabref/preferences/PreviewPreferences.java | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) rename src/main/java/org/jabref/logic/{ => preview}/PreviewLayout.java (90%) diff --git a/src/main/java/org/jabref/gui/DragAndDropDataFormats.java b/src/main/java/org/jabref/gui/DragAndDropDataFormats.java index 913035c465d..8b658a1655e 100644 --- a/src/main/java/org/jabref/gui/DragAndDropDataFormats.java +++ b/src/main/java/org/jabref/gui/DragAndDropDataFormats.java @@ -4,7 +4,7 @@ import javafx.scene.input.DataFormat; -import org.jabref.logic.PreviewLayout; +import org.jabref.logic.preview.PreviewLayout; /** * Contains all the different {@link DataFormat}s that may occur in JabRef. diff --git a/src/main/java/org/jabref/gui/maintable/RightClickMenu.java b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java index 36f5bed8390..58e5088175e 100644 --- a/src/main/java/org/jabref/gui/maintable/RightClickMenu.java +++ b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java @@ -21,9 +21,9 @@ import org.jabref.gui.mergeentries.MergeWithFetchedEntryAction; import org.jabref.gui.preview.CopyCitationAction; import org.jabref.gui.specialfields.SpecialFieldMenuItemFactory; -import org.jabref.logic.PreviewLayout; import org.jabref.logic.citationstyle.CitationStyleOutputFormat; import org.jabref.logic.citationstyle.CitationStylePreviewLayout; +import org.jabref.logic.preview.PreviewLayout; import org.jabref.model.entry.field.SpecialField; import org.jabref.preferences.JabRefPreferences; import org.jabref.preferences.PreferencesService; diff --git a/src/main/java/org/jabref/gui/preferences/PreviewTabView.java b/src/main/java/org/jabref/gui/preferences/PreviewTabView.java index 7058c8c218c..8d387006ce7 100644 --- a/src/main/java/org/jabref/gui/preferences/PreviewTabView.java +++ b/src/main/java/org/jabref/gui/preferences/PreviewTabView.java @@ -29,8 +29,8 @@ import org.jabref.gui.preview.PreviewViewer; import org.jabref.gui.util.IconValidationDecorator; import org.jabref.gui.util.ViewModelListCellFactory; -import org.jabref.logic.PreviewLayout; import org.jabref.logic.l10n.Localization; +import org.jabref.logic.preview.PreviewLayout; import org.jabref.logic.util.TestEntry; import org.jabref.model.database.BibDatabaseContext; import org.jabref.preferences.JabRefPreferences; diff --git a/src/main/java/org/jabref/gui/preferences/PreviewTabViewModel.java b/src/main/java/org/jabref/gui/preferences/PreviewTabViewModel.java index 6225445d7ce..1ff3f88a73b 100644 --- a/src/main/java/org/jabref/gui/preferences/PreviewTabViewModel.java +++ b/src/main/java/org/jabref/gui/preferences/PreviewTabViewModel.java @@ -32,11 +32,11 @@ import org.jabref.gui.util.CustomLocalDragboard; import org.jabref.gui.util.NoSelectionModel; import org.jabref.gui.util.TaskExecutor; -import org.jabref.logic.PreviewLayout; import org.jabref.logic.citationstyle.CitationStyle; import org.jabref.logic.citationstyle.CitationStylePreviewLayout; import org.jabref.logic.l10n.Localization; import org.jabref.logic.layout.TextBasedPreviewLayout; +import org.jabref.logic.preview.PreviewLayout; import org.jabref.preferences.JabRefPreferences; import org.jabref.preferences.PreviewPreferences; diff --git a/src/main/java/org/jabref/gui/preview/CopyCitationAction.java b/src/main/java/org/jabref/gui/preview/CopyCitationAction.java index 517976e61f3..ce7cbba25d6 100644 --- a/src/main/java/org/jabref/gui/preview/CopyCitationAction.java +++ b/src/main/java/org/jabref/gui/preview/CopyCitationAction.java @@ -15,7 +15,6 @@ import org.jabref.gui.actions.ActionHelper; import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.util.BackgroundTask; -import org.jabref.logic.PreviewLayout; import org.jabref.logic.citationstyle.CitationStyleGenerator; import org.jabref.logic.citationstyle.CitationStyleOutputFormat; import org.jabref.logic.citationstyle.CitationStylePreviewLayout; @@ -23,6 +22,7 @@ import org.jabref.logic.layout.Layout; import org.jabref.logic.layout.LayoutFormatterPreferences; import org.jabref.logic.layout.LayoutHelper; +import org.jabref.logic.preview.PreviewLayout; import org.jabref.logic.util.OS; import org.jabref.model.entry.BibEntry; import org.jabref.preferences.PreviewPreferences; diff --git a/src/main/java/org/jabref/gui/preview/PreviewPanel.java b/src/main/java/org/jabref/gui/preview/PreviewPanel.java index a8ec0bd69f1..3c8f9b69c6f 100644 --- a/src/main/java/org/jabref/gui/preview/PreviewPanel.java +++ b/src/main/java/org/jabref/gui/preview/PreviewPanel.java @@ -23,8 +23,8 @@ import org.jabref.gui.icon.IconTheme; import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.keyboard.KeyBindingRepository; -import org.jabref.logic.PreviewLayout; import org.jabref.logic.l10n.Localization; +import org.jabref.logic.preview.PreviewLayout; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.preferences.JabRefPreferences; diff --git a/src/main/java/org/jabref/gui/preview/PreviewViewer.java b/src/main/java/org/jabref/gui/preview/PreviewViewer.java index 5ec0464dc11..2ac50ebee2b 100644 --- a/src/main/java/org/jabref/gui/preview/PreviewViewer.java +++ b/src/main/java/org/jabref/gui/preview/PreviewViewer.java @@ -23,9 +23,9 @@ import org.jabref.gui.util.BackgroundTask; import org.jabref.gui.util.TaskExecutor; import org.jabref.gui.util.ThemeLoader; -import org.jabref.logic.PreviewLayout; import org.jabref.logic.exporter.ExporterFactory; import org.jabref.logic.l10n.Localization; +import org.jabref.logic.preview.PreviewLayout; import org.jabref.logic.search.SearchQuery; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; diff --git a/src/main/java/org/jabref/gui/util/CustomLocalDragboard.java b/src/main/java/org/jabref/gui/util/CustomLocalDragboard.java index 6ebbe3bcf03..3ba1b83de10 100644 --- a/src/main/java/org/jabref/gui/util/CustomLocalDragboard.java +++ b/src/main/java/org/jabref/gui/util/CustomLocalDragboard.java @@ -7,7 +7,7 @@ import org.jabref.gui.DragAndDropDataFormats; import org.jabref.gui.StateManager; -import org.jabref.logic.PreviewLayout; +import org.jabref.logic.preview.PreviewLayout; import org.jabref.model.entry.BibEntry; /** diff --git a/src/main/java/org/jabref/logic/citationstyle/CitationStyleCache.java b/src/main/java/org/jabref/logic/citationstyle/CitationStyleCache.java index f994bc945c1..bb7ba7f1f50 100644 --- a/src/main/java/org/jabref/logic/citationstyle/CitationStyleCache.java +++ b/src/main/java/org/jabref/logic/citationstyle/CitationStyleCache.java @@ -2,7 +2,7 @@ import java.util.Objects; -import org.jabref.logic.PreviewLayout; +import org.jabref.logic.preview.PreviewLayout; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.event.EntriesRemovedEvent; import org.jabref.model.entry.BibEntry; diff --git a/src/main/java/org/jabref/logic/citationstyle/CitationStylePreviewLayout.java b/src/main/java/org/jabref/logic/citationstyle/CitationStylePreviewLayout.java index 0055548682c..d40e86c7414 100644 --- a/src/main/java/org/jabref/logic/citationstyle/CitationStylePreviewLayout.java +++ b/src/main/java/org/jabref/logic/citationstyle/CitationStylePreviewLayout.java @@ -1,6 +1,6 @@ package org.jabref.logic.citationstyle; -import org.jabref.logic.PreviewLayout; +import org.jabref.logic.preview.PreviewLayout; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; diff --git a/src/main/java/org/jabref/logic/layout/TextBasedPreviewLayout.java b/src/main/java/org/jabref/logic/layout/TextBasedPreviewLayout.java index ed8fa9f4f85..011eced3f4e 100644 --- a/src/main/java/org/jabref/logic/layout/TextBasedPreviewLayout.java +++ b/src/main/java/org/jabref/logic/layout/TextBasedPreviewLayout.java @@ -3,8 +3,8 @@ import java.io.IOException; import java.io.StringReader; -import org.jabref.logic.PreviewLayout; import org.jabref.logic.l10n.Localization; +import org.jabref.logic.preview.PreviewLayout; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; diff --git a/src/main/java/org/jabref/logic/PreviewLayout.java b/src/main/java/org/jabref/logic/preview/PreviewLayout.java similarity index 90% rename from src/main/java/org/jabref/logic/PreviewLayout.java rename to src/main/java/org/jabref/logic/preview/PreviewLayout.java index 0d9db028cfc..3f6626924b0 100644 --- a/src/main/java/org/jabref/logic/PreviewLayout.java +++ b/src/main/java/org/jabref/logic/preview/PreviewLayout.java @@ -1,4 +1,4 @@ -package org.jabref.logic; +package org.jabref.logic.preview; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java index b27ea3e1d70..c1f78295f29 100644 --- a/src/main/java/org/jabref/preferences/JabRefPreferences.java +++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java @@ -54,7 +54,6 @@ import org.jabref.gui.push.PushToApplicationsManager; import org.jabref.gui.specialfields.SpecialFieldsPreferences; import org.jabref.gui.util.ThemeLoader; -import org.jabref.logic.PreviewLayout; import org.jabref.logic.bibtex.FieldContentFormatterPreferences; import org.jabref.logic.bibtex.FieldWriterPreferences; import org.jabref.logic.bibtexkeypattern.BibtexKeyPatternPreferences; @@ -80,6 +79,7 @@ import org.jabref.logic.openoffice.OpenOfficePreferences; import org.jabref.logic.openoffice.StyleLoader; import org.jabref.logic.preferences.TimestampPreferences; +import org.jabref.logic.preview.PreviewLayout; import org.jabref.logic.protectedterms.ProtectedTermsList; import org.jabref.logic.protectedterms.ProtectedTermsLoader; import org.jabref.logic.protectedterms.ProtectedTermsPreferences; diff --git a/src/main/java/org/jabref/preferences/PreviewPreferences.java b/src/main/java/org/jabref/preferences/PreviewPreferences.java index de5f74785ad..c6a7ad20742 100644 --- a/src/main/java/org/jabref/preferences/PreviewPreferences.java +++ b/src/main/java/org/jabref/preferences/PreviewPreferences.java @@ -3,9 +3,9 @@ import java.util.List; import org.jabref.Globals; -import org.jabref.logic.PreviewLayout; import org.jabref.logic.layout.LayoutFormatterPreferences; import org.jabref.logic.layout.TextBasedPreviewLayout; +import org.jabref.logic.preview.PreviewLayout; public class PreviewPreferences { From f6ee3ac42274e36e7c9c871fda1efc8b82840e89 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 21 Mar 2020 19:55:58 +0100 Subject: [PATCH 13/18] Refine JavaDoc and fix variable name --- .../org/jabref/logic/bibtex/BibEntryWriter.java | 6 +----- src/main/java/org/jabref/logic/bst/VM.java | 13 ++++++++----- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/jabref/logic/bibtex/BibEntryWriter.java b/src/main/java/org/jabref/logic/bibtex/BibEntryWriter.java index a5be765f4fe..257777abb69 100644 --- a/src/main/java/org/jabref/logic/bibtex/BibEntryWriter.java +++ b/src/main/java/org/jabref/logic/bibtex/BibEntryWriter.java @@ -87,11 +87,7 @@ public void writeWithoutPrependedNewlines(BibEntry entry, Writer out, BibDatabas } /** - * Write fields in the order of requiredFields, optionalFields and other fields, but does not sort the fields. - * - * @param entry - * @param out - * @throws IOException + * Writes fields in the order of requiredFields, optionalFields and other fields, but does not sort the fields. */ private void writeRequiredFieldsFirstRemainingFieldsSecond(BibEntry entry, Writer out, BibDatabaseMode bibDatabaseMode) throws IOException { diff --git a/src/main/java/org/jabref/logic/bst/VM.java b/src/main/java/org/jabref/logic/bst/VM.java index 448266e9c89..18ecbb589bf 100644 --- a/src/main/java/org/jabref/logic/bst/VM.java +++ b/src/main/java/org/jabref/logic/bst/VM.java @@ -843,11 +843,14 @@ public String run(Collection bibtex) { } /** - * @param bibtex list of entries to convert + * Transforms the given list of BibEntries to a rendered list of references using the underlying bst file + * + * @param bibEntries list of entries to convert * @param bibDatabase (may be null) the bibDatabase used for resolving strings / crossref + * @return list of references in plain text form */ - public String run(Collection bibtex, BibDatabase bibDatabase) { - Objects.requireNonNull(bibtex); + public String run(Collection bibEntries, BibDatabase bibDatabase) { + Objects.requireNonNull(bibEntries); // Reset bbl = new StringBuilder(); @@ -864,8 +867,8 @@ public String run(Collection bibtex, BibDatabase bibDatabase) { stack = new Stack<>(); // Create entries - entries = new ArrayList<>(bibtex.size()); - for (BibEntry entry : bibtex) { + entries = new ArrayList<>(bibEntries.size()); + for (BibEntry entry : bibEntries) { entries.add(new BstEntry(entry)); } From a89b7a1b4c0db1282fe97b19795586bd920bb9a4 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 21 Mar 2020 20:15:05 +0100 Subject: [PATCH 14/18] Use public final instead of getters --- ...008-use-public-final-instead-of-getters.md | 22 ++++++++++++ src/main/java/org/jabref/logic/bst/VM.java | 36 ++++++++----------- .../java/org/jabref/logic/bst/TestVM.java | 10 +++--- 3 files changed, 41 insertions(+), 27 deletions(-) create mode 100644 docs/adr/0008-use-public-final-instead-of-getters.md diff --git a/docs/adr/0008-use-public-final-instead-of-getters.md b/docs/adr/0008-use-public-final-instead-of-getters.md new file mode 100644 index 00000000000..daf781194ab --- /dev/null +++ b/docs/adr/0008-use-public-final-instead-of-getters.md @@ -0,0 +1,22 @@ +# Use `public final` instead of getters to offer access to immutable variables + +## Context and Problem Statement + +When making immutable data accessible in a java class, should it be using getters or by non-modifiable fields? + +## Considered Options + +* Offer public static field +* Offer getters + +## Decision Outcome + +Chosen option: "Offer public static field", because getters used to be a convention which was even more manifested due to libraries depending on the existence on getters/setters. In the case of immutable variables, adding public getters is just useless since one is not hiding anything. + +### Positive Consequences + +* Shorter code + +### Negative Consequences + +* new comers could get confused, because getters/setters are still teached diff --git a/src/main/java/org/jabref/logic/bst/VM.java b/src/main/java/org/jabref/logic/bst/VM.java index 18ecbb589bf..5b20b28c28c 100644 --- a/src/main/java/org/jabref/logic/bst/VM.java +++ b/src/main/java/org/jabref/logic/bst/VM.java @@ -270,7 +270,7 @@ private VM(CommonTree tree) { if (context == null) { throw new VMException("Call.type$ can only be called from within a context (ITERATE or REVERSE)."); } - VM.this.execute(context.getBibtexEntry().getType().getName(), context); + VM.this.execute(context.entry.getType().getName(), context); }); buildInFunctions.put("change.case$", new ChangeCaseFunction(this)); @@ -303,7 +303,7 @@ private VM(CommonTree tree) { if (context == null) { throw new VMException("Must have an entry to cite$"); } - stack.push(context.getBibtexEntry().getCiteKeyOptional().orElse(null)); + stack.push(context.entry.getCiteKeyOptional().orElse(null)); }); /* @@ -581,7 +581,7 @@ private VM(CommonTree tree) { throw new VMException("type$ need a context."); } - stack.push(context.getBibtexEntry().getType().getName()); + stack.push(context.entry.getType().getName()); }); /* @@ -925,16 +925,16 @@ public String run(Collection bibEntries, BibDatabase bibDatabase) { */ private void read(BibDatabase bibDatabase) { for (BstEntry e : entries) { - for (Map.Entry mEntry : e.getFields().entrySet()) { + for (Map.Entry mEntry : e.fields.entrySet()) { Field field = FieldFactory.parseField(mEntry.getKey()); - String fieldValue = e.getBibtexEntry().getResolvedFieldOrAlias(field, bibDatabase).orElse(null); + String fieldValue = e.entry.getResolvedFieldOrAlias(field, bibDatabase).orElse(null); mEntry.setValue(fieldValue); } } for (BstEntry e : entries) { - if (!e.getFields().containsKey(StandardField.CROSSREF.getName())) { - e.getFields().put(StandardField.CROSSREF.getName(), null); + if (!e.fields.containsKey(StandardField.CROSSREF.getName())) { + e.fields.put(StandardField.CROSSREF.getName(), null); } } } @@ -981,7 +981,7 @@ private void entry(Tree child) { String name = t.getChild(i).getText(); for (BstEntry entry : entries) { - entry.getFields().put(name, null); + entry.fields.put(name, null); } } @@ -1106,8 +1106,8 @@ private void execute(String name, BstEntry context) { if (context != null) { - if (context.getFields().containsKey(name)) { - stack.push(context.getFields().get(name)); + if (context.fields.containsKey(name)) { + stack.push(context.fields.get(name)); return; } if (context.localStrings.containsKey(name)) { @@ -1174,25 +1174,17 @@ private void strings(Tree child) { public static class BstEntry { - private final BibEntry entry; + public final BibEntry entry; - private final Map localStrings = new HashMap<>(); + public final Map localStrings = new HashMap<>(); - private final Map fields = new HashMap<>(); + public final Map fields = new HashMap<>(); - private final Map localIntegers = new HashMap<>(); + public final Map localIntegers = new HashMap<>(); public BstEntry(BibEntry e) { this.entry = e; } - - public Map getFields() { - return fields; - } - - public BibEntry getBibtexEntry() { - return entry; - } } private void push(Integer integer) { diff --git a/src/test/java/org/jabref/logic/bst/TestVM.java b/src/test/java/org/jabref/logic/bst/TestVM.java index 35d42d7e217..f468889d55a 100644 --- a/src/test/java/org/jabref/logic/bst/TestVM.java +++ b/src/test/java/org/jabref/logic/bst/TestVM.java @@ -54,7 +54,7 @@ public void testVMSimple() throws RecognitionException, IOException { assertEquals(2, vm.getStrings().size()); assertEquals(7, vm.getIntegers().size()); assertEquals(1, vm.getEntries().size()); - assertEquals(5, vm.getEntries().get(0).getFields().size()); + assertEquals(5, vm.getEntries().get(0).fields.size()); assertEquals(38, vm.getFunctions().size()); } @@ -366,10 +366,10 @@ public void testSort() throws RecognitionException, IOException { vm.run(v); List v2 = vm.getEntries(); - assertEquals(Optional.of("a"), v2.get(0).getBibtexEntry().getCiteKeyOptional()); - assertEquals(Optional.of("b"), v2.get(1).getBibtexEntry().getCiteKeyOptional()); - assertEquals(Optional.of("c"), v2.get(2).getBibtexEntry().getCiteKeyOptional()); - assertEquals(Optional.of("d"), v2.get(3).getBibtexEntry().getCiteKeyOptional()); + assertEquals(Optional.of("a"), v2.get(0).entry.getCiteKeyOptional()); + assertEquals(Optional.of("b"), v2.get(1).entry.getCiteKeyOptional()); + assertEquals(Optional.of("c"), v2.get(2).entry.getCiteKeyOptional()); + assertEquals(Optional.of("d"), v2.get(3).entry.getCiteKeyOptional()); } @Test From d72b8dcfac1ad43378df2631880e3e1199be2543 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 21 Mar 2020 20:27:23 +0100 Subject: [PATCH 15/18] JavaDoc improvements --- .../logic/bibtex/FieldContentFormatterPreferences.java | 4 +++- src/main/java/org/jabref/logic/bibtex/FieldWriter.java | 5 +---- .../java/org/jabref/logic/bibtex/FieldWriterPreferences.java | 4 ++++ src/main/java/org/jabref/logic/bst/VM.java | 3 ++- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/logic/bibtex/FieldContentFormatterPreferences.java b/src/main/java/org/jabref/logic/bibtex/FieldContentFormatterPreferences.java index 26f13248b85..02df6c020c0 100644 --- a/src/main/java/org/jabref/logic/bibtex/FieldContentFormatterPreferences.java +++ b/src/main/java/org/jabref/logic/bibtex/FieldContentFormatterPreferences.java @@ -9,8 +9,10 @@ public class FieldContentFormatterPreferences { private final List nonWrappableFields; + /** + * Constructor defining that there are not any non-wrappable fields + */ public FieldContentFormatterPreferences() { - // This constructor is only to allow an empty constructor in SavePreferences this.nonWrappableFields = Collections.emptyList(); } diff --git a/src/main/java/org/jabref/logic/bibtex/FieldWriter.java b/src/main/java/org/jabref/logic/bibtex/FieldWriter.java index e0ddfc9ace0..470b029d7c1 100644 --- a/src/main/java/org/jabref/logic/bibtex/FieldWriter.java +++ b/src/main/java/org/jabref/logic/bibtex/FieldWriter.java @@ -7,10 +7,7 @@ import org.jabref.model.strings.StringUtil; /** - * Obeys following settings: - * * JabRefPreferences.RESOLVE_STRINGS_ALL_FIELDS - * * JabRefPreferences.DO_NOT_RESOLVE_STRINGS_FOR - * * JabRefPreferences.WRITEFIELD_WRAPFIELD + * Converts JabRef's internal BibTeX representation of a BibTeX field to BibTeX text representation */ public class FieldWriter { diff --git a/src/main/java/org/jabref/logic/bibtex/FieldWriterPreferences.java b/src/main/java/org/jabref/logic/bibtex/FieldWriterPreferences.java index 5caaa76de1b..51654c788a8 100644 --- a/src/main/java/org/jabref/logic/bibtex/FieldWriterPreferences.java +++ b/src/main/java/org/jabref/logic/bibtex/FieldWriterPreferences.java @@ -19,6 +19,10 @@ public FieldWriterPreferences(boolean resolveStringsAllFields, List doNot this.fieldContentFormatterPreferences = fieldContentFormatterPreferences; } + /** + * Creates an instance with default values (not obeying any user preferences). This constructor should be used with + * caution. The other constructor has to be preferred. + */ public FieldWriterPreferences() { // This constructor is only to allow an empty constructor in SavePreferences this(true, Collections.emptyList(), new FieldContentFormatterPreferences()); diff --git a/src/main/java/org/jabref/logic/bst/VM.java b/src/main/java/org/jabref/logic/bst/VM.java index 5b20b28c28c..c9174ad6834 100644 --- a/src/main/java/org/jabref/logic/bst/VM.java +++ b/src/main/java/org/jabref/logic/bst/VM.java @@ -136,7 +136,7 @@ private VM(CommonTree tree) { stack.push(((Integer) o1).compareTo((Integer) o2) > 0 ? VM.TRUE : VM.FALSE); }); - /* Analogous. */ + /* Analogous to >. */ buildInFunctions.put("<", context -> { if (stack.size() < 2) { throw new VMException("Not enough operands on stack for operation <"); @@ -1178,6 +1178,7 @@ public static class BstEntry { public final Map localStrings = new HashMap<>(); + // keys filled by org.jabref.logic.bst.VM.entry based on the contents of the bst file public final Map fields = new HashMap<>(); public final Map localIntegers = new HashMap<>(); From c64ce4afd59bb48fad54ff9a8a314f7ca4b32706 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 21 Mar 2020 22:01:28 +0100 Subject: [PATCH 16/18] Inline global variable stringBuilder and add some JavaDoc and Logging --- .../logic/bibtex/FieldContentFormatter.java | 1 - .../org/jabref/logic/bibtex/FieldWriter.java | 51 ++++++++++++------- .../org/jabref/model/strings/StringUtil.java | 31 ++++++----- 3 files changed, 53 insertions(+), 30 deletions(-) diff --git a/src/main/java/org/jabref/logic/bibtex/FieldContentFormatter.java b/src/main/java/org/jabref/logic/bibtex/FieldContentFormatter.java index 5b2a2c6171d..183f174608c 100644 --- a/src/main/java/org/jabref/logic/bibtex/FieldContentFormatter.java +++ b/src/main/java/org/jabref/logic/bibtex/FieldContentFormatter.java @@ -43,7 +43,6 @@ public FieldContentFormatter(FieldContentFormatterPreferences preferences) { */ public String format(String fieldContent, Field field) { if (multiLineFields.contains(field)) { - // Unify line breaks return StringUtil.unifyLineBreaks(fieldContent, OS.NEWLINE); } diff --git a/src/main/java/org/jabref/logic/bibtex/FieldWriter.java b/src/main/java/org/jabref/logic/bibtex/FieldWriter.java index 470b029d7c1..c7ce8ea8a10 100644 --- a/src/main/java/org/jabref/logic/bibtex/FieldWriter.java +++ b/src/main/java/org/jabref/logic/bibtex/FieldWriter.java @@ -6,17 +6,22 @@ import org.jabref.model.entry.field.StandardField; import org.jabref.model.strings.StringUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Converts JabRef's internal BibTeX representation of a BibTeX field to BibTeX text representation */ public class FieldWriter { + private static final Logger LOGGER = LoggerFactory.getLogger(FieldWriter.class); + private static final char FIELD_START = '{'; private static final char FIELD_END = '}'; + private final boolean neverFailOnHashes; private final FieldWriterPreferences preferences; private final FieldContentFormatter formatter; - private StringBuilder stringBuilder; public FieldWriter(FieldWriterPreferences preferences) { this(true, preferences); @@ -55,12 +60,15 @@ private static void checkBraces(String text) throws InvalidFieldValueException { // Then we throw an exception if the error criteria are met. if (!(right == 0) && (left == 0)) { + LOGGER.error("Unescaped '}' character without opening bracket ends string prematurely. Field value: {}", text ); throw new InvalidFieldValueException("Unescaped '}' character without opening bracket ends string prematurely. Field value: " + text); } if (!(right == 0) && (right < left)) { + LOGGER.error("Unescaped '}' character without opening bracket ends string prematurely. Field value: {}", text); throw new InvalidFieldValueException("Unescaped '}' character without opening bracket ends string prematurely. Field value: " + text); } if (left != right) { + LOGGER.error("Braces don't match. Field value: {}", text); throw new InvalidFieldValueException("Braces don't match. Field value: " + text); } } @@ -92,9 +100,10 @@ public String write(Field field, String content) throws InvalidFieldValueExcepti * For instance, #jan# - #feb# gets jan #{ - } # feb (see @link{org.jabref.logic.bibtex.LatexFieldFormatterTests#makeHashEnclosedWordsRealStringsInMonthField()}) */ private String formatAndResolveStrings(String content, Field field) throws InvalidFieldValueException { - stringBuilder = new StringBuilder(); checkBraces(content); + StringBuilder stringBuilder = new StringBuilder(); + // Here we assume that the user encloses any bibtex strings in #, e.g.: // #jan# - #feb# // ...which will be written to the file like this: @@ -123,6 +132,9 @@ private String formatAndResolveStrings(String content, Field field) throws Inval if (neverFailOnHashes) { pos1 = content.length(); // just write out the rest of the text, and throw no exception } else { + LOGGER.error("The # character is not allowed in BibTeX strings unless escaped as in '\\#'. " + + "In JabRef, use pairs of # characters to indicate a string. " + + "Note that the entry causing the problem has been selected. Field value: {}", content); throw new InvalidFieldValueException( "The # character is not allowed in BibTeX strings unless escaped as in '\\#'.\n" + "In JabRef, use pairs of # characters to indicate a string.\n" @@ -132,13 +144,13 @@ private String formatAndResolveStrings(String content, Field field) throws Inval } if (pos1 > pivot) { - writeText(content, pivot, pos1); + writeText(stringBuilder, content, pivot, pos1); } if ((pos1 < content.length()) && ((pos2 - 1) > pos1)) { // We check that the string label is not empty. That means // an occurrence of ## will simply be ignored. Should it instead // cause an error message? - writeStringLabel(content, pos1 + 1, pos2, pos1 == pivot, + writeStringLabel(stringBuilder, content, pos1 + 1, pos2, pos1 == pivot, (pos2 + 1) == content.length()); } @@ -165,28 +177,33 @@ private boolean shouldResolveStrings(Field field) { private String formatWithoutResolvingStrings(String content, Field field) throws InvalidFieldValueException { checkBraces(content); - stringBuilder = new StringBuilder(String.valueOf(FIELD_START)); - + StringBuilder stringBuilder = new StringBuilder(String.valueOf(FIELD_START)); stringBuilder.append(formatter.format(content, field)); - stringBuilder.append(FIELD_END); - return stringBuilder.toString(); } - private void writeText(String text, int startPos, int endPos) { + /** + * @param stringBuilder the StringBuilder to append the text to + * @param text the text to append + */ + private void writeText(StringBuilder stringBuilder, String text, int startPos, int endPos) { stringBuilder.append(FIELD_START); stringBuilder.append(text, startPos, endPos); stringBuilder.append(FIELD_END); } - private void writeStringLabel(String text, int startPos, int endPos, boolean first, boolean last) { - putIn((first ? "" : " # ") + text.substring(startPos, endPos) - + (last ? "" : " # ")); - } - - private void putIn(String s) { - stringBuilder.append(StringUtil.wrap(s, preferences.getLineLength(), OS.NEWLINE)); + /** + * @param stringBuilder the StringBuilder to append the text to + * @param text the text use as basis to get the text to append + * @param startPos the position in text where the text to add starts + * @param endPos the position in text where the text to add ends + * @param isFirst true if the label to write is the first one to write + * @param isLast true if the label to write is the last one to write + */ + private void writeStringLabel(StringBuilder stringBuilder, String text, int startPos, int endPos, boolean isFirst, boolean isLast) { + String line = (isFirst ? "" : " # ") + text.substring(startPos, endPos) + (isLast ? "" : " # "); + String wrappedLine = StringUtil.wrap(line, preferences.getLineLength(), OS.NEWLINE); + stringBuilder.append(wrappedLine); } - } diff --git a/src/main/java/org/jabref/model/strings/StringUtil.java b/src/main/java/org/jabref/model/strings/StringUtil.java index a5f4a2fca0e..c3a46c0adfc 100644 --- a/src/main/java/org/jabref/model/strings/StringUtil.java +++ b/src/main/java/org/jabref/model/strings/StringUtil.java @@ -193,20 +193,19 @@ public static String getCorrectFileName(String orgName, String defaultExtension) } /** - * Formats field contents for output. Must be "symmetric" with the parse method above, - * so stored and reloaded fields are not mangled. + * Formats field contents for output. Must be "symmetric" with the parse method above, so stored and reloaded fields + * are not mangled. * - * @param in - * @param wrapAmount - * @param newline - * @return the wrapped String. + * @param in the string to wrap + * @param wrapAmount the number of characters belonging to a line of text + * @param newline the newline character(s) + * @return the wrapped string */ public static String wrap(String in, int wrapAmount, String newline) { - String[] lines = in.split("\n"); StringBuilder result = new StringBuilder(); // remove all whitespace at the end of the string, this especially includes \r created when the field content has \r\n as line separator - addWrappedLine(result, CharMatcher.whitespace().trimTrailingFrom(lines[0]), wrapAmount, newline); // See + addWrappedLine(result, CharMatcher.whitespace().trimTrailingFrom(lines[0]), wrapAmount, newline); for (int i = 1; i < lines.length; i++) { if (lines[i].trim().isEmpty()) { @@ -225,12 +224,21 @@ public static String wrap(String in, int wrapAmount, String newline) { return result.toString(); } - private static void addWrappedLine(StringBuilder result, String line, int wrapAmount, String newline) { + /** + * Appends a text to a string builder. Wraps the text so that each line is approx wrapAmount characters long. + * Wrapping is done using newline and tab character. + * + * @param line the line of text to be wrapped and appended + * @param wrapAmount the number of characters belonging to a line of text + * @param newlineString a string containing the newline character(s) + */ + private static void addWrappedLine(StringBuilder result, String line, int wrapAmount, String newlineString) { // Set our pointer to the beginning of the new line in the StringBuffer: int length = result.length(); // Add the line, unmodified: result.append(line); + // insert newlines and one tab character at each position, where wrapping is necessary while (length < result.length()) { int current = result.indexOf(" ", length + wrapAmount); if ((current < 0) || (current >= result.length())) { @@ -238,9 +246,8 @@ private static void addWrappedLine(StringBuilder result, String line, int wrapAm } result.deleteCharAt(current); - result.insert(current, newline + "\t"); - length = current + newline.length(); - + result.insert(current, newlineString + "\t"); + length = current + newlineString.length(); } } From 09a4e90b08a90f95b1f170813f6e05deaecad243 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 21 Mar 2020 22:14:50 +0100 Subject: [PATCH 17/18] Fix rendering of month field --- .../jabref/logic/bst/BstPreviewLayout.java | 4 --- src/main/java/org/jabref/logic/bst/VM.java | 29 ++++++++++++++++++- .../logic/bst/BstPreviewLayoutTest.java | 19 +++++++++--- 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java b/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java index 5e53fdd2bbe..1d113cd315d 100644 --- a/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java +++ b/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java @@ -27,10 +27,6 @@ public class BstPreviewLayout implements PreviewLayout { private VM vm; private String error; - public BstPreviewLayout(String filename) { - this(Paths.get(filename)); - } - public BstPreviewLayout(Path path) { name = path.getFileName().toString(); if (!Files.exists(path)) { diff --git a/src/main/java/org/jabref/logic/bst/VM.java b/src/main/java/org/jabref/logic/bst/VM.java index c9174ad6834..f3dce6d5cfb 100644 --- a/src/main/java/org/jabref/logic/bst/VM.java +++ b/src/main/java/org/jabref/logic/bst/VM.java @@ -14,9 +14,13 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.jabref.logic.bibtex.FieldWriter; +import org.jabref.logic.bibtex.FieldWriterPreferences; +import org.jabref.logic.bibtex.InvalidFieldValueException; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.AuthorList; import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.Month; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.FieldFactory; import org.jabref.model.entry.field.StandardField; @@ -924,10 +928,33 @@ public String run(Collection bibEntries, BibDatabase bibDatabase) { * @param bibDatabase */ private void read(BibDatabase bibDatabase) { + FieldWriter fieldWriter = new FieldWriter(new FieldWriterPreferences()); for (BstEntry e : entries) { for (Map.Entry mEntry : e.fields.entrySet()) { Field field = FieldFactory.parseField(mEntry.getKey()); - String fieldValue = e.entry.getResolvedFieldOrAlias(field, bibDatabase).orElse(null); + String fieldValue = e.entry.getResolvedFieldOrAlias(field, bibDatabase) + .map(content -> { + try { + String result = fieldWriter.write(field, content); + if (result.startsWith("{")) { + // Strip enclosing {} from the output + return result.substring(1, result.length() - 1); + } + if (field == StandardField.MONTH) { + // We don't have the internal BibTeX strings at hand. + // We nevertheless want to have the full month name. + // Thus, we lookup the full month name here. + return Month.parse(result) + .map(month -> month.getFullName()) + .orElse(result); + } + return result; + } catch (InvalidFieldValueException invalidFieldValueException) { + // in case there is something wrong with the content, just return the content itself + return content; + } + }) + .orElse(null); mEntry.setValue(fieldValue); } } diff --git a/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java b/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java index 09aaa037fea..945d5294abe 100644 --- a/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java +++ b/src/test/java/org/jabref/logic/bst/BstPreviewLayoutTest.java @@ -19,25 +19,36 @@ class BstPreviewLayoutTest { @Test public void generatePreviewForSimpleEntryUsingAbbr() throws Exception { BstPreviewLayout bstPreviewLayout = new BstPreviewLayout(Paths.get(BstPreviewLayoutTest.class.getResource("abbrv.bst").toURI())); - BibEntry entry = new BibEntry().withField(StandardField.AUTHOR, "Oliver Kopp"). - withField(StandardField.TITLE, "Thoughts on Development"); + BibEntry entry = new BibEntry().withField(StandardField.AUTHOR, "Oliver Kopp") + .withField(StandardField.TITLE, "Thoughts on Development"); BibDatabase bibDatabase = mock(BibDatabase.class); String preview = bstPreviewLayout.generatePreview(entry, bibDatabase); assertEquals("O. Kopp. Thoughts on development.", preview); } + @Test + public void monthMayIsCorrectlyRendered() throws Exception { + BstPreviewLayout bstPreviewLayout = new BstPreviewLayout(Paths.get(BstPreviewLayoutTest.class.getResource("abbrv.bst").toURI())); + BibEntry entry = new BibEntry().withField(StandardField.AUTHOR, "Oliver Kopp") + .withField(StandardField.TITLE, "Thoughts on Development") + .withField(StandardField.MONTH, "#May#"); + BibDatabase bibDatabase = mock(BibDatabase.class); + String preview = bstPreviewLayout.generatePreview(entry, bibDatabase); + assertEquals("O. Kopp. Thoughts on development, May.", preview); + } + @Test public void generatePreviewForSliceTheoremPaperUsingAbbr() throws Exception { BstPreviewLayout bstPreviewLayout = new BstPreviewLayout(Paths.get(BstPreviewLayoutTest.class.getResource("abbrv.bst").toURI())); String preview = bstPreviewLayout.generatePreview(getSliceTheoremPaper(), bibDatabase); - assertEquals("T. Diez. Slice theorem for fréchet group actions and covariant symplectic field theory. #may# 2014.", preview); + assertEquals("T. Diez. Slice theorem for fréchet group actions and covariant symplectic field theory. May 2014.", preview); } @Test public void generatePreviewForSliceTheoremPaperUsingIEEE() throws Exception { BstPreviewLayout bstPreviewLayout = new BstPreviewLayout(Paths.get(ClassLoader.getSystemResource("bst/IEEEtran.bst").toURI())); String preview = bstPreviewLayout.generatePreview(getSliceTheoremPaper(), bibDatabase); - assertEquals("T. Diez, \"Slice theorem for fréchet group actions and covariant symplectic field theory\" #may# 2014.", preview); + assertEquals("T. Diez, \"Slice theorem for fréchet group actions and covariant symplectic field theory\" May 2014.", preview); } private static BibEntry getSliceTheoremPaper() { From 0323f2c0c41c23450ab6f0a98fde2aa74fc670b4 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 21 Mar 2020 22:19:37 +0100 Subject: [PATCH 18/18] Fix checkstyle --- src/main/java/org/jabref/logic/bst/BstPreviewLayout.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java b/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java index 1d113cd315d..312df6bbf98 100644 --- a/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java +++ b/src/main/java/org/jabref/logic/bst/BstPreviewLayout.java @@ -2,16 +2,15 @@ import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; -import org.jabref.logic.preview.PreviewLayout; import org.jabref.logic.cleanup.ConvertToBibtexCleanup; import org.jabref.logic.formatter.bibtexfields.RemoveNewlinesFormatter; import org.jabref.logic.l10n.Localization; import org.jabref.logic.layout.format.LatexToUnicodeFormatter; import org.jabref.logic.layout.format.RemoveLatexCommandsFormatter; import org.jabref.logic.layout.format.RemoveTilde; +import org.jabref.logic.preview.PreviewLayout; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry;