Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions devel/200_60.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# [200_60] Goldfish Scheme 支持 shebang

## 2026/04/03 在 load_file_1 中实现 shebang 跳过逻辑

### What
在 `load_file_1` 函数中添加 shebang 行跳过逻辑,使 Goldfish Scheme 能够正确执行以 `#!` 开头的脚本文件。

### Why
shebang(`#!`)是 Unix-like 系统中用于指定脚本解释器的机制。用户希望能够直接运行 Goldfish Scheme 脚本,例如:

```scheme
#!/usr/bin/env goldfish
(display "Hello, World!")
```

在实现 shebang 支持之前,Goldfish 会将 `#!` 解析为注释或错误语法,导致脚本无法直接执行。

### How
在 `load_file_1` 函数中,加载文件内容后、解析执行前,检查文件内容是否以 `#!` 开头:

1. 检查端口数据是否以 `#` 和 `!` 开头
2. 如果是,则循环查找第一个换行符 `\n`
3. 找到换行符后,将端口位置设置为换行符之后的位置,跳过 shebang 行
4. 如果没有找到换行符(文件只有 shebang 一行),则将位置设置为文件末尾

## 任务相关的代码文件
- `src/s7.c` - 修改 `load_file_1` 函数,添加 shebang 跳过逻辑
15 changes: 15 additions & 0 deletions src/s7.c
Original file line number Diff line number Diff line change
Expand Up @@ -28935,6 +28935,21 @@ static s7_pointer load_file_1(s7_scheme *sc, const char *filename)
port_file_number(port) = remember_file_name(sc, (local_file_name) ? local_file_name : filename);
if (local_file_name) free(local_file_name);
set_loader_port(port);
/* 跳过 shebang 行:如果文件以 #! 开头,跳过第一行 */
if (is_string_port(port) &&
port_data_size(port) >= 2 &&
port_data(port)[0] == '#' &&
port_data(port)[1] == '!')
{
uint8_t *data = port_data(port);
s7_int pos = 0;
while (pos < port_data_size(port) && data[pos] != '\n')
pos++;
if (pos < port_data_size(port)) /* 找到换行符,跳过它 */
port_position(port) = pos + 1;
else /* 没有换行符,文件只有 shebang 行 */
port_position(port) = port_data_size(port);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Shebang support silently skipped on Windows

The shebang-skip logic is guarded by is_string_port(port), but on Windows, read_file always creates a file_port (not a string_port) — see the #else branch starting at line 27577 in src/s7.c. This means the #! line is never skipped on Windows, and the interpreter will encounter a syntax error when loading a shebang script on that platform.

The Windows-specific branch sets port_data = NULL and port_data_size = 0, so the is_string_port guard correctly prevents a NULL-dereference crash, but the feature silently fails to work.

If Windows shebang support is needed, a separate code path for file_port (using getc/ungetc or similar) would be required. If Windows is intentionally out of scope, a comment here would clarify the limitation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Shebang skipped for zero-size / pseudo-files (edge case)

When fseek/ftell reports size == 0 (e.g., files under /proc), read_file also creates a file_port, not a string_port. Those files won't receive shebang handling. This is unlikely to matter in practice since /proc pseudo-files don't use shebangs, but it is a subtle inconsistency worth noting alongside the Windows case above.

push_input_port(sc, port);
return(port);
}
Expand Down
Loading