Writing a simple text editor in D using a C tutorial
Răzvan Birișan
razvan.birisan at pm.me
Tue Aug 29 16:17:56 UTC 2023
Hello,
I'm following this
[tutorial](https://viewsourcecode.org/snaptoken/kilo/02.enteringRawMode.html#disable-ctrl-s-and-ctrl-q) and I'm having some trouble setting the flags.
I have this C program that works properly (exits as soon as I
press `q` and `CTRL+C` does not kill it).
```
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
struct termios orig_termios;
void disableRawMode() {
tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios);
}
void enableRawMode() {
tcgetattr(STDIN_FILENO, &orig_termios);
atexit(disableRawMode);
struct termios raw = orig_termios;
raw.c_lflag &= ~(ECHO | ICANON | ISIG);
tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
}
int main() {
enableRawMode();
char c;
while (read(STDIN_FILENO, &c, 1) == 1 && c != 'q') {
if (iscntrl(c)) {
printf("%d\n", c);
} else {
printf("%d ('%c')\n", c, c);
}
}
return 0;
}
```
I'm trying to write the equivalent program in D.
source/app.d
```
import adapter;
import core.stdc.stdlib : atexit;
import core.stdc.stdio : printf;
import core.stdc.ctype : iscntrl;
termios orig_termios;
extern (C)
{
void disableRawMode() {
tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios);
}
}
void enableRawMode() {
tcgetattr(STDIN_FILENO, &orig_termios);
atexit(&disableRawMode);
termios raw = orig_termios;
// TODO flags ICANON and ISIG do not work
raw.c_lflag &= ~(ECHO | ICANON | ISIG);
tcsetattr(STDIN_FILENO, TCSANOW, &raw);
}
int main()
{
enableRawMode();
char c;
while (read(STDIN_FILENO, &c, 1) == 1 && c != 'q') {
if (iscntrl(c)) {
printf("%d\n", c);
} else {
printf("%d ('%c')\n", c, c);
}
}
return 0;
}
```
source/adapter/package.d
```
module adapter;
public import adapter.termios;
public import adapter.unistd;
```
source/adapter/termios.d
```
module adapter.termios;
import std.typecons : Typedef;
// from termios.h,
https://github.com/openbsd/src/blob/master/sys/sys/termios.h
enum int ECHO = 0x00000008;
enum int ICANON = 0x00000100;
enum int ISIG = 0x00000080;
enum int IXON = 0x00000200;
enum int IEXTEN = 0x00000400;
enum int ICRNL = 0x00000100;
enum int TCSANOW = 0;
enum int TCSADRAIN = 1;
enum int TCSAFLUSH = 2;
enum int NCCS = 20;
alias tcflag_t = Typedef!uint;
alias cc_t = Typedef!ubyte;
// alias speed_t = Typedef!uint;
struct termios {
tcflag_t c_iflag; /* input flags */
tcflag_t c_oflag; /* output flags */
tcflag_t c_cflag; /* control flags */
tcflag_t c_lflag; /* local flags */
cc_t[NCCS] c_cc; /* control chars */
int c_ispeed; /* input speed */
int c_ospeed; /* output speed */
};
extern (C) int tcgetattr(int, termios *);
extern (C) int tcsetattr(int, int, const termios *);
```
source/adapter/unistd.d
```
module adapter.unistd;
import core.sys.posix.sys.types : ssize_t;
// TODO fix import
enum int STDIN_FILENO = 0;
// import core.stdc.stdio : STDIN_FILENO;
// from unistd.h
extern (C) ssize_t read(int fildes, void *buf, size_t nbytes);
```
When I try to run it with `dub run` the only flag that appears to
be set is `~(ECHO)`. It does exit when I press `CTRL+C` and it
does not exit as soon as I press `q`, I must follow that with an
`ENTER`.
Is there a better way to use `termios.h` inside D? Am I missing
the point and there is a way to set these flags in D without
using C libraries?
More information about the Digitalmars-d-learn
mailing list