1

I'm using a while loop with getc() to read from a file handle and it works fine. Now I'm adding support for pipes.

My problem is that while x0A, X0D, and x0A0D pass just fine, any cases of x0D0A get reduced to just x0A. Also x1A seems to stop the process entirely when encountered.

I'm piping in the output of tar, and is messing the files up.

FILE *FH;
FH=stdin; 
int buff;
while((buff=getc(FH))!=EOF) {
    //stuff
}

That's simplified, as FH needs to point to either a file or stdin. For testing I'm just writing the buff out to a file to see the changes. The code works perfectly if FH is a file.

I've seen the same behavior on using tar, type, and cat as the pipe source

  • What OS are you on? On Unix, all streams are binary (translating CRLF to `\n` is done by the terminal driver, not the C runtime). – Barmar Sep 08 '13 at 23:31
  • MS Windows XP SP3 with MinGW compiler. – user1488660 Sep 08 '13 at 23:37
  • It is possible to do. NT5.1 does pass binary data just fine. example "cat testfile.bin | cat > output.bin" passes the data unaltered. So does using the native "type" command i.e. "type testfile.bin | cat > output.bin" – user1488660 Sep 09 '13 at 17:04

2 Answers2

1

You will need to fopen with a binary mode. I'm not sure if you can use freopen on stdin, but give it a try:

freopen(NULL, "rb", stdin);
Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • I assume you meant: "FH= freopen(NULL, "rb", stdin);" but it segfaults when it hits the getc(FH) – user1488660 Sep 08 '13 at 23:31
  • "stdin = freopen(NULL, "rb", stdin);" will not compile " lvalue required as left operand of assignment" – user1488660 Sep 08 '13 at 23:36
  • Actually, it will probably work just fine by not assigning the result to anything (you may want to check that it's not NULL tho', as that means "error"). – Mats Petersson Sep 08 '13 at 23:50
  • @user1488660: Although the fact that it segfaults seems to indicate that the runtime doesn't like altering `stdin` to be in binary mode - so maybe you can't do that then... I'll delete the answer if you can confirm that it doesn't work, as I don't want to give misleading answers (they tend to be downvoted, and I like to keep my rep...) – Mats Petersson Sep 08 '13 at 23:56
  • It wouldn't be necessary to guess what's going on if you simply *check the return value* of the `freopen` call and use `perror` to produce an appropriate error message, which is sufficiently simple that there is no excuse for not doing it. However, my guess is that `FH` is `NULL` and that's why `getc` segfaults. (And you should also make `ch` an int, not a char, because there is no guarantee that `EOF` compares equal to any char, although I think on Windows you will luck out with that code.) – rici Sep 09 '13 at 01:55
  • "freopen(NULL, "rb", stdin);" then "FH= stdin);" results in no data (instant EOF), freopen's return is NULL, perror reports "No such file or directory" – user1488660 Sep 09 '13 at 16:56
  • I just tried this on my machine, and it accepts (happily "reopens" `stdin`). However, my machine is a Linux system, so it's perhaps less sensitive to things than a Windows system is. I'm afraid my only suggestion is to "find a diifferent solution than reading the content via `stdin`)" – Mats Petersson Sep 09 '13 at 17:01
  • I will post anything I come up with, but I'm still open to any suggesttions – user1488660 Sep 09 '13 at 17:08
  • Obviously, one solution is to use the `_read()` functions of the MS library, using `_fileno(stdin)` to get the actualy handle. – Mats Petersson Sep 09 '13 at 17:23
  • OK but how would you make it binary? fctrl doesn't change that flag (I think) and `char x;count = _read(_fileno(FH),&x,1);` gives the same non-binary output as described above. – user1488660 Sep 09 '13 at 19:04
  • Ah, forgot that `_read` also mangles the text. How about `FILE *fh = fdopen(fileno(stdin), "rb")` instead? – Mats Petersson Sep 09 '13 at 19:09
  • `FH = fdopen(fileno(stdin), "rb");` replacing `FH=stdin;` in the above example still gives the same non-binary output. – user1488660 Sep 09 '13 at 19:35
  • Then I think the only two options that remain is to use the raw Windows files (`CreateFile` and `ReadFile`) or "don't read files from `stdin`. – Mats Petersson Sep 09 '13 at 19:48
  • I got it, its a MS thing. MS VS05' and newer [specifically declares](http://msdn.microsoft.com/en-us/library/wk2h68td%28v=vs.80%29.aspx) that any NULL or "" fed to freopen is declared to be an error. The MS call is `_setmode( _fileno( File *FH ), _O_BINARY );`, you need `fcntl.h` to define `_O_BINARY` – user1488660 Sep 10 '13 at 15:23
0

You have to open the file in binary mode you are writing into. The combination 0d0a is a carriage return followed by new line and depending on the system will get changed when you write in text mode.

this
  • 5,229
  • 1
  • 22
  • 51