Сборка базовой оболочки, более конкретно с использованием execvp () - PullRequest
1 голос
/ 06 февраля 2011

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

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 */
}

}

1 Ответ

2 голосов
/ 06 февраля 2011

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

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

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

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

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

...