racket 是一個許多人在用的 scheme 實作,但其 interpreter 在 interactive mode 時並沒有很方便的控制方式。既不能使用方向鍵移動修改,也沒有 history 的功能。要為 racket 直接加入這個功能其實也不難,但想到要先找出進入點就有點累...
剛好在系統程序員成長計畫中看到類似的問題(想讓命令列 jdb 的使用更方便),該作者提出了一個解法 - 增加一層 shell。這個想法很棒,可以在使用原本 binary 檔的情況下預作 readline 的動作,這麼一來就可達成我要的效果。溝通的機制則用 pipe 即可(若是要為 terminal-based program 做這件事,就得祭出 pseudo terminal 了)。OK,江湖一點訣,點破不值錢,實作如下:
剛好在系統程序員成長計畫中看到類似的問題(想讓命令列 jdb 的使用更方便),該作者提出了一個解法 - 增加一層 shell。這個想法很棒,可以在使用原本 binary 檔的情況下預作 readline 的動作,這麼一來就可達成我要的效果。溝通的機制則用 pipe 即可(若是要為 terminal-based program 做這件事,就得祭出 pseudo terminal 了)。OK,江湖一點訣,點破不值錢,實作如下:
- #include <stdlib.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <readline/readline.h>
- #include <readline/history.h>
- int main()
- {
- char* input;
- int pipe_fds[2];
- ssize_t input_bytes = 0;
- char output[1024];
- if (pipe(pipe_fds) == -1) {
- fprintf(stderr, "pipe open fail\n");
- exit(-1);
- }
- switch (fork()) {
- case -1:
- fprintf(stderr, "fork fail\n");
- exit(-1);
- case 0: // child
- close(pipe_fds[1]);
- dup2(pipe_fds[0], STDIN_FILENO);
- close(pipe_fds[0]);
- execlp("racket", "racket", (char *) NULL); /* Writes to pipe */
- default: // parent
- break;
- }
- for(;;) {
- char cmd[1024] = {'\0'};
- // Display prompt and read input (n.b. input must be freed after use)...
- input = readline("");
- // Check for EOF.
- if (!input) {
- break;
- }
- // write to racket
- sprintf(cmd, "%s\n", input);
- write(pipe_fds[1], cmd, strlen(cmd));
- // Add input to history.
- add_history(input);
- // Free input.
- free(input);
- }
- }
今天又遇到另一個小程式沒有作好input介面...本來想說要寫一個通用版本,但找了一下,果然發現有人已經作出來了...簡單好用啊!!
回覆刪除http://utopia.knoware.nl/~hlub/rlwrap/
作者已經移除這則留言。
回覆刪除連 terminal-based program 都有支援,rlwrap真是太好用了!:-)
回覆刪除