1 /*
2  * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.tools.javadoc.main;
27 
28 import java.text.BreakIterator;
29 import java.text.Collator;
30 import java.util.Locale;
31 
32 /**
33  * This class holds the information about locales.
34  *
35  *  <p><b>This is NOT part of any supported API.
36  *  If you write code that depends on this, you do so at your own risk.
37  *  This code and its internal interfaces are subject to change or
38  *  deletion without notice.</b>
39  *
40  * @since 1.4
41  * @author Robert Field
42  */
43 @Deprecated(since="9", forRemoval=true)
44 @SuppressWarnings("removal")
45 class DocLocale {
46 
47     /**
48      * The locale name will be set by Main, if option is provided on the
49      * command line.
50      */
51     final String localeName;
52 
53     /**
54      * The locale to be used. If user doesn't provide this,
55      * then set it to default locale value.
56      */
57     final Locale locale;
58 
59     /**
60      * The collator for this application. This is to take care of Locale
61      * Specific or Natural Language Text sorting.
62      */
63     final Collator collator;
64 
65     /**
66      * Enclosing DocEnv
67      */
68     private final DocEnv docenv;
69 
70     /**
71      * Sentence instance from the BreakIterator.
72      */
73     private final BreakIterator sentenceBreaker;
74 
75     /**
76      * True is we should use <code>BreakIterator</code>
77      * to compute first sentence.
78      */
79     private boolean useBreakIterator = false;
80 
81     /**
82      * The HTML sentence terminators.
83      */
84     static final String[] sentenceTerminators =
85                     {
86                         "<p>", "</p>", "<h1>", "<h2>",
87                         "<h3>", "<h4>", "<h5>", "<h6>",
88                         "</h1>", "</h2>", "</h3>", "</h4>", "</h5>",
89                         "</h6>", "<hr>", "<pre>", "</pre>"
90                     };
91 
92     /**
93      * Constructor
94      */
DocLocale(DocEnv docenv, String localeName, boolean useBreakIterator)95     DocLocale(DocEnv docenv, String localeName, boolean useBreakIterator) {
96         this.docenv = docenv;
97         this.localeName = localeName;
98         this.useBreakIterator = useBreakIterator;
99         locale = getLocale();
100         if (locale == null) {
101             docenv.exit();
102         } else {
103             Locale.setDefault(locale); // NOTE: updating global state
104         }
105         collator = Collator.getInstance(locale);
106         sentenceBreaker = BreakIterator.getSentenceInstance(locale);
107     }
108 
109     /**
110      * Get the locale if specified on the command line
111      * else return null and if locale option is not used
112      * then return default locale.
113      */
getLocale()114     private Locale getLocale() {
115         Locale userlocale = null;
116         if (localeName.length() > 0) {
117             int firstuscore = localeName.indexOf('_');
118             int seconduscore = -1;
119             String language = null;
120             String country = null;
121             String variant = null;
122             if (firstuscore == 2) {
123                 language = localeName.substring(0, firstuscore);
124                 seconduscore = localeName.indexOf('_', firstuscore + 1);
125                 if (seconduscore > 0) {
126                     if (seconduscore != firstuscore + 3 ||
127                            localeName.length() <= seconduscore + 1) {
128                         docenv.error(null, "main.malformed_locale_name", localeName);
129                         return null;
130                     }
131                     country = localeName.substring(firstuscore + 1,
132                                                    seconduscore);
133                     variant = localeName.substring(seconduscore + 1);
134                 } else if (localeName.length() == firstuscore + 3) {
135                     country = localeName.substring(firstuscore + 1);
136                 } else {
137                     docenv.error(null, "main.malformed_locale_name", localeName);
138                     return null;
139                 }
140             } else if (firstuscore == -1 && localeName.length() == 2) {
141                 language = localeName;
142             } else {
143                 docenv.error(null, "main.malformed_locale_name", localeName);
144                 return null;
145             }
146             userlocale = searchLocale(language, country, variant);
147             if (userlocale == null) {
148                 docenv.error(null, "main.illegal_locale_name", localeName);
149                 return null;
150             } else {
151                 return userlocale;
152             }
153         } else {
154             return Locale.getDefault();
155         }
156     }
157 
158     /**
159      * Search the locale for specified language, specified country and
160      * specified variant.
161      */
searchLocale(String language, String country, String variant)162     private Locale searchLocale(String language, String country,
163                                 String variant) {
164         for (Locale loc : Locale.getAvailableLocales()) {
165             if (loc.getLanguage().equals(language) &&
166                 (country == null || loc.getCountry().equals(country)) &&
167                 (variant == null || loc.getVariant().equals(variant))) {
168                 return loc;
169             }
170         }
171         return null;
172     }
173 
localeSpecificFirstSentence(DocImpl doc, String s)174     String localeSpecificFirstSentence(DocImpl doc, String s) {
175         if (s == null || s.length() == 0) {
176             return "";
177         }
178         int index = s.indexOf("-->");
179         if(s.trim().startsWith("<!--") && index != -1) {
180             return localeSpecificFirstSentence(doc, s.substring(index + 3, s.length()));
181         }
182         if (useBreakIterator || !locale.getLanguage().equals("en")) {
183             sentenceBreaker.setText(s.replace('\n', ' '));
184             int start = sentenceBreaker.first();
185             int end = sentenceBreaker.next();
186             return s.substring(start, end).trim();
187         } else {
188             return englishLanguageFirstSentence(s).trim();
189         }
190     }
191 
192     /**
193      * Return the first sentence of a string, where a sentence ends
194      * with a period followed be white space.
195      */
englishLanguageFirstSentence(String s)196     private String englishLanguageFirstSentence(String s) {
197         if (s == null) {
198             return null;
199         }
200         int len = s.length();
201         boolean period = false;
202         for (int i = 0 ; i < len ; i++) {
203             switch (s.charAt(i)) {
204                 case '.':
205                     period = true;
206                     break;
207                 case ' ':
208                 case '\t':
209                 case '\n':
210             case '\r':
211             case '\f':
212                     if (period) {
213                         return s.substring(0, i);
214                     }
215                     break;
216             case '<':
217                     if (i > 0) {
218                         if (htmlSentenceTerminatorFound(s, i)) {
219                             return s.substring(0, i);
220                         }
221                     }
222                     break;
223                 default:
224                     period = false;
225             }
226         }
227         return s;
228     }
229 
230     /**
231      * Find out if there is any HTML tag in the given string. If found
232      * return true else return false.
233      */
htmlSentenceTerminatorFound(String str, int index)234     private boolean htmlSentenceTerminatorFound(String str, int index) {
235         for (String terminator : sentenceTerminators) {
236             if (str.regionMatches(true, index, terminator,
237                                   0, terminator.length())) {
238                 return true;
239             }
240         }
241         return false;
242     }
243 }
244