Создание базовой оболочки, в частности, с помощью execvp()

В моей программе я принимаю пользовательский ввод и анализирую его в массив 2d char. Массив объявлен как:

char parsedText[10][255] = {{""},{""},{""},{""},{""},
            {""},{""},{""},{""},{""}};

и я использую fgets для захвата пользовательского ввода и его анализа с помощью sscanf. Все это работает так, как я думаю.

После этого я хочу передать parsedText в execvp, parsedText[0] должен содержать путь, и если какие-либо аргументы предоставлены, они должны быть в parsedText[1] через parsedText[10].

Что не так с execvp(parsedText[0], parsedText[1])?

Одна вещь, вероятно, стоит упомянуть, это то, что если я укажу только команду, такую ​​​​как «ls», без каких-либо аргументов, она будет работать нормально.

Вот мой код:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "308shell.h"

int main( int argc, char *argv[] )
{
char prompt[40] = "308sh";
char text[40] = "";
char parsedText[10][40] = {{""},{""},{""},{""},{""},
                           {""},{""},{""},{""},{""}};

// Check for arguments to change the prompt.
if(argc >= 3){
    if(!(strcmp(argv[1], "-p"))){
        strcpy(prompt, argv[2]);
    }
}

strcat(prompt, "> ");

while(1){
    // Display the prompt.
    fputs(prompt, stdout);
    fflush(stdout);

    // Grab user input and parse it into parsedText. 
    mygetline(text, sizeof text);
    parseInput(text, parsedText);

    // Check if the user wants to exit.
    if(!(strcmp(parsedText[0], "exit"))){
        break;
    }
    execvp(parsedText[0], parsedText[1]);
    printf("%s\n%s\n", parsedText[0], parsedText[1]);
}

return 0;
}

char *mygetline(char *line, int size)
{
if ( fgets(line, size, stdin) )
{
    char *newline = strchr(line, '\n'); /* check for trailing '\n' */
    if ( newline )
    {
        *newline =  '\0'; /* overwrite the '\n' with a terminating null */
    }
}

return line;
}

char *parseInput(char *text, char parsedText[][40]){
char *ptr = text;
char field [ 40 ];
int n;
int count = 0;

while (*ptr != '\0') {
    int items_read = sscanf(ptr, "%s%n", field, &n);
    strcpy(parsedText[count++], field);
    field[0]='\0';
    if (items_read == 1)
        ptr += n; /* advance the pointer by the number of characters read     */
    if ( *ptr != ' ' ) {
        strcpy(parsedText[count], field);
        break; /* didn't find an expected delimiter, done? */
    }
    ++ptr; /* skip the delimiter */
}

}

person tgai    schedule 05.02.2011    source источник


Ответы (1)


execvp принимает указатель на указатель (char **), а не указатель на массив. Предполагается, что это указатель на первый элемент массива char * указателей, заканчивающийся нулевым указателем.

Редактировать: Вот один (не очень хороший) способ сделать массив указателей подходящим для execvp:

char argbuf[10][256] = {{0}};
char *args[10] = { argbuf[0], argbuf[1], argbuf[2], /* ... */ };

Конечно, в реальном мире ваши аргументы, вероятно, исходят из строки командной строки, введенной пользователем, и они, вероятно, имеют по крайней мере один символ (например, пробел) между ними, поэтому гораздо лучшим подходом было бы либо изменить исходную строку в- поместите его или создайте его дубликат, а затем измените дубликат, добавив разделители null после каждого аргумента и настроив args[i] так, чтобы он указывал на правильное смещение в строке.

Вместо этого вы могли бы выполнять много динамического распределения (malloc) на каждом этапе пути, но тогда вам придется писать код для обработки каждой возможной точки отказа. :-)

person R.. GitHub STOP HELPING ICE    schedule 05.02.2011
comment
Думаю, я все еще немного смущен (char **). Как именно тогда я попытаюсь правильно определить эти массивы символов? Кроме того, это домашнее задание, поэтому я полностью согласен с простым примером. Не пытаясь заложить мою домашнюю работу на /. - person tgai; 06.02.2011