www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Spawning a pty in D

reply "Colin Grogan" <grogan.colin gmail.com> writes:
Im having an issue
I can link to the C header file pty.h 
(http://man7.org/linux/man-pages/man3/openpty.3.html) and call 
forkpty like here:
http://dpaste.dzfl.pl/c3b07855

You have to compile that by linking with the util library
( add "libs-posix": ["util"] to dubs package.json )
For ease of reference, the main function is:

import std.stdio;
import pty;
void main(){
     int master, slave;
     char[16] name;
     int pid = forkpty(&master, &name[0], null, null);
     writefln("PID: %s", pid);
     writefln("Master : %s", master);
     writefln("Filename: %s", name);
}

If I run that I get:
~/Projects/D/dexpect$ ./dexpect
PID: 2224
Master : 3
Filename: /dev/pts/6�����

(As you can see, I'm attempting to create a D version of the 
expect library, good way to learn some of the intricacies of D 
and will be useful I suspect)

What I get back is a file name and a File Descriptor to the 
master side of the pty.
How do I then open this file and perform IO on it, preferably in 
a D way (std.stdio.File hopefully) rather than through C's mess 
of function calls?

If I open /dev/pts/6 with File("/dev/pts/6", "rw") and attempt to 
write to it, I get a "Bad file descriptor" error.
Reading from that file blocks (which I think is correct...)

Anyone have any experience with this?

As an aside, I'd prefer to do this in a pure D way, and not have 
to compile against any external C libraries, does anyone know if 
it is possible to spawn a pty in D without resorting to calling 
external C libs?

Sorry for the long post!
Thanks
Oct 17 2013
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thursday, 17 October 2013 at 13:53:39 UTC, Colin Grogan wrote:
 Anyone have any experience with this?
I actually have been writing a terminal emulator for the last few weeks https://github.com/adamdruppe/terminal-emulator But for reading and writing from the pty, I just used the unix read and write syscalls instead of wrapping it. tbh I don't think there's much point in wrapping it; I think std.stdio.File is hard to use for any byte-at-a-time tasks anyway... If you do want to wrap it... well I think you'd have to modify phobos. The constructor that takes a FILE* is private. (std.stdio is itself just a wrapper around C's <stdio.h>) But I wouldn't even bother, it is easiest to just use "import core.sys.posix.unistd;" and then read()/write() to it.
 As an aside, I'd prefer to do this in a pure D way, and not 
 have to compile against any external C libraries, does anyone 
 know if it is possible to spawn a pty in D without resorting to 
 calling external C libs?
eh you could probably open /dev/ptmx and the other /dev/pts/* to test and reimplement what openpty does yourself, but there really is no pure D way, because it is perfectly normal in D to use C interfaces to talk to the operating system (it IS possible to use D without a C lib, but even druntime assumes it is there). I've never seen a unix install without the terminal util lib, so it is basically part of the OS.
Oct 17 2013
parent reply "Colin Grogan" <grogan.colin gmail.com> writes:
On Thursday, 17 October 2013 at 14:12:36 UTC, Adam D. Ruppe wrote:
 On Thursday, 17 October 2013 at 13:53:39 UTC, Colin Grogan 
 wrote:
 Anyone have any experience with this?
I actually have been writing a terminal emulator for the last few weeks https://github.com/adamdruppe/terminal-emulator But for reading and writing from the pty, I just used the unix read and write syscalls instead of wrapping it. tbh I don't think there's much point in wrapping it; I think std.stdio.File is hard to use for any byte-at-a-time tasks anyway... If you do want to wrap it... well I think you'd have to modify phobos. The constructor that takes a FILE* is private. (std.stdio is itself just a wrapper around C's <stdio.h>) But I wouldn't even bother, it is easiest to just use "import core.sys.posix.unistd;" and then read()/write() to it.
 As an aside, I'd prefer to do this in a pure D way, and not 
 have to compile against any external C libraries, does anyone 
 know if it is possible to spawn a pty in D without resorting 
 to calling external C libs?
eh you could probably open /dev/ptmx and the other /dev/pts/* to test and reimplement what openpty does yourself, but there really is no pure D way, because it is perfectly normal in D to use C interfaces to talk to the operating system (it IS possible to use D without a C lib, but even druntime assumes it is there). I've never seen a unix install without the terminal util lib, so it is basically part of the OS.
Thanks for that Adam, was a great help to me. I studied your code quite a bit (and reused some of it if that's ok?!). I stuck an initial draft of dexpect up on github, located: https://github.com/grogancolin/dexpect if you want to see the fruits of your labor :) Theres still some bugs I need to iron out, but I threw it up there to keep safe nonetheless. I ended up going with what you said and didnt wrap any of the C functions, turns out using them is kind of satisfying and pretty easy anyway. Just need to read up on documentation a bit more is all! Cheers, Colin
Oct 22 2013
parent "Adam D. Ruppe" <destructionator gmail.com> writes:
looking at the comments:

     //pragma(lib, "util"); // pragma does not work for me at 
moment. TODO: FIND OUT WHY!

If you are using gdc, and I think ldc too, that pragma is 
unsupported since it doesn't fit well into the gcc code - there's 
no easy way to pass linker flags from the D frontend to the gcc 
backend. So it is a dmd only thing right now.

Otherwise, pretty cool. Feel free to use anything of mine you 
want!
Oct 22 2013