![]() |
arguments to main
Ok, so I understand how arguments to a C program are handled in main; they show up as char array elements in a char array, of size 'argc'. What I can't figure out is how you can get at data passed into a program through the unix pipe, for instance, or redirected from a file.
For example, if from the command line I type % echo "2+2" | yafu where yafu is the C program receiving the string from echo, then "2+2" does not show up in **argv, and argc == 1. Same if I do % yafu < in.txt where in.txt contains "2+2" Anyone here know how to get at data through arguments to main in these cases? A non-trivial amount of googling didn't get me anywhere... maybe I'm just a bad googler :ermm: - ben. |
10 seconds after posting the above, I figured something out, I think. The answer is you scan it in from stdin!
So, new question: how can I tell if what I got from scanf came from a pipe or a redirection rather than from the keyboard? My problem is that I'm building in the ability for yafu to take a command line expression, evaluate it, and exit. In addition to the normal mode of operation which is open, wait for manual input, evaulate, wait for next input, etc. If I scanf in a string from a pipe, because I can't tell it came from a pipe, the program doesn't exit like I want it to, it just waits for the next input. - ben. |
Ok, here's my hackish workaround. I'd still like to know how to do this right...
[code] [SIZE=2]start = clock();[/SIZE] [SIZE=2][COLOR=#008000]//wait for input from user[/COLOR][/SIZE] [SIZE=2][COLOR=#0000ff]while[/COLOR][/SIZE][SIZE=2] (1)[/SIZE] [SIZE=2]{[/SIZE] [COLOR=#008000]//get a new random seed after every transaction[/COLOR] [SIZE=2] srand(([/SIZE][SIZE=2][COLOR=#0000ff]unsigned[/COLOR][/SIZE][SIZE=2][COLOR=#0000ff]int[/COLOR][/SIZE][SIZE=2])time(&tt));[/SIZE] [COLOR=#008000]//if there are command line arguments, don't wait for user input[/COLOR] [COLOR=#008000] //the expression to be evaluated is already in 's'[/COLOR] [SIZE=2][COLOR=#0000ff] if[/COLOR][/SIZE][SIZE=2] (argc <= 1)[/SIZE] [SIZE=2] {[/SIZE] [SIZE=2] printf([/SIZE][SIZE=2][COLOR=#a31515]"\n"[/COLOR][/SIZE][SIZE=2]);[/SIZE] [SIZE=2] fflush(stdout); [/SIZE] [SIZE=2] scanf([/SIZE][SIZE=2][COLOR=#a31515]"%[^\n]"[/COLOR][/SIZE][SIZE=2],s); [/SIZE][SIZE=2][COLOR=#008000]//read everything up to carriage return[/COLOR][/SIZE] [SIZE=2] stop = clock();[/SIZE] [SIZE=2][COLOR=#008000] //hack. if no time has elapsed, this must have come from[/COLOR][/SIZE] [SIZE=2][COLOR=#008000] //the pipe or a redirect. treat the same as a command line expression.[/COLOR][/SIZE] [SIZE=2][COLOR=#0000ff] if[/COLOR][/SIZE][SIZE=2] ((([/SIZE][SIZE=2][COLOR=#0000ff]double[/COLOR][/SIZE][SIZE=2])(stop - start)/([/SIZE][SIZE=2][COLOR=#0000ff]double[/COLOR][/SIZE][SIZE=2])CLOCKS_PER_SEC) < 0.01)[/SIZE] [SIZE=2] do_once = 1; [/SIZE] [SIZE=2] }[/SIZE] . . . [/code] |
The msieve demo application uses a switch (-m) to determine whether to expect inputs from a pipe or from file. In principle you can assign a FILE * to either stdin or the result of fopen() and then proceed like normal, but IIRC when I tried that there were problems determining when a list of numbers was finished.
|
There is some function to query open file descriptors that tells, among other things, whether the fd points to a tty or to a disk file. That's the usual way of determining whether stdio has been redirected, afaik. But for the life of me, I can't remember what the function is called... can someone help out here?
Btw, assigning something to stdin or stdout usually works, but is non-portable, strictly speaking... freopen() should be used instead. Alex |
This is getting bizarre.
The following works for everything (windows, linux, gcc, MSVC, pipes, redirects, normal operation) *except* pipes in linux. [code] [SIZE=2]fseek(in,-1,SEEK_END);[/SIZE] [SIZE=2][COLOR=#0000ff]if[/COLOR][/SIZE][SIZE=2] (argc > 1)[/SIZE] [SIZE=2]{[/SIZE] [COLOR=#008000]//handle the case where we have command line arguments[/COLOR] [SIZE=2] do_once = 1;[/SIZE] [SIZE=2] strcpy(s,argv[1]);[/SIZE] [SIZE=2]}[/SIZE] [SIZE=2][COLOR=#0000ff]else[/COLOR][/SIZE] [SIZE=2]{[/SIZE] [SIZE=2][COLOR=#008000] //on linux, gcc-3.2.3, this works for redirects but not for pipes[/COLOR][/SIZE] [SIZE=2][COLOR=#008000] //works fine for both on win, MSVC express edition 2008[/COLOR][/SIZE] [SIZE=2][COLOR=#0000ff] if[/COLOR][/SIZE][SIZE=2] (ftell(stdin) >= 0)[/SIZE] [SIZE=2] {[/SIZE] [SIZE=2] rewind(stdin);[/SIZE] [SIZE=2] fgets(s,1024,in);[/SIZE] [SIZE=2] do_once = 1;[/SIZE] [SIZE=2] }[/SIZE] [SIZE=2]}[/SIZE] [/code] In that exceptional case, fseek says that there is nothing to read (returns -1), but if the very next thing I do is attempt to read stdin, it finds the string!! WTF!! |
Return value of -1 means an error. Does the global variable errno get set to something? According to "man 3 fseek", if the stream is not seekable (and I would expect a pipe not to be), errno should be set to EBADF.
Alex |
:blush:. yeah, -1 means an error... sorry.
So the bizarre thing is that windows is fine with seeking in a pipe. In windows I do echo "2+2" | yafu and get fseek returned 0, errno = 0 while in linux I get fseek returned -1, errno = 29 |
I think in MS-DOS times, redirection didn't really do piping but created temporary files since the programs could not run concurrently (no multi tasking), so in MS-DOS an fseek() call on a pipe may have worked. I don't know if the temp file thing is still the case in multi-tasking capable Windows versions, but even if it isn't, MS may have decided to make fseek() not return an error in Windows if it didn't in MS-DOS. At any rate, I would expect fseek() on pipes not to be portable at all.
I'll try to find out again how to determine whether a file descriptor points to a tty. Alex |
Alex,
Do you mean fstat() ? The man page seems to indicate it almost gets you what you need, but it works with unix file descriptors and not FILE structures. BTW I meant that stdin and stdout are lvalues and can be used as the RHS in an assignment (they are not compile-time constants though) |
I could also make it work if there were such a thing as a non-blocking read of a character from a stream. I'm showcasing my C ignorance here, but is there such a function? If so then I could just test a read, and handle the error if there was nothing there, rather than have the program sit there waiting for input. No beans for fgetc, getc, fgets, scanf...
|
| All times are UTC. The time now is 07:59. |
Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.