Package org.erlide.util

Source Code of org.erlide.util.Util

/*******************************************************************************
* Copyright (c) 2000, 2004 IBM Corporation 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
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.erlide.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UTFDataFormatException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Scanner;
import java.util.StringTokenizer;

import com.ericsson.otp.erlang.OtpErlangAtom;
import com.ericsson.otp.erlang.OtpErlangBinary;
import com.ericsson.otp.erlang.OtpErlangException;
import com.ericsson.otp.erlang.OtpErlangInt;
import com.ericsson.otp.erlang.OtpErlangList;
import com.ericsson.otp.erlang.OtpErlangLong;
import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangRangeException;
import com.ericsson.otp.erlang.OtpErlangString;
import com.ericsson.otp.erlang.OtpErlangTuple;
import com.google.common.base.Charsets;
import com.google.common.collect.Lists;

/**
* Provides convenient utility methods to other types in this package.
*/
public final class Util {

    private static final String ARGUMENTS_DELIMITER = "#"; //$NON-NLS-1$
    private static final String BUNDLE_NAME = "org.erlide.util.util"; //$NON-NLS-1$
    private static final char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$
    private static final String EMPTY_ARGUMENT = "   "; //$NON-NLS-1$
    // public static final String[] fgEmptyStringArray = new String[0];
    private static final char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$

    /* Bundle containing messages */
    private static ResourceBundle bundle;

    static {
        relocalize();
    }

    private Util() {
        // cannot be instantiated
    }

    /**
     * Lookup the message with the given PLUGIN_ID in this catalog
     */
    public static String bind(final String id) {
        return bind(id, (String[]) null);
    }

    /**
     * Lookup the message with the given PLUGIN_ID in this catalog and bind its
     * substitution locations with the given string.
     */
    public static String bind(final String id, final String binding) {
        return bind(id, new String[] { binding });
    }

    /**
     * Lookup the message with the given PLUGIN_ID in this catalog and bind its
     * substitution locations with the given strings.
     */
    public static String bind(final String id, final String binding1,
            final String binding2) {
        return bind(id, new String[] { binding1, binding2 });
    }

    /**
     * Lookup the message with the given PLUGIN_ID in this catalog and bind its
     * substitution locations with the given string values.
     */
    public static String bind(final String id, final String[] bindings) {
        if (id == null) {
            return "No message available"; //$NON-NLS-1$
        }
        String message = null;
        try {
            message = bundle.getString(id);
        } catch (final MissingResourceException e) {
            // If we got an exception looking for the message, fail gracefully
            // by just returning
            // the id we were looking for. In most cases this is
            // semi-informative so is not too bad.
            return "Missing message: " + id + " in: " + BUNDLE_NAME; //$NON-NLS-2$ //$NON-NLS-1$
        }
        // for compatibility with MessageFormat which eliminates double quotes
        // in original message
        final char[] messageWithNoDoubleQuotes = CharOperation.replace(
                message.toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE);

        if (bindings == null) {
            return new String(messageWithNoDoubleQuotes);
        }

        final int length = messageWithNoDoubleQuotes.length;
        int start = 0;
        int end = length;
        final StringBuilder output = new StringBuilder();
        while (true) {
            end = CharOperation.indexOf('{', messageWithNoDoubleQuotes, start);
            if (end > -1) {
                output.append(messageWithNoDoubleQuotes, start, end - start);
                if ((start = CharOperation.indexOf('}', messageWithNoDoubleQuotes,
                        end + 1)) > -1) {
                    int index = -1;
                    final String argId = new String(messageWithNoDoubleQuotes, end + 1,
                            start - end - 1);
                    try {
                        index = Integer.parseInt(argId);
                        output.append(bindings[index]);
                    } catch (final NumberFormatException nfe) { // could be
                        // nested
                        // message PLUGIN_ID
                        // {compiler.name}
                        boolean done = false;
                        if (!argId.equals(id)) {
                            String argMessage = null;
                            try {
                                argMessage = bundle.getString(argId);
                                output.append(argMessage);
                                done = true;
                            } catch (final MissingResourceException e) {
                                // unable to bind argument, ignore (will leave
                                // argument in)
                            }
                        }
                        if (!done) {
                            output.append(messageWithNoDoubleQuotes, end + 1, start - end);
                        }
                    } catch (final ArrayIndexOutOfBoundsException e) {
                        output.append("{missing " + Integer.toString(index) + "}"); //$NON-NLS-2$ //$NON-NLS-1$
                    }
                    start++;
                } else {
                    output.append(messageWithNoDoubleQuotes, end, length);
                    break;
                }
            } else {
                output.append(messageWithNoDoubleQuotes, start, length - start);
                break;
            }
        }
        return output.toString();
    }

