www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - setmode again

reply Brian Myers <bmyers harryanddavid.com> writes:
Hi all,

Seems this gets revisited every so often on the forums, so I guess it's time to
visit it again...

I need to set stdout to binary mode in Windows. I've tried the following:

import std.string;
import std.stdio;
import std.c.windows.windows;

extern (C)
alias int function(int,int) setmode_f;

void main(char[][] args)
{
    int O_BINARY = 0x8000;
    setmode_f f;
    HMODULE m = cast(HMODULE) LoadLibraryA(toStringz("msvcrt.dll"));
    f = cast(setmode_f) GetProcAddress(m, toStringz("_setmode"));
    f(fileno(stdout), O_BINARY);

    writef("test line1\r\ntestline2");
}

and

import std.string;
import std.stdio;

extern (C)
alias int function(int,int) setmode_f;

extern ( C ) int setmode(int,int);

void main(char[][] args)
{
    int O_BINARY = 0x8000;

    if (setmode(fileno(stdout) ,O_BINARY) < 0)
        writefln("setmode failed.");
    writef("test line1\r\ntest line2");
}

No luck. Both compile and run without error, but Windows is still doing
LF->CRLF translation.

I know I need a version statement for a cross platform compile, but this is
just example code.

Brian
Aug 07 2008
parent reply Brian Myers <bmyers harryanddavid.com> writes:
Ugh,

By the rush to respond I'm getting so far, I'm guessing nobody does these kind
of programs these days. Can't say I'm surprised, but I'm stuck working with
legacy data.

Anyway, for everyone's reference, the following python code works perfectly:

import os, msvcrt
import sys

msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
print "test line1\r\ntestline2"

Brian Myers Wrote:

 Hi all,
 
 Seems this gets revisited every so often on the forums, so I guess it's time
to visit it again...
 
 I need to set stdout to binary mode in Windows. I've tried the following:
 
 import std.string;
 import std.stdio;
 import std.c.windows.windows;
 
 extern (C)
 alias int function(int,int) setmode_f;
 
 void main(char[][] args)
 {
     int O_BINARY = 0x8000;
     setmode_f f;
     HMODULE m = cast(HMODULE) LoadLibraryA(toStringz("msvcrt.dll"));
     f = cast(setmode_f) GetProcAddress(m, toStringz("_setmode"));
     f(fileno(stdout), O_BINARY);
 
     writef("test line1\r\ntestline2");
 }
 
 and
 
 import std.string;
 import std.stdio;
 
 extern (C)
 alias int function(int,int) setmode_f;
 
 extern ( C ) int setmode(int,int);
 
 void main(char[][] args)
 {
     int O_BINARY = 0x8000;
 
     if (setmode(fileno(stdout) ,O_BINARY) < 0)
         writefln("setmode failed.");
     writef("test line1\r\ntest line2");
 }
 
 No luck. Both compile and run without error, but Windows is still doing
LF->CRLF translation.
 
 I know I need a version statement for a cross platform compile, but this is
just example code.
 
 Brian
 
Aug 08 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Brian Myers" wrote
 Ugh,

 By the rush to respond I'm getting so far, I'm guessing nobody does these 
 kind of programs these days. Can't say I'm surprised, but I'm stuck 
 working with legacy data.

 Anyway, for everyone's reference, the following python code works 
 perfectly:

 import os, msvcrt
 import sys

 msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
 print "test line1\r\ntestline2"

 Brian Myers Wrote:

 Hi all,

 Seems this gets revisited every so often on the forums, so I guess it's 
 time to visit it again...

 I need to set stdout to binary mode in Windows. I've tried the following:

 import std.string;
 import std.stdio;
 import std.c.windows.windows;

 extern (C)
 alias int function(int,int) setmode_f;

 void main(char[][] args)
 {
     int O_BINARY = 0x8000;
     setmode_f f;
     HMODULE m = cast(HMODULE) LoadLibraryA(toStringz("msvcrt.dll"));
     f = cast(setmode_f) GetProcAddress(m, toStringz("_setmode"));
     f(fileno(stdout), O_BINARY);

     writef("test line1\r\ntestline2");
 }

 and

 import std.string;
 import std.stdio;

 extern (C)
 alias int function(int,int) setmode_f;

 extern ( C ) int setmode(int,int);

 void main(char[][] args)
 {
     int O_BINARY = 0x8000;

     if (setmode(fileno(stdout) ,O_BINARY) < 0)
         writefln("setmode failed.");
     writef("test line1\r\ntest line2");
 }

 No luck. Both compile and run without error, but Windows is still doing 
 LF->CRLF translation.

 I know I need a version statement for a cross platform compile, but this 
 is just example code.

 Brian
