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    */
023    package org.eigenbase.resgen;
024    
025    import java.io.File;
026    import 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     */
035    class 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