Thread overview
Writing a simple text editor in D using a C tutorial
Aug 29, 2023
Răzvan Birișan
Aug 29, 2023
Dejan Lekic
Aug 29, 2023
Răzvan Birișan
August 29, 2023

Hello,

I'm following this tutorial 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?

August 29, 2023

On Tuesday, 29 August 2023 at 16:17:56 UTC, Răzvan Birișan wrote:

>

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?

I would try to use termios from druntime instead.

Try: import core.sys.posix.termios;

August 29, 2023

On Tuesday, 29 August 2023 at 16:59:57 UTC, Dejan Lekic wrote:

>

On Tuesday, 29 August 2023 at 16:17:56 UTC, Răzvan Birișan wrote:

>

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?

I would try to use termios from druntime instead.

Try: import core.sys.posix.termios;

I've made the change and that fixed the issue. Looks like there is also core.sys.posix.unistd, I'll use this and remove the C bindings that I've created.

I was only searching the official documentation and "termios" returned 0 results.
I also stumbled upon the unofficial documentation but didn't find it useful.

I now realize the I can browse the dmd source code on github...