C Code for a Calculator Using Pipes and ‘bc’

This code implements a calculator that reads arithmetic operations from an input file, uses the ‘bc’ command-line utility to perform the calculations, and writes the results to an output file. It demonstrates the use of pipes for inter-process communication in a Linux environment.

Code Description

The program takes two command-line arguments:

  • Input file: Contains arithmetic operations.
  • Output file: Stores the results of the calculations.

The leer_op function reads the input file, identifies arithmetic operations, formats them for ‘bc’, and sends them through a pipe. The child process executes ‘bc’, receives the formatted operations, performs the calculations, and sends the results back through another pipe. The parent process then writes these results to the output file.

The code uses the following system calls:

  • pipe(): Creates a pipe for inter-process communication.
  • fork(): Creates a child process.
  • exec(): Replaces the child process’s image with the ‘bc’ command.
  • read(): Reads data from a file or pipe.
  • write(): Writes data to a file or pipe.
  • open(): Opens a file.
  • close(): Closes a file or pipe.
  • lseek(): Moves the file pointer.
  • wait(): Waits for the child process to terminate.

Code Example


#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>

#define NARGS 2 + 1
#define BUFFER_LENGTH 1
#define OP_LENGTH 7

int
esnumero(char c){
	return c >= '0' && c<= '9';
	}
	
void
leer_op(int infile,int outfile,int padrehijo[],int hijopadre[],int *lines,int *operations){
	int finish;
	char buffer[BUFFER_LENGTH];
	char op[OP_LENGTH+1];
	int finish_result;
	ssize_t br;
	int i;
	
	finish = 0;
	(*lines) = 0;
	(*operations)  = 0;
	
	while(!finish){
		finish = (br = read(infile,buffer,BUFFER_LENGTH)) <= 0;
		if(buffer[0] == '\n'){
			(*lines)++;
			}
		if((!finish)&&(esnumero(buffer[0]))){
			lseek(infile,-1,SEEK_CUR);
			finish = (br = read(infile,op,OP_LENGTH)) <= 0;
			if(!finish){
				op[OP_LENGTH] = '\n';
				for(i = 0;i<OP_LENGTH;i++){
					if(op[i] == 'A'){
						op[i] = ' ';
						op[i+1] = '+';
						op[i+2] = ' ';
						write(outfile,op,OP_LENGTH);
					}
						
					if(op[i] == 'S'){
						op[i] = ' ';
						op[i+1] = '-';
						op[i+2] = ' ';
						write(outfile,op,OP_LENGTH);
					} 													
						
					if(op[i] == 'D'){				
						op[i] = ' ';
						op[i+1] = '/';
						op[i+2] = ' ';
						write(outfile,op,OP_LENGTH);
					}
						
					if(op[i] == 'M'){
						op[i] = ' ';
						op[i+1] = '*';
						op[i+2] = ' ';
						write(outfile,op,OP_LENGTH);																		
					}
				} 				
				write(outfile," = ",3);
				write(padrehijo[1],op,OP_LENGTH +1);
				finish_result = 0;
				while((!finish_result)&&(br = read(hijopadre[0],buffer,1)) >0){
					write(outfile,buffer,1);
					finish_result = buffer[0] == '\n';
					}
				(*operations)++;
			}
			
		} 	
	}
	write(padrehijo[1],"quit\n",5);
	}
	
int
main(int argc,char *argv[]){
	int padrehijo[2], hijopadre[2];
	int infile, outfile;
	int pid;
	int status;
	int lines;
	int operations;
	
	switch(argc){
		case NARGS: 
			pipe(padrehijo);
			pipe(hijopadre);
			
			pid = fork();
			switch(pid){
				case -1:
					perror("Fork Error");
					exit(EXIT_FAILURE);
					break;
				case 0:
					close(padrehijo[1]);
					close(hijopadre[0]);
					
					close(0);
					dup(padrehijo[0]);
					close(padrehijo[0]);
					
					close(1);
					dup(hijopadre[1]);
					close(hijopadre[1]);
					
					execlp("bc","bc",NULL);
					exit(EXIT_FAILURE);
					break;
					
				default:
					close(padrehijo[0]);
					close(hijopadre[1]);
					
					infile = open(argv[1],O_RDONLY);
					outfile = open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,0777);
					
					lines = 0;
					operations = 0;
					leer_op(infile,outfile,padrehijo,hijopadre,&lines,&operations);
					
					wait(&status);
					if(WIFEXITED(status)){
						printf("Se han contado %d lineas,", lines-1);
						printf(" %d de ellas con operaciones aritméticas.",operations);
						printf("El valor de retorno es %d\n",WEXITSTATUS(status));
						}
					close(infile);
					close(outfile);
				} 				
			break;
		default:
			fprintf(stderr,"[Usage Error]: %s IN_FILE OUT_FILE\n",argv[0]);
			exit(EXIT_FAILURE);
			break;
		}
	
	exit(EXIT_SUCCESS);
	
	}

//gcc -o calculadora calculadora.c
// --> ./calculadora archivo archivo

How to Compile and Run

  1. Save the code as calculadora.c.
  2. Compile: gcc -o calculadora calculadora.c
  3. Run: ./calculadora input_file output_file

Replace input_file with the path to your input file and output_file with the desired output file path.