1 package org.apache.velocity.runtime.directive;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.Writer;
23 import java.io.IOException;
24
25 import java.util.List;
26 import java.util.ArrayList;
27
28 import org.apache.velocity.context.InternalContextAdapter;
29 import org.apache.velocity.exception.TemplateInitException;
30
31 import org.apache.velocity.runtime.parser.node.Node;
32 import org.apache.velocity.runtime.parser.node.NodeUtils;
33 import org.apache.velocity.runtime.parser.Token;
34 import org.apache.velocity.runtime.parser.ParseException;
35 import org.apache.velocity.runtime.parser.ParserTreeConstants;
36 import org.apache.velocity.runtime.RuntimeServices;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 public class Macro extends Directive
59 {
60 private static boolean debugMode = false;
61
62
63
64
65
66 public String getName()
67 {
68 return "macro";
69 }
70
71
72
73
74
75 public int getType()
76 {
77 return BLOCK;
78 }
79
80
81
82
83
84
85
86
87
88
89 public boolean render(InternalContextAdapter context,
90 Writer writer, Node node)
91 throws IOException
92 {
93
94
95
96
97 return true;
98 }
99
100
101
102
103 public void init(RuntimeServices rs, InternalContextAdapter context,
104 Node node)
105 throws TemplateInitException
106 {
107 super.init(rs, context, node);
108
109
110
111
112
113
114 }
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132 public static void processAndRegister(RuntimeServices rs, Token t, Node node,
133 String sourceTemplate)
134 throws IOException, ParseException
135 {
136
137
138
139
140
141
142 int numArgs = node.jjtGetNumChildren();
143
144
145
146
147
148
149 if (numArgs < 2)
150 {
151
152
153
154
155
156
157 rs.getLog().error("#macro error : Velocimacro must have name as 1st " +
158 "argument to #macro(). #args = " + numArgs);
159
160 throw new MacroParseException("First argument to #macro() must be " +
161 " macro name.", sourceTemplate, t);
162 }
163
164
165
166
167
168 int firstType = node.jjtGetChild(0).getType();
169
170 if(firstType != ParserTreeConstants.JJTWORD)
171 {
172 throw new MacroParseException("First argument to #macro() must be a"
173 + " token without surrounding \' or \", which specifies"
174 + " the macro name. Currently it is a "
175 + ParserTreeConstants.jjtNodeName[firstType], sourceTemplate, t);
176 }
177
178
179
180
181
182 String argArray[] = getArgArray(node, rs);
183
184
185
186
187
188 List macroArray =
189 getASTAsStringArray(node.jjtGetChild(numArgs - 1));
190
191
192
193
194
195 StringBuffer macroBody = new StringBuffer();
196
197 for (int i=0; i < macroArray.size(); i++)
198 {
199 macroBody.append(macroArray.get(i));
200 }
201
202
203
204
205
206
207 boolean macroAdded = rs.addVelocimacro(argArray[0],
208 macroBody.toString(),
209 argArray, sourceTemplate);
210
211 if (!macroAdded && rs.getLog().isWarnEnabled())
212 {
213 StringBuffer msg = new StringBuffer("Failed to add macro: ");
214 macroToString(msg, argArray);
215 msg.append(" : source = ").append(sourceTemplate);
216 rs.getLog().warn(msg);
217 }
218 }
219
220
221
222
223
224
225
226
227
228
229
230
231 private static String[] getArgArray(Node node, RuntimeServices rsvc)
232 {
233
234
235
236
237
238 int numArgs = node.jjtGetNumChildren();
239 numArgs--;
240
241 String argArray[] = new String[numArgs];
242
243 int i = 0;
244
245
246
247
248
249 while (i < numArgs)
250 {
251 argArray[i] = node.jjtGetChild(i).getFirstToken().image;
252
253
254
255
256
257
258 if (i > 0)
259 {
260 if (argArray[i].startsWith("$"))
261 {
262 argArray[i] = argArray[i]
263 .substring(1, argArray[i].length());
264 }
265 }
266
267 i++;
268 }
269
270 if (debugMode)
271 {
272 StringBuffer msg = new StringBuffer("Macro.getArgArray() : nbrArgs=");
273 msg.append(numArgs).append(" : ");
274 macroToString(msg, argArray);
275 rsvc.getLog().debug(msg);
276 }
277
278 return argArray;
279 }
280
281
282
283
284
285
286 private static List getASTAsStringArray(Node rootNode)
287 {
288
289
290
291
292
293 Token t = rootNode.getFirstToken();
294 Token tLast = rootNode.getLastToken();
295
296
297
298
299
300
301 List list = new ArrayList();
302
303 while (t != tLast)
304 {
305 list.add(NodeUtils.tokenLiteral(t));
306 t = t.next;
307 }
308
309
310
311
312
313 list.add(NodeUtils.tokenLiteral(t));
314
315 return list;
316 }
317
318
319
320
321
322
323
324
325
326
327
328 public static final StringBuffer macroToString(final StringBuffer buf,
329 final String[] argArray)
330 {
331 StringBuffer ret = (buf == null) ? new StringBuffer() : buf;
332
333 ret.append('#').append(argArray[0]).append("( ");
334 for (int i = 1; i < argArray.length; i++)
335 {
336 ret.append(' ').append(argArray[i]);
337 }
338 ret.append(" )");
339 return ret;
340 }
341 }