001/*
002// $Id: //open/util/resgen/src/org/eigenbase/resgen/CppGenerator.java#3 $
003// Package org.eigenbase.resgen is an i18n resource generator.
004// Copyright (C) 2005-2005 The Eigenbase Project
005// Copyright (C) 2005-2005 Disruptive Tech
006// Copyright (C) 2005-2005 LucidEra, Inc.
007// Portions Copyright (C) 2001-2005 Kana Software, Inc. and others.
008//
009// This library is free software; you can redistribute it and/or modify it
010// under the terms of the GNU Lesser General Public License as published by the
011// Free Software Foundation; either version 2 of the License, or (at your
012// option) any later version approved by The Eigenbase Project.
013//
014// This library is distributed in the hope that it will be useful, 
015// but WITHOUT ANY WARRANTY; without even the implied warranty of
016// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
017// GNU Lesser General Public License for more details.
018// 
019// You should have received a copy of the GNU Lesser General Public License
020// along with this library; if not, write to the Free Software
021// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
022*/
023package org.eigenbase.resgen;
024
025import java.io.File;
026import java.io.PrintWriter;
027
028/**
029 * Generates a C++ class containing resource definitions.
030 *
031 * @author jhyde
032 * @since 19 September, 2005
033 * @version $Id: //open/util/resgen/src/org/eigenbase/resgen/CppGenerator.java#3 $
034 */
035class CppGenerator extends AbstractGenerator
036{
037    private final String className;
038    private final String defaultExceptionClassName;
039    private final String headerFilename;
040    private final String baseClassName;
041
042    private static final String CPP_STRING = "const std::string &";
043    private static final String CPP_NUMBER = "int";
044    private static final String CPP_DATE_TIME = "time_t";
045    private static final String[] CPP_TYPE_NAMES =
046        {CPP_STRING, CPP_NUMBER, CPP_DATE_TIME, CPP_DATE_TIME};
047
048    /**
049     * Creates a C++ header generator.
050     *
051     * @param srcFile
052     * @param file
053     * @param className
054     * @param baseClassName Name of base class, must not be null, typically
055     * @param defaultExceptionClassName
056     */
057    CppGenerator(
058        File srcFile,
059        File file,
060        String className,
061        String baseClassName,
062        String defaultExceptionClassName,
063        String headerFilename)
064    {
065        super(srcFile, file);
066        assert className.indexOf('.') < 0 :
067                "C++ class name must not contain '.': " + className;
068        this.className = className;
069        this.defaultExceptionClassName = defaultExceptionClassName;
070        this.headerFilename = headerFilename;
071        assert baseClassName != null;
072        this.baseClassName = baseClassName;
073    }
074
075    protected String getClassName()
076    {
077        return className;
078    }
079
080    protected String getBaseClassName()
081    {
082        return baseClassName;
083    }
084
085    protected String[] getArgTypes(String message) {
086        return ResourceDefinition.getArgTypes(message, CPP_TYPE_NAMES);
087    }
088
089    public void generateModule(ResourceGen generator, ResourceDef.ResourceBundle resourceList, PrintWriter pw)
090    {
091        generateDoNotModifyHeader(pw);
092        generateGeneratedByBlock(pw);
093
094        String className = getClassName();
095        String bundleCacheClassName = className + "BundleCache";
096        String baseClass = getBaseClassName();
097
098        if (resourceList.cppCommonInclude != null) {
099            pw.println(
100                "// begin common include specified by " 
101                + getSrcFileForComment());
102            pw.println("#include \"" + resourceList.cppCommonInclude + "\"");
103            pw.println(
104                "// end common include specified by " 
105                + getSrcFileForComment());
106        }
107
108        pw.println("#include \"" + headerFilename + "\"");
109        pw.println("#include \"ResourceBundle.h\"");
110        pw.println("#include \"Locale.h\"");
111        pw.println();
112        pw.println("#include <map>");
113        pw.println("#include <string>");
114        pw.println();
115
116        if (resourceList.cppNamespace != null) {
117            pw.println("namespace " + resourceList.cppNamespace + " {");
118            pw.println();
119        }
120
121        pw.println("using namespace std;");
122        pw.println();
123        pw.println("#define BASENAME (\"" + className + "\")");
124        pw.println();
125        pw.println("static " + bundleCacheClassName + " bundleCache;");
126        pw.println("static string bundleLocation(\"\");");
127        pw.println();
128
129        pw.println("const " + className + " &" + className + "::instance()");
130        pw.println("{");
131        pw.println("    return " + className + "::instance(Locale::getDefault());");
132        pw.println("}");
133        pw.println();
134        pw.println("const " + className
135            + " &" + className + "::instance(const Locale &locale)");
136        pw.println("{");
137        pw.println("    return *makeInstance<"
138            + className + ", "
139            + bundleCacheClassName + ", "
140            + bundleCacheClassName
141            + "::iterator>(bundleCache, locale);");
142        pw.println("}");
143        pw.println();
144        pw.println("void "
145            + className
146            + "::setResourceFileLocation(const string &location)");
147        pw.println("{");
148        pw.println("    bundleLocation = location;");
149        pw.println("}");
150        pw.println();
151
152        pw.println("" + className + "::" + className + "(Locale locale)");
153        pw.println("    : " + baseClass
154            + "(BASENAME, locale, bundleLocation),");
155
156        for(int i = 0; i < resourceList.resources.length; i++) {
157            ResourceDef.Resource resource = resourceList.resources[i];
158
159            pw.print("      _"
160                + resource.name
161                + "(this, \""
162                + resource.name
163                + "\")");
164
165            if (i + 1 < resourceList.resources.length) {
166                pw.println(',');
167            } else {
168                pw.println();
169            }
170        }
171        pw.println("{ }");
172        pw.println();
173
174        for (int i = 0; i < resourceList.resources.length; i++) {
175            generateResource(resourceList.resources[i], pw);
176        }
177
178        if (resourceList.cppNamespace != null) {
179            pw.println();
180            pw.println("} // end namespace " + resourceList.cppNamespace);
181        }
182    }
183
184    public void generateResource(
185        ResourceDef.Resource resource,
186        PrintWriter pw)
187    {
188        String text = resource.text.cdata;
189        //String comment = ResourceGen.getComment(resource);
190
191        // e.g. "Internal"
192        final String resourceInitCap =
193            ResourceGen.getResourceInitcap(resource);
194
195        String parameterList = getParameterList(text);
196        String argumentList = getArgumentList(text);
197
198        pw.println("string " + className + "::" + resource.name + "("
199            + parameterList + ") const");
200        pw.println("{");
201        pw.println("    return _"
202            + resource.name
203            + ".format("
204            + argumentList
205            + ");");
206        pw.println("}");
207
208        if (resource instanceof ResourceDef.Exception) {
209            ResourceDef.Exception exception =
210                (ResourceDef.Exception)resource;
211
212            String exceptionClass = exception.cppClassName;
213            if (exceptionClass == null) {
214                exceptionClass = defaultExceptionClassName;
215            }
216
217            pw.println(exceptionClass + "* "
218                + className + "::new" + resourceInitCap + "("
219                + parameterList + ") const");
220            pw.println("{");
221            pw.println("    return new "
222                + exceptionClass
223                + "("
224                + resource.name
225                + "("
226                + argumentList
227                + "));");
228            pw.println("}");
229            pw.println();
230
231            boolean chainExceptions =
232                (exception.cppChainExceptions != null &&
233                exception.cppChainExceptions.equalsIgnoreCase("true"));
234
235            if (chainExceptions) {
236                if (parameterList.length() > 0) {
237                    pw.println(exceptionClass
238                        + "* "
239                        + className
240                        + "::new"
241                        + resourceInitCap
242                        + "("
243                        + parameterList
244                        + ", const "
245                        + exceptionClass
246                        + " * const prev) const");
247                } else {
248                    pw.println(exceptionClass
249                        + " "
250                        + className
251                        + "::new"
252                        + resourceInitCap
253                        + "(const "
254                        + exceptionClass
255                        + " * const prev) const");
256                }
257                pw.println("{");
258
259                pw.println("    return new "
260                    + exceptionClass
261                    + "("
262                    + resource.name
263                    + "("
264                    + argumentList
265                    + "), prev);");
266                pw.println("}");
267                pw.println();
268            }
269        }
270    }
271}
272
273// End CppGenerator.java