001: /*
002: * Copyright (c) 2003 The Visigoth Software Society. All rights
003: * reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions
007: * are met:
008: *
009: * 1. Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: *
012: * 2. Redistributions in binary form must reproduce the above copyright
013: * notice, this list of conditions and the following disclaimer in
014: * the documentation and/or other materials provided with the
015: * distribution.
016: *
017: * 3. The end-user documentation included with the redistribution, if
018: * any, must include the following acknowledgement:
019: * "This product includes software developed by the
020: * Visigoth Software Society (http://www.visigoths.org/)."
021: * Alternately, this acknowledgement may appear in the software itself,
022: * if and wherever such third-party acknowledgements normally appear.
023: *
024: * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
025: * project contributors may be used to endorse or promote products derived
026: * from this software without prior written permission. For written
027: * permission, please contact visigoths@visigoths.org.
028: *
029: * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
030: * nor may "FreeMarker" or "Visigoth" appear in their names
031: * without prior written permission of the Visigoth Software Society.
032: *
033: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
034: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
035: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
036: * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
037: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
038: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
039: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
040: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
041: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
042: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
043: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
044: * SUCH DAMAGE.
045: * ====================================================================
046: *
047: * This software consists of voluntary contributions made by many
048: * individuals on behalf of the Visigoth Software Society. For more
049: * information on the Visigoth Software Society, please see
050: * http://www.visigoths.org/
051: */
052:
053: package freemarker.core;
054:
055: import freemarker.template.*;
056: import freemarker.template.utility.StringUtil;
057:
058: import java.io.StringReader;
059: import java.util.StringTokenizer;
060:
061: /**
062: * A holder for builtins that operate exclusively on strings.
063: */
064:
065: abstract class StringBuiltins {
066: abstract static class StringBuiltIn extends BuiltIn {
067: TemplateModel _getAsTemplateModel(Environment env)
068: throws TemplateException {
069: return calculateResult(target.getStringValue(env), env);
070: }
071:
072: abstract TemplateModel calculateResult(String s, Environment env)
073: throws TemplateException;
074: }
075:
076: static class capitalizeBI extends StringBuiltIn {
077: TemplateModel calculateResult(String s, Environment env) {
078: return new SimpleScalar(StringUtil.capitalize(s));
079: }
080: }
081:
082: static class chop_linebreakBI extends StringBuiltIn {
083: TemplateModel calculateResult(String s, Environment env) {
084: return new SimpleScalar(StringUtil.chomp(s));
085: }
086: }
087:
088: static class j_stringBI extends StringBuiltIn {
089: TemplateModel calculateResult(String s, Environment env) {
090: return new SimpleScalar(StringUtil.javaStringEnc(s));
091: }
092: }
093:
094: static class js_stringBI extends StringBuiltIn {
095: TemplateModel calculateResult(String s, Environment env) {
096: return new SimpleScalar(StringUtil.javaScriptStringEnc(s));
097: }
098: }
099:
100: static class cap_firstBI extends StringBuiltIn {
101: TemplateModel calculateResult(String s, Environment env) {
102: int i = 0;
103: int ln = s.length();
104: while (i < ln && Character.isWhitespace(s.charAt(i))) {
105: i++;
106: }
107: if (i < ln) {
108: StringBuffer b = new StringBuffer(s);
109: b.setCharAt(i, Character.toUpperCase(s.charAt(i)));
110: s = b.toString();
111: }
112: return new SimpleScalar(s);
113: }
114: }
115:
116: static class uncap_firstBI extends StringBuiltIn {
117: TemplateModel calculateResult(String s, Environment env) {
118: int i = 0;
119: int ln = s.length();
120: while (i < ln && Character.isWhitespace(s.charAt(i))) {
121: i++;
122: }
123: if (i < ln) {
124: StringBuffer b = new StringBuffer(s);
125: b.setCharAt(i, Character.toLowerCase(s.charAt(i)));
126: s = b.toString();
127: }
128: return new SimpleScalar(s);
129: }
130: }
131:
132: static class upper_caseBI extends StringBuiltIn {
133: TemplateModel calculateResult(String s, Environment env) {
134: return new SimpleScalar(s.toUpperCase(env.getLocale()));
135: }
136: }
137:
138: static class lower_caseBI extends StringBuiltIn {
139: TemplateModel calculateResult(String s, Environment env) {
140: return new SimpleScalar(s.toLowerCase(env.getLocale()));
141: }
142: }
143:
144: static class word_listBI extends StringBuiltIn {
145: TemplateModel calculateResult(String s, Environment env) {
146: SimpleSequence result = new SimpleSequence();
147: StringTokenizer st = new StringTokenizer(s);
148: while (st.hasMoreTokens()) {
149: result.add(st.nextToken());
150: }
151: return result;
152: }
153: }
154:
155: static class evalBI extends StringBuiltIn {
156: TemplateModel calculateResult(String s, Environment env)
157: throws TemplateException {
158: SimpleCharStream scs = new SimpleCharStream(
159: new StringReader("(" + s + ")"), target.beginLine,
160: target.beginColumn, s.length() + 2);
161: FMParserTokenManager token_source = new FMParserTokenManager(
162: scs);
163: token_source.SwitchTo(FMParserConstants.FM_EXPRESSION);
164: FMParser parser = new FMParser(token_source);
165: parser.template = getTemplate();
166: Expression exp = null;
167: try {
168: exp = parser.Expression();
169: } catch (ParseException pe) {
170: throw new TemplateException(pe, env);
171: }
172: return exp.getAsTemplateModel(env);
173: }
174: }
175:
176: static class numberBI extends StringBuiltIn {
177: TemplateModel calculateResult(String s, Environment env)
178: throws TemplateException {
179: try {
180: return new SimpleNumber(env.getArithmeticEngine()
181: .toNumber(s));
182: } catch (NumberFormatException nfe) {
183: String mess = "Error: " + getStartLocation()
184: + "\nExpecting a number here, found: " + s;
185: throw new NonNumericalException(mess, env);
186: }
187: }
188: }
189:
190: static class substringBI extends StringBuiltIn {
191: TemplateModel calculateResult(final String s,
192: final Environment env) throws TemplateException {
193: return new TemplateMethodModelEx() {
194: public Object exec(java.util.List args)
195: throws TemplateModelException {
196: int argCount = args.size(), left = 0, right = 0;
197: if (argCount != 1 && argCount != 2) {
198: throw new TemplateModelException(
199: "Error: +getStartLocation() + \nExpecting 1 or 2 numerical arguments here");
200: }
201: try {
202: TemplateNumberModel tnm = (TemplateNumberModel) args
203: .get(0);
204: left = tnm.getAsNumber().intValue();
205: if (argCount == 2) {
206: tnm = (TemplateNumberModel) args.get(1);
207: right = tnm.getAsNumber().intValue();
208: }
209: } catch (ClassCastException cce) {
210: String mess = "Error: " + getStartLocation()
211: + "\nExpecting numerical argument here";
212: throw new TemplateModelException(mess);
213: }
214: if (argCount == 1) {
215: return new SimpleScalar(s.substring(left));
216: }
217: return new SimpleScalar(s.substring(left, right));
218: }
219: };
220: }
221: }
222: }
|