| 
31499
 | 
     1  | 
/*  Title:      Pure/System/cygwin.scala
  | 
| 
 | 
     2  | 
    Author:     Makarius
  | 
| 
 | 
     3  | 
  | 
| 
 | 
     4  | 
Accessing the Cygwin installation.
  | 
| 
 | 
     5  | 
*/
  | 
| 
 | 
     6  | 
  | 
| 
 | 
     7  | 
package isabelle
  | 
| 
 | 
     8  | 
  | 
| 
 | 
     9  | 
import java.lang.reflect.Method
  | 
| 
31826
 | 
    10  | 
import java.io.File
  | 
| 
31499
 | 
    11  | 
  | 
| 
 | 
    12  | 
  | 
| 
 | 
    13  | 
object Cygwin
  | 
| 
 | 
    14  | 
{
 | 
| 
 | 
    15  | 
  /* registry access */
  | 
| 
 | 
    16  | 
  | 
| 
 | 
    17  | 
  // Some black magic involving private WindowsPreferences from Sun, cf.
  | 
| 
 | 
    18  | 
  // http://www.docjar.com/html/api/java/util/prefs/WindowsPreferences.java.html
  | 
| 
 | 
    19  | 
  | 
| 
 | 
    20  | 
  private val WindowsPreferences = Class.forName("java.util.prefs.WindowsPreferences")
 | 
| 
 | 
    21  | 
  | 
| 
 | 
    22  | 
  private val HKEY_CURRENT_USER = 0x80000001
  | 
| 
 | 
    23  | 
  private val HKEY_LOCAL_MACHINE = 0x80000002
  | 
| 
 | 
    24  | 
  private val KEY_READ = 0x20019
  | 
| 
 | 
    25  | 
  private val NATIVE_HANDLE = 0
  | 
| 
 | 
    26  | 
  private val ERROR_CODE = 1
  | 
| 
 | 
    27  | 
  | 
| 
 | 
    28  | 
  private def C_string(s: String): Array[Byte] =
  | 
| 
 | 
    29  | 
    (s + "\0").getBytes("US-ASCII")
 | 
| 
 | 
    30  | 
  | 
| 
 | 
    31  | 
  private def J_string(bs: Array[Byte]): String =
  | 
| 
 | 
    32  | 
    new String(bs, 0, bs.length - 1, "US-ASCII")
  | 
| 
 | 
    33  | 
  | 
| 
 | 
    34  | 
  private val INT = Integer.TYPE
  | 
| 
 | 
    35  | 
  private val BYTES = (new Array[Byte](0)).getClass
  | 
| 
 | 
    36  | 
  | 
| 
 | 
    37  | 
  private def open_key(handle: Int, subkey: Array[Byte], mask: Int): Array[Int] =
  | 
| 
 | 
    38  | 
  {
 | 
| 
 | 
    39  | 
    val m = WindowsPreferences.getDeclaredMethod("WindowsRegOpenKey", INT, BYTES, INT)
 | 
| 
 | 
    40  | 
    m.setAccessible(true)
  | 
| 
 | 
    41  | 
    m.invoke(null, handle.asInstanceOf[Object], subkey.asInstanceOf[Object],
  | 
| 
 | 
    42  | 
      mask.asInstanceOf[Object]).asInstanceOf[Array[Int]]
  | 
| 
 | 
    43  | 
  }
  | 
| 
 | 
    44  | 
  | 
| 
 | 
    45  | 
  private def close_key(handle: Int): Int =
  | 
| 
 | 
    46  | 
  {
 | 
| 
 | 
    47  | 
    val m = WindowsPreferences.getDeclaredMethod("WindowsRegCloseKey", INT)
 | 
| 
 | 
    48  | 
    m.setAccessible(true)
  | 
| 
 | 
    49  | 
    m.invoke(null, handle.asInstanceOf[Object]).asInstanceOf[Int]
  | 
| 
 | 
    50  | 
  }
  | 
| 
 | 
    51  | 
  | 
| 
 | 
    52  | 
  private def query(handle: Int, name: Array[Byte]) =
  | 
| 
 | 
    53  | 
  {
 | 
| 
 | 
    54  | 
    val m = WindowsPreferences.getDeclaredMethod("WindowsRegQueryValueEx", INT, BYTES)
 | 
| 
 | 
    55  | 
    m.setAccessible(true)
  | 
| 
 | 
    56  | 
    m.invoke(null, handle.asInstanceOf[Object], name.asInstanceOf[Object]).
  | 
| 
 | 
    57  | 
      asInstanceOf[Array[Byte]]
  | 
| 
 | 
    58  | 
  }
  | 
| 
 | 
    59  | 
  | 
| 
 | 
    60  | 
  def query_registry(sys: Boolean, path: String, name: String): Option[String] =
  | 
| 
 | 
    61  | 
  {
 | 
| 
 | 
    62  | 
    val handle = if (sys) HKEY_LOCAL_MACHINE else HKEY_CURRENT_USER
  | 
| 
 | 
    63  | 
    val result = open_key(handle, C_string(path), KEY_READ)
  | 
| 
 | 
    64  | 
    if (result(ERROR_CODE) != 0) None
  | 
| 
 | 
    65  | 
    else {
 | 
| 
 | 
    66  | 
      val res = query(result(NATIVE_HANDLE), C_string(name))
  | 
| 
 | 
    67  | 
      if (res == null) None
  | 
| 
 | 
    68  | 
      else Some(J_string(res))
  | 
| 
 | 
    69  | 
    }
  | 
| 
 | 
    70  | 
  }
  | 
| 
 | 
    71  | 
  | 
| 
 | 
    72  | 
  def query_registry(path: String, name: String): Option[String] =
  | 
| 
 | 
    73  | 
    query_registry(false, path, name) orElse
  | 
| 
 | 
    74  | 
      query_registry(true, path, name)
  | 
| 
 | 
    75  | 
  | 
| 
 | 
    76  | 
  | 
| 
 | 
    77  | 
  /* Cygwin installation */
  | 
| 
 | 
    78  | 
  | 
| 
31826
 | 
    79  | 
  // old-style mount points (Cygwin 1.5)
  | 
| 
31499
 | 
    80  | 
  private val CYGWIN_MOUNTS = "Software\\Cygnus Solutions\\Cygwin\\mounts v2"
  | 
| 
 | 
    81  | 
  | 
| 
31826
 | 
    82  | 
  // new-style setup (Cygwin 1.7)
  | 
| 
 | 
    83  | 
  private val CYGWIN_SETUP1 = "Software\\Cygwin\\setup"
  | 
| 
 | 
    84  | 
  private val CYGWIN_SETUP2 = "Software\\Wow6432Node\\Cygwin\\setup"  // !?
  | 
| 
31499
 | 
    85  | 
  | 
| 
31826
 | 
    86  | 
  def config(): (String, String) =
  | 
| 
 | 
    87  | 
  {
 | 
| 
 | 
    88  | 
    query_registry(CYGWIN_SETUP1, "rootdir") match {
 | 
| 
 | 
    89  | 
      case Some(root) => (root, "/cygdrive")
  | 
| 
 | 
    90  | 
      case None =>
  | 
| 
 | 
    91  | 
        val root =
  | 
| 
 | 
    92  | 
          query_registry(CYGWIN_MOUNTS + "\\/", "native") getOrElse "C:\\cygwin"
  | 
| 
 | 
    93  | 
        val cygdrive =
  | 
| 
 | 
    94  | 
          query_registry(CYGWIN_MOUNTS, "cygdrive prefix") getOrElse "cygdrive"
  | 
| 
 | 
    95  | 
        (root, cygdrive)
  | 
| 
 | 
    96  | 
    }
  | 
| 
 | 
    97  | 
  }
  | 
| 
 | 
    98  | 
  | 
| 
 | 
    99  | 
  | 
| 
 | 
   100  | 
  /* basic sanity check */
  | 
| 
 | 
   101  | 
  | 
| 
 | 
   102  | 
  def check(root: String): Boolean =
  | 
| 
 | 
   103  | 
    new File(root + "\\bin\\bash.exe").isFile &&
  | 
| 
 | 
   104  | 
    new File(root + "\\bin\\env.exe").isFile
  | 
| 
31499
 | 
   105  | 
}
  | 
| 
 | 
   106  | 
  |