// ex: se sts=4 sw=4 expandtab:
/**
* Yeti core library.
*
* Copyright (c) 2007-2013 Madis Janson
* Copyright (c) 2012 Chris Cannam
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package yeti.lang;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
public final class Core {
private static final int DEC_SHIFT[] = { 1, 10, 100, 1000, 10000,
100000, 1000000, 10000000, 100000000, 1000000000 };
public static final String UNDEF_STR = new String();
public static String replace(String f, String r, String s) {
StringBuffer result = new StringBuffer();
int p = 0, i, l = f.length();
while ((i = s.indexOf(f, p)) >= 0) {
result.append(s.substring(p, i));
result.append(r);
p = i + l;
}
if (p < s.length())
result.append(s.substring(p));
return result.toString();
}
public static Num parseNum(String str) {
String s = str.trim();
int l;
if ((l = s.length()) == 0)
throw new IllegalArgumentException("Number expected");
int radix = 10, st = s.charAt(0) == '-' ? 1 : 0;
if (l > 2 && s.charAt(st) == '0')
switch (s.charAt(st + 1)) {
case 'o': case 'O':
radix = 2;
case 'x': case 'X':
s = s.substring(st += 2);
if (st != 2)
s = "-".concat(s);
radix += 6;
}
if (radix == 10) {
if (s.indexOf('e') >= 0 || s.indexOf('E') >= 0) {
char c;
if ((c = s.charAt(l - 1)) == 'e' || c == 'E')
return new FloatNum(Double.parseDouble(
s.substring(0, l - 1)));
return new FloatNum(Double.parseDouble(s));
}
int dot = s.indexOf('.');
if (dot == l - 1) {
s = s.substring(0, dot);
dot = -1;
}
if (dot > 0) do {
while (s.charAt(--l) == '0');
if (s.charAt(l) == '.') {
s = s.substring(0, l);
break;
}
if (l <= 11) {
long n = Long.parseLong(s.substring(0, dot).concat(
s.substring(dot + 1, l + 1)));
if (n >= Integer.MIN_VALUE && n <= Integer.MAX_VALUE)
return new RatNum((int) n, DEC_SHIFT[l - dot]);
}
return new FloatNum(Double.parseDouble(s));
} while (false);
}
if ((l - st) < 96 / radix + 10) // 22, 19, 16
return new IntNum(Long.parseLong(s, radix));
return new BigNum(s, radix);
}
public static String concat(String[] param) {
int l = 0;
for (int i = param.length; --i >= 0;)
l += param[i].length();
if (l == 0)
return "";
char[] res = new char[l];
int p = 0;
for (int i = 0, cnt = param.length; i < cnt; ++i) {
String s = param[i];
s.getChars(0, l = s.length(), res, p);
p += l;
}
return new String(res);
}
public static String show(Object o) {
StringBuffer r;
if (o == null)
return "[]";
if (o instanceof String) {
// TODO escaping
char[] s = ((String) o).toCharArray();
r = new StringBuffer().append('"');
int p = 0, i = 0, cnt = s.length;
for (String c; i < cnt; ++i) {
if (s[i] == '\\') {
c = "\\\\";
} else if (s[i] == '"') {
c = "\\\"";
} else if (s[i] == '\n') {
c = "\\n";
} else if (s[i] == '\r') {
c = "\\r";
} else if (s[i] == '\t') {
c = "\\t";
} else if (s[i] >= '\u0000' && s[i] < ' ') {
c = "000".concat(Integer.toHexString(s[i]));
c = "\\u".concat(c.substring(c.length() - 4));
} else {
continue;
}
r.append(s, p, i - p).append(c);
p = i + 1;
}
return r.append(s, p, i - p).append('"').toString();
}
if (o.getClass().isArray()) {
r = new StringBuffer().append('[');
for (int i = 0, len = Array.getLength(o); i < len; ++i) {
if (i != 0)
r.append(',');
if (i == 50 && len > 110) {
r.append("...");
i = len - 50;
}
r.append(Array.get(o, i));
}
return r.append(']').toString();
}
return o.toString();
}
static String read(java.io.Reader r, int max) throws IOException {
char[] buf = new char[max];
int n = r.read(buf, 0, max);
return n < 0 ? null : new String(buf, 0, n);
}
static String readAll(java.io.Reader r) throws IOException {
StringBuffer result = new StringBuffer();
char[] buf = new char[8192];
int n;
while ((n = r.read(buf, 0, buf.length)) > 0)
result.append(buf, 0, n);
return result.toString();
}
static AList readAll(int limit, Fun read, Fun close) {
byte[] buf = new byte[0 < limit && limit <= 65536 ? limit : 8192];
int l = 0, n;
try {
while ((n = ((Number) read.apply(buf, new IntNum(l)))
.intValue()) >= 0)
if (buf.length - (l += n) < 2048) {
int reserve = buf.length << 1;
if (limit > 0 && reserve > limit) {
if (buf.length >= limit)
Unsafe.unsafeThrow(new java.io.IOException(
"Read limit " + limit + " exceeded"));
reserve = limit;
}
byte[] tmp = new byte[reserve];
System.arraycopy(buf, 0, tmp, 0, l);
buf = tmp;
}
} finally {
close.apply(null);
}
return l > 0 ? new ByteArray(0, l, buf) : null;
}
public static final ThreadLocal ARGV = new ThreadLocal() {
protected Object initialValue() {
return new MList();
}
};
public static void setArgv(String[] argv) {
if (argv != null) {
ARGV.set(new MList(argv));
}
}
public static Object badMatch(Object match) {
throw new BadMatch(match, null, 0, 0);
}
public static String capitalize(String s) {
char[] tmp = s.toCharArray();
if (tmp.length == 0)
return s;
tmp[0] = Character.toUpperCase(tmp[0]);
return new String(tmp);
}
static String uncapitalize(String s) {
char[] tmp = s.toCharArray();
if (tmp.length == 0)
return s;
tmp[0] = Character.toLowerCase(tmp[0]);
return new String(tmp);
}
private static final char base64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
.toCharArray();
static String b64enc(byte[] buf, int len) {
char[] res = new char[(len + 2) / 3 * 4];
for (int s = 0, d = 0; len > 0; len -= 3) {
res[d] = base64[buf[s] >>> 2 & 63];
res[d + 1] = base64[((buf[s] & 3) << 4) |
(len > 1 ? buf[s + 1] >>> 4 & 15 : 0)];
res[d + 2] = len > 1 ? base64[((buf[s + 1] & 15) << 2) |
(len > 2 ? buf[s + 2] >>> 6 & 3: 0)] : '=';
res[d + 3] = len > 2 ? base64[buf[s + 2] & 63] : '=';
s += 3;
d += 4;
}
return new String(res);
}
static AList b64dec(String src) throws Exception {
int n = 0, outp = 0;
byte[] buf = new byte[src.length() * 3 / 4];
for (int s = 0, len = src.length(); s < len; ++s) {
char c = src.charAt(s);
int v = c == '+' ? 0x3e : c == '/' ? 0x3f : c >= 'A' && c <= 'Z'
? c - 'A' : c >= 'a' && c <= 'z'
? c - 'G' : c >= '0' && c <= '9' ? c + 4 : -1;
if (v == -1) {
if (c == '=')
break;
continue;
}
switch (n) {
case 0:
buf[outp] = (byte) (v << 2);
break;
case 1:
buf[outp] |= v >>> 4;
buf[outp + 1] = (byte) ((v & 15) << 4);
break;
case 2:
buf[outp + 1] |= v >>> 2;
buf[outp + 2] = (byte) ((v & 3) << 6);
break;
case 3:
buf[outp + 2] |= v;
outp += 3;
n = -1;
break;
}
++n;
}
if (n > 0) // 1, 2, 3
outp += n - 1;
return outp > 0 ? new ByteArray(0, outp, buf) : null;
}
public static byte[] bytes(AList list) {
if (list == null) {
return new byte[0];
}
try {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
AIter i = list;
list = null; // help gc
while (i != null)
i = i.write(buf);
return buf.toByteArray();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}