1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.velocity.internal.util

File VelocityParser.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart6.png
69% of files have more coverage

Code metrics

134
223
22
1
737
383
109
0.49
10.14
22
4.95

Classes

Class Line # Actions
VelocityParser 33 223 0% 109 149
0.6068601660.7%
 

Contributing tests

This file is covered by 13 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.velocity.internal.util;
21   
22    import java.util.HashSet;
23    import java.util.Set;
24   
25    import org.slf4j.Logger;
26    import org.slf4j.LoggerFactory;
27   
28    /**
29    * Provide helpers to parse velocity scripts.
30    *
31    * @version $Id: e889b220e19cc998ddb2c8766390448db0125b65 $
32    */
 
33    public class VelocityParser
34    {
35    /**
36    * The directives which start a new level which will have to be close by a #end.
37    */
38    public static final Set<String> VELOCITYDIRECTIVE_BEGIN = new HashSet<String>();
39   
40    /**
41    * Close an opened level.
42    */
43    public static final Set<String> VELOCITYDIRECTIVE_END = new HashSet<String>();
44   
45    /**
46    * Reserved directive containing parameter(s) like #if.
47    */
48    public static final Set<String> VELOCITYDIRECTIVE_PARAM = new HashSet<String>();
49   
50    /**
51    * Reserved directives without parameters like #else.
52    */
53    public static final Set<String> VELOCITYDIRECTIVE_NOPARAM = new HashSet<String>();
54   
55    /**
56    * All the velocity reserved directives.
57    */
58    public static final Set<String> VELOCITYDIRECTIVE_ALL = new HashSet<String>();
59   
60    /**
61    * The Logger to use for logging.
62    */
63    private static final Logger LOGGER = LoggerFactory.getLogger(VelocityParser.class);
64   
 
65  2 toggle static {
66  2 VELOCITYDIRECTIVE_BEGIN.add("if");
67  2 VELOCITYDIRECTIVE_BEGIN.add("foreach");
68  2 VELOCITYDIRECTIVE_BEGIN.add("literal");
69  2 VELOCITYDIRECTIVE_BEGIN.add("macro");
70  2 VELOCITYDIRECTIVE_BEGIN.add("define");
71   
72  2 VELOCITYDIRECTIVE_END.add("end");
73   
74  2 VELOCITYDIRECTIVE_PARAM.addAll(VELOCITYDIRECTIVE_BEGIN);
75  2 VELOCITYDIRECTIVE_PARAM.add("set");
76  2 VELOCITYDIRECTIVE_PARAM.add("elseif");
77  2 VELOCITYDIRECTIVE_PARAM.add("evaluate");
78  2 VELOCITYDIRECTIVE_PARAM.add("include");
79   
80  2 VELOCITYDIRECTIVE_NOPARAM.addAll(VELOCITYDIRECTIVE_END);
81  2 VELOCITYDIRECTIVE_NOPARAM.add("else");
82  2 VELOCITYDIRECTIVE_NOPARAM.add("break");
83  2 VELOCITYDIRECTIVE_NOPARAM.add("stop");
84   
85  2 VELOCITYDIRECTIVE_ALL.addAll(VELOCITYDIRECTIVE_PARAM);
86  2 VELOCITYDIRECTIVE_ALL.addAll(VELOCITYDIRECTIVE_NOPARAM);
87    }
88   
89    /**
90    * Get any valid Velocity block starting with a sharp character (#if, #somemaccro(), ##comment etc.).
91    *
92    * @param array the source to parse
93    * @param currentIndex the current index in the <code>array</code>
94    * @param velocityBlock the buffer where to append matched velocity block
95    * @param context the parser context to put some informations
96    * @return the index in the <code>array</code> after the matched block
97    * @throws InvalidVelocityException not a valid velocity block
98    */
 
99  43 toggle public int getKeyWord(char[] array, int currentIndex, StringBuffer velocityBlock, VelocityParserContext context)
100    throws InvalidVelocityException
101    {
102  43 int i = currentIndex;
103   
104  43 if (i + 1 >= array.length) {
105  0 throw new InvalidVelocityException();
106    }
107   
108  43 if (array[i + 1] == '#') {
109    // A simple line comment
110  3 i = getSimpleComment(array, currentIndex, velocityBlock, context);
111  40 } else if (array[i + 1] == '*') {
112    // A multi lines comment
113  2 i = getMultilinesComment(array, currentIndex, velocityBlock, context);
114  38 } else if (array[i + 1] == '{' || Character.isLetter(array[i + 1])) {
115    // A directive
116  36 i = getDirective(array, currentIndex, velocityBlock, context);
117    } else {
118  2 throw new InvalidVelocityException();
119    }
120   
121  41 return i;
122    }
123   
124    /**
125    * Get any valid Velocity block starting with a sharp character except comments.
126    *
127    * @param array the source to parse
128    * @param currentIndex the current index in the <code>array</code>
129    * @param velocityBlock the buffer where to append matched velocity block
130    * @param context the parser context to put some informations
131    * @return the index in the <code>array</code> after the matched block
132    * @throws InvalidVelocityException not a valid velocity block
133    */
 
134  36 toggle public int getDirective(char[] array, int currentIndex, StringBuffer velocityBlock, VelocityParserContext context)
135    throws InvalidVelocityException
136    {
137  36 int i = currentIndex + 1;
138   
139    // Get macro name
140  36 StringBuffer directiveNameBuffer = new StringBuffer();
141  36 i = getDirectiveName(array, i, directiveNameBuffer, null, context);
142   
143  36 String directiveName = directiveNameBuffer.toString();
144   
145  36 if (!VELOCITYDIRECTIVE_NOPARAM.contains(directiveName)) {
146    // Skip spaces
147  33 while (i < array.length && array[i] == ' ') {
148  6 ++i;
149    }
150   
151  27 if (i < array.length && array[i] == '(') {
152    // Skip condition
153  27 i = getMethodParameters(array, i, null, context);
154    } else {
155  0 throw new InvalidVelocityException();
156    }
157    }
158   
159  36 if (VELOCITYDIRECTIVE_ALL.contains(directiveName)) {
160  31 if (VELOCITYDIRECTIVE_BEGIN.contains(directiveName)) {
161  10 context.pushVelocityElement(new VelocityBlock(directiveName, VelocityBlock.VelocityType.DIRECTIVE));
162  21 } else if (VELOCITYDIRECTIVE_END.contains(directiveName)) {
163  8 context.popVelocityElement();
164    }
165   
166    // consume the end of the line
167  31 i = getDirectiveEndOfLine(array, i, null, context);
168   
169  31 context.setType(VelocityBlock.VelocityType.DIRECTIVE);
170    } else {
171  5 context.setType(VelocityBlock.VelocityType.MACRO);
172    }
173   
174  36 if (velocityBlock != null) {
175  1 velocityBlock.append(array, currentIndex, i - currentIndex);
176    }
177   
178  36 return i;
179    }
180   
181    /**
182    * Get a valid Velocity identifier used for variable of macro.
183    *
184    * @param array the source to parse
185    * @param currentIndex the current index in the <code>array</code>
186    * @param velocityBlock the buffer where to append matched velocity block
187    * @param context the parser context to put some informations
188    * @return the index in the <code>array</code> after the matched block
189    * @throws InvalidVelocityException not a valid velocity block
190    */
 
191  52 toggle public int getVelocityIdentifier(char[] array, int currentIndex, StringBuffer velocityBlock,
192    VelocityParserContext context) throws InvalidVelocityException
193    {
194    // The first character of an identifier must be a [a-zA-Z]
195  52 if (!Character.isLetter(array[currentIndex])) {
196  1 throw new InvalidVelocityException();
197    }
198   
199  51 int i = currentIndex + 1;
200   
201  199 while (i < array.length && array[i] != '}' && isValidVelocityIdentifierChar(array[i])) {
202  148 ++i;
203    }
204   
205  51 if (velocityBlock != null) {
206  51 velocityBlock.append(array, currentIndex, i - currentIndex);
207    }
208   
209  51 return i;
210    }
211   
212    /**
213    * Indicate if the provided character is valid in a velocity identifier.
214    *
215    * @param c the character
216    * @return true if the character is valid
217    */
 
218  191 toggle public boolean isValidVelocityIdentifierChar(char c)
219    {
220  191 return Character.isLetterOrDigit(c) || c == '_' || c == '-';
221    }
222   
223    /**
224    * Get a Velocity directive name block. It's different from
225    * {@link #getVelocityIdentifier(char[], int, StringBuffer, VelocityParserContext)} because is include the optional
226    * <code>{</code> and <code>}</code>.
227    *
228    * @param array the source to parse
229    * @param currentIndex the current index in the <code>array</code>
230    * @param directiveName the buffer where to append the name of the directive
231    * @param velocityBlock the buffer where to append matched velocity block
232    * @param context the parser context to put some informations
233    * @return the index in the <code>array</code> after the matched block
234    * @throws InvalidVelocityException not a valid velocity block
235    */
 
236  36 toggle public int getDirectiveName(char[] array, int currentIndex, StringBuffer directiveName, StringBuffer velocityBlock,
237    VelocityParserContext context) throws InvalidVelocityException
238    {
239  36 int i = currentIndex;
240   
241  36 if (i == array.length) {
242  0 throw new InvalidVelocityException();
243    }
244   
245  36 if (array[i] == '{') {
246  0 ++i;
247    }
248   
249  36 i = getVelocityIdentifier(array, i, directiveName, context);
250   
251  36 if (i < array.length && array[i] == '}') {
252  0 ++i;
253    }
254   
255  36 if (velocityBlock != null) {
256  0 velocityBlock.append(array, currentIndex, i - currentIndex);
257    }
258   
259  36 return i;
260    }
261   
262    /**
263    * Get the newline consumed by Velocity directive other than macros.
264    *
265    * @param array the source to parse
266    * @param currentIndex the current index in the <code>array</code>
267    * @param velocityBlock the buffer where to append matched velocity block
268    * @param context the parser context to put some informations
269    * @return the index in the <code>array</code> after the matched block
270    */
 
271  31 toggle public int getDirectiveEndOfLine(char[] array, int currentIndex, StringBuffer velocityBlock,
272    VelocityParserContext context)
273    {
274  31 int i = currentIndex;
275   
276  32 for (; i < array.length; ++i) {
277  25 if (array[i] == '\n') {
278  23 ++i;
279  23 break;
280  2 } else if (!Character.isWhitespace(array[i])) {
281  1 return currentIndex;
282    }
283    }
284   
285  30 if (velocityBlock != null) {
286  0 velocityBlock.append(array, currentIndex, i - currentIndex);
287    }
288   
289  30 return i;
290    }
291   
292    /**
293    * Get comment single line comment (starting with <code>##</code>).
294    *
295    * @param array the source to parse
296    * @param currentIndex the current index in the <code>array</code>
297    * @param velocityBlock the buffer where to append matched velocity block
298    * @param context the parser context to put some informations
299    * @return the index in the <code>array</code> after the matched block
300    */
 
301  3 toggle public int getSimpleComment(char[] array, int currentIndex, StringBuffer velocityBlock,
302    VelocityParserContext context)
303    {
304  3 int i = currentIndex + 2;
305   
306  33 while (i < array.length && array[i - 1] != '\n') {
307  30 ++i;
308    }
309   
310  3 if (velocityBlock != null) {
311  1 velocityBlock.append(array, currentIndex, i - currentIndex);
312    }
313   
314  3 context.setType(VelocityBlock.VelocityType.COMMENT);
315   
316  3 return i;
317    }
318   
319    /**
320    * Get multilines comment (between <code>#*</code> and <code>*#</code>).
321    *
322    * @param array the source to parse
323    * @param currentIndex the current index in the <code>array</code>
324    * @param velocityBlock the buffer where to append matched velocity block
325    * @param context the parser context to put some informations
326    * @return the index in the <code>array</code> after the matched block
327    */
 
328  2 toggle public int getMultilinesComment(char[] array, int currentIndex, StringBuffer velocityBlock,
329    VelocityParserContext context)
330    {
331  2 int i = currentIndex + 2;
332   
333  28 while (i < array.length && (array[i - 1] != '#' || array[i - 2] != '*')) {
334  26 ++i;
335    }
336   
337  2 if (velocityBlock != null) {
338  1 velocityBlock.append(array, currentIndex, i - currentIndex);
339    }
340   
341  2 context.setType(VelocityBlock.VelocityType.COMMENT);
342   
343  2 return i;
344    }
345   
346    /**
347    * Get any valid Velocity starting with a <code>$</code>.
348    *
349    * @param array the source to parse
350    * @param currentIndex the current index in the <code>array</code>
351    * @param velocityBlock the buffer where to append matched velocity block
352    * @param context the parser context to put some informations
353    * @return the index in the <code>array</code> after the matched block
354    * @throws InvalidVelocityException not a valid velocity block
355    */
 
356  0 toggle public int getVar(char[] array, int currentIndex, StringBuffer velocityBlock, VelocityParserContext context)
357    throws InvalidVelocityException
358    {
359  0 return getVar(array, currentIndex, null, velocityBlock, context);
360    }
361   
362    /**
363    * Get any valid Velocity starting with a <code>$</code>.
364    *
365    * @param array the source to parse
366    * @param currentIndex the current index in the <code>array</code>
367    * @param varName the buffer where to append the name of the variable
368    * @param velocityBlock the buffer where to append matched velocity block
369    * @param context the parser context to put some informations
370    * @return the index in the <code>array</code> after the matched block
371    * @throws InvalidVelocityException not a valid velocity block
372    */
 
373  20 toggle public int getVar(char[] array, int currentIndex, StringBuffer varName, StringBuffer velocityBlock,
374    VelocityParserContext context) throws InvalidVelocityException
375    {
376  20 if (isVarEscaped(array, currentIndex)) {
377  4 throw new InvalidVelocityException();
378    }
379   
380  16 int i = currentIndex + 1;
381   
382  16 if (i == array.length) {
383  0 throw new InvalidVelocityException();
384    }
385   
386  16 if (array[i] == '!') {
387  0 ++i;
388    }
389   
390  16 if (i == array.length) {
391  0 throw new InvalidVelocityException();
392    }
393   
394  16 boolean fullSyntax = false;
395  16 if (array[i] == '{') {
396  3 ++i;
397  3 fullSyntax = true;
398    }
399   
400  16 if (i == array.length) {
401  0 throw new InvalidVelocityException();
402    }
403   
404    // get the variable name
405  16 i = getVelocityIdentifier(array, i, varName, context);
406   
407    // get the method(s)
408  15 i = followVar(array, i, fullSyntax, context);
409   
410  15 if (velocityBlock != null) {
411  0 velocityBlock.append(array, currentIndex, i - currentIndex);
412    }
413   
414  15 context.setType(VelocityBlock.VelocityType.VAR);
415   
416  15 return i;
417    }
418   
419    /**
420    * Look in previous characters of the array to find if the current var is escaped (like \$var).
421    *
422    * @param array the source to parse
423    * @param currentIndex the current index in the <code>array</code>
424    * @return the parser context to put some informations
425    */
 
426  20 toggle private boolean isVarEscaped(char[] array, int currentIndex)
427    {
428  20 int i = currentIndex - 1;
429   
430  24 while (i >= 0 && array[i] == '\\') {
431  4 --i;
432    }
433   
434  20 return (currentIndex - i) % 2 == 0;
435    }
436   
437    /**
438    * Get the right part of a Velocity variable (the methods and properties starting from the dot).
439    *
440    * @param array the source to parse
441    * @param currentIndex the current index in the <code>array</code>
442    * @param fullSyntax indicate if it's between <code>{</code> and <code>}</code>
443    * @param context the parser context to put some informations
444    * @return the index in the <code>array</code> after the matched block
445    */
 
446  15 toggle private int followVar(char[] array, int currentIndex, boolean fullSyntax, VelocityParserContext context)
447    {
448  15 int i = currentIndex;
449   
450  17 while (i < array.length) {
451  12 if (fullSyntax && array[i] == '}') {
452  3 ++i;
453  3 break;
454  9 } else if (array[i] == '.') {
455  2 try {
456  2 i = getMethodOrProperty(array, i, null, context);
457    } catch (InvalidVelocityException e) {
458  0 LOGGER.debug("Not a valid method at char [{}]", i, e);
459  0 break;
460    }
461  7 } else if (array[i] == '[') {
462  0 i = getTableElement(array, i, null, context);
463  0 break;
464    } else {
465  7 break;
466    }
467    }
468   
469  15 return i;
470    }
471   
472    /**
473    * Get a velocity method call or a property starting with a <code>.</code>.
474    *
475    * @param array the source to parse
476    * @param currentIndex the current index in the <code>array</code>
477    * @param velocityBlock the buffer where to append matched velocity block
478    * @param context the parser context to put some informations
479    * @return the index in the <code>array</code> after the matched block
480    * @throws InvalidVelocityException not a valid velocity block
481    */
 
482  2 toggle public int getMethodOrProperty(char[] array, int currentIndex, StringBuffer velocityBlock,
483    VelocityParserContext context) throws InvalidVelocityException
484    {
485  2 int i = currentIndex + 1;
486   
487    // A Velocity method starts with [a-zA-Z]
488  2 if (i < array.length && Character.isLetter(array[i])) {
489  4 for (; i < array.length; ++i) {
490  4 if (array[i] == '(') {
491  0 i = getMethodParameters(array, i, null, context);
492  0 break;
493  4 } else if (!Character.isLetterOrDigit(array[i])) {
494  2 break;
495    }
496    }
497    } else {
498  0 throw new InvalidVelocityException();
499    }
500   
501  2 if (velocityBlock != null) {
502  0 velocityBlock.append(array, currentIndex, i - currentIndex);
503    }
504   
505  2 return i;
506    }
507   
508    /**
509    * Get a Velocity table.
510    *
511    * @param array the source to parse
512    * @param currentIndex the current index in the <code>array</code>
513    * @param velocityBlock the buffer where to append matched velocity block
514    * @param context the parser context to put some informations
515    * @return the index in the <code>array</code> after the matched block
516    */
 
517  0 toggle public int getTableElement(char[] array, int currentIndex, StringBuffer velocityBlock,
518    VelocityParserContext context)
519    {
520  0 return getParameters(array, currentIndex, velocityBlock, ']', context);
521    }
522   
523    /**
524    * Get the Velocity method parameters (including <code>(</code> and <code>)</code>).
525    *
526    * @param array the source to parse
527    * @param currentIndex the current index in the <code>array</code>
528    * @param velocityBlock the buffer where to append matched velocity block
529    * @param context the parser context to put some informations
530    * @return the index in the <code>array</code> after the matched block
531    */
 
532  27 toggle public int getMethodParameters(char[] array, int currentIndex, StringBuffer velocityBlock,
533    VelocityParserContext context)
534    {
535  27 return getParameters(array, currentIndex, velocityBlock, ')', context);
536    }
537   
538    /**
539    * Get a group of parameters between two characters. Generic version of
540    * {@link #getTableElement(char[], int, StringBuffer, VelocityParserContext)} and
541    * {@link #getMethodParameters(char[], int, StringBuffer, VelocityParserContext)}.
542    *
543    * @param array the source to parse
544    * @param currentIndex the current index in the <code>array</code>
545    * @param velocityBlock the buffer where to append matched velocity block
546    * @param endingChar the char to end to
547    * @param context the parser context to put some informations
548    * @return the index in the <code>array</code> after the matched block
549    */
 
550  27 toggle public int getParameters(char[] array, int currentIndex, StringBuffer velocityBlock, char endingChar,
551    VelocityParserContext context)
552    {
553  27 char beginChar = array[currentIndex];
554   
555  27 int i = currentIndex + 1;
556   
557  27 int depth = 1;
558   
559  73 while (i < array.length) {
560  73 if (array[i] == endingChar) {
561  27 --depth;
562  27 if (depth == 0) {
563  27 ++i;
564  27 break;
565    }
566  46 } else if (array[i] == beginChar) {
567  0 ++depth;
568  46 } else if (array[i] == '"' || array[i] == '\'') {
569  0 i = getEscape(array, i, null, context);
570  0 continue;
571    }
572   
573  46 ++i;
574    }
575   
576  27 if (velocityBlock != null) {
577  0 velocityBlock.append(array, currentIndex, i - currentIndex);
578    }
579   
580  27 return i;
581    }
582   
583    /**
584    * @param array the source to parse
585    * @param currentIndex the current index in the <code>array</code>
586    * @param velocityBlock the buffer where to append matched velocity block
587    * @param context the parser context to put some informations
588    * @return the index in the <code>array</code> after the matched block
589    */
 
590  0 toggle public int getEscape(char[] array, int currentIndex, StringBuffer velocityBlock, VelocityParserContext context)
591    {
592  0 char escapeChar = array[currentIndex];
593   
594  0 int i = currentIndex + 1;
595   
596  0 boolean escaped = false;
597   
598  0 for (; i < array.length;) {
599  0 if (!escaped) {
600  0 if (array[i] == '\\') {
601  0 escaped = true;
602  0 } else if (array[i] == '$') {
603  0 try {
604  0 i = getVar(array, i, null, context);
605  0 continue;
606    } catch (InvalidVelocityException e) {
607  0 LOGGER.debug("Not a valid variable at char [{}]", i, e);
608    }
609  0 } else if (array[i] == escapeChar) {
610  0 ++i;
611  0 break;
612    }
613    } else {
614  0 escaped = false;
615    }
616   
617  0 ++i;
618    }
619   
620  0 if (velocityBlock != null) {
621  0 velocityBlock.append(array, currentIndex, i - currentIndex);
622    }
623   
624  0 return i;
625    }
626   
627    /**
628    * Match a group of {@link Character#isWhitespace(char)}.
629    *
630    * @param array the source to parse
631    * @param currentIndex the current index in the <code>array</code>
632    * @param velocityBlock the buffer where to append matched velocity block
633    * @param context the parser context to put some informations
634    * @return the index in the <code>array</code> after the matched block
635    */
 
636  0 toggle public int getWhiteSpaces(char[] array, int currentIndex, StringBuffer velocityBlock, VelocityParserContext context)
637    {
638  0 int i = currentIndex;
639   
640  0 while (i < array.length && Character.isWhitespace(array[i])) {
641  0 ++i;
642    }
643   
644  0 if (velocityBlock != null) {
645  0 velocityBlock.append(array, currentIndex, i - currentIndex);
646    }
647   
648  0 return i;
649    }
650   
651    /**
652    * Match a group of space characters (ASCII 32).
653    *
654    * @param array the source to parse
655    * @param currentIndex the current index in the <code>array</code>
656    * @param velocityBlock the buffer where to append matched velocity block
657    * @param context the parser context to put some informations
658    * @return the index in the <code>array</code> after the matched block
659    */
 
660  0 toggle public int getSpaces(char[] array, int currentIndex, StringBuffer velocityBlock,
661    VelocityParserContext context)
662    {
663  0 int i = currentIndex;
664   
665  0 while (i < array.length && Character.isWhitespace(array[i])) {
666  0 ++i;
667    }
668   
669  0 if (velocityBlock != null) {
670  0 velocityBlock.append(array, currentIndex, i - currentIndex);
671    }
672   
673  0 return i;
674    }
675   
676    /**
677    * @param array the source to parse
678    * @param currentIndex the current index in the <code>array</code>
679    * @param velocityBlock the buffer where to append matched velocity block
680    * @param context the parser context to put some informations
681    * @return the index in the <code>array</code> after the matched block
682    */
 
683  0 toggle public int getMacroParametersSeparator(char[] array, int currentIndex, StringBuffer velocityBlock,
684    VelocityParserContext context)
685    {
686  0 int i = currentIndex;
687   
688  0 i = getWhiteSpaces(array, i, null, context);
689  0 if (array[i] == ',') {
690  0 i++;
691    }
692  0 i = getWhiteSpaces(array, i, null, context);
693   
694  0 if (velocityBlock != null) {
695  0 velocityBlock.append(array, currentIndex, i - currentIndex);
696    }
697   
698  0 return i;
699    }
700   
701    /**
702    * @param array the source to parse
703    * @param currentIndex the current index in the <code>array</code>
704    * @param velocityBlock the buffer where to append matched velocity block
705    * @param context the parser context to put some informations
706    * @return the index in the <code>array</code> after the matched block
707    */
 
708  0 toggle public int getMacroParameter(char[] array, int currentIndex, StringBuffer velocityBlock,
709    VelocityParserContext context)
710    {
711  0 int i = currentIndex;
712   
713  0 for (; i < array.length; ++i) {
714  0 if (array[i] == '$') {
715  0 try {
716  0 i = getVar(array, i, null, context);
717  0 break;
718    } catch (InvalidVelocityException e) {
719  0 LOGGER.debug("Not a valid velocity variable at char [{}]", i, e);
720    }
721  0 } else if (array[i] == '"' || array[i] == '\'') {
722  0 i = getEscape(array, i, null, context);
723  0 break;
724  0 } else if (Character.isWhitespace(array[i]) || array[i] == ',') {
725  0 break;
726  0 } else if (array[i] == ')') {
727  0 break;
728    }
729    }
730   
731  0 if (velocityBlock != null) {
732  0 velocityBlock.append(array, currentIndex, i - currentIndex);
733    }
734   
735  0 return i;
736    }
737    }