Skip to content

Commit d6fc05a

Browse files
Implement openkal.terminal, and follow openkal 0.8 (#13)
* ci: 把引导阶段绑定指名的 glibc 载荷装给它(过渡步骤) `xim:glibc` 的 `latest` 从 `2.44` 移到了 `2.44.2`。载荷目录按请求**解析成**的版本 命名,而 RuntimeBinding 带的是**声明的**版本 —— 而一个已发布的 mcpp vendor 进自己 沙箱的那份 xlings 仍然声明 `2.44`。于是干净机器装出 `2.44.2`,工具链 fixup 要 `2.44`,构建在编译任何东西之前就停住: error: selected RuntimeBinding glibc@2.44 requires payload '.../xpkgs/xim-x-glibc/2.44', but it is not installed ⚠️ 在每一台**新**机器上出现,在任何已存在的机器上都不出现 —— 所以开发机看不见。 索引的 `pkgs/g/glibc.lua` 把这次失败逐字记着,并给出规则: 「The index is DATA and the client is a PROGRAM: the consumer ships first。」 ## ⚠️ 我先试过 bump xlings,撤回了 把 `XLINGS_VERSION` 提到 2026.8.27.1 会让**沙箱里那份** xlings 被换掉 (mcpp 的 `acquire_xlings_binary` 在 pin 前移时更新它),绑定于是**前移**到 `glibc@2.44.2`,而已经装好的是 `2.44` —— 请求比已装的**更新**。那是更糟的一侧: 接受一个更旧的载荷去回答更新的请求,等于静默用上索引明说 「IT IS NOT THE ONE TO INSTALL」的那份(带 mcpp#484 的 preload 缺陷)。 ⇒ 保持 xlings 不动,把缺的那个载荷直接装上。 ⭐ 待 mcpp 2026.8.27.1(mcpp-community/mcpp#515)发布后移除:它接受 「版本精化了请求」的已装载荷,从它引导就不需要这一步。 * Implement openkal.terminal, and follow openkal 0.8 The console operations this environment offers map onto the interface directly: ENABLE_LINE_INPUT is what openkal.terminal calls line editing and ENABLE_ECHO_INPUT is what it calls echo, which is the same division the interface draws. GetConsoleMode is already what kal_stream_props asks, so a stream that is not a console is reported as unsupported by the same test. The mode is read, modified and written rather than written alone. The console mode carries processed input, mouse input, window input and virtual terminal processing, none of which the interface names; a word composed from the two positions alone would turn all of them off, and a program that asked only to stop echoing would find its console changed in ways it did not ask for. kal_terminal_size reports the WINDOW and not the buffer. This environment's screen buffer may be taller than the window that shows it, and a program drawing a full screen against the buffer's height would scroll its own output away. The other four interfaces version 0.8 adds are not provided, which clause 6.1 makes an absence at the link rather than a deviation. * Provide the three operations openkal 0.8 adds to openkal.process ADDING TO AN EXISTING INTERFACE OBLIGES EVERY IMPLEMENTATION OF IT, and adding a new interface obliges none. Clause 6.1 makes an interface a backend does not provide absent at the link and not a deviation; it makes one provided IN PART a deviation. The five interfaces version 0.8 adds are therefore free to decline, and the three names added to openkal.process are not. The specification's own surface checker said so before anything else noticed: openkal.process is provided in part: 3 of 8 names are not exported -- kal_process_channel kal_process_channel_close kal_process_spawn_with kal_process_channel is CreatePipe. THIS ENVIRONMENT DECIDES INHERITANCE PER HANDLE AND NOT PER EXEC, which is the opposite of the other two: there every handle is inherited unless marked otherwise, so those implementations mark both ends close-on-exec and let the spawn place the far one. Here the default is not to inherit, so the far end is created inheritable and the near end is withdrawn afterwards --- otherwise the started program would hold both ends and the writer would never observe the end of input. kal_process_spawn_with refuses a non-empty set of grants, and the refusal is the honest answer rather than a gap. A preopened directory is a handle a started program reads back by NUMBER, and this environment has no numbering: a handle crosses a spawn by being inheritable, and the started program learns of it through a mechanism the parent arranges. There is no correspondence to descriptor three. Clause 6.2 is what makes that conforming: the operation exists, reports kal_err_not_supported, and the property word does not claim KAL_PROCESS_PROP_GRANT_DIR --- so a caller learns from the word what it would otherwise learn from a failed call. A count of zero is still answered, by the ordinary spawn, because a program with no preopens is what this environment starts anyway. * Export the three names the new declarations call `port/*.def` is an explicit list, and the import library generated from it contains exactly those names. I added three declarations to `src/win32.h` for openkal 0.8 and did not add the names, so the import library this package generates for its consumers was missing them. ⚠️ AND THIS PACKAGE'S OWN CI STAYED GREEN, because this package does not link. The failure appeared one repository away, in openkal-llvm-runtime's cross-build: ld.lld: error: undefined symbol: __declspec(dllimport) CreatePipe ld.lld: error: undefined symbol: __declspec(dllimport) GetConsoleScreenBufferInfo ld.lld: error: undefined symbol: __declspec(dllimport) SetConsoleMode which reads as a defect in the consumer and is nothing of the kind. ⭐ IT WAS FOUND BY COMPARING IMPORT LIBRARIES, NOT BY READING THE ERROR. Every copy of a vendor `libkernel32.a` on the machine had all three; the one generated here had `GetConsoleMode` and not `SetConsoleMode`, which is not a shape a vendor's library takes and pointed straight at the generated list. The check added here is the one that would have caught it: every name `src/win32.h` declares must be exported by some `.def`. It belongs in this repository, where the two lists are, rather than in the consumer that trips over the difference. Measured both ways: removing `CreatePipe` from the list makes it red and names the symbol; the lists as committed are 42 declared, 49 exported, none missing. A denominator is asserted on both sides, since two empty lists have an empty difference too. * ci: name the encoding the check reads its sources in Python opens a file with the platform's default encoding, which on the Windows runner is cp1252, and these sources are UTF-8: UnicodeDecodeError: 'charmap' codec can't decode byte 0x90 in position 90 A check that reads source files must say what they are encoded in, or it reports on the runner's locale rather than on the sources. The byte it stopped at is in a comment marker, so the check would have passed on a repository whose comments happened to be ASCII and failed on this one --- which is the least useful place for a difference to appear. Both reads name utf-8. Rehearsed locally under cp1252: 42 declared, 49 exported, none missing. * Name the released specification and the released engine openkal 0.8.0 is published, so the manifest names it by version rather than by branch. A branch is how a change spanning these repositories is developed and is not a form a published package may carry: a consumer resolving from the index would be handed a reference that moves. The engine pin moves to mcpp 2026.8.27.1 and the repository variable MCPP_SOURCE_REF is cleared, so what this repository tests is the engine a user installs. --------- Co-authored-by: speak-agent <x.d2learn.org@gmail.com>
1 parent 4ac8d37 commit d6fc05a

6 files changed

Lines changed: 289 additions & 4 deletions

File tree

.github/workflows/ci.yml

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ on:
2626
default: ""
2727
env:
2828
MCPP_SOURCE_REF: ${{ github.event.inputs.mcpp_ref || vars.MCPP_SOURCE_REF }}
29-
MCPP_VERSION: 2026.8.26.2
29+
MCPP_VERSION: 2026.8.27.1
3030
XLINGS_VERSION: v2026.8.17.2
3131
XLINGS_NON_INTERACTIVE: '1'
3232

@@ -82,6 +82,34 @@ jobs:
8282
else
8383
xlings install "mcpp@$MCPP_VERSION" -y -g
8484
fi
85+
# ⚠️⚠️ TRANSITION: GIVE THE BOOTSTRAP THE glibc ITS BINDING NAMES.
86+
#
87+
# `xim:glibc`'s `latest` moved from `2.44` to `2.44.2`. A payload
88+
# directory is named after the version a request RESOLVED to, while a
89+
# RuntimeBinding carries the version that was DECLARED — and the xlings
90+
# a released mcpp vendors into its own sandbox still declares `2.44`.
91+
# So a clean machine installs `2.44.2`, the toolchain fixup asks for
92+
# `2.44`, and the build stops before anything is compiled:
93+
#
94+
# error: selected RuntimeBinding glibc@2.44 requires payload
95+
# '…/xpkgs/xim-x-glibc/2.44', but it is not installed
96+
#
97+
# ⚠️ On every NEW machine and on none that already existed, which is why
98+
# it is invisible from a developer's own. Measured on `main` as readily
99+
# as on any branch — the index records the same failure verbatim in
100+
# `pkgs/g/glibc.lua` and states the rule it broke: "The index is DATA
101+
# and the client is a PROGRAM: the consumer ships first."
102+
#
103+
# ⭐ REMOVE THIS once a released mcpp resolves it. `mcpp 2026.8.27.1`
104+
# accepts an installed payload whose version REFINES the requested one
105+
# (`payload_dir_for_version`), so a bootstrap from it needs nothing
106+
# here. Until then the missing payload is simply installed.
107+
if [ -x "$HOME/.mcpp/registry/bin/xlings" ]; then
108+
XLINGS_HOME="$HOME/.mcpp/registry" XLINGS_NON_INTERACTIVE=1 \
109+
"$HOME/.mcpp/registry/bin/xlings" install glibc@2.44 -y -g \
110+
>/dev/null 2>&1 || true
111+
echo "glibc payloads present: $(ls "$HOME/.mcpp/registry/data/xpkgs/xim-x-glibc" 2>/dev/null | tr '\n' ' ')"
112+
fi
85113
mcpp --version
86114
mcpp self config --mirror GLOBAL
87115
# ⭐⭐ CROSS-VALIDATION: BUILD THE mcpp UNDER REVIEW AND USE THAT ONE.
@@ -135,6 +163,55 @@ jobs:
135163
echo "under review: $("$built" --version) (from $MCPP_SOURCE_REF)"
136164
fi
137165
166+
# EVERY NAME THE HEADER DECLARES IS EXPORTED BY ONE OF THE .def FILES.
167+
#
168+
# `port/*.def` is an explicit list, and an import library generated from it
169+
# contains exactly those names. So a declaration added to `src/win32.h`
170+
# without a matching line in a `.def` compiles, and fails at the link of a
171+
# CONSUMER --- not of this package, which does not link.
172+
#
173+
# ⚠️ MEASURED. Three declarations were added for openkal 0.8 and the names
174+
# were not, and this package's own CI stayed green: the failure appeared in
175+
# openkal-llvm-runtime's cross-build, one repository away, as
176+
#
177+
# ld.lld: error: undefined symbol: __declspec(dllimport) CreatePipe
178+
#
179+
# which reads as a defect in the consumer. The check belongs here, where
180+
# the two lists are.
181+
- name: Every declared name is exported by a .def
182+
run: |
183+
python3 - <<'PY'
184+
import glob, os, re, sys
185+
# ⚠️ THE ENCODING IS NAMED. Python opens a file with the platform's
186+
# default, which on this runner is cp1252, and these sources are UTF-8:
187+
#
188+
# UnicodeDecodeError: 'charmap' codec can't decode byte 0x90
189+
#
190+
# A check that reads source files must say what they are encoded in, or
191+
# it reports on the runner's locale.
192+
declared = set(re.findall(r'OKW_IMPORT\s+\w+\s+OKW_API\s+(\w+)\s*\(',
193+
open("src/win32.h", encoding="utf-8").read()))
194+
exported = set()
195+
for f in glob.glob("port/*.def"):
196+
body = open(f, encoding="utf-8").read().split("EXPORTS", 1)
197+
if len(body) < 2: continue
198+
exported |= {l.strip() for l in body[1].split("\n")
199+
if l.strip() and not l.lstrip().startswith(';')}
200+
# A denominator on both sides: with either list empty the difference is
201+
# vacuously empty too.
202+
if not declared or not exported:
203+
print(f"::error::declared={len(declared)} exported={len(exported)}; nothing was compared")
204+
sys.exit(1)
205+
missing = sorted(declared - exported)
206+
print(f" {len(declared)} declared, {len(exported)} exported across "
207+
f"{len(glob.glob('port/*.def'))} .def files")
208+
if missing:
209+
print("::error::declared in src/win32.h and exported by no .def:")
210+
for m in missing: print(f" {m}")
211+
sys.exit(1)
212+
print(" ok every declared name is exported")
213+
PY
214+
138215
- name: Select the toolchain
139216
run: |
140217
spec='${{ matrix.toolchain }}'

mcpp.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
namespace = "mcpplibs"
33
name = "openkal-windows"
4-
version = "0.1.5"
4+
version = "0.2.0"
55
description = "An implementation of openkal for Windows, written on the Win32 interfaces and the object manager beneath them, using no C runtime symbol."
66
license = "Apache-2.0"
77

@@ -18,7 +18,7 @@ authors = ["mcpplibs"]
1818
repo = "https://github.com/mcpplibs/openkal-windows"
1919

2020
[dependencies]
21-
openkal = "0.7.0"
21+
openkal = "0.8.0"
2222

2323
# The package contributes definitions and no modules. The interface it
2424
# implements is declared by the specification package, which this package

port/kernel32.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ LIBRARY KERNEL32.dll
66
EXPORTS
77
CloseHandle
88
CreateFileW
9+
CreatePipe
910
CreateProcessW
1011
CreateThread
1112
FlushFileBuffers
1213
FreeEnvironmentStringsW
1314
GetCommandLineW
1415
GetConsoleMode
16+
GetConsoleScreenBufferInfo
1517
GetCurrentDirectoryW
1618
GetCurrentProcess
1719
GetCurrentThreadId
@@ -31,6 +33,7 @@ MultiByteToWideChar
3133
QueryPerformanceCounter
3234
QueryPerformanceFrequency
3335
ReadFile
36+
SetConsoleMode
3437
SetFilePointerEx
3538
SetHandleInformation
3639
Sleep

src/process.cpp

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,81 @@ int kal_process_spawn(kal_dir base,
177177
return kal_ok;
178178
}
179179

180+
// A channel: a pair of streams of which one end is meant to cross a spawn.
181+
//
182+
// THIS ENVIRONMENT DECIDES INHERITANCE PER HANDLE AND NOT PER EXEC, which is the
183+
// opposite of the other two and is why the far end is created inheritable while
184+
// the near end is not. On a descriptor system every handle is inherited unless
185+
// marked otherwise, so those implementations mark the ends close-on-exec and let
186+
// the spawn place the far one deliberately. Here the default is not to inherit,
187+
// so the far end must be marked to be inheritable and the near end must be left
188+
// alone --- otherwise the started program would hold both ends and the writer
189+
// would never observe the end of input.
190+
int kal_process_channel(kal_stream* mine, kal_stream* theirs) {
191+
if (mine == nullptr || theirs == nullptr) return kal_err_invalid;
192+
193+
SECURITY_ATTRIBUTES sa{};
194+
sa.nLength = sizeof sa;
195+
sa.bInheritHandle = TRUE;
196+
197+
HANDLE reading = nullptr, writing = nullptr;
198+
if (!CreatePipe(&reading, &writing, &sa, 0))
199+
return okw::translate_win32(GetLastError());
200+
201+
// The near end is withdrawn from inheritance after the fact, because
202+
// CreatePipe applies one set of attributes to both.
203+
SetHandleInformation(reading, HANDLE_FLAG_INHERIT, 0);
204+
205+
// Bare handles rather than packed ones, because openkal.stream's transfer
206+
// operations take what this environment takes. kal_fs_stream reports a
207+
// file's stream the same way and for the same reason.
208+
*mine = kal_stream{ reinterpret_cast<kal_uintptr>(reading) };
209+
*theirs = kal_stream{ reinterpret_cast<kal_uintptr>(writing) };
210+
return kal_ok;
211+
}
212+
213+
void kal_process_channel_close(kal_stream s) {
214+
void* h = reinterpret_cast<void*>(s.h);
215+
if (h == nullptr || h == INVALID_HANDLE_VALUE) return;
216+
// The standard streams are borrowed. Closing one through this operation
217+
// would take a stream away from the whole program.
218+
if (h == GetStdHandle(STD_INPUT_HANDLE) ||
219+
h == GetStdHandle(STD_OUTPUT_HANDLE) ||
220+
h == GetStdHandle(STD_ERROR_HANDLE)) return;
221+
CloseHandle(h);
222+
}
223+
224+
// Starting a program that receives exactly the directories named.
225+
//
226+
// ⚠️ NOT PROVIDED, AND THE REFUSAL IS THE HONEST ANSWER RATHER THAN A GAP. A
227+
// preopened directory is a handle a started program reads back through
228+
// kal_fs_preopen by NUMBER, and this environment has no numbering: a handle
229+
// crosses a spawn by being inheritable, and the started program learns of it
230+
// through a mechanism the parent has to arrange itself. There is no
231+
// correspondence here to descriptor three.
232+
//
233+
// Clause 6.2 is what makes the refusal conforming rather than a deviation: the
234+
// operation exists, reports kal_err_not_supported, and the property word does
235+
// not claim KAL_PROCESS_PROP_GRANT_DIR. A caller therefore learns from the word
236+
// what it would otherwise learn from a failed call.
237+
int kal_process_spawn_with(kal_dir base,
238+
const char* path, kal_uintptr path_len,
239+
const char** argv, const kal_uintptr* argv_lens, kal_uintptr argc,
240+
const char** envp, const kal_uintptr* envp_lens, kal_uintptr envc,
241+
const kal_spawn_streams* streams,
242+
const kal_preopen* grants, kal_uintptr grant_count,
243+
kal_process* out) {
244+
// A count of zero asks for a program with no preopens, which this
245+
// environment gives a started program anyway --- it has none to pass. That
246+
// request is therefore answerable, and is answered by the ordinary spawn.
247+
if (grant_count == 0)
248+
return kal_process_spawn(base, path, path_len,
249+
argv, argv_lens, argc,
250+
envp, envp_lens, envc, streams, out);
251+
(void)grants;
252+
return kal_err_not_supported;
253+
}
254+
180255
int kal_process_wait(kal_process p, int* status, int* terminated) {
181256
void* h = okw::unpack(p.h);
182257
if (!h) return kal_err_invalid;
@@ -212,8 +287,12 @@ void kal_process_close(kal_process p) {
212287
if (h) { okw::retire(p.h); CloseHandle(h); }
213288
}
214289

290+
// KAL_PROCESS_PROP_GRANT_DIR is deliberately absent: kal_process_spawn_with
291+
// refuses a non-empty set of grants here, and a word claiming a facility the
292+
// next call refuses is the disagreement clause 6.2 exists to prevent.
215293
const kal_uintptr kal_process_props =
216294
KAL_PROCESS_PROP_TERMINATE | KAL_PROCESS_PROP_STREAM_PASSING
217-
| KAL_PROCESS_PROP_EXIT_STATUS;
295+
| KAL_PROCESS_PROP_EXIT_STATUS
296+
| KAL_PROCESS_PROP_CHANNEL;
218297

219298
}

src/terminal.cpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#include "win32.h"
2+
#include <openkal/terminal.h>
3+
4+
// openkal.terminal upon this environment's console operations.
5+
//
6+
// THE TWO POSITIONS THIS INTERFACE DEFINES ARE TWO CONSOLE FLAGS, AND THEY ARE
7+
// NOT THE SAME TWO A UNIX TERMINAL HAS. This environment assembles lines under
8+
// ENABLE_LINE_INPUT and shows what is typed under ENABLE_ECHO_INPUT, which is
9+
// the same division openkal.terminal draws; what differs is that the flags live
10+
// on the INPUT handle and this interface takes a stream. A caller asking about
11+
// the output handle is answered for the output handle, which reports neither
12+
// position, and that is correct rather than a limitation: the mode of an output
13+
// console is not what the interface asks about.
14+
15+
namespace {
16+
17+
void* handle_of(kal_stream s) { return reinterpret_cast<void*>(s.h); }
18+
bool valid(void* h) { return h != nullptr && h != INVALID_HANDLE_VALUE; }
19+
20+
// This environment's console input flags.
21+
constexpr DWORD enable_line_input = 0x0002;
22+
constexpr DWORD enable_echo_input = 0x0004;
23+
24+
} // namespace
25+
26+
extern "C" {
27+
28+
int kal_terminal_get_mode(kal_stream s, kal_uintptr* mode) {
29+
if (mode == nullptr) return kal_err_invalid;
30+
void* h = handle_of(s);
31+
if (!valid(h)) return kal_err_invalid;
32+
33+
DWORD m = 0;
34+
// Reading a console's mode succeeds for a console and fails otherwise, which
35+
// is the same enquiry kal_stream_props performs. A stream that is not a
36+
// console is therefore reported as unsupported rather than as an error of
37+
// this environment.
38+
if (!GetConsoleMode(h, &m)) return kal_err_not_supported;
39+
40+
kal_uintptr out = 0;
41+
if ((m & enable_line_input) != 0) out |= KAL_TERM_LINE_EDIT;
42+
if ((m & enable_echo_input) != 0) out |= KAL_TERM_ECHO;
43+
*mode = out;
44+
return kal_ok;
45+
}
46+
47+
int kal_terminal_set_mode(kal_stream s, kal_uintptr mode) {
48+
void* h = handle_of(s);
49+
if (!valid(h)) return kal_err_invalid;
50+
51+
// READ, MODIFY, WRITE. The console mode carries processed input, mouse
52+
// input, window input and virtual terminal processing, none of which this
53+
// interface names. Writing a word composed from the two positions alone
54+
// would turn all of them off, and a program that asked only to stop echoing
55+
// would find its console changed in ways it did not ask for.
56+
DWORD m = 0;
57+
if (!GetConsoleMode(h, &m)) return kal_err_not_supported;
58+
59+
if ((mode & KAL_TERM_LINE_EDIT) != 0) m |= enable_line_input;
60+
else m &= ~enable_line_input;
61+
if ((mode & KAL_TERM_ECHO) != 0) m |= enable_echo_input;
62+
else m &= ~enable_echo_input;
63+
64+
// A position this implementation does not distinguish is ignored rather than
65+
// refused, which clause 6.2 requires of a word.
66+
if (!SetConsoleMode(h, m)) return kal_err_not_supported;
67+
return kal_ok;
68+
}
69+
70+
int kal_terminal_size(kal_stream s, kal_uintptr* cols, kal_uintptr* rows) {
71+
if (cols == nullptr || rows == nullptr) return kal_err_invalid;
72+
void* h = handle_of(s);
73+
if (!valid(h)) return kal_err_invalid;
74+
75+
CONSOLE_SCREEN_BUFFER_INFO_ info{};
76+
// Both outputs are left untouched on failure, which the interface requires.
77+
if (!GetConsoleScreenBufferInfo(h, &info)) return kal_err_not_supported;
78+
79+
// THE WINDOW AND NOT THE BUFFER. This environment's screen buffer may be
80+
// taller than the window that shows it, and a program drawing a full screen
81+
// against the buffer's height would scroll its own output away. The window
82+
// is what a caller asking for the size of the display means.
83+
*cols = static_cast<kal_uintptr>(info.srWindow.Right - info.srWindow.Left + 1);
84+
*rows = static_cast<kal_uintptr>(info.srWindow.Bottom - info.srWindow.Top + 1);
85+
return kal_ok;
86+
}
87+
88+
kal_uintptr kal_terminal_props(kal_stream s) {
89+
void* h = handle_of(s);
90+
if (!valid(h)) return 0;
91+
92+
kal_uintptr p = 0;
93+
94+
DWORD m = 0;
95+
if (GetConsoleMode(h, &m)) p |= KAL_TERM_PROP_MODE;
96+
97+
// Asked for rather than derived from the first: an input console answers the
98+
// mode and not the size, and an output console answers the size and not the
99+
// mode. Deriving either from the other would make the word claim a facility
100+
// the next call refuses.
101+
CONSOLE_SCREEN_BUFFER_INFO_ info{};
102+
if (GetConsoleScreenBufferInfo(h, &info)) p |= KAL_TERM_PROP_SIZE;
103+
104+
return p;
105+
}
106+
107+
} // extern "C"

src/win32.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,26 @@ OKW_IMPORT BOOL OKW_API CloseHandle(HANDLE);
244244
OKW_IMPORT DWORD OKW_API GetLastError(void);
245245
OKW_IMPORT DWORD OKW_API GetFileType(HANDLE);
246246
OKW_IMPORT BOOL OKW_API SetHandleInformation(HANDLE, DWORD, DWORD);
247+
// For kal_process_channel. The security attributes decide whether the ends are
248+
// inheritable, which is what makes one of them able to cross a spawn.
249+
OKW_IMPORT BOOL OKW_API CreatePipe(HANDLE*, HANDLE*, SECURITY_ATTRIBUTES*, DWORD);
247250
OKW_IMPORT BOOL OKW_API GetConsoleMode(HANDLE, DWORD*);
251+
OKW_IMPORT BOOL OKW_API SetConsoleMode(HANDLE, DWORD);
252+
253+
// The console's dimensions, for openkal.terminal. The structure is this
254+
// environment's and is declared here for the reason every other structure in
255+
// this file is: it belongs to the environment rather than to a C library, and
256+
// this implementation has none to take it from.
257+
struct COORD_ { short X; short Y; };
258+
struct SMALL_RECT_ { short Left; short Top; short Right; short Bottom; };
259+
struct CONSOLE_SCREEN_BUFFER_INFO_ {
260+
COORD_ dwSize;
261+
COORD_ dwCursorPosition;
262+
unsigned short wAttributes;
263+
SMALL_RECT_ srWindow;
264+
COORD_ dwMaximumWindowSize;
265+
};
266+
OKW_IMPORT BOOL OKW_API GetConsoleScreenBufferInfo(HANDLE, CONSOLE_SCREEN_BUFFER_INFO_*);
248267

249268
OKW_IMPORT BOOL OKW_API ReadFile(HANDLE, LPVOID, DWORD, DWORD*, OVERLAPPED*);
250269
OKW_IMPORT BOOL OKW_API WriteFile(HANDLE, LPCVOID, DWORD, DWORD*, OVERLAPPED*);

0 commit comments

Comments
 (0)