Have you tried changing extern(C) to extern(Windows)? -Steve
Aug 08 2008
parent reply Brian Myers <bmyers harryanddavid.com> writes:
No, I haven't because I thought that would result in a compiler or linker
error. What happens is the function is executed at run time, but has no effect.
I think I have a better idea now thought:

Check out this C code:

#include <fcntl.h>
#include <io.h>
#include <string.h>
#include <stdio.h>

void main() {
    char *tmp = "Test line1\r\ntest line2\n";
    _setmode(_fileno(stdout), _O_BINARY);
    fwrite(tmp, strlen(tmp), sizeof(char), stdout);
}

When compiled and linked with MSVC, it works properly. When compiled with DMC,
it doesn't. Could there be something wrong with the DMC CRT? I would suspect
the D runtime library is built on the same code, and that's why it's not
working properly.

OTOH, then why didn't it work properly when I loaded the _setmode function out
of MSVCRT directly? I'm sure that's what the python code is doing. Well, pretty
sure anyway.

Errrrgh! This is one of the many reasons I hate M$.

Steven Schveighoffer Wrote:

 
 "Brian Myers" wrote
 Ugh,

 By the rush to respond I'm getting so far, I'm guessing nobody does these 
 kind of programs these days. Can't say I'm surprised, but I'm stuck 
 working with legacy data.

 Anyway, for everyone's reference, the following python code works 
 perfectly:

 import os, msvcrt
 import sys

 msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
 print "test line1\r\ntestline2"

 Brian Myers Wrote:

 Hi all,

 Seems this gets revisited every so often on the forums, so I guess it's 
 time to visit it again...

 I need to set stdout to binary mode in Windows. I've tried the following:

 import std.string;
 import std.stdio;
 import std.c.windows.windows;

 extern (C)
 alias int function(int,int) setmode_f;

 void main(char[][] args)
 {
     int O_BINARY = 0x8000;
     setmode_f f;
     HMODULE m = cast(HMODULE) LoadLibraryA(toStringz("msvcrt.dll"));
     f = cast(setmode_f) GetProcAddress(m, toStringz("_setmode"));
     f(fileno(stdout), O_BINARY);

     writef("test line1\r\ntestline2");
 }

 and

 import std.string;
 import std.stdio;

 extern (C)
 alias int function(int,int) setmode_f;

 extern ( C ) int setmode(int,int);

 void main(char[][] args)
 {
     int O_BINARY = 0x8000;

     if (setmode(fileno(stdout) ,O_BINARY) < 0)
         writefln("setmode failed.");
     writef("test line1\r\ntest line2");
 }

 No luck. Both compile and run without error, but Windows is still doing 
 LF->CRLF translation.

 I know I need a version statement for a cross platform compile, but this 
 is just example code.

 Brian
Have you tried changing extern(C) to extern(Windows)? -Steve
Aug 08 2008
next sibling parent reply Wyverex <wyverex.cypher gmail.com> writes:
You can always build it into a VS DLL then link it into D
Aug 08 2008
parent reply Brian Myers <bmyers harryanddavid.com> writes:
I could and probably will, but the fact that it's a problem remains. I don't
like having to depend on the M$ compiler to build my D language projects, and I
don't like having to distribute a DLL with them. I prefer all of the programs
to be standalone executables.

Does Walter have a bugzilla for the C/C++ forum?

Wyverex Wrote:

 
 You can always build it into a VS DLL then link it into D
Aug 08 2008
parent Walter Bright <newshound1 digitalmars.com> writes:
Brian Myers wrote:
 Does Walter have a bugzilla for the C/C++ forum?
http://bugzilla.digitalmars.com/issues/buglist.cgi?quicksearch=.
Aug 08 2008
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Brian Myers wrote:
 No, I haven't because I thought that would result in a compiler or
 linker error. What happens is the function is executed at run time,
 but has no effect. I think I have a better idea now thought:
 
 Check out this C code:
 
 #include <fcntl.h> #include <io.h> #include <string.h> #include
 <stdio.h>
 
 void main() { char *tmp = "Test line1\r\ntest line2\n"; 
 _setmode(_fileno(stdout), _O_BINARY); fwrite(tmp, strlen(tmp),
 sizeof(char), stdout); }
 
 When compiled and linked with MSVC, it works properly. When compiled
 with DMC, it doesn't. Could there be something wrong with the DMC
 CRT? I would suspect the D runtime library is built on the same code,
 and that's why it's not working properly.
Try: stdout->_flag &= ~_IOTRAN; in the C code.
Aug 08 2008
parent Brian Myers <bmyers harryanddavid.com> writes:
Hi Walter,

The following code compiled with DMC still doesn't work:

#include <fcntl.h>
#include <io.h>
#include <string.h>
#include <stdio.h>

void main() {
    char *tmp = "Test line1\r\ntest line2\n";
    //_setmode(_fileno(stdout), _O_BINARY);
    stdout->_flag &= ~_IOTRAN;
    fwrite(tmp, strlen(tmp), sizeof(char), stdout);
}

