我一直在ChezScheme中使用一段简单的FFI代码 获取程序正在运行的终端仿真器的行数和列数。该过程在使用 x86 版本的 Chez (9.5.8) 运行时有效。
但是,我最近改用了基于 Apple Silicon 的 开发机器和代码不再返回正确答案。苹果机上使用的Chez版本是 9.9.9-预发布-20.
相同的代码加载并运行没有错误,但总是返回 无论终端窗口的实际大小如何,都为
(0 0)
的大小。我无法访问基于 Intel 的机器来确保某些更改不会潜入某个地方,但我没有看到它,并且在该过程所在的任何版本控制存储库中它都没有出现不同使用过。
这是代码:
;;; win-size-demo.ss -- Procedure to return the size (in rows and columns)
;;; of the terminal it is running in.
(import (chezscheme))
;; Load the C runtime library. Only tested on macOS. The other clauses
;; were taken from examples in other files of the Chez Scheme
;; source distribution.
(case (machine-type)
[(i3le ti3le a6le ta6le) (load-shared-object "libc.so.6")]
[(i3osx ti3osx a6osx ta6osx) (load-shared-object "libc.dylib")]
[(i3nt ti3nt a6nt ta6nt) (begin (load-shared-object "msvcrt.dll")
(load-shared-object "kernel32.dll"))]
;; The following is a new addition for Apple Silicon systems.
[(arm64osx tarm64osx) (load-shared-object "libSystem.dylib")]
[else (load-shared-object "libc.so")])
;; The preferred way to interrogate the window size is through the
;; `ioctl` function from the underlying C implementation. Here's
;; how that (used to) works.
;; Define some file descriptors for stdin/out. Couldn't find this
;; documented anywhere. These values are from Chez expediter.c.
(define STDIN_FD 0)
(define STDOUT_FD 1)
;; Value from /Library/Developer/CommandLineTools/SDKs/MacOSX13.3.sdk/usr/includes/sys/ttycom.h.
;; This value is caclulated via a C macro in <sys/ioccom.h>.
(define TIOCGWINSZ #x40087468)
;; From <sys/ttycom.h>.
(define-ftype win-size
(struct
[ws-row unsigned-short] ; number of rows in the window, in characters
[ws-col unsigned-short] ; number of columns in the window, in characters
[ws-xpixel unsigned-short] ; horizontal size of the window, in pixels
[ws-ypixel unsigned-short] ; vertical size of the window, in pixels
))
(define ioctl (foreign-procedure "ioctl" (int int (* win-size)) int))
(define errno (foreign-procedure "(cs)s_errno" () int))
(define strerror (foreign-procedure "(cs)s_strerror" (int) scheme-object))
;; Return the size of the terminal window using the `ioctl` function
;; from the underlying C library.
(define (window-size)
(let* ((win-size-buf (foreign-alloc (ftype-sizeof win-size)))
(win-size-ptr (make-ftype-pointer win-size win-size-buf)))
(let ((the-size (dynamic-wind
(lambda () #f)
(lambda () (let ((ctl-result (ioctl STDIN_FD TIOCGWINSZ win-size-ptr)))
(if (negative? ctl-result)
(let ((cep (current-error-port)))
(display "Error getting display size.\n" cep)
(display (strerror (errno)) cep)
(newline cep)
(list -1 -1))
(list (ftype-ref win-size (ws-row) win-size-ptr)
(ftype-ref win-size (ws-col) win-size-ptr)))))
(lambda () (foreign-free win-size-buf)))))
the-size)))
阅读 Chez Scheme 9.9.9 的发行说明,有关 FFI 更改的部分似乎不会产生任何影响。但显然我错过了一些东西。
对于 Chez Scheme 9.9.9 及更高版本,您必须显式声明 varargs 函数,如 ioctl:
(定义ioctl(外部过程(__varargs_after 2)“ioctl”(int int(* win-size))int))
此外,您可以将 libc.dylib 用于 arm64osx 和 tarm64osx,因此不需要在 case 语句中单独添加一行。