    /**
     * Given a qualified name, extract the last component. If the input is not
     * qualified, the same string is answered.
     */
    public static String extractLastName(final String qualifiedName) {
        final int i = qualifiedName.lastIndexOf('.');
        if (i == -1) {
            return qualifiedName;
        }
        return qualifiedName.substring(i + 1);
    }

    /**
     * Finds the first line separator used by the given text.
     *
     * @return</code> "\n"</code> or</code> "\r"</code> or</code> "\r\n"
     *                </code>, or <code>null</code> if none found
     */
    public static String findLineSeparator(final char[] text) {
        // find the first line separator
        final int length = text.length;
        if (length > 0) {
            char nextChar = text[0];
            for (int i = 0; i < length; i++) {
                final char currentChar = nextChar;
                nextChar = i < length - 1 ? text[i + 1] : ' ';
                if (currentChar == '\n') {
                    return "\n"; //$NON-NLS-1$
                }
                if (currentChar == '\r') {
                    return nextChar == '\n' ? "\r\n" : "\r"; //$NON-NLS-1$ //$NON-NLS-2$
                }

            }
        }
        // not found
        return null;
    }

    /**
     * Put all the arguments in one String.
     */
    public static String getProblemArgumentsForMarker(final String[] arguments) {
        final StringBuilder args = new StringBuilder(10);

        args.append(arguments.length);
        args.append(':');

        for (int j = 0; j < arguments.length; j++) {
            if (j != 0) {
                args.append(ARGUMENTS_DELIMITER);
            }

            if (arguments[j].length() == 0) {
                args.append(EMPTY_ARGUMENT);
            } else {
                args.append(arguments[j]);
            }
        }

        return args.toString();
    }

    /**
     * Separate all the arguments of a String made by
     * getProblemArgumentsForMarker
     */
    public static String[] getProblemArgumentsFromMarker(final String argumentsString) {
        if (argumentsString == null) {
            return null;
        }
        final int index = argumentsString.indexOf(':');
        if (index == -1) {
            return null;
        }

        final int length = argumentsString.length();
        int numberOfArg;
        try {
            numberOfArg = Integer.parseInt(argumentsString.substring(0, index));
        } catch (final NumberFormatException e) {
            return null;
        }
        final String argumentsString1 = argumentsString.substring(index + 1, length);

        String[] args = new String[length];
        int count = 0;

        final StringTokenizer tokenizer = new StringTokenizer(argumentsString1,
                ARGUMENTS_DELIMITER);
        while (tokenizer.hasMoreTokens()) {
            String argument = tokenizer.nextToken();
            if (EMPTY_ARGUMENT.equals(argument)) {
                argument = ""; //$NON-NLS-1$
            }
            args[count++] = argument;
        }

        if (count != numberOfArg) {
            return null;
        }

        System.arraycopy(args, 0, args = new String[count], 0, count);
        return args;
    }

    /**
     * Validate the given compilation unit name. A compilation unit name must
     * obey the following rules:
     * <ul>
     * <li>it must not be null
     * <li>it must include the <code>".erl"</code> suffix
     * <li>its prefix must be a valid identifier
     * </ul>
     * </p>
     *
     * @param name
     *            the name of a compilation unit
     * @return a boolean
     */
    public static boolean isValidModuleFileName(final String name) {
        if (!name.endsWith(".erl")) {
            return false;
        }
        final int pos = name.lastIndexOf('.');
        return isValidModuleName(name.substring(0, pos));
    }

