rewind(stdin) assistance needed

How do I make this function work under linux? When I compile and run my program in Windows, this function works perfectly. But when I compile and run in linux it doesn't do anything.
Unlikely.
Ok, then maybe you can help me. Below is a sample of my code and the root of my problem. My program is a command interpreter. The following code will execute the 'dump' command which needs two parameters. Now when I enter 'dump 100 200' it works fine. But when I enter just the dump command, it is suppose to ask for the starting and ending value's. When I enter the starting and ending values it loops back and displays "COMMAND->COMMAND->" instead of just "COMMAND->". I tried rewind(stdin) and it works in windows.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

bool prefix_match( const char* arg, const char* pattern )
{
	return strstr( pattern, arg ) == pattern;
}

int main()
{
    //declare variables
    char command_line[256]; //store entire command line
    char* arguments[100]; //store arguments from command line
    int argcount; //argument count index
    int startAddress,endAddress; //start and end address for the dump command

	printf("Welcome to the Command Interpreter\nCreated by Michael Herald\n\n");
    do
    {

	//show prompt to user
	printf("COMMAND->");
	fgets(command_line,256,stdin); //get command from user
	argcount = 0; //argument counter index
	//split command line into tokens
	(arguments[argcount]) = strtok(command_line," \n");
	while(arguments[argcount]!=NULL)
	{
	    argcount ++;
	    arguments[argcount] = strtok(NULL," \n");
	}
	
	//select command from list
	if(argcount >0 )
	{
			.
			.		
			.

	    else if(prefix_match(arguments[0],"dump")==true)
	    {
			if (argcount!=3)
			{ //If the user does not enter parameters, then ask for them
				switch(argcount)
				{
				case 1: // Start Address
					printf("Enter start address: ");
					scanf("%x", &startAddress); 
				case 2: // End Address
					if(argcount==2)
					startAddress = strtol(arguments[1],NULL,16);
					printf("Enter end address: ");
					scanf("%x",&endAddress); 
					break;
				default: 
					printf("Wrong number of arguments! See help for more info.\n");
					continue; 
				}
			}
			else
			{
    			startAddress = strtol(arguments[1],NULL,16); 
				endAddress = strtol(arguments[2],NULL,16);
			}

			printf("Dumping memory from %x to %x.\n",startAddress,endAddress);
			continue;
	    
	    }
			.
			.
			.
	}
    }while(1); //main loop
    
    return 0;
}
There seems to be a leftover '\n' in the buffer. Try fflush(stdin). I read that it's not guaranteed to flush the buffer ("In some implementations this causes the input buffer to be cleared, but this is not standard behavior."), but it's worth a try.
I tried that, and it doesn't work under linux. Works fine in Windows though.
Would you be willing to change all your stdin to std::cin?
Last edited on
Yeah, I'm willing to try anything to get it working. Everything else works great except for this.
You can use getline() (http://www.cplusplus.com/reference/string/getline.html ) to input directly into an std::string. This doesn't leave '\n' leftovers.
If you don't want to get rid of all your C strings code, you can later extract the C string with std::string::c_str() and maybe copy it to an actual C string.

PS: Although I still find it (kind of) weird that the code has different behaviors in different platforms.
Last edited on
I looked at the examples and tried a few times, but I'm not sure how to implement the getline() into my above code.
The std::cin and getline() stuff are all C++ entities. You won't get them to work without compiling with a C++ compiler. I don't recommend mixing C and C++ files blithely.

helios hit it right on:

fgets() reads everything up to and including the terminating '\n'. You can tell whether or not you have read the entire line of input by checking for that '\n' at the end of the line.

scanf() reads only that which it is asked, and no more. So not only will you leave an extra '\n' in the input, your user could have left other stuff there also.

In C, I always recommend that you not use the standard input functions directly, but that you build something a little more powerful on top of them.

This is such a common need that you might want to check out the GNU Readline Library. You won't be disappointed.
http://tiswww.case.edu/php/chet/readline/rltop.html

If you can't use it (for whatever reason), you can roll your own input very simply:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
char* simple_readline( const char* prompt, unsigned block_size )
  {
  char* result;   /* The malloc()ed string to return */
  char* block;    /* Each chunk of the string */
  char* ok;       /* Used to check for input errors */
  unsigned size;  /* The current size of the entire string */
  unsigned n;     /* strlen() of the last block */

  if (!block_size) block_size = 50;

  if (prompt) printf( "%s", prompt );

  block = result = (char*)malloc( size = block_size );
  if (!result) return NULL;
  *result = '\0';

  for (;;)
    {
    /* Get the next block of characters until EOL */
    ok = fgets( block, block_size, stdin );
    if (!ok) break;

    /* If we found EOL we are done */
    n = strlen( block );
    if (block[ n -1 ] == '\n') break;

    /* Else add more memory and try again */
    ok = (char*)realloc( result, size += block_size );
    if (!ok) break;

    block  = ok +block -result -1;
    result = ok;
    }

  if (!(*result))
    {
    free( result );
    result = NULL;
    }

  return result;
  }


Now use it exclusively for input.
1
2
3
4
5
6
7
8
9
10
char* users_input;

printf( "%s", "What is your name? " );
users_input = simple_readline( NULL, 0 );
if (!users_input) return complaint( "fooey!" );

printf( "Hello %s!\n", users_input );

free( users_input );
users_input = NULL;


Etc. To read numbers and the like, use the strtox() functions on the string.
1
2
3
4
5
6
7
8
9
10
double age;
char* users_input = simple_readline( "How old are you? ", 0 );
if (!users_input) return complaint( "fooey again!" );

age = strtod( users_input, NULL );  /* don't forget to actually do some error checking here (I didn't) */

free( users_input );
users_input = NULL;

printf( "You are %f dog-years old.\n", age / 7.0 );

Hope this helps.
Last edited on
Thanks for the info, but I think I might try changing it to C++.

What is the similiar C++ code for scanf() and printf()? Just cout and cin?

And can I just use cin.getline(command_line,256); instead of fgets?

Duoas, my cpp file is only 3K right now.
You are going to have the same problem in either language. You cannot blithely mix input methods.

C (char*) C++ (char*) C++ (string)
fgets( s, n, stdin ) cin.getline( s, n ) getline( cin, s )
scanf( "...", ... ) cin >> ... stringstream( s ) >> ...
printf( "...", ... ) cout << ... cout << ...

Again, I recommend against using the simple char* stuff directly. If you are going to switch to C++ then just use std::strings and make your life easier and your programs more robust.

And again, if you mix fgets/getline/whatever with scanf/>>/whatever you'll still get those leftover character problems.

C++ does make things easier for you. At a minimum, you will want to
1
2
3
#include <iostream>
#include <sstream>
#include <string> 


Here are the examples again, but in C++
1
2
3
4
5
6
7
string users_input

cout << "What is your name? ";
getline( cin, users_input );
if (!cin) return complaint( "fooey!" );

cout << "Hello " << users_input << "!\n";

1
2
3
4
5
6
7
8
9
10
double age;
string users_input;

cout << "How old are you? ";
getline( cin, users_input );
if (!cin) then complaint( "fooey again!" );

if (!(stringstream( users_input ) >> age)) return complaint( "numbers, please" );

cout << "You are " << fixed << (age / 7.0) << " dog-years old.\n" );


