diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/actions/SingleStringArgFormatter.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/actions/SingleStringArgFormatter.java | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/actions/SingleStringArgFormatter.java b/src/main/java/com/google/devtools/build/lib/actions/SingleStringArgFormatter.java new file mode 100644 index 0000000000..b4b3d028d0 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/actions/SingleStringArgFormatter.java @@ -0,0 +1,102 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.lib.actions; + +/** + * Implementation of a formatter that supports only a single '%s' + * + * <p>This implementation is used in command line item expansions that use formatting. We use a + * custom implementation to improve performance and avoid GC. + */ +public class SingleStringArgFormatter { + + /** + * Returns true if the format string contains a single '%s'. + * + * <p>%% escape sequences are supported. + */ + public static boolean isValid(String formatStr) { + return onlyOccurrence(formatStr, formatStr.length()) != -1; + } + + /** + * Returns the equivalent result of <code>String.format(formatStr, subject)</code>, under the + * assumption that the format string contains a single %s. + * + * <p>Use {@link #isValid} to validate the format string. + * + * @throws IllegalArgumentException if the format string is invalid. + */ + public static String format(String formatStr, String subject) { + int n = formatStr.length(); + int idx = onlyOccurrence(formatStr, n); + if (idx < 0) { + throw new IllegalArgumentException( + "Expected format string with single '%s', found: " + formatStr); + } + return new StringBuilder(n + subject.length() - 2) + .append(formatStr, 0, idx) + .append(subject) + .append(formatStr, idx + 2, n) + .toString(); + } + + /* + * Returns the index of the only occurrence of %s. Skips any %%. Returns -1 if {@code formatStr} + * is malformed. + */ + private static int onlyOccurrence(String formatStr, int n) { + int idx = nextOccurrence(formatStr, n, 0); + if (idx < 0) { + return -1; + } + // Only one occurrence please + if (nextOccurrence(formatStr, n, idx + 2) != -1) { + return -1; + } + return idx; + } + + /** + * Returns next occurrence of %s. Skips any %%. + * + * @return + * <li>[0-n]: Index of next %s + * <li>-1: No %s found until end of string + * <li>-2: Illegal sequence found, eg. %f + */ + private static int nextOccurrence(String formatStr, int n, int idx) { + while (idx < n) { + idx = formatStr.indexOf('%', idx); + if (idx == -1) { + break; + } + if ((idx + 1) < n) { + char c = formatStr.charAt(idx + 1); + if (c == 's') { + return idx; + } + if (c != '%') { + // Illegal sequence found + return -2; + } + idx += 2; + } else { + // Terminating '%' found, illegal + return -2; + } + } + return -1; + } +} |