    public static boolean isValidModuleName(final String name) {
        return name.matches("[a-z][a-zA-Z0-9_]*");
    }

    /**
     * Returns the length of the common prefix between s1 and s2.
     */
    public static int prefixLength(final char[] s1, final char[] s2) {
        int len = 0;
        final int max = Math.min(s1.length, s2.length);
        for (int i = 0; i < max && s1[i] == s2[i]; ++i) {
            ++len;
        }
        return len;
    }

    /**
     * Returns the length of the common prefix between s1 and s2.
     */
    public static int prefixLength(final String s1, final String s2) {
        int len = 0;
        final int max = Math.min(s1.length(), s2.length());
        for (int i = 0; i < max && s1.charAt(i) == s2.charAt(i); ++i) {
            ++len;
        }
        return len;
    }

    /**
     * Creates a NLS catalog for the given locale.
     */
    public static void relocalize() {
        try {
            bundle = ResourceBundle.getBundle(BUNDLE_NAME, Locale.getDefault());
        } catch (final MissingResourceException e) {
            ErlLogger
                    .error("Missing resource : " + BUNDLE_NAME.replace('.', '/') + ".properties for locale " + Locale.getDefault()); //$NON-NLS-1$//$NON-NLS-2$
            throw e;
        }
    }

    /**
     * Converts a String[] to char[][].
     */
    public static char[][] toCharArrays(final String[] a) {
        final int len = a.length;
        final char[][] result = new char[len][];
        for (int i = 0; i < len; ++i) {
            result[i] = toChars(a[i]);
        }
        return result;
    }

    /**
     * Converts a String to char[].
     */
    public static char[] toChars(final String s) {
        final int len = s.length();
        final char[] chars = new char[len];
        s.getChars(0, len, chars, 0);
        return chars;
    }

    /**
     * Converts a String to char[][], where segments are separate by '.'.
     */
    public static char[][] toCompoundChars(final String s) {
        final int len = s.length();
        if (len == 0) {
            return CharOperation.NO_CHAR_CHAR;
        }
        int segCount = 1;
        for (int off = s.indexOf('.'); off != -1; off = s.indexOf('.', off + 1)) {
            ++segCount;
        }
        final char[][] segs = new char[segCount][];
        int start = 0;
        for (int i = 0; i < segCount; ++i) {
            final int dot = s.indexOf('.', start);
            final int end = dot == -1 ? s.length() : dot;
            segs[i] = new char[end - start];
            s.getChars(start, end, segs[i], 0);
            start = end + 1;
        }
        return segs;
    }

    /**
     * Converts a char[] to String.
     */
    public static String toString(final char[] c) {
        return new String(c);
    }

    /**
     * Converts a char[][] to String, where segments are separated by '.'.
     */
    public static String toString(final char[][] c) {
        final StringBuilder sb = new StringBuilder();
        for (int i = 0, max = c.length; i < max; ++i) {
            if (i != 0) {
                sb.append('.');
            }
            sb.append(c[i]);
        }
        return sb.toString();
    }

    /**
     * Converts a char[][] and a char[] to String, where segments are separated
     * by '.'.
     */
    public static String toString(final char[][] c, final char[] d) {
        if (c == null) {
            return new String(d);
        }
        final StringBuilder sb = new StringBuilder();
        for (final char[] element : c) {
            sb.append(element);
            sb.append('.');
        }
        sb.append(d);
        return sb.toString();
    }

