0

I've tried thousand options to parse the set of strings I store inside the buffer, but can't find a good way to store them string by string in the *args[] array of strings. What I want to do afterwards is to run execvp inside the Child process.

Thanks!!

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


#define MAX_LINE 80

int main(){

char *args[MAX_LINE/2 + 1];
int should_run = 1;
int background = 1;
char buffer[1024];

    while (should_run){
            printf("jaime$ ");
            int i = 0;
            fflush(stdout);
            while (fgets(buffer, 1024, stdin)){
                    sscanf(buffer, "%s", args[i]);
                    i++;
            }

            pid_t pid;
            pid = fork();

            if (pid < 1){
                    fprintf(stderr, "fork() failed");
..........
4
  • 1
    I don't understand the question. Are you asking how to split and tokenize the input string to parse commands to run with arguments? Commented Dec 26, 2014 at 20:31
  • 2
    You need to read more about the fork system call, you're not checking for the correct return code. Commented Dec 26, 2014 at 20:31
  • Joachim, what do you suggest then for the fork system call? I'm following all the Operating Systems Concepts book instructions... thanks! Commented Dec 27, 2014 at 11:16
  • Etan, yes, that's right. I can't find a way to tokenize the input string. Going to follow some of the guys answers and see how it works... Commented Dec 27, 2014 at 11:19

2 Answers 2

1

Code is not allocating memory to save the stirng

sscanf(buffer, "%s", args[i]);  args[i] is not initialized

Instead allocate needed memory.

Below uses "%n" to note the offset in the string at that point in the scan. " " consumes leading white-space. "%n" stores the scan offset in n1. "%*s" scans just like "%s", but does not store the result. Finally "%n" stores the scan offset in n2. Now code knows, n2-n1, the width in buffer to extract.

 while (fgets(buffer, 1024, stdin)) {
   int n1 = 0;
   int n2 = 0;
   sscanf(buffer, " %n%*s%n", &n1, &n2);
   int length = n2 - n1;
   args[i] = malloc(length + 1);
   if (args[i] == NULL) {
     Handle_OutOfMemory(); // TBD code to cope with OOM.
   } 
   memcpy(args[i], &buffer[n1], length);
   args[i][length] = '\0';
   i++;
 }

 // use args[0] to args[i-1]

 for (int j = 0  j < i; j++) {
   free(args[j]);
   j++;
 }
Sign up to request clarification or add additional context in comments.

3 Comments

Hi Chux, This is really helpful. I have two questions: 1. When I try to compile the program, it tells me that I have an "incompatible declaration of built-in function 'memcpy' [enabled by default]. It also tells me "undefined reference to Handle_OutOfMemory. Any ideas? 2. Could you add comments on lines 4 to 9 explaining exactly what they are doing? Thanks again!
@Jaime Add <string.h> for memcpy(). Handle_OutOfMemory() is a place holder for code you write to cope with the rare event of running out of memory. Maybe print an error message and exit the program? Post updated
Thanks Chux! Now I get it. (Can't vote your post since I still don't have 15 of reputation, but will do it as soon as I do :)
0

Parsing complex strings using the standard C library isn't going to be easy, nor clean. This is especially true if you're trying to create a shell (which is what it looks like).

I would suggest taking a look at lex and yacc, which can be used to build tokenizers and parsers for complex syntaxes (including shell languages like bash).

Here's a decent introductory tutorial on lex and yacc. If you want to learn by example, you can check out bash/parse.y, although its grammar is fairly convoluted and complex.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.