1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
//! Port of `ProcessLocksScreen.c` — htop's "file locks of a process"
//! `InfoScreen` subclass (F-key screen listing the fcntl/flock locks held
//! by the selected process).
//!
//! `ProcessLocksScreen` (`ProcessLocksScreen.h:19`) is a thin subclass:
//! `struct ProcessLocksScreen_ { InfoScreen super; pid_t pid; }`. The
//! constructor stores the process's (thread-group) pid, builds the shared
//! `InfoScreen` substrate via [`InfoScreen_init`], and installs the
//! fixed-column table header. The `scan`/`draw`/`delete` hooks are the
//! `InfoScreenClass` virtual methods.
//!
//! C names are preserved verbatim (htop uses `CamelCase_snake`), so
//! `non_snake_case` is allowed for the whole module. A C fn
//! `Foo_bar(Foo* this)` ports to a free fn `Foo_bar(this: &mut Foo)` — free
//! fns, not methods, matching the `Vector.c` / `History.c` / `InfoScreen.c`
//! ports.
//!
//! # Struct mapping (`ProcessLocksScreen.h:19`)
//!
//! `InfoScreen super` becomes an owned [`InfoScreen`] field named `super_`
//! (`super` is a Rust keyword; the `super_` convention matches
//! `backtracescreen.rs` / `affinitypanel.rs`). `pid_t pid` becomes `i32`,
//! the type [`Process_getPid`] / [`Process_getThreadGroup`] return.
//!
//! # Ported
//!
//! - The [`ProcessLocksScreen`] struct (`ProcessLocksScreen.h:19`).
//! - [`ProcessLocksScreen_new`] (`ProcessLocksScreen.c:23`) — resolves the
//! pid (thread-group id for a thread, else the pid), then chains through
//! [`InfoScreen_init`] with `LINES - 2` height and the column header.
//! - [`ProcessLocksScreen_draw`] (`ProcessLocksScreen.c:38`) — the
//! `InfoScreenClass` `draw` hook; a single forward to [`InfoScreen_drawTitled`]
//! (now ported) with the `"Snapshot of file locks of process %d - %s"` title
//! built from the stored pid and [`Process_getCommand`]. The latter is still a
//! `todo!()`, so a real draw panics through it — faithful chain-of-stubs
//! wiring (matching `CommandScreen_draw`).
//!
//! ## Divergences (documented)
//!
//! - **`xMalloc` + `Object_setClass`.** C allocates uninitialized storage
//! and installs the `ProcessLocksScreen_class` vtable pointer, then
//! `InfoScreen_init` overwrites every `super` field. The port builds a
//! throwaway zeroed [`InfoScreen`] (the same field set `InfoScreen::empty`
//! uses — private there, so replicated inline) which `InfoScreen_init`
//! immediately overwrites; the vtable install has no analog (the ported
//! `InfoScreen` carries no `Object super` vtable — see `infoscreen.rs`).
//! - **`LINES`.** C passes the ncurses `LINES` global; the ported analog is
//! `Ncurses::lines`, the terminal row count (the same source
//! `Panel_draw` reads), matching how `InfoScreen_init` maps `COLS` to
//! `Ncurses::cols`.
//! - **`const Process*` return.** C returns a `ProcessLocksScreen*` (the
//! `InfoScreen_init` identity chain-return, cast back). The port returns
//! the owned struct by value.
//!
//! # Stubbed (cannot be ported faithfully yet), each naming its blocker
//!
//! - [`ProcessLocksScreen_delete`] (`ProcessLocksScreen.c:34`) —
//! `free(InfoScreen_done((InfoScreen*)this))`, i.e. heap-free only.
//! [`InfoScreen_done`] is
//! itself a `todo!()` (heap-free with no safe-Rust analog: an owned
//! `InfoScreen`/`ProcessLocksScreen` releases its fields via `Drop`), so
//! there is no algorithm to port (same class as `InfoScreen_done` /
//! `History_delete`).
//! - [`FileLocks_Data_clear`] (`ProcessLocksScreen.c:42`) — `static inline`;
//! frees the four `char*` fields (`locktype`/`exclusive`/`readwrite`/
//! `filename`) of a `FileLocks_Data`. It is heap-free only: modeled with
//! owned `String`s those fields free themselves via `Drop`, so there is no
//! body to port. The `FileLocks_Data` / `FileLocks_LockData` /
//! `FileLocks_ProcessData` structs (`ProcessLocksScreen.h:24`/`36`/`41`)
//! are not modeled here because the only consumers are this free-only
//! helper and [`ProcessLocksScreen_scan`] + `Platform_getProcessLocks`,
//! all blocked below — defining them now would unblock nothing.
//! - [`ProcessLocksScreen_scan`] (`ProcessLocksScreen.c:49`) — the
//! `InfoScreenClass` `scan` hook. Its per-line substrate is available
//! (`Panel_getSelectedIndex` / `Panel_prune` / `Panel_setSelected`
//! (`panel.rs`), `InfoScreen_addLine` (`infoscreen.rs`),
//! `Vector_insertionSort` (`vector.rs`)), but its data source
//! `Platform_getProcessLocks(pid)` (`Platform.c:555`) is an unported
//! `todo!()` (`linux/platform.rs`): it parses `/proc/<pid>/*` lock state
//! into the unmodeled `FileLocks_ProcessData` list. Without that lock
//! enumeration there is nothing to iterate, format, and add — the whole
//! function is gated on it.
use crateNcurses;
use crateIncSet_new;
use crate;
use crateListItem_new;
use crate;
use cratePanel_new;
use crate;
use crateVector_new;
/// Port of `#define VECTOR_DEFAULT_SIZE (10)` from `Vector.h:15` — the
/// initial `lines` capacity for the throwaway `InfoScreen` (overwritten by
/// [`InfoScreen_init`]); mirrors the value `InfoScreen::empty` uses.
const VECTOR_DEFAULT_SIZE: i32 = 10;
/// Port of `struct ProcessLocksScreen_` (`ProcessLocksScreen.h:19`): an
/// `InfoScreen super` (owned; named `super_` since `super` is reserved) plus
/// the resolved `pid_t pid` of the process whose locks are shown.
/// Port of `ProcessLocksScreen* ProcessLocksScreen_new(const Process*
/// process)` from `ProcessLocksScreen.c:23`.
///
/// Resolves `pid` to the thread-group id when `process` is a thread
/// (C `Process_isThread`), else its own pid, then chains through
/// [`InfoScreen_init`] with height `LINES - 2` (`Ncurses::lines`) and the
/// fixed column header. The `xMalloc` + `Object_setClass` allocation maps to
/// a throwaway zeroed `super_` that `InfoScreen_init` overwrites (see the
/// module docs). Returns the owned struct (C returns the `InfoScreen_init`
/// identity, cast back to `ProcessLocksScreen*`).
/// Port of `void ProcessLocksScreen_delete(Object* this)` from
/// `ProcessLocksScreen.c:34`: `free(InfoScreen_done((InfoScreen*)this))`.
/// Taking `this` by value consumes the screen; the embedded `super_`
/// [`InfoScreen`] is handed to [`InfoScreen_done`] (mirroring the C call
/// graph), whose by-value consume folds in the outer `free`. The `pid`
/// scalar drops with it.
/// Port of `static void ProcessLocksScreen_draw(InfoScreen* this)` from
/// `ProcessLocksScreen.c:38`. A single forward to [`InfoScreen_drawTitled`]:
/// C `InfoScreen_drawTitled(this, "Snapshot of file locks of process %d - %s",
/// ((ProcessLocksScreen*)this)->pid, Process_getCommand(this->process))`.
///
/// `%d` is the stored [`ProcessLocksScreen::pid`] (C's `(ProcessLocksScreen*)this`
/// downcast — so the port takes `&mut ProcessLocksScreen`, not `&mut InfoScreen`,
/// to reach the field) and `%s` is [`Process_getCommand`] on the
/// `super_.process` back-pointer (a `const char*`, rendered lossily from its
/// bytes; `None` -> empty). The variadic `fmt, ...` becomes a pre-built `&str`
/// (the `xSnprintf`/`vsnprintf` idiom [`InfoScreen_drawTitled`] expects).
/// `Process_getCommand` is still a `todo!()` stub, so a real draw panics
/// through it — the faithful chain-of-stubs wiring (same as `CommandScreen_draw`).
/// TODO: port of `static inline void FileLocks_Data_clear(FileLocks_Data*
/// data)` from `ProcessLocksScreen.c:42`. Frees the four `char*` fields
/// (`locktype`/`exclusive`/`readwrite`/`filename`). Blocked on the missing
/// substrate: the `FileLocks_Data` struct (`FileLocks.h`) is not modeled in
/// this port — there is no Rust type to take as a parameter and clear. Its
/// only consumers are this helper and [`ProcessLocksScreen_scan`], which is
/// itself blocked on the unported `Platform_getProcessLocks`. Left a stub
/// rather than inventing an unused struct.
/// TODO: port of `static void ProcessLocksScreen_scan(InfoScreen* this)` from
/// `ProcessLocksScreen.c:49`. Blocked on `Platform_getProcessLocks(pid)`
/// (`Platform.c:555`), an unported `todo!()` in `linux/platform.rs` that
/// parses `/proc/<pid>` lock state into the unmodeled `FileLocks_ProcessData`
/// list. The per-line substrate (`Panel_prune` / `Panel_getSelectedIndex` /
/// `Panel_setSelected`, `InfoScreen_addLine`, `Vector_insertionSort`) is
/// available, but there is no lock data to iterate and format without it.