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