jodd-madvoc/src/main/java/jodd/madvoc/macro/BasePathMacros.java
private String[] process(final String actionPath, final boolean match) {
		// first check the first fixed as a prefix
		if (match && !actionPath.startsWith(fixed[0])) {
			return null;
		}

		String[] values = new String[macrosCount];

		int offset = fixed[0].length();
		int i = 0;

		while (i < macrosCount) {
			int nexti = i;

			// defines next fixed string to match
			String nextFixed;
			while (true) {
				nexti++;
				if (nexti > macrosCount) {
					nextFixed = null;	// match to the end of line
					break;
				}
				nextFixed = fixed[nexti];
				if (nextFixed.length() != 0) {
					break;
				}
				// next fixed is an empty string, so skip the next macro.
			}

			// find next fixed string
			int ndx;

			if (nextFixed != null) {
				ndx = actionPath.indexOf(nextFixed, offset);
			} else {
				ndx = actionPath.length();
			}

			if (ndx == -1) {
				return null;
			}

			String macroValue = actionPath.substring(offset, ndx);
			values[i] = macroValue;

			if (match && patterns[i] != null) {
				if (!matchValue(i, macroValue)) {
					return null;
				}
			}

			if (nextFixed == null) {
				offset = ndx;
				break;
			}

			// iterate
			int nextFixedLength = nextFixed.length();
			offset = ndx + nextFixedLength;

			i = nexti;
		}

		if (offset != actionPath.length()) {
			// action path is not consumed fully during this matching
			return null;
		}

		return values;
	}
private String[] process(final String actionPath, final boolean match) {
		// first check the first fixed as a prefix
		if (match && !actionPath.startsWith(fixed[0])) {
			return null;
		}

		String[] values = new String[macrosCount];

		int offset = fixed[0].length();
		int i = 0;

		while (i < macrosCount) {
			int nexti = i;

			// defines next fixed string to match
			String nextFixed;
			while (true) {
				nexti++;
				if (nexti > macrosCount) {
					nextFixed = null;	// match to the end of line
					break;
				}
				nextFixed = fixed[nexti];
				if (nextFixed.length() != 0) {
					break;
				}
				// next fixed is an empty string, so skip the next macro.
			}

			// find next fixed string
			int ndx;

			if (nextFixed != null) {
				ndx = actionPath.indexOf(nextFixed, offset);
			} else {
				ndx = actionPath.length();
			}

			if (ndx == -1) {
				return null;
			}

			String macroValue = actionPath.substring(offset, ndx);
			values[i] = macroValue;

			if (match && patterns[i] != null) {
				if (!matchValue(i, macroValue)) {
					return null;
				}
			}

			if (nextFixed == null) {
				offset = ndx;
				break;
			}

			// iterate
			int nextFixedLength = nextFixed.length();
			offset = ndx + nextFixedLength;

			i = nexti;
		}

		if (offset != actionPath.length()) {
			// action path is not consumed fully during this matching
			return null;
		}

		return values;
	}
Process action path in two modes: matching mode and extracting mode.
@return string array of extracted macro values (null element is allowed) or null