tags:

views:

96

answers:

3

This Program works fine with exception for one aspect of smarthistory(). I cannot figure out why when I enter a command number from the smarthistory array why it doesn't execute. After entering the command to execute from the list nothing happens not even the printf statement right after. I am using the gcc compiler.

const int MAX_HISTORY=100;

const int MAX_COMMAND_LENGTH=64;

char history[100][64];
int historyCount = 0;
char smarthistory[100][64];
int smarthistoryCount=0;

void chopnl(char *s) { //strip '\n'
    s[strcspn(s, "\n")] = '\0';
}

void printHistory() {
    int i;
    for (i = 0; i < historyCount; i++)
        printf("%d | %s\n", i, history[i]);
}

void printSmartHistory() {
    int i;
    for (i = 0; i < smarthistoryCount; i++)
        printf("%d | %s\n", i, smarthistory[i]);
}

void isPartialMatch(char *commandQuery,char *history, int historyString)
{
    int lengthOfQuery=strlen(commandQuery);
    if(strncmp( history, commandQuery,lengthOfQuery)==0)
    {
        memcpy(smarthistory[smarthistoryCount++], history, strlen(history) + 1);
    }
    else
        return;

}

void smartHistory()
{
    char commandQuery[MAX_COMMAND_LENGTH];
    int commandNumber=0;
    int i=0;
    printHistory();
    printf("enter partial command:> ");
    fgets(commandQuery,MAX_COMMAND_LENGTH,stdin);
    chopnl(commandQuery);
    //printf("%d", strlen(commandQuery));

    for(i=0;i<=historyCount;i++)
    {
            isPartialMatch(commandQuery, history[i], i);
    }
    printf("SmartHistory Search Results\n");
    printSmartHistory();
    printf("enter a command number to execute:> ");
    scanf("%d", commandNumber);
    //chopnl(commandNumber);
    printf("command entered >");
    handleCommand(smarthistory[commandNumber]);
}
void placeInHistory(char *command) {
    // printf("command:> %s |stored in:> %d",command,historyCount );
    memcpy(history[historyCount++], command, strlen(command) + 1);
}

int main(int argc, char** argv) {
    char command[MAX_COMMAND_LENGTH];

    while (1) {
        printf("SHELL:>");
        fgets(command, MAX_COMMAND_LENGTH, stdin);
        chopnl(command);
        if (strcmpi(command, "exit") == 0)
            return EXIT_SUCCESS;
        placeInHistory(command);
        handleCommand(command);
    }
    return (EXIT_SUCCESS);
}

int handleCommand(char *command) {
    pid_t pid;
    int test=0;
    pid = fork();

    if (pid > 0) {
        wait(&test);
    } else if (pid == 0) {
        execCommand(command);
        exit(0);
    } else {
        printf("ERROR");
    }
}

int execCommand(char *command) {
    //system(command);    

    if (strcmpi(command, "history") == 0)
    {
        printHistory();
    }
    else if(strcmpi(command, "smarthistory") == 0)
    {
        smartHistory();
    }
    else if (strcmpi(command, "ls") == 0 || (strcmpi(command, "pwd") == 0)) {
        char *path[] = {"/bin/", NULL};
        strcat(path[0], command);
        execve(path[0], path, NULL);
    }else{system(command);}
}
+1  A: 

Recheck this:

char *path[] = {"/bin/", NULL};
strcat(path[0], command);

path[0] is initialised with const char*, and you cannot use strcat() on that.

Another one:

memcpy(smarthistory[smarthistoryCount++], history, strlen(history) + 1);

shouldn't both, source and destination, be of the same type, char*?

Also, I'd suggest to use char* history[MAX_HLEN]

instead of char history[x][y].

ruslik
That part of the program works for example if I enter ls as a command it prints the desired result, and this is true for many other commands. The only problem I am having is getting the commands sent from the smarthistory function to execute.
Joe
It works only because your OS don't enforce the read-only flag on the constant memory area. And it better crash there, because the memory of your program will be corrupted so you'll get the so called `undefined behavior`.
ruslik
I see now, "many other commands" being `ls` and `pwd`. Anything longer than `strlen("/bin/")` would be dangerous anyway.
ruslik
No it works for du,cat,cal,date,dir,dirs,echo...and as i said many more.
Joe
In ISO C, string constants are *not* type `const char[]`, they are simply `char[]`. In C++, they are `const`.
Loadmaster
@Loadmaster does it mean that `char x[] = "a"; strcat(x, "buhaha");` is safe in ISO C?
ruslik
Oh and sorry ruslik i see what you measn about ls and pwd....
Joe
`char x[] = "a"; x[0] = 'b';` is safe in ISO C (but `char *x = "a"; x[0] = 'b';` is not). With `strcat` it's not safe either way.
Zack
@rsulik: No, because you're overwriting static data (which could be implemented as const (ROM) data, even though its type is not const), and you're writing to memory past the end of the data item (string).
Loadmaster
A: 

I'm not sure, but it looks like the handling of "history" and "smarthistory" should be moved from execCommand to handleCommand and should occur INSTEAD OF forking. There may be other bugs.

Zack
The desired functionality is for the child process to execute all the commands.
Joe
I made this change and now when I select a command from the smarthistory prompt I get a seg fault.
Joe
A: 

Problem solved the problem was I needed to add an '&' before commandNumber in the statement: scanf("%d", commandNumber); located in the smartHistory function. What strikes me as odd is I made another version of this where I moved the "history" and "smarthistory" into the handle command function instead of the execCommand function. When I did this the program prints the shell prompt 3 times...if anyone knows why, please let me know. However in the version above just adding the '&' works great.

Joe