mersenneforum.org

mersenneforum.org (https://www.mersenneforum.org/index.php)
-   Programming (https://www.mersenneforum.org/forumdisplay.php?f=29)
-   -   arguments to main (https://www.mersenneforum.org/showthread.php?t=11087)

bsquared 2008-12-04 18:36

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.

bsquared 2008-12-04 18:43

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.

bsquared 2008-12-04 19:41

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]

jasonp 2008-12-04 20:59

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.

akruppa 2008-12-04 21:26

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

bsquared 2008-12-04 22:46

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!!

akruppa 2008-12-04 22:50

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

bsquared 2008-12-04 23:00

: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

akruppa 2008-12-04 23:09

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

jasonp 2008-12-04 23:13

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)

bsquared 2008-12-04 23:14

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.