0

I'm currently programming a shell which grabs input and stores it in a string (char*) array. To enable UNIX operations like pipelining, I want to be able to write commands like

echo this | function more | function2

To do this, I'm collecting the command and its arguments in a while loop, and try to copy all contents of the argument array into a new, 2-dimensional array which holds the entire command line, e.g. "ls -f -a". So far, this works, but then, I'm trying to reset the loop as soon as a "|" was found in the command line, ignore the "|", and begin a new loop doing the same thing until '\0' is found, which marks the end of the original input:

char* arguments[MAXARGS]; // holds argument components, e.g. "ls" or "-f"
char** arg_collection[MAXARGS][MAXARGS]; // supposed to hold command lines, e.g. "ls -f -a"
argc_current = 0; // iterator for the loop, counts arguments
col_iterator = 0; // iterator for amount of command lines
int sentinel = 1; // sentinel value for while loop
...

while(sentinel)
{
    arguments[argc_current] = (char*) malloc (sizeof(word)); // word is defined, just not listed on here - refers to the currently read command / argument
     strcpy(arguments[argc_current], word); // copy current word into arguments

    if(tokens[argc_current] == TOKEN_TERMINATOR || tokens[argc_curernt] == TOKEN_NULL)
    {
       sentinel = 0; // tokens holds information about the type of word, e.g. if it is '\0'
    }

    if(tokens[argc_current] == T_BAR) // if the word is "|"
    {
       for(i = 0; i < argc_current; i++)
       {
          strcpy(arg_collection[col_iterator][i], arguments[i]); // copy argument list into collection
       }

       col_iterator++; // increment command line counter
       argc_current = 0; // reset argument counter, restart the loop
    }

    else
    {
        arg_current++; // increment current argument counter
    }
}

evaluating arguments here..

The first loop works fine, e.g. if I type

echo this | echo more |

It fills arg_collection[0][0] and arg_collection[0][1], so I get "echo this" as a result. After having incremented col_iterator to 1, however, I hit a brick wall in form of a segmentation fault when calling strcpy upon noticing the second "|". Why?

Shikai
  • 1
  • 2
  • We can't diagnose problems with code that doesn't compile to begin with. Make a minimal, compilable testcase. Minimal means "excluding any code that isn't absolutely necessary to produce the symptoms of your problem". Compilable means "including enough code for us to be able to compile and debug your program on our systems without having to fill in the blanks or fix basic syntax errors". Please ensure both of these criteria are fulfilled. – autistic Apr 12 '13 at 15:51
  • Yeah, I'll do so in the future. I think I have found the culprit though - I was doing whacky memory allocation, which, of course!, I didn't include here.. – Shikai Apr 12 '13 at 17:10
  • I think you've learnt the value of producing a minimal, compilable testcase: Not only does it verify that the problem is what you think it is, but it also makes the problem stick out like a sore thumb to anyone who you're asking for help. – autistic Apr 13 '13 at 09:13

2 Answers2

2

It looks like word is a char*. If so, you should change

arguments[argc_current] = (char*) malloc (sizeof(word));

to

arguments[argc_current] = malloc(strlen(word)+1);

sizeof(word) will give you the size of a pointer variable, not the size of the data it points to. strlen tells you the number of characters in word. The +1 is needed for the '\0' terminator.

simonc
  • 41,632
  • 12
  • 85
  • 103
0

First you should allocate arg_collection before using it. (As you don't give the entire code, I assume you don't do it).

Then you are dereferencing two times your arg_collection on line:

strcpy(arg_collection[col_iterator][i], arguments[i]); // copy argument list into collection

When you must

strcpy(arg_collection[col_iterator], arguments[i]); 

That is, you are treating the char at index i of string col_iterator in arg_collection as char *, when it is only a char.

silen
  • 524
  • 6
  • 5