Read all user input as a string terminated by pressing ENTER (using getline()) and use stringstreams to convert strings to other things.

Good luck!
Last edited on
I changed everything to the C++(char*) method above. Again everything works fine in windows, but I am having the same problem under linux. I will give the C++(string) method a try.

Thanks again for all the help!
Ok, I got it working now in both Linux and Windows. I just created a temp storage for my starting and ending values.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
          char temp[256]; //temporary store input
          .
          .
          .


			else if(prefix_match(arguments[0],"dump") == 1)
			{
				if (argcount!=3)
				{ //If the user does not enter parameters, then ask for them
					switch(argcount)
					{
					case 1: // Start Address
						cout << "Enter start address: ";
						//get string from user into temporary string
						cin.getline(temp,256);
						//convert start address into integer from hex notation
						startAddress = strtol(temp,NULL,16);
					case 2: // End Address
						if(argcount==2)
						//convert start address into integer from hex notation
						startAddress = strtol(arguments[1],NULL,16);
						cout << "Enter end address: ";
						//get string from user into temporary string
						cin.getline(temp,256);
						//convert string into integer from hex notation
						endAddress = strtol(temp,NULL,16);
						break;
					default: // Wrong number of arguments, default case
						cout << "Wrong number of arguments! See help for more info.\n";
						continue; // continue until the correct # of arguments are entered
					}
				}
				else
				//If the user enters the 'dump' command with parameters, then execute the following
				//code
				{   //character string representation of a number into a long integer
					startAddress = strtol(arguments[1],NULL,16);
					endAddress = strtol(arguments[2],NULL,16);
				}
				cout << "Dumping memory from " << hex << startAddress << " to " << endAddress <<endl;
				continue;
			}


Thanks again for all the help and suggestions!
Topic archived. No new replies allowed.