    /**
     * Writes a string to the given output stream using UTF-8 encoding in a
     * machine-independent manner.
     * <p>
     * First, two bytes are written to the output stream as if by the
     * <code>writeShort</code> method giving the number of bytes to follow. This
     * value is the number of bytes actually written out, not the length of the
     * string. Following the length, each character of the string is output, in
     * sequence, using the UTF-8 encoding for the character.
     *
     * @param str
     *            a string to be written.
     * @return the number of bytes written to the stream.
     * @exception IOException
     *                if an I/O error occurs.
     *
     */
    public static int writeUTF(final OutputStream out, final char[] str)
            throws IOException {
        final int strlen = str.length;
        int utflen = 0;
        for (int i = 0; i < strlen; i++) {
            final int c = str[i];
            if (c >= 0x0001 && c <= 0x007F) {
                utflen++;
            } else if (c > 0x07FF) {
                utflen += 3;
            } else {
                utflen += 2;
            }
        }
        if (utflen > 65535) {
            throw new UTFDataFormatException();
        }
        out.write(utflen >>> 8 & 0xFF);
        out.write(utflen >>> 0 & 0xFF);
        if (strlen == utflen) {
            for (int i = 0; i < strlen; i++) {
                out.write(str[i]);
            }
        } else {
            for (int i = 0; i < strlen; i++) {
                final int c = str[i];
                if (c >= 0x0001 && c <= 0x007F) {
                    out.write(c);
                } else if (c > 0x07FF) {
                    out.write(0xE0 | c >> 12 & 0x0F);
                    out.write(0x80 | c >> 6 & 0x3F);
                    out.write(0x80 | c >> 0 & 0x3F);
                } else {
                    out.write(0xC0 | c >> 6 & 0x1F);
                    out.write(0x80 | c >> 0 & 0x3F);
                }
            }
        }
        return utflen + 2; // the number of bytes written to the stream
    }

    /**
     * Get the string value of an Erlang string, empty if empty list
     *
     * @param o
     *            Erlang string or list
     * @return string value
     */
    public static String stringValue(final OtpErlangObject o) {
        if (o instanceof OtpErlangString) {
            final OtpErlangString s = (OtpErlangString) o;
            return s.stringValue();
        } else if (o instanceof OtpErlangList) {
            final OtpErlangList l = (OtpErlangList) o;
            if (l.arity() == 0) {
                return "";
            }
            try {
                return l.stringValue();
            } catch (final OtpErlangException e) {
                ErlLogger.error(e);
                return null;
            }
        } else if (o instanceof OtpErlangBinary) {
            final OtpErlangBinary b = (OtpErlangBinary) o;
            String result;
            result = decode(b.binaryValue(), Charsets.UTF_8);
            if (result == null) {
                result = decode(b.binaryValue(), Charsets.ISO_8859_1);
            }
            if (result == null) {
                ErlLogger.error("bad binary value in stringValue" + " (can't decode): "
                        + o);
            }
            return result;
        }
        // ErlLogger.warn("bad value in stringValue: " + o);
        return null;
    }

    public static String decode(final byte[] binaryValue, final Charset charset) {
        final CharsetDecoder decoder = charset.newDecoder();
        try {
            final ByteBuffer bbuf = ByteBuffer.wrap(binaryValue);
            final CharBuffer cbuf = decoder.decode(bbuf);
            return cbuf.toString();
        } catch (final CharacterCodingException e) {
            return null;
        }
    }

    public static byte[] encode(final String string, final String encoding) {
        final Charset charset = Charset.forName(encoding);
        final CharsetEncoder encoder = charset.newEncoder();
        try {
            final CharBuffer cbuf = CharBuffer.wrap(string);
            final ByteBuffer bbuf = encoder.encode(cbuf);
            return bbuf.array();
        } catch (final CharacterCodingException e) {
            return null;
        }
    }

    /**
     * Return true if it's the atom ok or a tuple {ok, ...}
     *
     * @param o
     *            atom or tuple
     * @return true if ok
     */
    public static boolean isOk(final OtpErlangObject o) {
        return isTag(o, "ok");
    }

    /**
     * return true if it's the atom error or a tuple {error, ...}
     *
     * @param o
     *            atom or tuple
     * @return true if error
     */
    public static boolean isError(final OtpErlangObject o) {
        return isTag(o, "error");
    }

