c/test/file_api.c · 4312 字节 · 下载原文
/* file_api.c —— `Lib/shared/src/file.c` 那 8 个包装的**实参传递**判据。
* file_api.c — criterion for **argument passing** in the 8 wrappers of `Lib/shared/src/file.c`.
*
* ## 为什么单独立一个
* ## Why a dedicated probe
*
* 那批包装原先写的是 `asm("SYSCALL #110")` —— **一个寄存器都不装**:
* · C 调用点靠 R0–R3「兼容镜像」**碰巧**能跑,所以桌面上看着一直是对的;
* · `fsize`/`ftell`/`fseek`/`ftruncate` 四者都发 `#114` 却**连 op 号都没填**(R1 是上一次的残留)
* ⇒ **即使 C 也是错的**(`Examples/c/app/filedlg.c` 取文件大小读到垃圾)。
* ⇒ 判据必须问「**传进去的值,宿主真收到了吗**」,而不是"函数有没有返回"。
*
* The wrappers used to be `asm("SYSCALL #110")` — **not loading a single register**. C call sites
* worked by luck off the R0–R3 "compatibility mirror"; `fsize`/`ftell`/`fseek`/`ftruncate` all issued
* `#114` **without even setting the op code** in R1. So the criterion must ask "did the host actually
* receive the values", not "did the function return something".
*
* ## 判据
* ## Criteria
*
* 建一个 5 字节的文件,然后逐项核对**数值**:写 5 ⇒ `fsize` 必须是 5(不是垃圾)、
* `ftell` 必须是 5、三种 whence 各自定位到 5/3/0、`ftruncate(2)` 之后大小必须是 2。
* 任何一项对不上就 FAIL 并以非 0 退出(`echo $?` 可直接当判据)。
*
* ⚠ 跑完在 **cwd** 留下一个 `_file_api_probe.txt`(沙箱根 = 工作区,相对路径)。
* Running it leaves a `_file_api_probe.txt` in the **cwd**.
*
* 跑法(桌面,秒级):
* How to run (desktop, seconds):
* dotnet scripts/vmlcli/bin/Release/net10.0/vmlcli.dll third_party/vml/Examples/c/test/file_api.c
* 手机上:命令行页敲 `vml run examples/c/test/file_api.c`
* On mobile: type `vml run examples/c/test/file_api.c` in the command line page.
*/
#include <file.h>
int fails = 0;
/* 逐项核对:对不上就记一笔,并把期望值一起打出来("差多少"比"错了"有用)。 */
void ck(char* name, int got, int want) {
if (got == want) {
printf("OK %s = %d\n", name, got);
} else {
printf("FAIL %s: got %d, want %d\n", name, got, want);
fails = fails + 1;
}
}
int main(void) {
int h;
int n;
int sz;
int pos;
char buf[32];
/* ① 只写建文件(mode 1 = 建 + 截断)—— 这条同时验 `fopen` 的**文件名指针**真的传进去了:
* 文件名没传进去的话宿主读不到路径,句柄必然是负的。 */
h = fopen("_file_api_probe.txt", 1);
if (h < 0) {
printf("FAIL fopen(write) = %d\n", h);
return 1;
}
printf("OK fopen(write) = %d\n", h);
/* ② 写 5 字节 */
n = fwrite(h, "hello", 5);
ck("fwrite", n, 5);
/* ③ 取大小 —— 本次修复的核心:原先 op 号没填,这里读到的是垃圾 */
sz = fsize(h);
ck("fsize", sz, 5);
/* ④ 取当前位置(写完之后应停在 5) */
pos = ftell(h);
ck("ftell", pos, 5);
/* ⑤ 从文件头定位(SEEK_SET = 0) */
fseek(h, 0, 0);
pos = ftell(h);
ck("fseek SET", pos, 0);
/* ⑥ 从末尾定位(SEEK_END = 2)—— 库内换算成绝对位置 */
fseek(h, 0, 2);
pos = ftell(h);
ck("fseek END", pos, 5);
/* ⑦ 从当前位置往前挪 2(SEEK_CUR = 1)⇒ 5 - 2 = 3 */
fseek(h, -2, 1);
pos = ftell(h);
ck("fseek CUR", pos, 3);
/* ⑧ 截断到 2 字节 */
ftruncate(h, 2);
sz = fsize(h);
ck("ftruncate", sz, 2);
fclose(h);
/* ⑨ 只读打开 + 读回(mode 0 = 只读,文件已存在) */
h = fopen("_file_api_probe.txt", 0);
if (h < 0) {
printf("FAIL fopen(read) = %d\n", h);
return 1;
}
printf("OK fopen(read) = %d\n", h);
n = fread(h, buf, 2);
if (n < 0) n = 0;
buf[n] = 0;
ck("fread", n, 2);
printf(" text=%s\n", buf);
fclose(h);
printf("FILE_API %s (fails=%d)\n", fails == 0 ? "PASS" : "FAIL", fails);
return fails;
}