*/
package org.opendaylight.yangtools.yang.parser.rfc7950.repo;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.CharMatcher;
import java.util.Collections;
import java.util.List;
import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
final class ArgumentContextUtils {
+ private static final CharMatcher WHITESPACE_MATCHER = CharMatcher.whitespace();
private static final CharMatcher ANYQUOTE_MATCHER = CharMatcher.anyOf("'\"");
private static final Pattern ESCAPED_DQUOT = Pattern.compile("\\\"", Pattern.LITERAL);
private static final Pattern ESCAPED_BACKSLASH = Pattern.compile("\\\\", Pattern.LITERAL);
* in the inner string and trim the result.
*/
checkDoubleQuotedString(innerStr, yangVersion, ref);
+
sb.append(ESCAPED_TAB.matcher(
ESCAPED_LF.matcher(
ESCAPED_BACKSLASH.matcher(
- ESCAPED_DQUOT.matcher(innerStr).replaceAll("\\\""))
+ ESCAPED_DQUOT.matcher(
+ trimWhitespace(innerStr, stringNode.getSymbol().getCharPositionInLine()))
+ .replaceAll("\\\""))
.replaceAll("\\\\"))
.replaceAll("\\\n"))
.replaceAll("\\\t"));
}
}
}
+
+ @VisibleForTesting
+ static String trimWhitespace(final String str, final int dquot) {
+ int brk = str.indexOf('\n');
+ if (brk == -1) {
+ // No need to trim whitespace
+ return str;
+ }
+
+ // Okay, we may need to do some trimming, set up a builder and append the first segment
+ final int length = str.length();
+ final StringBuilder sb = new StringBuilder(length);
+
+ // Append first segment, which needs only tail-trimming
+ sb.append(str, 0, trimTrailing(str, 0, brk)).append('\n');
+
+ // With that out of the way, setup our iteration state. The string segment we are looking at is
+ // str.substring(start, end), which is guaranteed not to include any line breaks, i.e. end <= brk unless we are
+ // at the last segment.
+ int start = brk + 1;
+ brk = str.indexOf('\n', start);
+
+ // Loop over inner strings
+ while (brk != -1) {
+ final int end = brk != -1 ? brk : length;
+ trimLeadingAndAppend(sb, dquot, str, start, trimTrailing(str, start, end)).append('\n');
+ start = end + 1;
+ brk = str.indexOf('\n', start);
+ }
+
+ return trimLeadingAndAppend(sb, dquot, str, start, length).toString();
+ }
+
+ private static StringBuilder trimLeadingAndAppend(final StringBuilder sb, final int dquot, final String str,
+ final int start, final int end) {
+ int offset = start;
+ int pos = 0;
+
+ while (pos <= dquot) {
+ if (offset == end) {
+ // We ran out of data, nothing to append
+ return sb;
+ }
+
+ final char ch = str.charAt(offset);
+ if (ch == '\t') {
+ // tabs are to be treated as 8 spaces
+ pos += 8;
+ } else if (WHITESPACE_MATCHER.matches(ch)) {
+ pos++;
+ } else {
+ break;
+ }
+
+ offset++;
+ }
+
+ // We have expanded beyond double quotes, push equivalent spaces
+ while (pos - 1 > dquot) {
+ sb.append(' ');
+ pos--;
+ }
+
+ return sb.append(str, offset, end);
+ }
+
+ private static int trimTrailing(final String str, final int start, final int end) {
+ int ret = end;
+ while (ret > start) {
+ final int prev = ret - 1;
+ if (!WHITESPACE_MATCHER.matches(str.charAt(prev))) {
+ break;
+ }
+ ret = prev;
+ }
+ return ret;
+ }
}
--- /dev/null
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.rfc7950.repo;
+
+import static org.junit.Assert.assertEquals;
+import static org.opendaylight.yangtools.yang.parser.rfc7950.repo.ArgumentContextUtils.trimWhitespace;
+
+import org.junit.Test;
+
+public class AugmentContextUtilsTest {
+
+ @Test
+ public void testTrimWhitespace() {
+ assertEquals("\n", trimWhitespace("\n", 0));
+ assertEquals("\n", trimWhitespace("\n", 5));
+ assertEquals("\n\n\n\n", trimWhitespace("\n\n\n\n", 0));
+ assertEquals("\n\n\n\n", trimWhitespace("\n\n\n\n", 5));
+ assertEquals("abc\n\n", trimWhitespace("abc \n \n", 0));
+ assertEquals("abc\n\n", trimWhitespace("abc \n \n", 1));
+ assertEquals("abc\n ", trimWhitespace("abc\n ", 0));
+ assertEquals("abc\n", trimWhitespace("abc\n ", 2));
+ assertEquals("abc\n\n", trimWhitespace("abc\n \n", 2));
+ assertEquals("abc\n ", trimWhitespace("abc\n\t ", 0));
+ assertEquals("abc\n ", trimWhitespace("abc\n\t ", 2));
+ assertEquals("abc\n ", trimWhitespace("abc\n\t ", 4));
+ assertEquals("abc\n ", trimWhitespace("abc\n \t", 4));
+ assertEquals("abc\n a\n a\n", trimWhitespace("abc\n\ta\n\t a\n", 4));
+ assertEquals("abc\n\n a\n", trimWhitespace("abc\n\t\n\t a\n", 4));
+ assertEquals(" \ta\n", trimWhitespace(" \ta\n", 3));
+ assertEquals(" \ta\n", trimWhitespace(" \ta\n ", 3));
+ assertEquals(" \ta\n", trimWhitespace(" \ta\n ", 3));
+ assertEquals(" \ta\n", trimWhitespace(" \ta\n ", 3));
+ assertEquals(" \ta\n ", trimWhitespace(" \ta\n ", 3));
+ }
+}