001/*
002 * BridJ - Dynamic and blazing-fast native interop for Java.
003 * http://bridj.googlecode.com/
004 *
005 * Copyright (c) 2010-2013, Olivier Chafik (http://ochafik.com/)
006 * All rights reserved.
007 *
008 * Redistribution and use in source and binary forms, with or without
009 * modification, are permitted provided that the following conditions are met:
010 * 
011 *     * Redistributions of source code must retain the above copyright
012 *       notice, this list of conditions and the following disclaimer.
013 *     * Redistributions in binary form must reproduce the above copyright
014 *       notice, this list of conditions and the following disclaimer in the
015 *       documentation and/or other materials provided with the distribution.
016 *     * Neither the name of Olivier Chafik nor the
017 *       names of its contributors may be used to endorse or promote products
018 *       derived from this software without specific prior written permission.
019 * 
020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY
021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030 */
031package org.bridj;
032
033import java.io.FileNotFoundException;
034import org.bridj.ann.*;
035
036//import static org.bridj.LastError.Windows.*;
037//import static org.bridj.LastError.Unix.*;
038import static org.bridj.Pointer.*;
039
040/**
041 * Native error that correspond to the <a
042 * href="http://en.wikipedia.org/wiki/Errno.h">errno</a> or <a
043 * href="http://msdn.microsoft.com/en-us/library/ms679360(v=vs.85).aspx">GetLastError()</a>
044 * mechanism.<br>
045 * Some C functions declare errors by marking an error code in <a
046 * href="http://en.wikipedia.org/wiki/Errno.h">errno</a> or through <a
047 * href="http://msdn.microsoft.com/en-us/library/ms680627(v=vs.85).aspx">SetLastError(int)</a>.<br>
048 * If you want their corresponding bindings to throw an exception whenever such
049 * an error was marked, simply make them throw this exception explicitly.<br>
050 * On Windows, BridJ will first check <a
051 * href="http://msdn.microsoft.com/en-us/library/ms679360(v=vs.85).aspx">GetLastError()</a>,
052 * then if no error was found it will check <a
053 * href="http://en.wikipedia.org/wiki/Errno.h">errno</a> (on the other platforms
054 * only <a href="http://en.wikipedia.org/wiki/Errno.h">errno</a> is
055 * available).<br>
056 * For instance, look at the following binding of the C-library <a
057 * href="http://www.cplusplus.com/reference/clibrary/cstdlib/strtoul/">strtoul</a>
058 * function :
059 * <pre>
060 * &#064;Library("c")
061 * {@code
062 * public static native long strtoul(Pointer<Byte> str, Pointer<Pointer<Byte>> endptr, int base) throws LastError;
063 * }</pre>
064 *
065 * @author Olivier Chafik
066 */
067public class LastError extends NativeError {
068
069    final int code, kind;
070    String description;
071    
072    static final int eLastErrorKindWindows = 1, eLastErrorKindCLibrary = 2;
073
074    LastError(int code, int kind) {
075        super(null);
076        this.code = code;
077        this.kind = kind;
078        /*
079        if (BridJ.verbose) {
080            BridJ.info("Last error detected : " + getMessage());
081        }*/
082    }
083
084    public int hashCode() {
085        return Integer.valueOf(code).hashCode() ^ Integer.valueOf(kind).hashCode();
086    }
087
088    public boolean equals(Object o) {
089        if (!(o instanceof LastError)) {
090                return false;
091        }
092        LastError e = (LastError) o;
093        return code == e.code && kind == e.kind;
094    }
095
096    /**
097     * Native error code (as returned by <a
098     * href="http://en.wikipedia.org/wiki/Errno.h">errno</a> or <a
099     * href="http://msdn.microsoft.com/en-us/library/ms679360(v=vs.85).aspx">GetLastError()</a>).
100     */
101    public int getCode() {
102        return code;
103    }
104
105    /**
106     * Native error description (as returned by <a
107     * href="http://www.cplusplus.com/reference/clibrary/cstring/strerror/">strerror</a>
108     * or <a
109     * href="http://msdn.microsoft.com/en-us/library/ms680582(v=vs.85).aspx">FormatMessage</a>).
110     */
111    public String getDescription() {
112        if (description == null) {
113                description = getDescription(code, kind);
114        }
115        return description;
116    }
117    
118    @Override
119    public String getMessage() {
120        String description = getDescription();
121        return (description == null ? "?" : description.trim()) + " (error code = " + code + ")";
122    }
123    
124    private static native String getDescription(int value, int kind);
125
126    private static final ThreadLocal<LastError> lastError = new ThreadLocal<LastError>();
127
128    public static LastError getLastError() {
129        return lastError.get();
130    }
131    
132    static LastError setLastError(int code, int kind) {
133                if (code == 0) {
134                                lastError.set(null);
135            return null;
136        }
137        LastError err = new LastError(code, kind);
138        err.fillInStackTrace();
139        lastError.set(err);
140        return err;
141    }
142}