diff --git a/classpath/avian/Continuations.java b/classpath/avian/Continuations.java index ecec10b348..42565830d4 100644 --- a/classpath/avian/Continuations.java +++ b/classpath/avian/Continuations.java @@ -128,7 +128,7 @@ public class Continuations { * receiver.receive(Callback), propagate the exception * thrown by that method, return the result passed to the * handleResult(T) method of the continuation, or throw the - * exception passed to the handleException(Throwable) of the + * exception passed to the handleException(Throwable) method of the * continuation. */ public static native T callWithCurrentContinuation diff --git a/classpath/java-io.cpp b/classpath/java-io.cpp index 134045bdd2..f134d6dc0c 100644 --- a/classpath/java-io.cpp +++ b/classpath/java-io.cpp @@ -25,6 +25,7 @@ # include # include +# define ACCESS _waccess # define CLOSE _close # define READ _read # define WRITE _write @@ -56,6 +57,7 @@ typedef wchar_t char_t; # include # include "sys/mman.h" +# define ACCESS access # define OPEN open # define CLOSE close # define READ read @@ -377,6 +379,31 @@ Java_java_io_File_delete(JNIEnv* e, jclass, jstring path) } } +extern "C" JNIEXPORT jboolean JNICALL +Java_java_io_File_canRead(JNIEnv* e, jclass, jstring path) +{ + string_t chars = getChars(e, path); + if (chars) { + int r = ACCESS(chars, R_OK); + releaseChars(e, path, chars); + return (r == 0); + } + return false; +} + +extern "C" JNIEXPORT jboolean JNICALL +Java_java_io_File_canWrite(JNIEnv* e, jclass, jstring path) +{ + string_t chars = getChars(e, path); + if (chars) { + int r = ACCESS(chars, W_OK); + releaseChars(e, path, chars); + return (r == 0); + } + return false; +} + + extern "C" JNIEXPORT jboolean JNICALL Java_java_io_File_rename(JNIEnv* e, jclass, jstring old, jstring new_) { diff --git a/classpath/java-lang.cpp b/classpath/java-lang.cpp index 8303e3e4e1..ea37b2f275 100644 --- a/classpath/java-lang.cpp +++ b/classpath/java-lang.cpp @@ -36,9 +36,6 @@ # define isnan _isnan # define isfinite _finite # define strtof strtod -# define FTIME _ftime_s -# else -# define FTIME _ftime # endif #else // not PLATFORM_WINDOWS @@ -234,7 +231,8 @@ extern "C" JNIEXPORT void JNICALL Java_java_lang_Runtime_exec(JNIEnv* e, jclass, jobjectArray command, jlongArray process) { - char** argv = static_cast(malloc((e->GetArrayLength(command) + 1) * sizeof(char*))); + char** argv = static_cast + (malloc((e->GetArrayLength(command) + 1) * sizeof(char*))); int i; for(i = 0; i < e->GetArrayLength(command); i++){ jstring element = (jstring) e->GetObjectArrayElement(command, i); @@ -255,11 +253,11 @@ Java_java_lang_Runtime_exec(JNIEnv* e, jclass, makePipe(e, out); if(e->ExceptionCheck()) return; jlong outDescriptor = static_cast(out[1]); - e->SetLongArrayRegion(process, 1, 1, &outDescriptor); + e->SetLongArrayRegion(process, 2, 1, &outDescriptor); makePipe(e, err); if(e->ExceptionCheck()) return; jlong errDescriptor = static_cast(err[0]); - e->SetLongArrayRegion(process, 1, 1, &errDescriptor); + e->SetLongArrayRegion(process, 3, 1, &errDescriptor); makePipe(e, msg); if(e->ExceptionCheck()) return; if(fcntl(msg[1], F_SETFD, FD_CLOEXEC) != 0) { @@ -468,9 +466,13 @@ extern "C" JNIEXPORT jlong JNICALL Java_java_lang_System_currentTimeMillis(JNIEnv*, jclass) { #ifdef PLATFORM_WINDOWS - _timeb tb; - FTIME(&tb); - return (static_cast(tb.time) * 1000) + static_cast(tb.millitm); + // We used to use _ftime here, but that only gives us 1-second + // resolution on Windows 7. _ftime_s might work better, but MinGW + // doesn't have it as of this writing. So we use this mess instead: + FILETIME time; + GetSystemTimeAsFileTime(&time); + return (((static_cast(time.dwHighDateTime) << 32) + | time.dwLowDateTime) / 10000) - 11644473600000LL; #else timeval tv = { 0, 0 }; gettimeofday(&tv, 0); diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index c3fa42932f..86ef77c6a3 100644 --- a/classpath/java/io/File.java +++ b/classpath/java/io/File.java @@ -60,7 +60,19 @@ public class File { public boolean isFile() { return isFile(path); } + + private static native boolean canRead(String path); + + public boolean canRead() { + return canRead(path); + } + private static native boolean canWrite(String path); + + public boolean canWrite() { + return canWrite(path); + } + public String getName() { int index = path.lastIndexOf(FileSeparator); if (index >= 0) { diff --git a/classpath/java/io/ObjectInputStream.java b/classpath/java/io/ObjectInputStream.java index 001a192a73..8447e10efa 100644 --- a/classpath/java/io/ObjectInputStream.java +++ b/classpath/java/io/ObjectInputStream.java @@ -79,6 +79,10 @@ public class ObjectInputStream extends InputStream { read('d'); return readDoubleToken(); } + + public void defaultReadObject() throws IOException { + throw new UnsupportedOperationException(); + } private void skipSpace() throws IOException { int c; diff --git a/classpath/java/io/ObjectOutputStream.java b/classpath/java/io/ObjectOutputStream.java index 42d080f676..90743a5b32 100644 --- a/classpath/java/io/ObjectOutputStream.java +++ b/classpath/java/io/ObjectOutputStream.java @@ -82,6 +82,10 @@ public class ObjectOutputStream extends OutputStream { out.print(v); } + public void defaultWriteObject() throws IOException { + throw new UnsupportedOperationException(); + } + private void writeObject(Object o, IdentityHashMap map, int nextId) throws IOException diff --git a/classpath/java/io/PrintStream.java b/classpath/java/io/PrintStream.java index d4aa83eceb..520b676a29 100644 --- a/classpath/java/io/PrintStream.java +++ b/classpath/java/io/PrintStream.java @@ -31,6 +31,7 @@ public class PrintStream extends OutputStream { public synchronized void print(String s) { try { out.write(s.getBytes()); + if (autoFlush) flush(); } catch (IOException e) { } } diff --git a/classpath/java/lang/SecurityManager.java b/classpath/java/lang/SecurityManager.java new file mode 100644 index 0000000000..0b522c5bfb --- /dev/null +++ b/classpath/java/lang/SecurityManager.java @@ -0,0 +1,30 @@ +/* Copyright (c) 2010, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.lang; + +import java.security.AccessController; +import java.security.Permission; +import java.security.SecurityPermission; + +public class SecurityManager { + + public SecurityManager() { + } + + public void checkPermission(Permission perm) { + AccessController.checkPermission(perm); + } + + public void checkSecurityAccess(String target) { + checkPermission(new SecurityPermission(target)); + } + +} diff --git a/classpath/java/lang/String.java b/classpath/java/lang/String.java index 143c60fd72..9362822b65 100644 --- a/classpath/java/lang/String.java +++ b/classpath/java/lang/String.java @@ -236,19 +236,31 @@ public final class String } public String toLowerCase() { - char[] b = new char[length]; - for (int i = 0; i < length; ++i) { - b[i] = Character.toLowerCase(charAt(i)); + for (int j = 0; j < length; ++j) { + char ch = charAt(j); + if (Character.toLowerCase(ch) != ch) { + char[] b = new char[length]; + for (int i = 0; i < length; ++i) { + b[i] = Character.toLowerCase(charAt(i)); + } + return new String(b, 0, length, false); + } } - return new String(b, 0, length, false); + return this; } public String toUpperCase() { - char[] b = new char[length]; - for (int i = 0; i < length; ++i) { - b[i] = Character.toUpperCase(charAt(i)); + for (int j = 0; j < length; ++j) { + char ch = charAt(j); + if (Character.toUpperCase(ch) != ch) { + char[] b = new char[length]; + for (int i = 0; i < length; ++i) { + b[i] = Character.toUpperCase(charAt(i)); + } + return new String(b, 0, length, false); + } } - return new String(b, 0, length, false); + return this; } public int indexOf(int c) { @@ -581,11 +593,19 @@ public final class String } public String toUpperCase(Locale locale) { - throw new UnsupportedOperationException(); + if (locale == Locale.ENGLISH) { + return toUpperCase(); + } else { + throw new UnsupportedOperationException("toUpperCase("+locale+')'); + } } public String toLowerCase(Locale locale) { - throw new UnsupportedOperationException(); + if (locale == Locale.ENGLISH) { + return toLowerCase(); + } else { + throw new UnsupportedOperationException("toLowerCase("+locale+')'); + } } public static String format(Locale locale, String format, Object ... args) { diff --git a/classpath/java/lang/System.java b/classpath/java/lang/System.java index ac3ee11b3a..c060493e7c 100644 --- a/classpath/java/lang/System.java +++ b/classpath/java/lang/System.java @@ -22,6 +22,7 @@ import java.util.Properties; public abstract class System { private static Property properties; + private static SecurityManager securityManager; // static { // loadLibrary("natives"); // } @@ -118,6 +119,14 @@ public abstract class System { public static void exit(int code) { Runtime.getRuntime().exit(code); } + + public static SecurityManager getSecurityManager() { + return securityManager; + } + + public static void setSecurityManager(SecurityManager securityManager) { + System.securityManager = securityManager; + } private static class Property { public final String name; diff --git a/classpath/java/nio/channels/ServerSocketChannel.java b/classpath/java/nio/channels/ServerSocketChannel.java index c8a691c5c5..61dfe60559 100644 --- a/classpath/java/nio/channels/ServerSocketChannel.java +++ b/classpath/java/nio/channels/ServerSocketChannel.java @@ -40,7 +40,7 @@ public class ServerSocketChannel extends SelectableChannel { channel.close(); } - public SocketChannel accept() throws Exception { + public SocketChannel accept() throws IOException { SocketChannel c = new SocketChannel(); c.socket = doAccept(); c.connected = true; diff --git a/classpath/java/security/AccessController.java b/classpath/java/security/AccessController.java index 804dfe70a7..b219e450ae 100644 --- a/classpath/java/security/AccessController.java +++ b/classpath/java/security/AccessController.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, Avian Contributors +/* Copyright (c) 2008, 2010 Avian Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided @@ -21,5 +21,9 @@ public class AccessController { public static Object doPrivileged (PrivilegedAction action) { return action.run(); } + + public static void checkPermission(Permission perm) throws AccessControlException { + + } } diff --git a/classpath/java/security/AllPermission.java b/classpath/java/security/AllPermission.java index 6bc99d53e8..b35004f609 100644 --- a/classpath/java/security/AllPermission.java +++ b/classpath/java/security/AllPermission.java @@ -10,4 +10,10 @@ package java.security; -public class AllPermission extends Permission { } +public class AllPermission extends Permission { + public AllPermission() { + super(""); + } + + +} diff --git a/classpath/java/security/BasicPermission.java b/classpath/java/security/BasicPermission.java new file mode 100644 index 0000000000..756e70139d --- /dev/null +++ b/classpath/java/security/BasicPermission.java @@ -0,0 +1,19 @@ +/* Copyright (c) 2010, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.security; + +public class BasicPermission extends Permission { + + public BasicPermission(String name) { + super(name); + } + +} diff --git a/classpath/java/security/Permission.java b/classpath/java/security/Permission.java index bc6c438e18..528795a127 100644 --- a/classpath/java/security/Permission.java +++ b/classpath/java/security/Permission.java @@ -11,6 +11,22 @@ package java.security; public abstract class Permission { + + protected String name; + + public Permission(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + '['+name+']'; + } + public PermissionCollection newPermissionCollection() { return null; } diff --git a/classpath/java/security/SecurityPermission.java b/classpath/java/security/SecurityPermission.java new file mode 100644 index 0000000000..22660f6111 --- /dev/null +++ b/classpath/java/security/SecurityPermission.java @@ -0,0 +1,19 @@ +/* Copyright (c) 2010, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.security; + +public class SecurityPermission extends BasicPermission { + + public SecurityPermission(String name) { + super(name); + } + +} diff --git a/classpath/java/util/Arrays.java b/classpath/java/util/Arrays.java index 8206988d90..cf05144d7d 100644 --- a/classpath/java/util/Arrays.java +++ b/classpath/java/util/Arrays.java @@ -148,5 +148,11 @@ public class Arrays { array[i] = value; } } + + public static void fill(T[] array, T value) { + for (int i=0;i (c.iterator()); } + public static Comparator reverseOrder(Comparator cmp) { + return new ReverseComparator(cmp); + } + static class IteratorEnumeration implements Enumeration { private final Iterator it; @@ -379,4 +384,20 @@ public class Collections { it.remove(); } } + + private static final class ReverseComparator implements Comparator { + + Comparator cmp; + + public ReverseComparator(Comparator cmp) { + this.cmp = cmp; + } + + @Override + public int compare(T o1, T o2) { + return - cmp.compare(o1, o2); + } + + } + } diff --git a/classpath/java/util/ConcurrentModificationException.java b/classpath/java/util/ConcurrentModificationException.java new file mode 100644 index 0000000000..28fe2bf7ee --- /dev/null +++ b/classpath/java/util/ConcurrentModificationException.java @@ -0,0 +1,47 @@ +/* Copyright (c) 2010, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +package java.util; + +/** + * @author zsombor + * + */ +public class ConcurrentModificationException extends RuntimeException { + + /** + * @param message + * @param cause + */ + public ConcurrentModificationException(String message, Throwable cause) { + super(message, cause); + } + + /** + * @param message + */ + public ConcurrentModificationException(String message) { + super(message); + } + + /** + * @param cause + */ + public ConcurrentModificationException(Throwable cause) { + super(cause); + } + + /** + * + */ + public ConcurrentModificationException() { + } + +} diff --git a/classpath/java/util/HashMap.java b/classpath/java/util/HashMap.java index c0a8a2474a..0f00f920b2 100644 --- a/classpath/java/util/HashMap.java +++ b/classpath/java/util/HashMap.java @@ -269,8 +269,10 @@ public class HashMap implements Map { return value; } - public void setValue(V value) { + public V setValue(V value) { + V old = this.value; this.value = value; + return old; } public HashMap.Cell next() { diff --git a/classpath/java/util/Map.java b/classpath/java/util/Map.java index 5b58bbb4f9..cd20bbc809 100644 --- a/classpath/java/util/Map.java +++ b/classpath/java/util/Map.java @@ -40,6 +40,6 @@ public interface Map { public V getValue(); - public void setValue(V value); + public V setValue(V value); } } diff --git a/classpath/java/util/Properties.java b/classpath/java/util/Properties.java index 749869823b..1ff67dcf16 100644 --- a/classpath/java/util/Properties.java +++ b/classpath/java/util/Properties.java @@ -14,10 +14,15 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.io.IOException; +import java.io.Reader; public class Properties extends Hashtable { public void load(InputStream in) throws IOException { - new Parser().parse(in, this); + new InputStreamParser(in).parse(this); + } + + public void load(Reader reader) throws IOException { + new ReaderParser(reader).parse(this); } public void store(OutputStream out, String comment) throws IOException { @@ -53,7 +58,7 @@ public class Properties extends Hashtable { return keys(); } - private static class Parser { + private abstract static class Parser { private StringBuilder key = null; private StringBuilder value = null; private StringBuilder current = null; @@ -79,13 +84,15 @@ public class Properties extends Hashtable { key = value = current = null; } - private void parse(InputStream in, Map map) + abstract int readCharacter() throws IOException; + + void parse(Map map) throws IOException { boolean escaped = false; int c; - while ((c = in.read()) != -1) { + while ((c = readCharacter()) != -1) { if (c == '\\') { if (escaped) { escaped = false; @@ -98,7 +105,7 @@ public class Properties extends Hashtable { case '#': case '!': if (key == null) { - while ((c = in.read()) != -1 && c != '\n'); + while ((c = readCharacter()) != -1 && c != '\n'); } else { append(c); } @@ -153,4 +160,32 @@ public class Properties extends Hashtable { finishLine(map); } } + + static class InputStreamParser extends Parser { + InputStream in; + + + public InputStreamParser(InputStream in) { + this.in = in; + } + + @Override + int readCharacter() throws IOException { + return in.read(); + } + } + + static class ReaderParser extends Parser { + Reader in; + + public ReaderParser(Reader in) { + this.in = in; + } + + @Override + int readCharacter() throws IOException { + return in.read(); + } + } + } diff --git a/classpath/java/util/TreeMap.java b/classpath/java/util/TreeMap.java index 686e9ffda3..b3141422cd 100644 --- a/classpath/java/util/TreeMap.java +++ b/classpath/java/util/TreeMap.java @@ -112,9 +112,12 @@ public class TreeMap implements Map { return value; } - public void setValue(V value) { + public V setValue(V value) { + V old = this.value; this.value = value; + return old; } + } private class KeySet implements Set { diff --git a/classpath/java/util/WeakHashMap.java b/classpath/java/util/WeakHashMap.java index d8fdbc7968..81365b9816 100644 --- a/classpath/java/util/WeakHashMap.java +++ b/classpath/java/util/WeakHashMap.java @@ -114,8 +114,10 @@ public class WeakHashMap implements Map { return value; } - public void setValue(V value) { + public V setValue(V value) { + V old = this.value; this.value = value; + return old; } public HashMap.Cell next() { diff --git a/classpath/java/util/regex/Pattern.java b/classpath/java/util/regex/Pattern.java index a3ec90c676..2a48591592 100644 --- a/classpath/java/util/regex/Pattern.java +++ b/classpath/java/util/regex/Pattern.java @@ -115,23 +115,34 @@ public class Pattern { List list = new LinkedList(); int index = 0; int trailing = 0; - while (index < input.length() && list.size() < limit) { - int i = indexOf(input, pattern, index); + int patternLength = pattern.length(); + while (index < input.length() && list.size() < limit - 1) { + int i; + if (patternLength == 0) { + if (list.size() == 0) { + i = 0; + } else { + i = index + 1; + } + } else { + i = indexOf(input, pattern, index); + } + if (i >= 0) { - if (i == index) { + if (patternLength != 0 && i == index) { ++ trailing; } else { trailing = 0; } list.add(input.subSequence(index, i)); - index = i + pattern.length(); + index = i + patternLength; } else { break; } } - if (strip && index == input.length()) { + if (strip && index > 0 && index == input.length()) { ++ trailing; } else { trailing = 0; diff --git a/src/posix.cpp b/src/posix.cpp index 0d34e2828a..da0397c107 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -65,13 +65,16 @@ const int AltSegFaultSignal = SIGBUS; const int AltSegFaultSignal = InvalidSignal; #endif const unsigned AltSegFaultSignalIndex = 3; +const int PipeSignal = SIGPIPE; +const unsigned PipeSignalIndex = 4; const int signals[] = { VisitSignal, SegFaultSignal, InterruptSignal, - AltSegFaultSignal }; + AltSegFaultSignal, + PipeSignal }; -const unsigned SignalCount = 4; +const unsigned SignalCount = 5; class MySystem; MySystem* system; @@ -530,6 +533,7 @@ class MySystem: public System { system = this; registerHandler(&nullHandler, InterruptSignalIndex); + registerHandler(&nullHandler, PipeSignalIndex); registerHandler(&nullHandler, VisitSignalIndex); expect(this, make(&visitLock) == 0); @@ -755,7 +759,9 @@ class MySystem: public System { return 0; } else { -// fprintf(stderr, "dlerror: %s\n", dlerror()); + if (Verbose) { + fprintf(stderr, "dlerror opening %s: %s\n", name, dlerror()); + } return 1; } } @@ -784,6 +790,7 @@ class MySystem: public System { registerHandler(0, InterruptSignalIndex); registerHandler(0, VisitSignalIndex); + registerHandler(0, PipeSignalIndex); system = 0; ::free(this); @@ -860,6 +867,10 @@ handleSignal(int signal, siginfo_t* info, void* context) index = InterruptSignalIndex; } break; + case PipeSignal: { + index = PipeSignalIndex; + } break; + default: abort(); } @@ -871,6 +882,7 @@ handleSignal(int signal, siginfo_t* info, void* context) switch (signal) { case VisitSignal: case InterruptSignal: + case PipeSignal: break; default: diff --git a/test/Strings.java b/test/Strings.java index 9927ba2983..6b993bcb4f 100644 --- a/test/Strings.java +++ b/test/Strings.java @@ -3,6 +3,24 @@ public class Strings { if (! v) throw new RuntimeException(); } + private static boolean equal(Object a, Object b) { + return a == b || (a != null && a.equals(b)); + } + + private static boolean arraysEqual(Object[] a, Object[] b) { + if (a.length != b.length) { + return false; + } + + for (int i = 0; i < a.length; ++i) { + if (! equal(a[i], b[i])) { + return false; + } + } + + return true; + } + public static void main(String[] args) { expect(new String(new byte[] { 99, 111, 109, 46, 101, 99, 111, 118, 97, 116, 101, 46, 110, 97, 116, 46, 98, 117, @@ -13,6 +31,31 @@ public class Strings { expect(months.split("\u00ae").length == 3); expect(months.replaceAll("\u00ae", ".").equals("Jan.Feb.Mar.")); + expect(arraysEqual + ("xyz".split("", 0), new String[] { "", "x", "y", "z" })); + expect(arraysEqual + ("xyz".split("", 1), new String[] { "xyz" })); + expect(arraysEqual + ("xyz".split("", 2), new String[] { "", "xyz" })); + expect(arraysEqual + ("xyz".split("", 3), new String[] { "", "x", "yz" })); + expect(arraysEqual + ("xyz".split("", 4), new String[] { "", "x", "y", "z" })); + expect(arraysEqual + ("xyz".split("", 5), new String[] { "", "x", "y", "z", "" })); + expect(arraysEqual + ("xyz".split("", 6), new String[] { "", "x", "y", "z", "" })); + expect(arraysEqual + ("xyz".split("", -1), new String[] { "", "x", "y", "z", "" })); + + expect(arraysEqual("".split("xyz", 0), new String[] { "" })); + expect(arraysEqual("".split("xyz", 1), new String[] { "" })); + expect(arraysEqual("".split("xyz", -1), new String[] { "" })); + + expect(arraysEqual("".split("", 0), new String[] { "" })); + expect(arraysEqual("".split("", 1), new String[] { "" })); + expect(arraysEqual("".split("", -1), new String[] { "" })); + expect("foo_foofoo__foo".replaceAll("_", "__") .equals("foo__foofoo____foo")); diff --git a/vm.pro b/vm.pro index a6a2a54413..c2bd83c3d6 100644 --- a/vm.pro +++ b/vm.pro @@ -97,3 +97,9 @@ -keepnames public class avian.Callback -keepnames public class java.util.concurrent.Callable + +# Proguard gets confused about clone() and array classes (http://sourceforge.net/tracker/index.php?func=detail&aid=2851344&group_id=54750&atid=474704): + +-keepclassmembers class java.lang.Object { + protected java.lang.Object clone(); + }