PageRenderTime 160ms CodeModel.GetById 37ms RepoModel.GetById 0ms app.codeStats 0ms

/src/code/win32.lisp

http://github.com/nikodemus/SBCL
Lisp | 1186 lines | 757 code | 132 blank | 297 comment | 0 complexity | 4d55d271932c8b5a1293a6b3199e1bdb MD5 | raw file
  1. ;;;; This file contains Win32 support routines that SBCL needs to
  2. ;;;; implement itself, in addition to those that apply to Win32 in
  3. ;;;; unix.lisp. In theory, some of these functions might someday be
  4. ;;;; useful to the end user.
  5. ;;;; This software is part of the SBCL system. See the README file for
  6. ;;;; more information.
  7. ;;;;
  8. ;;;; This software is derived from the CMU CL system, which was
  9. ;;;; written at Carnegie Mellon University and released into the
  10. ;;;; public domain. The software is in the public domain and is
  11. ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
  12. ;;;; files for more information.
  13. (in-package "SB!WIN32")
  14. ;;; Alien definitions for commonly used Win32 types. Woe unto whoever
  15. ;;; tries to untangle this someday for 64-bit Windows.
  16. ;;;
  17. ;;; FIXME: There used to be many more here, which are now groveled,
  18. ;;; but groveling HANDLE makes it unsigned, which currently breaks the
  19. ;;; build. --NS 2006-06-18
  20. (define-alien-type handle int-ptr)
  21. (define-alien-type lispbool (boolean 32))
  22. (define-alien-type system-string
  23. #!-sb-unicode c-string
  24. #!+sb-unicode (c-string :external-format :ucs-2))
  25. (define-alien-type tchar #!-sb-unicode char
  26. #!+sb-unicode (unsigned 16))
  27. (defconstant default-environment-length 1024)
  28. ;;; HANDLEs are actually pointers, but an invalid handle is -1 cast
  29. ;;; to a pointer.
  30. (defconstant invalid-handle -1)
  31. (defconstant file-attribute-readonly #x1)
  32. (defconstant file-attribute-hidden #x2)
  33. (defconstant file-attribute-system #x4)
  34. (defconstant file-attribute-directory #x10)
  35. (defconstant file-attribute-archive #x20)
  36. (defconstant file-attribute-device #x40)
  37. (defconstant file-attribute-normal #x80)
  38. (defconstant file-attribute-temporary #x100)
  39. (defconstant file-attribute-sparse #x200)
  40. (defconstant file-attribute-reparse-point #x400)
  41. (defconstant file-attribute-reparse-compressed #x800)
  42. (defconstant file-attribute-reparse-offline #x1000)
  43. (defconstant file-attribute-not-content-indexed #x2000)
  44. (defconstant file-attribute-encrypted #x4000)
  45. (defconstant file-flag-overlapped #x40000000)
  46. (defconstant file-flag-sequential-scan #x8000000)
  47. ;; Possible results of GetFileType.
  48. (defconstant file-type-disk 1)
  49. (defconstant file-type-char 2)
  50. (defconstant file-type-pipe 3)
  51. (defconstant file-type-remote 4)
  52. (defconstant file-type-unknown 0)
  53. (defconstant invalid-file-attributes (mod -1 (ash 1 32)))
  54. ;;;; File Type Introspection by handle
  55. (define-alien-routine ("GetFileType" get-file-type) dword
  56. (handle handle))
  57. ;;;; Error Handling
  58. ;;; Retrieve the calling thread's last-error code value. The
  59. ;;; last-error code is maintained on a per-thread basis.
  60. (define-alien-routine ("GetLastError" get-last-error) dword)
  61. ;;; Flag constants for FORMAT-MESSAGE.
  62. (defconstant format-message-from-system #x1000)
  63. ;;; Format an error message based on a lookup table. See MSDN for the
  64. ;;; full meaning of the all options---most are not used when getting
  65. ;;; system error codes.
  66. (define-alien-routine ("FormatMessageA" format-message) dword
  67. (flags dword)
  68. (source (* t))
  69. (message-id dword)
  70. (language-id dword)
  71. (buffer c-string)
  72. (size dword)
  73. (arguments (* t)))
  74. ;;;; File Handles
  75. ;;; Historically, SBCL on Windows used CRT (lowio) file descriptors,
  76. ;;; unlike other Lisps. They really help to minimize required effort
  77. ;;; for porting Unix-specific software, at least to the level that it
  78. ;;; mostly works most of the time.
  79. ;;;
  80. ;;; Alastair Bridgewater recommended to switch away from CRT
  81. ;;; descriptors, and Anton Kovalenko thinks it's the time to heed his
  82. ;;; advice. I see that SBCL for Windows needs much more effort in the
  83. ;;; area of OS IO abstractions and the like; using or leaving lowio
  84. ;;; FDs doesn't change the big picture so much.
  85. ;;;
  86. ;;; Lowio layer, in exchange for `semi-automatic almost-portability',
  87. ;;; brings some significant problems, which a grown-up cross-platform
  88. ;;; CL implementation shouldn't have. Therefore, as its benefits
  89. ;;; become negligible, it's a good reason to throw it away.
  90. ;;;
  91. ;;; -- comment from AK's branch
  92. ;;; For a few more releases, let's preserve old functions (now
  93. ;;; implemented as identity) for user code which might have had to peek
  94. ;;; into our internals in past versions when we hadn't been using
  95. ;;; handles yet. -- DFL, 2012
  96. (defun get-osfhandle (fd) fd)
  97. (defun open-osfhandle (handle flags) (declare (ignore flags)) handle)
  98. ;;; Get the operating system handle for a C file descriptor. Returns
  99. ;;; INVALID-HANDLE on failure.
  100. (define-alien-routine ("_get_osfhandle" real-get-osfhandle) handle
  101. (fd int))
  102. (define-alien-routine ("_close" real-crt-close) int
  103. (fd int))
  104. ;;; Read data from a file handle into a buffer. This may be used
  105. ;;; synchronously or with "overlapped" (asynchronous) I/O.
  106. (define-alien-routine ("ReadFile" read-file) bool
  107. (file handle)
  108. (buffer (* t))
  109. (bytes-to-read dword)
  110. (bytes-read (* dword))
  111. (overlapped (* t)))
  112. ;;; Write data from a buffer to a file handle. This may be used
  113. ;;; synchronously or with "overlapped" (asynchronous) I/O.
  114. (define-alien-routine ("WriteFile" write-file) bool
  115. (file handle)
  116. (buffer (* t))
  117. (bytes-to-write dword)
  118. (bytes-written (* dword))
  119. (overlapped (* t)))
  120. ;;; Copy data from a named or anonymous pipe into a buffer without
  121. ;;; removing it from the pipe. BUFFER, BYTES-READ, BYTES-AVAIL, and
  122. ;;; BYTES-LEFT-THIS-MESSAGE may be NULL if no data is to be read.
  123. ;;; Return TRUE on success, FALSE on failure.
  124. (define-alien-routine ("PeekNamedPipe" peek-named-pipe) bool
  125. (pipe handle)
  126. (buffer (* t))
  127. (buffer-size dword)
  128. (bytes-read (* dword))
  129. (bytes-avail (* dword))
  130. (bytes-left-this-message (* dword)))
  131. ;;; Flush the console input buffer if HANDLE is a console handle.
  132. ;;; Returns true on success, false if the handle does not refer to a
  133. ;;; console.
  134. (define-alien-routine ("FlushConsoleInputBuffer" flush-console-input-buffer) bool
  135. (handle handle))
  136. ;;; Read data from the console input buffer without removing it,
  137. ;;; without blocking. Buffer should be large enough for LENGTH *
  138. ;;; INPUT-RECORD-SIZE bytes.
  139. (define-alien-routine ("PeekConsoleInputA" peek-console-input) bool
  140. (handle handle)
  141. (buffer (* t))
  142. (length dword)
  143. (nevents (* dword)))
  144. (define-alien-routine ("socket_input_available" socket-input-available) int
  145. (socket handle))
  146. ;;; Listen for input on a Windows file handle. Unlike UNIX, there
  147. ;;; isn't a unified interface to do this---we have to know what sort
  148. ;;; of handle we have. Of course, there's no way to actually
  149. ;;; introspect it, so we have to try various things until we find
  150. ;;; something that works. Returns true if there could be input
  151. ;;; available, or false if there is not.
  152. (defun handle-listen (handle)
  153. (with-alien ((avail dword)
  154. (buf (array char #.input-record-size)))
  155. (when
  156. ;; Make use of the fact that console handles are technically no
  157. ;; real handles, and unlike those, have these bits set:
  158. (= 3 (logand 3 handle))
  159. (return-from handle-listen
  160. (alien-funcall (extern-alien "win32_tty_listen"
  161. (function boolean handle))
  162. handle)))
  163. (unless (zerop (peek-named-pipe handle nil 0 nil (addr avail) nil))
  164. (return-from handle-listen (plusp avail)))
  165. (let ((res (socket-input-available handle)))
  166. (unless (zerop res)
  167. (return-from handle-listen (= res 1))))
  168. t))
  169. ;;; Listen for input on a C runtime file handle. Returns true if
  170. ;;; there could be input available, or false if there is not.
  171. (defun fd-listen (fd)
  172. (let ((handle (get-osfhandle fd)))
  173. (if handle
  174. (handle-listen handle)
  175. t)))
  176. ;;; Clear all available input from a file handle.
  177. (defun handle-clear-input (handle)
  178. (flush-console-input-buffer handle)
  179. (with-alien ((buf (array char 1024))
  180. (count dword))
  181. (loop
  182. (unless (handle-listen handle)
  183. (return))
  184. (when (zerop (read-file handle (cast buf (* t)) 1024 (addr count) nil))
  185. (return))
  186. (when (< count 1024)
  187. (return)))))
  188. ;;; Clear all available input from a C runtime file handle.
  189. (defun fd-clear-input (fd)
  190. (let ((handle (get-osfhandle fd)))
  191. (when handle
  192. (handle-clear-input handle))))
  193. ;;;; System Functions
  194. #!-sb-thread
  195. (define-alien-routine ("Sleep" millisleep) void
  196. (milliseconds dword))
  197. #!+sb-thread
  198. (defun sb!unix:nanosleep (sec nsec)
  199. (let ((*allow-with-interrupts* *interrupts-enabled*))
  200. (without-interrupts
  201. (let ((timer (sb!impl::os-create-wtimer)))
  202. (sb!impl::os-set-wtimer timer sec nsec)
  203. (unwind-protect
  204. (do () ((with-local-interrupts
  205. (zerop (sb!impl::os-wait-for-wtimer timer)))))
  206. (sb!impl::os-close-wtimer timer))))))
  207. (define-alien-routine ("win32_wait_object_or_signal" wait-object-or-signal)
  208. (signed 16)
  209. (handle handle))
  210. #!+sb-unicode
  211. (progn
  212. (defvar *ansi-codepage* nil)
  213. (defvar *oem-codepage* nil)
  214. (defvar *codepage-to-external-format* (make-hash-table)))
  215. #!+sb-unicode
  216. (dolist
  217. (cp '(;;037 IBM EBCDIC - U.S./Canada
  218. (437 :CP437) ;; OEM - United States
  219. ;;500 IBM EBCDIC - International
  220. ;;708 Arabic - ASMO 708
  221. ;;709 Arabic - ASMO 449+, BCON V4
  222. ;;710 Arabic - Transparent Arabic
  223. ;;720 Arabic - Transparent ASMO
  224. ;;737 OEM - Greek (formerly 437G)
  225. ;;775 OEM - Baltic
  226. (850 :CP850) ;; OEM - Multilingual Latin I
  227. (852 :CP852) ;; OEM - Latin II
  228. (855 :CP855) ;; OEM - Cyrillic (primarily Russian)
  229. (857 :CP857) ;; OEM - Turkish
  230. ;;858 OEM - Multilingual Latin I + Euro symbol
  231. (860 :CP860) ;; OEM - Portuguese
  232. (861 :CP861) ;; OEM - Icelandic
  233. (862 :CP862) ;; OEM - Hebrew
  234. (863 :CP863) ;; OEM - Canadian-French
  235. (864 :CP864) ;; OEM - Arabic
  236. (865 :CP865) ;; OEM - Nordic
  237. (866 :CP866) ;; OEM - Russian
  238. (869 :CP869) ;; OEM - Modern Greek
  239. ;;870 IBM EBCDIC - Multilingual/ROECE (Latin-2)
  240. (874 :CP874) ;; ANSI/OEM - Thai (same as 28605, ISO 8859-15)
  241. ;;875 IBM EBCDIC - Modern Greek
  242. (932 :CP932) ;; ANSI/OEM - Japanese, Shift-JIS
  243. ;;936 ANSI/OEM - Simplified Chinese (PRC, Singapore)
  244. ;;949 ANSI/OEM - Korean (Unified Hangul Code)
  245. ;;950 ANSI/OEM - Traditional Chinese (Taiwan; Hong Kong SAR, PRC)
  246. ;;1026 IBM EBCDIC - Turkish (Latin-5)
  247. ;;1047 IBM EBCDIC - Latin 1/Open System
  248. ;;1140 IBM EBCDIC - U.S./Canada (037 + Euro symbol)
  249. ;;1141 IBM EBCDIC - Germany (20273 + Euro symbol)
  250. ;;1142 IBM EBCDIC - Denmark/Norway (20277 + Euro symbol)
  251. ;;1143 IBM EBCDIC - Finland/Sweden (20278 + Euro symbol)
  252. ;;1144 IBM EBCDIC - Italy (20280 + Euro symbol)
  253. ;;1145 IBM EBCDIC - Latin America/Spain (20284 + Euro symbol)
  254. ;;1146 IBM EBCDIC - United Kingdom (20285 + Euro symbol)
  255. ;;1147 IBM EBCDIC - France (20297 + Euro symbol)
  256. ;;1148 IBM EBCDIC - International (500 + Euro symbol)
  257. ;;1149 IBM EBCDIC - Icelandic (20871 + Euro symbol)
  258. (1200 :UCS-2LE) ;; Unicode UCS-2 Little-Endian (BMP of ISO 10646)
  259. (1201 :UCS-2BE) ;; Unicode UCS-2 Big-Endian
  260. (1250 :CP1250) ;; ANSI - Central European
  261. (1251 :CP1251) ;; ANSI - Cyrillic
  262. (1252 :CP1252) ;; ANSI - Latin I
  263. (1253 :CP1253) ;; ANSI - Greek
  264. (1254 :CP1254) ;; ANSI - Turkish
  265. (1255 :CP1255) ;; ANSI - Hebrew
  266. (1256 :CP1256) ;; ANSI - Arabic
  267. (1257 :CP1257) ;; ANSI - Baltic
  268. (1258 :CP1258) ;; ANSI/OEM - Vietnamese
  269. ;;1361 Korean (Johab)
  270. ;;10000 MAC - Roman
  271. ;;10001 MAC - Japanese
  272. ;;10002 MAC - Traditional Chinese (Big5)
  273. ;;10003 MAC - Korean
  274. ;;10004 MAC - Arabic
  275. ;;10005 MAC - Hebrew
  276. ;;10006 MAC - Greek I
  277. (10007 :X-MAC-CYRILLIC) ;; MAC - Cyrillic
  278. ;;10008 MAC - Simplified Chinese (GB 2312)
  279. ;;10010 MAC - Romania
  280. ;;10017 MAC - Ukraine
  281. ;;10021 MAC - Thai
  282. ;;10029 MAC - Latin II
  283. ;;10079 MAC - Icelandic
  284. ;;10081 MAC - Turkish
  285. ;;10082 MAC - Croatia
  286. ;;12000 Unicode UCS-4 Little-Endian
  287. ;;12001 Unicode UCS-4 Big-Endian
  288. ;;20000 CNS - Taiwan
  289. ;;20001 TCA - Taiwan
  290. ;;20002 Eten - Taiwan
  291. ;;20003 IBM5550 - Taiwan
  292. ;;20004 TeleText - Taiwan
  293. ;;20005 Wang - Taiwan
  294. ;;20105 IA5 IRV International Alphabet No. 5 (7-bit)
  295. ;;20106 IA5 German (7-bit)
  296. ;;20107 IA5 Swedish (7-bit)
  297. ;;20108 IA5 Norwegian (7-bit)
  298. ;;20127 US-ASCII (7-bit)
  299. ;;20261 T.61
  300. ;;20269 ISO 6937 Non-Spacing Accent
  301. ;;20273 IBM EBCDIC - Germany
  302. ;;20277 IBM EBCDIC - Denmark/Norway
  303. ;;20278 IBM EBCDIC - Finland/Sweden
  304. ;;20280 IBM EBCDIC - Italy
  305. ;;20284 IBM EBCDIC - Latin America/Spain
  306. ;;20285 IBM EBCDIC - United Kingdom
  307. ;;20290 IBM EBCDIC - Japanese Katakana Extended
  308. ;;20297 IBM EBCDIC - France
  309. ;;20420 IBM EBCDIC - Arabic
  310. ;;20423 IBM EBCDIC - Greek
  311. ;;20424 IBM EBCDIC - Hebrew
  312. ;;20833 IBM EBCDIC - Korean Extended
  313. ;;20838 IBM EBCDIC - Thai
  314. (20866 :KOI8-R) ;; Russian - KOI8-R
  315. ;;20871 IBM EBCDIC - Icelandic
  316. ;;20880 IBM EBCDIC - Cyrillic (Russian)
  317. ;;20905 IBM EBCDIC - Turkish
  318. ;;20924 IBM EBCDIC - Latin-1/Open System (1047 + Euro symbol)
  319. ;;20932 JIS X 0208-1990 & 0121-1990
  320. ;;20936 Simplified Chinese (GB2312)
  321. ;;21025 IBM EBCDIC - Cyrillic (Serbian, Bulgarian)
  322. ;;21027 (deprecated)
  323. (21866 :KOI8-U) ;; Ukrainian (KOI8-U)
  324. (28591 :LATIN-1) ;; ISO 8859-1 Latin I
  325. (28592 :ISO-8859-2) ;; ISO 8859-2 Central Europe
  326. (28593 :ISO-8859-3) ;; ISO 8859-3 Latin 3
  327. (28594 :ISO-8859-4) ;; ISO 8859-4 Baltic
  328. (28595 :ISO-8859-5) ;; ISO 8859-5 Cyrillic
  329. (28596 :ISO-8859-6) ;; ISO 8859-6 Arabic
  330. (28597 :ISO-8859-7) ;; ISO 8859-7 Greek
  331. (28598 :ISO-8859-8) ;; ISO 8859-8 Hebrew
  332. (28599 :ISO-8859-9) ;; ISO 8859-9 Latin 5
  333. (28605 :LATIN-9) ;; ISO 8859-15 Latin 9
  334. ;;29001 Europa 3
  335. (38598 :ISO-8859-8) ;; ISO 8859-8 Hebrew
  336. ;;50220 ISO 2022 Japanese with no halfwidth Katakana
  337. ;;50221 ISO 2022 Japanese with halfwidth Katakana
  338. ;;50222 ISO 2022 Japanese JIS X 0201-1989
  339. ;;50225 ISO 2022 Korean
  340. ;;50227 ISO 2022 Simplified Chinese
  341. ;;50229 ISO 2022 Traditional Chinese
  342. ;;50930 Japanese (Katakana) Extended
  343. ;;50931 US/Canada and Japanese
  344. ;;50933 Korean Extended and Korean
  345. ;;50935 Simplified Chinese Extended and Simplified Chinese
  346. ;;50936 Simplified Chinese
  347. ;;50937 US/Canada and Traditional Chinese
  348. ;;50939 Japanese (Latin) Extended and Japanese
  349. (51932 :EUC-JP) ;; EUC - Japanese
  350. ;;51936 EUC - Simplified Chinese
  351. ;;51949 EUC - Korean
  352. ;;51950 EUC - Traditional Chinese
  353. ;;52936 HZ-GB2312 Simplified Chinese
  354. ;;54936 Windows XP: GB18030 Simplified Chinese (4 Byte)
  355. ;;57002 ISCII Devanagari
  356. ;;57003 ISCII Bengali
  357. ;;57004 ISCII Tamil
  358. ;;57005 ISCII Telugu
  359. ;;57006 ISCII Assamese
  360. ;;57007 ISCII Oriya
  361. ;;57008 ISCII Kannada
  362. ;;57009 ISCII Malayalam
  363. ;;57010 ISCII Gujarati
  364. ;;57011 ISCII Punjabi
  365. ;;65000 Unicode UTF-7
  366. (65001 :UTF8))) ;; Unicode UTF-8
  367. (setf (gethash (car cp) *codepage-to-external-format*) (cadr cp)))
  368. #!+sb-unicode
  369. ;; FIXME: Something odd here: why are these two #+SB-UNICODE, whereas
  370. ;; the console just behave differently?
  371. (progn
  372. (declaim (ftype (function () keyword) ansi-codepage))
  373. (defun ansi-codepage ()
  374. (or *ansi-codepage*
  375. (setq *ansi-codepage*
  376. (gethash (alien-funcall (extern-alien "GetACP" (function UINT)))
  377. *codepage-to-external-format*
  378. :latin-1))))
  379. (declaim (ftype (function () keyword) oem-codepage))
  380. (defun oem-codepage ()
  381. (or *oem-codepage*
  382. (setq *oem-codepage*
  383. (gethash (alien-funcall (extern-alien "GetOEMCP" (function UINT)))
  384. *codepage-to-external-format*
  385. :latin-1)))))
  386. ;; http://msdn.microsoft.com/library/en-us/dllproc/base/getconsolecp.asp
  387. (declaim (ftype (function () keyword) console-input-codepage))
  388. (defun console-input-codepage ()
  389. (or #!+sb-unicode
  390. (gethash (alien-funcall (extern-alien "GetConsoleCP" (function UINT)))
  391. *codepage-to-external-format*)
  392. :latin-1))
  393. ;; http://msdn.microsoft.com/library/en-us/dllproc/base/getconsoleoutputcp.asp
  394. (declaim (ftype (function () keyword) console-output-codepage))
  395. (defun console-output-codepage ()
  396. (or #!+sb-unicode
  397. (gethash (alien-funcall
  398. (extern-alien "GetConsoleOutputCP" (function UINT)))
  399. *codepage-to-external-format*)
  400. :latin-1))
  401. (define-alien-routine ("LocalFree" local-free) void
  402. (lptr (* t)))
  403. (defmacro cast-and-free (value &key (type 'system-string)
  404. (free-function 'free-alien))
  405. `(prog1 (cast ,value ,type)
  406. (,free-function ,value)))
  407. (eval-when (:compile-toplevel :load-toplevel :execute)
  408. (defmacro with-funcname ((name description) &body body)
  409. `(let
  410. ((,name (etypecase ,description
  411. (string ,description)
  412. (cons (destructuring-bind (s &optional c) ,description
  413. (format nil "~A~A" s
  414. (if c #!-sb-unicode "A" #!+sb-unicode "W" "")))))))
  415. ,@body)))
  416. (defmacro make-system-buffer (x)
  417. `(make-alien char #!+sb-unicode (ash ,x 1) #!-sb-unicode ,x))
  418. (defmacro with-handle ((var initform
  419. &key (close-operator 'close-handle))
  420. &body body)
  421. `(without-interrupts
  422. (block nil
  423. (let ((,var ,initform))
  424. (unwind-protect
  425. (with-local-interrupts
  426. ,@body)
  427. (,close-operator ,var))))))
  428. (define-alien-type pathname-buffer
  429. (array char #.(ash (1+ max_path) #!+sb-unicode 1 #!-sb-unicode 0)))
  430. (define-alien-type long-pathname-buffer
  431. #!+sb-unicode (array char 65536)
  432. #!-sb-unicode pathname-buffer)
  433. (defmacro decode-system-string (alien)
  434. `(cast (cast ,alien (* char)) system-string))
  435. ;;; FIXME: The various FOO-SYSCALL-BAR macros, and perhaps some other
  436. ;;; macros in this file, are only used in this file, and could be
  437. ;;; implemented using SB!XC:DEFMACRO wrapped in EVAL-WHEN.
  438. (defmacro syscall ((name ret-type &rest arg-types) success-form &rest args)
  439. (with-funcname (sname name)
  440. `(locally
  441. (declare (optimize (sb!c::float-accuracy 0)))
  442. (let ((result (alien-funcall
  443. (extern-alien ,sname
  444. (function ,ret-type ,@arg-types))
  445. ,@args)))
  446. (declare (ignorable result))
  447. ,success-form))))
  448. ;;; This is like SYSCALL, but if it fails, signal an error instead of
  449. ;;; returning error codes. Should only be used for syscalls that will
  450. ;;; never really get an error.
  451. (defmacro syscall* ((name &rest arg-types) success-form &rest args)
  452. (with-funcname (sname name)
  453. `(locally
  454. (declare (optimize (sb!c::float-accuracy 0)))
  455. (let ((result (alien-funcall
  456. (extern-alien ,sname (function bool ,@arg-types))
  457. ,@args)))
  458. (when (zerop result)
  459. (win32-error ,sname))
  460. ,success-form))))
  461. (defmacro with-sysfun ((func name ret-type &rest arg-types) &body body)
  462. (with-funcname (sname name)
  463. `(with-alien ((,func (function ,ret-type ,@arg-types)
  464. :extern ,sname))
  465. ,@body)))
  466. (defmacro void-syscall* ((name &rest arg-types) &rest args)
  467. `(syscall* (,name ,@arg-types) (values t 0) ,@args))
  468. (defun get-last-error-message (err)
  469. "http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/retrieving_the_last_error_code.asp"
  470. (let ((message
  471. (with-alien ((amsg (* char)))
  472. (syscall (("FormatMessage" t)
  473. dword dword dword dword dword (* (* char)) dword dword)
  474. (cast-and-free amsg :free-function local-free)
  475. (logior FORMAT_MESSAGE_ALLOCATE_BUFFER
  476. FORMAT_MESSAGE_FROM_SYSTEM
  477. FORMAT_MESSAGE_MAX_WIDTH_MASK)
  478. 0 err 0 (addr amsg) 0 0))))
  479. (and message (string-right-trim '(#\Space) message))))
  480. (defmacro win32-error (func-name &optional err)
  481. `(let ((err-code ,(or err `(get-last-error))))
  482. (declare (type (unsigned-byte 32) err-code))
  483. (error "~%Win32 Error [~A] - ~A~%~A"
  484. ,func-name
  485. err-code
  486. (get-last-error-message err-code))))
  487. (defun get-folder-namestring (csidl)
  488. "http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/shgetfolderpath.asp"
  489. (with-alien ((apath pathname-buffer))
  490. (syscall (("SHGetFolderPath" t) int handle int handle dword (* char))
  491. (concatenate 'string (decode-system-string apath) "\\")
  492. 0 csidl 0 0 (cast apath (* char)))))
  493. (defun get-folder-pathname (csidl)
  494. (parse-native-namestring (get-folder-namestring csidl)))
  495. (defun sb!unix:posix-getcwd ()
  496. (with-alien ((apath pathname-buffer))
  497. (with-sysfun (afunc ("GetCurrentDirectory" t) dword dword (* char))
  498. (let ((ret (alien-funcall afunc (1+ max_path) (cast apath (* char)))))
  499. (when (zerop ret)
  500. (win32-error "GetCurrentDirectory"))
  501. (if (> ret (1+ max_path))
  502. (with-alien ((apath (* char) (make-system-buffer ret)))
  503. (alien-funcall afunc ret apath)
  504. (cast-and-free apath))
  505. (decode-system-string apath))))))
  506. (defun sb!unix:unix-mkdir (name mode)
  507. (declare (type sb!unix:unix-pathname name)
  508. (type sb!unix:unix-file-mode mode)
  509. (ignore mode))
  510. (syscall (("CreateDirectory" t) lispbool system-string (* t))
  511. (values result (if result 0 (- (get-last-error))))
  512. name nil))
  513. (defun sb!unix:unix-rename (name1 name2)
  514. (declare (type sb!unix:unix-pathname name1 name2))
  515. (syscall (("MoveFile" t) lispbool system-string system-string)
  516. (values result (if result 0 (- (get-last-error))))
  517. name1 name2))
  518. (defun sb!unix::posix-getenv (name)
  519. (declare (type simple-string name))
  520. (with-alien ((aenv (* char) (make-system-buffer default-environment-length)))
  521. (with-sysfun (afunc ("GetEnvironmentVariable" t)
  522. dword system-string (* char) dword)
  523. (let ((ret (alien-funcall afunc name aenv default-environment-length)))
  524. (when (> ret default-environment-length)
  525. (free-alien aenv)
  526. (setf aenv (make-system-buffer ret))
  527. (alien-funcall afunc name aenv ret))
  528. (if (> ret 0)
  529. (cast-and-free aenv)
  530. (free-alien aenv))))))
  531. ;; GET-CURRENT-PROCESS
  532. ;; The GetCurrentProcess function retrieves a pseudo handle for the current
  533. ;; process.
  534. ;;
  535. ;; http://msdn.microsoft.com/library/en-us/dllproc/base/getcurrentprocess.asp
  536. (declaim (inline get-current-process))
  537. (define-alien-routine ("GetCurrentProcess" get-current-process) handle)
  538. ;;;; Process time information
  539. (defconstant 100ns-per-internal-time-unit
  540. (/ 10000000 sb!xc:internal-time-units-per-second))
  541. ;; FILETIME
  542. ;; The FILETIME structure is a 64-bit value representing the number of
  543. ;; 100-nanosecond intervals since January 1, 1601 (UTC).
  544. ;;
  545. ;; http://msdn.microsoft.com/library/en-us/sysinfo/base/filetime_str.asp?
  546. (define-alien-type FILETIME (sb!alien:unsigned 64))
  547. ;; FILETIME definition above is almost correct (on little-endian systems),
  548. ;; except for the wrong alignment if used in another structure: the real
  549. ;; definition is a struct of two dwords.
  550. ;; Let's define FILETIME-MEMBER for that purpose; it will be useful with
  551. ;; GetFileAttributesEx and FindFirstFileExW.
  552. (define-alien-type FILETIME-MEMBER
  553. (struct nil (low dword) (high dword)))
  554. (defmacro with-process-times ((creation-time exit-time kernel-time user-time)
  555. &body forms)
  556. `(with-alien ((,creation-time filetime)
  557. (,exit-time filetime)
  558. (,kernel-time filetime)
  559. (,user-time filetime))
  560. (syscall* (("GetProcessTimes") handle (* filetime) (* filetime)
  561. (* filetime) (* filetime))
  562. (progn ,@forms)
  563. (get-current-process)
  564. (addr ,creation-time)
  565. (addr ,exit-time)
  566. (addr ,kernel-time)
  567. (addr ,user-time))))
  568. (declaim (inline system-internal-real-time))
  569. (let ((epoch 0))
  570. (declare (unsigned-byte epoch))
  571. ;; FIXME: For optimization ideas see the unix implementation.
  572. (defun reinit-internal-real-time ()
  573. (setf epoch 0
  574. epoch (get-internal-real-time)))
  575. (defun get-internal-real-time ()
  576. (- (with-alien ((system-time filetime))
  577. (syscall (("GetSystemTimeAsFileTime") void (* filetime))
  578. (values (floor system-time 100ns-per-internal-time-unit))
  579. (addr system-time)))
  580. epoch)))
  581. (defun system-internal-run-time ()
  582. (with-process-times (creation-time exit-time kernel-time user-time)
  583. (values (floor (+ user-time kernel-time) 100ns-per-internal-time-unit))))
  584. (define-alien-type hword (unsigned 16))
  585. (define-alien-type systemtime
  586. (struct systemtime
  587. (year hword)
  588. (month hword)
  589. (weekday hword)
  590. (day hword)
  591. (hour hword)
  592. (minute hword)
  593. (second hword)
  594. (millisecond hword)))
  595. ;; Obtained with, but the XC can't deal with that -- but
  596. ;; it's not like the value is ever going to change...
  597. ;; (with-alien ((filetime filetime)
  598. ;; (epoch systemtime))
  599. ;; (setf (slot epoch 'year) 1970
  600. ;; (slot epoch 'month) 1
  601. ;; (slot epoch 'day) 1
  602. ;; (slot epoch 'hour) 0
  603. ;; (slot epoch 'minute) 0
  604. ;; (slot epoch 'second) 0
  605. ;; (slot epoch 'millisecond) 0)
  606. ;; (syscall (("SystemTimeToFileTime" 8) void
  607. ;; (* systemtime) (* filetime))
  608. ;; filetime
  609. ;; (addr epoch)
  610. ;; (addr filetime)))
  611. (defconstant +unix-epoch-filetime+ 116444736000000000)
  612. (defconstant +filetime-unit+ (* 100ns-per-internal-time-unit
  613. internal-time-units-per-second))
  614. (defconstant +common-lisp-epoch-filetime-seconds+ 9435484800)
  615. #!-sb-fluid
  616. (declaim (inline get-time-of-day))
  617. (defun get-time-of-day ()
  618. "Return the number of seconds and microseconds since the beginning of the
  619. UNIX epoch: January 1st 1970."
  620. (with-alien ((system-time filetime))
  621. (syscall (("GetSystemTimeAsFileTime") void (* filetime))
  622. (multiple-value-bind (sec 100ns)
  623. (floor (- system-time +unix-epoch-filetime+)
  624. (* 100ns-per-internal-time-unit
  625. internal-time-units-per-second))
  626. (values sec (floor 100ns 10)))
  627. (addr system-time))))
  628. ;; Data for FindFirstFileExW and GetFileAttributesEx
  629. (define-alien-type find-data
  630. (struct nil
  631. (attributes dword)
  632. (ctime filetime-member)
  633. (atime filetime-member)
  634. (mtime filetime-member)
  635. (size-low dword)
  636. (size-high dword)
  637. (reserved0 dword)
  638. (reserved1 dword)
  639. (long-name (array tchar #.max_path))
  640. (short-name (array tchar 14))))
  641. (define-alien-type file-attributes
  642. (struct nil
  643. (attributes dword)
  644. (ctime filetime-member)
  645. (atime filetime-member)
  646. (mtime filetime-member)
  647. (size-low dword)
  648. (size-high dword)))
  649. (define-alien-routine ("FindClose" find-close) lispbool
  650. (handle handle))
  651. (defun attribute-file-kind (dword)
  652. (if (logtest file-attribute-directory dword)
  653. :directory :file))
  654. (defun native-file-write-date (native-namestring)
  655. "Return file write date, represented as CL universal time."
  656. (with-alien ((file-attributes file-attributes))
  657. (syscall (("GetFileAttributesEx" t) lispbool
  658. system-string int file-attributes)
  659. (and result
  660. (- (floor (deref (cast (slot file-attributes 'mtime)
  661. (* filetime)))
  662. +filetime-unit+)
  663. +common-lisp-epoch-filetime-seconds+))
  664. native-namestring 0 file-attributes)))
  665. (defun native-probe-file-name (native-namestring)
  666. "Return truename \(using GetLongPathName\) as primary value,
  667. File kind as secondary.
  668. Unless kind is false, null truename shouldn't be interpreted as error or file
  669. absense."
  670. (with-alien ((file-attributes file-attributes)
  671. (buffer long-pathname-buffer))
  672. (syscall (("GetFileAttributesEx" t) lispbool
  673. system-string int file-attributes)
  674. (values
  675. (syscall (("GetLongPathName" t) dword
  676. system-string long-pathname-buffer dword)
  677. (and (plusp result) (decode-system-string buffer))
  678. native-namestring buffer 32768)
  679. (and result
  680. (attribute-file-kind
  681. (slot file-attributes 'attributes))))
  682. native-namestring 0 file-attributes)))
  683. (defun native-delete-file (native-namestring)
  684. (syscall (("DeleteFile" t) lispbool system-string)
  685. result native-namestring))
  686. (defun native-delete-directory (native-namestring)
  687. (syscall (("RemoveDirectory" t) lispbool system-string)
  688. result native-namestring))
  689. (defun native-call-with-directory-iterator (function namestring errorp)
  690. (declare (type (or null string) namestring)
  691. (function function))
  692. (when namestring
  693. (with-alien ((find-data find-data))
  694. (with-handle (handle (syscall (("FindFirstFile" t) handle
  695. system-string find-data)
  696. (if (eql result invalid-handle)
  697. (if errorp
  698. (win32-error "FindFirstFile")
  699. (return))
  700. result)
  701. (concatenate 'string
  702. namestring "*.*")
  703. find-data)
  704. :close-operator find-close)
  705. (let ((more t))
  706. (dx-flet ((one-iter ()
  707. (tagbody
  708. :next
  709. (when more
  710. (let ((name (decode-system-string
  711. (slot find-data 'long-name)))
  712. (attributes (slot find-data 'attributes)))
  713. (setf more
  714. (syscall (("FindNextFile" t) lispbool
  715. handle find-data) result
  716. handle find-data))
  717. (cond ((equal name ".") (go :next))
  718. ((equal name "..") (go :next))
  719. (t
  720. (return-from one-iter
  721. (values name
  722. (attribute-file-kind
  723. attributes))))))))))
  724. (funcall function #'one-iter)))))))
  725. ;; SETENV
  726. ;; The SetEnvironmentVariable function sets the contents of the specified
  727. ;; environment variable for the current process.
  728. ;;
  729. ;; http://msdn.microsoft.com/library/en-us/dllproc/base/setenvironmentvariable.asp
  730. (defun setenv (name value)
  731. (declare (type (or null simple-string) value))
  732. (if value
  733. (void-syscall* (("SetEnvironmentVariable" t) system-string system-string)
  734. name value)
  735. (void-syscall* (("SetEnvironmentVariable" t) system-string int-ptr)
  736. name 0)))
  737. ;; Let SETENV be an accessor for POSIX-GETENV.
  738. ;;
  739. ;; DFL: Merged this function because it seems useful to me. But
  740. ;; shouldn't we then define it on actual POSIX, too?
  741. (defun (setf sb!unix::posix-getenv) (new-value name)
  742. (if (setenv name new-value)
  743. new-value
  744. (posix-getenv name)))
  745. (defmacro c-sizeof (s)
  746. "translate alien size (in bits) to c-size (in bytes)"
  747. `(/ (alien-size ,s) 8))
  748. ;; OSVERSIONINFO
  749. ;; The OSVERSIONINFO data structure contains operating system version
  750. ;; information. The information includes major and minor version numbers,
  751. ;; a build number, a platform identifier, and descriptive text about
  752. ;; the operating system. This structure is used with the GetVersionEx function.
  753. ;;
  754. ;; http://msdn.microsoft.com/library/en-us/sysinfo/base/osversioninfo_str.asp
  755. (define-alien-type nil
  756. (struct OSVERSIONINFO
  757. (dwOSVersionInfoSize dword)
  758. (dwMajorVersion dword)
  759. (dwMinorVersion dword)
  760. (dwBuildNumber dword)
  761. (dwPlatformId dword)
  762. (szCSDVersion (array char #!-sb-unicode 128 #!+sb-unicode 256))))
  763. (defun get-version-ex ()
  764. (with-alien ((info (struct OSVERSIONINFO)))
  765. (setf (slot info 'dwOSVersionInfoSize) (c-sizeof (struct OSVERSIONINFO)))
  766. (syscall* (("GetVersionEx" t) (* (struct OSVERSIONINFO)))
  767. (values (slot info 'dwMajorVersion)
  768. (slot info 'dwMinorVersion)
  769. (slot info 'dwBuildNumber)
  770. (slot info 'dwPlatformId)
  771. (cast (slot info 'szCSDVersion) system-string))
  772. (addr info))))
  773. ;; GET-COMPUTER-NAME
  774. ;; The GetComputerName function retrieves the NetBIOS name of the local
  775. ;; computer. This name is established at system startup, when the system
  776. ;; reads it from the registry.
  777. ;;
  778. ;; http://msdn.microsoft.com/library/en-us/sysinfo/base/getcomputername.asp
  779. (declaim (ftype (function () simple-string) get-computer-name))
  780. (defun get-computer-name ()
  781. (with-alien ((aname (* char) (make-system-buffer (1+ MAX_COMPUTERNAME_LENGTH)))
  782. (length dword (1+ MAX_COMPUTERNAME_LENGTH)))
  783. (with-sysfun (afunc ("GetComputerName" t) bool (* char) (* dword))
  784. (when (zerop (alien-funcall afunc aname (addr length)))
  785. (let ((err (get-last-error)))
  786. (unless (= err ERROR_BUFFER_OVERFLOW)
  787. (win32-error "GetComputerName" err))
  788. (free-alien aname)
  789. (setf aname (make-system-buffer length))
  790. (alien-funcall afunc aname (addr length))))
  791. (cast-and-free aname))))
  792. (define-alien-routine ("SetFilePointerEx" set-file-pointer-ex) lispbool
  793. (handle handle)
  794. (offset long-long)
  795. (new-position long-long :out)
  796. (whence dword))
  797. (defun lseeki64 (handle offset whence)
  798. (multiple-value-bind (moved to-place)
  799. (set-file-pointer-ex handle offset whence)
  800. (if moved
  801. (values to-place 0)
  802. (values -1 (- (get-last-error))))))
  803. ;; File mapping support routines
  804. (define-alien-routine (#!+sb-unicode "CreateFileMappingW"
  805. #!-sb-unicode "CreateFileMappingA"
  806. create-file-mapping)
  807. handle
  808. (handle handle)
  809. (security-attributes (* t))
  810. (protection dword)
  811. (maximum-size-high dword)
  812. (maximum-size-low dword)
  813. (name system-string))
  814. (define-alien-routine ("MapViewOfFile" map-view-of-file)
  815. system-area-pointer
  816. (file-mapping handle)
  817. (desired-access dword)
  818. (offset-high dword)
  819. (offset-low dword)
  820. (size dword))
  821. (define-alien-routine ("UnmapViewOfFile" unmap-view-of-file) bool
  822. (address (* t)))
  823. (define-alien-routine ("FlushViewOfFile" flush-view-of-file) bool
  824. (address (* t))
  825. (length dword))
  826. ;; Constants for CreateFile `disposition'.
  827. (defconstant file-create-new 1)
  828. (defconstant file-create-always 2)
  829. (defconstant file-open-existing 3)
  830. (defconstant file-open-always 4)
  831. (defconstant file-truncate-existing 5)
  832. ;; access rights
  833. (defconstant access-generic-read #x80000000)
  834. (defconstant access-generic-write #x40000000)
  835. (defconstant access-generic-execute #x20000000)
  836. (defconstant access-generic-all #x10000000)
  837. (defconstant access-file-append-data #x4)
  838. (defconstant access-delete #x00010000)
  839. ;; share modes
  840. (defconstant file-share-delete #x04)
  841. (defconstant file-share-read #x01)
  842. (defconstant file-share-write #x02)
  843. ;; CreateFile (the real file-opening workhorse).
  844. (define-alien-routine (#!+sb-unicode "CreateFileW"
  845. #!-sb-unicode "CreateFileA"
  846. create-file)
  847. handle
  848. (name (c-string #!+sb-unicode #!+sb-unicode :external-format :ucs-2))
  849. (desired-access dword)
  850. (share-mode dword)
  851. (security-attributes (* t))
  852. (creation-disposition dword)
  853. (flags-and-attributes dword)
  854. (template-file handle))
  855. ;; GetFileSizeEx doesn't work with block devices :[
  856. (define-alien-routine ("GetFileSizeEx" get-file-size-ex)
  857. bool
  858. (handle handle) (file-size (signed 64) :in-out))
  859. ;; GetFileAttribute is like a tiny subset of fstat(),
  860. ;; enough to distinguish directories from anything else.
  861. (define-alien-routine (#!+sb-unicode "GetFileAttributesW"
  862. #!-sb-unicode "GetFileAttributesA"
  863. get-file-attributes)
  864. dword
  865. (name (c-string #!+sb-unicode #!+sb-unicode :external-format :ucs-2)))
  866. (define-alien-routine ("CloseHandle" close-handle) bool
  867. (handle handle))
  868. (define-alien-routine ("_open_osfhandle" real-open-osfhandle)
  869. int
  870. (handle handle)
  871. (flags int))
  872. ;; Intended to be an imitation of sb!unix:unix-open based on
  873. ;; CreateFile, as complete as possibly.
  874. ;; FILE_FLAG_OVERLAPPED is a must for decent I/O.
  875. (defun unixlike-open (path flags mode &optional revertable)
  876. (declare (type sb!unix:unix-pathname path)
  877. (type fixnum flags)
  878. (type sb!unix:unix-file-mode mode)
  879. (ignorable mode))
  880. (let* ((disposition-flags
  881. (logior
  882. (if (zerop (logand sb!unix:o_creat flags)) 0 #b100)
  883. (if (zerop (logand sb!unix:o_excl flags)) 0 #b010)
  884. (if (zerop (logand sb!unix:o_trunc flags)) 0 #b001)))
  885. (create-disposition
  886. ;; there are 8 combinations of creat|excl|trunc, some of
  887. ;; them are equivalent. Case stmt below maps them to 5
  888. ;; dispositions (see CreateFile manual).
  889. (case disposition-flags
  890. ((#b110 #b111) file-create-new)
  891. ((#b001 #b011) file-truncate-existing)
  892. ((#b000 #b010) file-open-existing)
  893. (#b100 file-open-always)
  894. (#b101 file-create-always))))
  895. (let ((handle
  896. (create-file path
  897. (logior
  898. (if revertable #x10000 0)
  899. (if (plusp (logand sb!unix:o_append flags))
  900. access-file-append-data
  901. 0)
  902. (ecase (logand 3 flags)
  903. (0 FILE_GENERIC_READ)
  904. (1 FILE_GENERIC_WRITE)
  905. ((2 3) (logior FILE_GENERIC_READ
  906. FILE_GENERIC_WRITE))))
  907. (logior FILE_SHARE_READ
  908. FILE_SHARE_WRITE)
  909. nil
  910. create-disposition
  911. (logior
  912. file-attribute-normal
  913. file-flag-overlapped
  914. file-flag-sequential-scan)
  915. 0)))
  916. (if (eql handle invalid-handle)
  917. (values nil
  918. (let ((error-code (get-last-error)))
  919. (case error-code
  920. (#.error_file_not_found
  921. sb!unix:enoent)
  922. ((#.error_already_exists #.error_file_exists)
  923. sb!unix:eexist)
  924. (otherwise (- error-code)))))
  925. (progn
  926. ;; FIXME: seeking to the end is not enough for real APPEND
  927. ;; semantics, but it's better than nothing.
  928. ;; -- AK
  929. ;;
  930. ;; On the other hand, the CL spec implies the "better than
  931. ;; nothing" seek-once semantics implemented here, and our
  932. ;; POSIX backend is incorrect in implementing :APPEND as
  933. ;; O_APPEND. Other CL implementations get this right across
  934. ;; platforms.
  935. ;;
  936. ;; Of course, it would be nice if we had :IF-EXISTS
  937. ;; :ATOMICALLY-APPEND separately as an extension, and in
  938. ;; that case, we will have to worry about supporting it
  939. ;; here after all.
  940. ;;
  941. ;; I've tested this only very briefly (on XP and Windows 7),
  942. ;; but my impression is that WriteFile (without documenting
  943. ;; it?) is like ZwWriteFile, i.e. if we pass in -1 as the
  944. ;; offset in our overlapped structure, WriteFile seeks to the
  945. ;; end for us. Should we depend on that? How do we communicate
  946. ;; our desire to do so to the runtime?
  947. ;; -- DFL
  948. ;;
  949. (set-file-pointer-ex handle 0 (if (plusp (logand sb!unix::o_append flags)) 2 0))
  950. (values handle 0))))))
  951. (define-alien-routine ("closesocket" close-socket) int (handle handle))
  952. (define-alien-routine ("shutdown" shutdown-socket) int (handle handle)
  953. (how int))
  954. (define-alien-routine ("DuplicateHandle" duplicate-handle) lispbool
  955. (from-process handle)
  956. (from-handle handle)
  957. (to-process handle)
  958. (to-handle handle :out)
  959. (access dword)
  960. (inheritp lispbool)
  961. (options dword))
  962. (defconstant +handle-flag-inherit+ 1)
  963. (defconstant +handle-flag-protect-from-close+ 2)
  964. (define-alien-routine ("SetHandleInformation" set-handle-information) lispbool
  965. (handle handle)
  966. (mask dword)
  967. (flags dword))
  968. (define-alien-routine ("GetHandleInformation" get-handle-information) lispbool
  969. (handle handle)
  970. (flags dword :out))
  971. (define-alien-routine getsockopt int
  972. (handle handle)
  973. (level int)
  974. (opname int)
  975. (dataword int-ptr :in-out)
  976. (socklen int :in-out))
  977. (defconstant sol_socket #xFFFF)
  978. (defconstant so_type #x1008)
  979. (defun socket-handle-p (handle)
  980. (zerop (getsockopt handle sol_socket so_type 0 (alien-size int :bytes))))
  981. (defconstant ebadf 9)
  982. ;;; For sockets, CloseHandle first and closesocket() afterwards is
  983. ;;; legal: winsock tracks its handles separately (that's why we have
  984. ;;; the problem with simple _close in the first place).
  985. ;;;
  986. ;;; ...Seems to be the problem on some OSes, though. We could
  987. ;;; duplicate a handle and attempt close-socket on a duplicated one,
  988. ;;; but it also have some problems...
  989. (defun unixlike-close (fd)
  990. (if (or (zerop (close-socket fd))
  991. (close-handle fd))
  992. t (values nil ebadf)))
  993. (defconstant +std-input-handle+ -10)
  994. (defconstant +std-output-handle+ -11)
  995. (defconstant +std-error-handle+ -12)
  996. (defun get-std-handle-or-null (identity)
  997. (let ((handle (alien-funcall
  998. (extern-alien "GetStdHandle" (function handle dword))
  999. (logand (1- (ash 1 (alien-size dword))) identity))))
  1000. (and (/= handle invalid-handle)
  1001. (not (zerop handle))
  1002. handle)))
  1003. (defun get-std-handles ()
  1004. (values (get-std-handle-or-null +std-input-handle+)
  1005. (get-std-handle-or-null +std-output-handle+)
  1006. (get-std-handle-or-null +std-error-handle+)))
  1007. (defconstant +duplicate-same-access+ 2)
  1008. (defun duplicate-and-unwrap-fd (fd &key inheritp)
  1009. (let ((me (get-current-process)))
  1010. (multiple-value-bind (duplicated handle)
  1011. (duplicate-handle me (real-get-osfhandle fd)
  1012. me 0 inheritp +duplicate-same-access+)
  1013. (if duplicated
  1014. (prog1 handle (real-crt-close fd))
  1015. (win32-error 'duplicate-and-unwrap-fd)))))
  1016. (define-alien-routine ("CreatePipe" create-pipe) lispbool
  1017. (read-pipe handle :out)
  1018. (write-pipe handle :out)
  1019. (security-attributes (* t))
  1020. (buffer-size dword))
  1021. (defun windows-pipe ()
  1022. (multiple-value-bind (created read-handle write-handle)
  1023. (create-pipe nil 256)
  1024. (if created (values read-handle write-handle)
  1025. (win32-error 'create-pipe))))
  1026. (defun windows-isatty (handle)
  1027. (if (= file-type-char (get-file-type handle))
  1028. 1 0))
  1029. (defun inheritable-handle-p (handle)
  1030. (multiple-value-bind (got flags)
  1031. (get-handle-information handle)
  1032. (if got (plusp (logand flags +handle-flag-inherit+))
  1033. (win32-error 'inheritable-handle-p))))
  1034. (defun (setf inheritable-handle-p) (allow handle)
  1035. (if (set-handle-information handle
  1036. +handle-flag-inherit+
  1037. (if allow +handle-flag-inherit+ 0))
  1038. allow
  1039. (win32-error '(setf inheritable-handle-p))))
  1040. (defun sb!unix:unix-dup (fd)
  1041. (let ((me (get-current-process)))
  1042. (multiple-value-bind (duplicated handle)
  1043. (duplicate-handle me fd me 0 t +duplicate-same-access+)
  1044. (if duplicated
  1045. (values handle 0)
  1046. (values nil (- (get-last-error)))))))
  1047. (defun call-with-crt-fd (thunk handle &optional (flags 0))
  1048. (multiple-value-bind (duplicate errno)
  1049. (sb!unix:unix-dup handle)
  1050. (if duplicate
  1051. (let ((fd (real-open-osfhandle duplicate flags)))
  1052. (unwind-protect (funcall thunk fd)
  1053. (real-crt-close fd)))
  1054. (values nil errno))))