mersenneforum.org  

Go Back   mersenneforum.org > Extra Stuff > Programming

Reply
 
Thread Tools
Old 2008-12-04, 18:36   #1
bsquared
 
bsquared's Avatar
 
"Ben"
Feb 2007

D1116 Posts
Default 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

- ben.
bsquared is online now   Reply With Quote
Old 2008-12-04, 18:43   #2
bsquared
 
bsquared's Avatar
 
"Ben"
Feb 2007

334510 Posts
Default

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 is online now   Reply With Quote
Old 2008-12-04, 19:41   #3
bsquared
 
bsquared's Avatar
 
"Ben"
Feb 2007

3·5·223 Posts
Default

Ok, here's my hackish workaround. I'd still like to know how to do this right...

Code:
start = clock();
//wait for input from user
while (1)
{
   //get a new random seed after every transaction
 srand((unsignedint)time(&tt));
 
  //if there are command line arguments, don't wait for user input
 //the expression to be evaluated is already in 's'
 if (argc <= 1)
 {
    printf("\n");
    fflush(stdout); 
    scanf("%[^\n]",s); //read everything up to carriage return
    stop = clock();
    //hack. if no time has elapsed, this must have come from
    //the pipe or a redirect. treat the same as a command line expression.
    if (((double)(stop - start)/(double)CLOCKS_PER_SEC) < 0.01)
       do_once = 1; 
 }
 
.
.
.
bsquared is online now   Reply With Quote
Old 2008-12-04, 20:59   #4
jasonp
Tribal Bullet
 
jasonp's Avatar
 
Oct 2004

66418 Posts
Default

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.
jasonp is offline   Reply With Quote
Old 2008-12-04, 21:26   #5
akruppa
 
akruppa's Avatar
 
"Nancy"
Aug 2002
Alexandria

9A016 Posts
Default

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

Last fiddled with by akruppa on 2008-12-04 at 21:27 Reason: typo
akruppa is offline   Reply With Quote
Old 2008-12-04, 22:46   #6
bsquared
 
bsquared's Avatar
 
"Ben"
Feb 2007

1101000100012 Posts
Default

This is getting bizarre.

The following works for everything (windows, linux, gcc, MSVC, pipes, redirects, normal operation) *except* pipes in linux.

Code:
fseek(in,-1,SEEK_END);
if (argc > 1)
{
  //handle the case where we have command line arguments
  do_once = 1;
  strcpy(s,argv[1]);
}
else
{
  //on linux, gcc-3.2.3, this works for redirects but not for pipes
  //works fine for both on win, MSVC express edition 2008
  if (ftell(stdin) >= 0)
  {
     rewind(stdin);
     fgets(s,1024,in);
     do_once = 1;
  }
}
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!!
bsquared is online now   Reply With Quote
Old 2008-12-04, 22:50   #7
akruppa
 
akruppa's Avatar
 
"Nancy"
Aug 2002
Alexandria

25·7·11 Posts
Default

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
akruppa is offline   Reply With Quote
Old 2008-12-04, 23:00   #8
bsquared
 
bsquared's Avatar
 
"Ben"
Feb 2007

3×5×223 Posts
Default

. 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
bsquared is online now   Reply With Quote
Old 2008-12-04, 23:09   #9
akruppa
 
akruppa's Avatar
 
"Nancy"
Aug 2002
Alexandria

25×7×11 Posts
Default

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

Last fiddled with by akruppa on 2008-12-04 at 23:10
akruppa is offline   Reply With Quote
Old 2008-12-04, 23:13   #10
jasonp
Tribal Bullet
 
jasonp's Avatar
 
Oct 2004

3×1,163 Posts
Default

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)
jasonp is offline   Reply With Quote
Old 2008-12-04, 23:14   #11
bsquared
 
bsquared's Avatar
 
"Ben"
Feb 2007

3·5·223 Posts
Default

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...
bsquared is online now   Reply With Quote
Reply

Thread Tools


Similar Threads
Thread Thread Starter Forum Replies Last Post
More User friendly main page Sutton Shin mersennewiki 0 2012-09-29 08:03
What is the main cause of the high oil prices? MooooMoo Lounge 17 2009-04-10 22:36
Question about RAM usage for dual-core for OPN's main effort. jasong GMP-ECM 18 2006-07-17 00:23
[Problem] Going to main page when logging in alpertron mersennewiki 0 2006-01-03 13:23
Main Computer Dead Prime95 Hardware 11 2004-11-02 22:29

All times are UTC. The time now is 21:08.

Mon Nov 30 21:08:18 UTC 2020 up 81 days, 18:19, 2 users, load averages: 2.46, 2.45, 2.34

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.

This forum has received and complied with 0 (zero) government requests for information.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation.
A copy of the license is included in the FAQ.