    public static boolean isTag(final OtpErlangObject o, final String string) {
        OtpErlangAtom tag = null;
        if (o instanceof OtpErlangAtom) {
            tag = (OtpErlangAtom) o;
        } else if (o instanceof OtpErlangTuple) {
            final OtpErlangTuple t = (OtpErlangTuple) o;
            if (t.elementAt(0) instanceof OtpErlangAtom) {
                tag = (OtpErlangAtom) t.elementAt(0);
            }
        }
        return tag != null && string.equals(tag.atomValue());
    }

    public static String ioListToString(final OtpErlangObject o) {
        return ioListToString(o, Integer.MAX_VALUE - 1);
    }

    public static String ioListToString(final OtpErlangObject o, final int maxLength) {
        StringBuilder sb = new StringBuilder();
        sb = ioListToStringBuilder(o, sb, maxLength);
        return sb.toString();
    }

    public static String getInputStreamAsString(final InputStream is,
            final String encoding) {
    Scanner scanner = new Scanner(is, encoding);
    try {
      scanner.useDelimiter("\\A");
      return scanner.hasNext() ? scanner.next() : "";
    } finally {
      scanner.close();
    }
    }

    private static StringBuilder ioListToStringBuilder(final OtpErlangObject o,
            final StringBuilder sb0, final int maxLength) {
        StringBuilder sb = sb0;
        if (sb.length() >= maxLength) {
            return sb;
        }
        if (o instanceof OtpErlangLong) {
            final OtpErlangLong l = (OtpErlangLong) o;
            try {
                sb.append(l.charValue());
            } catch (final OtpErlangRangeException e) {
            }
        } else if (o instanceof OtpErlangString) {
            final OtpErlangString s = (OtpErlangString) o;
            sb.append(s.stringValue());
        } else if (o instanceof OtpErlangList) {
            final OtpErlangList l = (OtpErlangList) o;
            for (final OtpErlangObject i : l) {
                if (sb.length() < maxLength) {
                    ioListToStringBuilder(i, sb, maxLength);
                }
            }
            if (sb.length() < maxLength) {
                ioListToStringBuilder(l.getLastTail(), sb, maxLength);
            }
        } else if (o instanceof OtpErlangBinary) {
            final OtpErlangBinary b = (OtpErlangBinary) o;
            String s = decode(b.binaryValue(), Charsets.UTF_8);
            if (s == null) {
                s = new String(b.binaryValue(), Charsets.ISO_8859_1);
            }
            sb.append(s);
        } else if (o != null) {
            sb.append(o.toString());
        }
        if (sb.length() > maxLength) {
            sb = new StringBuilder(sb.substring(0, maxLength));
            sb.append("... <truncated>");
        }
        return sb;
    }

    public static int getIntegerValue(final OtpErlangObject object, final int defaultValue) {
        if (object instanceof OtpErlangLong) {
            final OtpErlangLong l = (OtpErlangLong) object;
            try {
                return l.intValue();
            } catch (final OtpErlangRangeException e) {
            }
        }
        if (object instanceof OtpErlangInt) {
            final OtpErlangInt l = (OtpErlangInt) object;
            try {
                return l.intValue();
            } catch (final OtpErlangRangeException e) {
            }
        }
        return defaultValue;
    }

    public static OtpErlangList listValue(final OtpErlangObject o) {
        if (o instanceof OtpErlangList) {
            return (OtpErlangList) o;
        } else if (o instanceof OtpErlangString) {
            final OtpErlangString erlangString = (OtpErlangString) o;
            final int[] codePoints = OtpErlangString.stringToCodePoints(erlangString
                    .stringValue());
            final OtpErlangObject elements[] = new OtpErlangObject[codePoints.length];
            for (int i = 0; i < codePoints.length; i++) {
                elements[i] = new OtpErlangLong(codePoints[i]);
            }
            return new OtpErlangList(elements);
        }
        return null;
    }

    public static List<String> asStringList(final OtpErlangList l) {
        final List<String> result = Lists.newArrayListWithCapacity(l.arity());
        for (final OtpErlangObject o : l) {
            result.add(Util.stringValue(o));
        }
        return result;
    }

}
TOP

Related Classes of org.erlide.util.Util

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.