1

When I use shell and eshell in Emacs on Windows I have problems with the output of my C programs if they have scanf in them. For instance this program after compilation works just fine

#include <stdio.h>

int main()
{
    printf("Hello, world!");
    return 0;
}

and if I run it from shell or eshell it prints following:

c:\Users\xxx>a.exe 
a.exe 
Hello, world!

But this program doesn't quite work as expected

#include <stdio.h>

int main()
{
    int a;
    printf("Hello, world!\nEnter number:");
    scanf("%d", &a);
    return 0;
}

When I run it in shell it prints

c:\Users\xxx>a.exe 
a.exe 

and then it's stuck. If I type 123 and then Enter it goes as

123                      <= this is what I entered
Hello, world!
Enter number:

Looks like some weird buffering behavior. When I check echo %SHELL% in the shell buffer it prints

C:/App/emacs/libexec/emacs/24.5/i686-pc-mingw32/cmdproxy.exe

What do I need to do in order to fix the behaviour of the shell and have it working as one normally would expect? Changing SHELL variable to %ComSpec% doesn't help.

EvgeniySharapov
  • 3,078
  • 3
  • 27
  • 38

1 Answers1

1

When emacs runs external commands in the shell process is on the end of a pipe. For this reason the output is optimized for throughput rather than the terminal which means the output is buffered in blocks. I suspect this is what you are seeing.

C99 Standard

This buffering is part of the C99 standard see §7.19.3/7

At program startup, three text streams are predefined and need not be opened explicitly — standard input (for reading conventional input), standard output (for writing conventional output), and standard error (for writing diagnostic output). As initially opened, the standard error stream is not fully buffered; the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive device.

GNU's advice

The emacs W32 FAQ has some advice of what should be done in this case:

W32 FAQ: Buffering in Shells

Disabling buffering from C

As the article suggests one way that programs often get the best of both worlds: that is allowing emacs to operate yet getting higher performance on pipes is to use the TERM variable to indicate that the the program is running within emacs. So that would be something like:

char *term = getenv("TERM");
if (term != NULL && !strcmp(term,"emacs")==0) {
    setvbuf(stdout, NULL, _IONBF, 0);
}

Just as an illustration. The different buffering modes of the stdio library are listed on the page for setvbuf.

std:cout and C++

The relationship between iostream and libc, and whether they are synched is a little more complex. But I suspect that you are using endl in your write to std::cout which includes a flush. std::cerr is unbuffered by default.

Solution on Unix-like Environment

On Unix environments that have pty is it possible to set up the process communicating with the pseudo terminal. The expect toolkit has a command for this called unbuffer.

andygavin
  • 2,784
  • 22
  • 32
  • Interestingly using `std::cout` and `std:cin` and g++ compiler works just find. – EvgeniySharapov Sep 06 '15 at 02:51
  • As the FAQ says you are experiencing buffering from libc. Stdio is detecting that you're output is not a tty and selecting buffering for higher throughput, probably block buffering. – andygavin Sep 06 '15 at 14:10
  • I suspect you are inadvertently using C++ in a different way, I've updated my answer above to be more explicit: although this is just elaborating what the FAQ says. – andygavin Sep 06 '15 at 15:03
  • ok. that seems to work, although now i have to change C program rather than term settings for emacs which would be a preferred way – EvgeniySharapov Sep 07 '15 at 15:34
  • If you were on Unix you'd be able to set the process up with a pty. Expect has a command called `unbuffer` for this purpose. Whether one of the windows ports would work. I've seen a report that the cygwin port doesn't always work: http://superuser.com/questions/840903/shell-unbuffering-for-cygwin-is-it-possible – andygavin Sep 07 '15 at 15:52
  • There's still no solution to this problem. if I run `shell` or `eshell` programs like `ack` or `ag` output help screen but not the search results. However, `shell-comman` work fine. I can execute the command and get the result instantly. So, problem seems to be in `shell` and `eshell` implementations. – EvgeniySharapov Nov 05 '15 at 22:05
  • That's still explained by the answer above, it's a product of how I/O works and that programs block buffer if they don't think they are talking to a console. There are other solutions by creating something similar to a pty for instance. But you pose a slightly different question here which is answered by others, I'm not convinced you'd want to solve every case of this in the same general way. – andygavin Nov 09 '15 at 17:22