Simple Shell with pipes. Unable to count the pipes

Viewed 36

I'm tasked with implementing pipes in a simple shell program sshell.c. Right now, I am just trying to count the number of pipes, but for some reason I am unable to increment my pipe_count despite being able to print it out and see it from the same array args[ARR_SIZE]. Each argument is printed as a string so when I type "ls | grep hello", I get "ls", "|", "grep", "hello" all in a row when i run it in a for loop (see #ifdef step1).

My question is: How should I set my conditional statement to identify the "|" symbol?

The program that was given to us does the following:

  1. Reads in the Command Line
  2. Stores read data into memory and sends the data into function parse_args()
  3. parse_args() replaces delimiters like '\n', ' ', or '\t' with '\0'and stores those values as tokens in args[ARR_SIZE]
  4. if the number of arguments, num_args is greater than zero, it forks().

My implementations are in the #ifdef directives step1 and step2. I was trying to break it into small steps.

/*
 *  This is a simple shell program from
 *  rik0.altervista.org/snippetss/csimpleshell.html
 *  It's been modified a bit and comments were added.
 *
 *  But it doesn't allow misdirection, e.g., <, >, >>, or |
 *  The project is to fix this.
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <errno.h>
#include <sys/types.h>
#define BUFFER_SIZE 80
#define ARR_SIZE 80

#define DEBUG 1  /* In case you want debug messages */
#define step1 /*Detect the pipe char*/
//#define step2 /*create pipes*/
//#define step3 /*fork*/

/*Variables for pipes*/
int in[2], out[2], n;
char buf[255];

void error(char *s);

void parse_args(char *buffer, char** args, 
                size_t args_size, size_t *nargs)
{
    char *buf_args[args_size]; 
    
    char *wbuf = buffer;
    buf_args[0]=buffer; 
    args[0]=buffer;  /* First argument */
/*
 *  The following replaces delimiting characters with '\0'. 
 *  Example:  " Aloha World\n" becomes "\0Aloha\0World\0\0"
 *  Note that the for-loop stops when it finds a '\0' or it
 *  reaches the end of the buffer.
 */   
    for(char **cp=buf_args; (*cp=strsep(&wbuf, " \n\t")) != NULL ;){
        if ((**cp != '\0') && (++cp >= &buf_args[args_size]))
            break; 
    }


/* Copy 'buf_args' into 'args' */    
    size_t j=0;
    for (size_t i=0; buf_args[i]!=NULL; i++){ 
        if(strlen(buf_args[i])>0)  /* Store only non-empty tokens */
            args[j++]=buf_args[i];
    }
    
    *nargs=j;
    args[j]=NULL;


}

int main(int argc, char *argv[], char *envp[]){
    char buffer[BUFFER_SIZE];
    char *args[ARR_SIZE];
    int num_pipes = 0;
    size_t num_args;
    pid_t pid;
    
    while(1){
        printf("ee468>> "); 
        fgets(buffer, BUFFER_SIZE, stdin); /* Read in command line */
        parse_args(buffer, args, ARR_SIZE, &num_args);


#ifdef step1 /*Detect pipe symbol in args*/
        printf("Printing the args returned from parse_args:\n");
        for(int i = 0; i < ARR_SIZE && args[i]!= NULL; i++){
            printf("args[%d]: %s\n",i, args[i]);
            if(args[i]== "\0|\0" || args[i]=="|"){
                num_pipes++;
            }
        }
        printf("There are %d pipes in the buffer.\n",num_pipes);
#endif

        if (num_args>0) {
            if (!strcmp(args[0], "exit" )) exit(0);       
            pid = fork();
            if (pid){  /* Parent */
#ifdef DEBUG
                printf("Waiting for child (%d)\n", pid);
#endif
                pid = wait(NULL);
#ifdef DEBUG
                printf("Child (%d) finished\n", pid);
#endif
            } 
            else{  /* Child executing the command */
                if( execvp(args[0], args)) {
                    puts(strerror(errno));
                    exit(127);
                }
            }

        }
    }    
    return 0;
}

void error(char *s) 
{ 
  perror(s); 
  exit(1); 
}

Example Result

1 Answers
if(args[i]== "\0|\0" || args[i]=="|"){

This line does not work as you are only comparing the pointers. To compare strings in C you have to use strcmp(), so it should look something like this:

if (!strcmp(args[i], "|")) {
    num_pipes++;
}

Moreover, you shouldn't have a string that contains a NUL character. C treats the NUL char as the end of the string so everything that follows the NUL char is basically ignored.

Related