Want me to try anything else?

Walter Bright Wrote:

 Brian Myers wrote:
 No, I haven't because I thought that would result in a compiler or
 linker error. What happens is the function is executed at run time,
 but has no effect. I think I have a better idea now thought:
 
 Check out this C code:
 
 #include <fcntl.h> #include <io.h> #include <string.h> #include
 <stdio.h>
 
 void main() { char *tmp = "Test line1\r\ntest line2\n"; 
 _setmode(_fileno(stdout), _O_BINARY); fwrite(tmp, strlen(tmp),
 sizeof(char), stdout); }
 
 When compiled and linked with MSVC, it works properly. When compiled
 with DMC, it doesn't. Could there be something wrong with the DMC
 CRT? I would suspect the D runtime library is built on the same code,
 and that's why it's not working properly.
Try: stdout->_flag &= ~_IOTRAN; in the C code.
Aug 08 2008
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Brian Myers" wrote
 No, I haven't because I thought that would result in a compiler or linker 
 error. What happens is the function is executed at run time, but has no 
 effect. I think I have a better idea now thought:
Try the extern(Windows). The difference is the call stack layout. what could be happening is you are calling a function one way, but the function expects to be called a different way. So it isn't reading the parameters like you think it is (in fact, it might be reading garbage). You won't get a compiler or linker error because you are not linking the function in, you are dynamically loading it. -Steve
Aug 08 2008
parent reply Brian Myers <bmyers harryanddavid.com> writes:
Ok, here's the current version I tried:

import std.string;
import std.stdio;
import std.c.windows.windows;

extern (Windows)
alias int function(int,int) setmode_f;

//extern ( C ) int setmode(int,int);

void main(char[][] args)
{
    int O_BINARY = 0x8000;
    setmode_f f;
    HMODULE m = cast(HMODULE) LoadLibraryA(toStringz("msvcrt.dll"));
    f = cast(setmode_f) GetProcAddress(m, toStringz("_setmode"));
    if (f(fileno(stdout), O_BINARY) < 0)
        writefln("setmode failed.");

//    if (setmode(fileno(stdout) ,O_BINARY) < 0)
//        writefln("setmode failed.");
    writef("test line1\r\ntestline2\n");
}

No dice. Still doing CR/LF translation.

Steven Schveighoffer Wrote:

 "Brian Myers" wrote
 No, I haven't because I thought that would result in a compiler or linker 
 error. What happens is the function is executed at run time, but has no 
 effect. I think I have a better idea now thought:
Try the extern(Windows). The difference is the call stack layout. what could be happening is you are calling a function one way, but the function expects to be called a different way. So it isn't reading the parameters like you think it is (in fact, it might be reading garbage). You won't get a compiler or linker error because you are not linking the function in, you are dynamically loading it. -Steve
Aug 08 2008
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Brian Myers"
 Ok, here's the current version I tried:

 import std.string;
 import std.stdio;
 import std.c.windows.windows;

 extern (Windows)
 alias int function(int,int) setmode_f;

 //extern ( C ) int setmode(int,int);

 void main(char[][] args)
 {
    int O_BINARY = 0x8000;
    setmode_f f;
    HMODULE m = cast(HMODULE) LoadLibraryA(toStringz("msvcrt.dll"));
    f = cast(setmode_f) GetProcAddress(m, toStringz("_setmode"));
    if (f(fileno(stdout), O_BINARY) < 0)
        writefln("setmode failed.");

 //    if (setmode(fileno(stdout) ,O_BINARY) < 0)
 //        writefln("setmode failed.");
    writef("test line1\r\ntestline2\n");
 }

 No dice. Still doing CR/LF translation.

 Steven Schveighoffer Wrote:

 "Brian Myers" wrote
 No, I haven't because I thought that would result in a compiler or 
 linker
 error. What happens is the function is executed at run time, but has no
 effect. I think I have a better idea now thought:
Try the extern(Windows). The difference is the call stack layout. what could be happening is you are calling a function one way, but the function expects to be called a different way. So it isn't reading the parameters like you think it is (in fact, it might be reading garbage). You won't get a compiler or linker error because you are not linking the function in, you are dynamically loading it. -Steve
I think I see the problem. dmd is using the digital mars C functions, not the MS C functions. I think the binary/text translation is done in the C library not in the OS, so setmode will only affect MS C functions. Unfortunately, in looking at Digital Mars' documentation, you cannot reopen an open FILE * object by descriptor only. I tried using _fdopen, but that isn't available in the lib that ships with dmd. More proof that it's in the C lib, if you use Tango (which only uses system calls for I/O), setmode also does nothing, but Cout also prints only LF. -Steve
Aug 09 2008