#1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Apr 2002
    Location
    Inside the GNU/Hurd kernel
    Posts
    492
    Rep Power
    13

    Creating a frontend for bc


    I am trying to create a simple Gtk2 frontend for the bc program, so I started playing around with pipes.
    Bc is a program that can solve expression (e.g. 2+2), and when you run the "bc " command you can type an expression folowed by <enter> and it will output the solution plus a \n .
    Well, my question is, how can I run bc and then pass the expression that the user types into my GUI frontend to bc, and then get the solution and show it in on my GUI?
    I have tried popen(), and I can read the output if I pass a file containing the expression as an argument, but I cant seem pass the expression that the user typed in and then read the output. The code below is what I have so far.

    Code:
    FILE *bc_read;
      int bytes_read;
      size_t nbytes = 100;
      char *my_string;
    
       bc_read = popen ("bc -q /tmp/expression", "r");
     
     
      if ((!bc_read) )
        {
          cout <<   "Pipe failed.\n" << endl;
          return EXIT_FAILURE;
        }
        
      my_string = (char *) malloc (nbytes );
      bytes_read = getline (&my_string, &nbytes,bc_read);
      
      if (pclose (bc_read) != 0)
        {
                  cout <<  "Error.\n" << endl;
        }
      
      cout << my_string;
    Could someone help me out?

    Thank you in advance.
  2. #2
  3. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,175
    Rep Power
    2222
    Just to offer a little brain-storming.

    Is it possible to do a popen for both read and write?

    Or, lay the pipe by hand, so to speak.
    1. call pipe.
    2. fork
    3. have the child dup its end of the pipe to stdin and stdout, then close its end of the pipe. This will make reads from stdin and writes to stdout come from and go to the pipe.
    4. do your favorite flavor of exec* to run bc.
    5. The parent process communicates with bc through the pipe.

    I've seen it described, but I haven't tried it yet.
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Apr 2002
    Location
    Inside the GNU/Hurd kernel
    Posts
    492
    Rep Power
    13
    I don't think so, because you cant do popen ("bc", "rw") .

    I'll try what you have described, although I don't understand what you are talking about :)
    Last edited by Tuxie; June 16th, 2003 at 02:05 PM.
  6. #4
  7. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,175
    Rep Power
    2222
    For fun, I put a rudimentary example together of fork-exec'ing bc with its stdin and stdout redirected to pipes. Sorry for the delay, but I kept getting a "broken pipe" error which I finally tracked down to having not called exec* properly:
    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <wait.h>
    
    /* bcfe -- bc front end
    	Create a process running bc and send commands and read responses
    	via pipes.
    */
    
    int main(void) 
    {
    	char buf[64]; 
    	int wrpipe[2];	// two file descriptors:
    	int rdpipe[2]; 	//   [0] read, [1] write
    	int pid;
    
    	// open the two pipes
    	// note that a single pipe should not be used for bidirectional
    	//  communication, so we open one to write to and one to read from.
    	if (pipe(wrpipe) == -1) 
    	{
    		perror("wrpipe error"); 
    		exit(-1);
    	}
    	if (pipe(rdpipe) == -1) 
    	{
    		perror("rdpipe error"); 
    		exit(-1);
    	}
    
    	// fork a child process
    	pid = fork( );
    	if (pid == -1) 
    	{
    		perror("fork error"); 
    		exit(-1);
    	}
    
    	// initialize the buffer
            memset(buf,0,64);
    
    	// different actions for child and parent
    	if (pid == 0) 
    	{	// child
    		// perform redirection 
    		// close stdin & stdout then dup pipes to them
    		close(0);    	// close stdin
    		dup2(wrpipe[0],0);
    		close(1);	// close stdout
    		dup2(rdpipe[1],1);
    
    		// close our end of the pipes
    		close(wrpipe[0]);	// write pipe
    		close(wrpipe[1]);	// write pipe
    		close(rdpipe[0]);	// read pipe
    		close(rdpipe[1]);	// read pipe
    
    		// run bc
    		// this replaces the child process, but keeps its file descriptors
    		execlp("bc","bc",0);
    
    		// will never reach here
    	}
    	else 
    	{	// parent
    		// close the read-end of the write pipe and
    		// the write-end of the read pipe
    		close(wrpipe[0]);	// write pipe
    		close(rdpipe[1]);	// read pipe
    
    		// send a problem to bc
    		write(wrpipe[1],"1+1\n",4);
    
    		// read bc's answer and echo it to stdout
    		read(rdpipe[0],buf,64);
    		printf("%s\n",buf);
    
    		// command bc to quit
    		write(wrpipe[1],"quit\n",5);
    
    		// wait for bc to terminate
    		waitpid(pid,NULL,0);
    
    		// close the pipes
    		close(wrpipe[1]);	// write pipe
    		close(rdpipe[0]);	// read pipe
    	}
        return 0;
    }
    Of course, in your case the parent's communication with bc and with the user will be more complex and interactive, but this should give you the basics of tying stdin and stdout to pipes and using them with a child process. Hope it helps.
    Last edited by dwise1_aol; June 17th, 2003 at 11:43 AM.

IMN logo majestic logo threadwatch logo seochat tools logo