How to implement history function? - c

I am new to C programming and currently learning this into a course. I'm facing an issues while trying to practice the below history function.
I'm able to display the shell commands. However, when I type history, the past shell commands are not getting saved into the history buffer.
Can anyone help me to find where I went wrong?
Here is my code:
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#define BUFSIZE 20
#define MAX_WORD_IN_LINE 20
int tokenize(char *str, char **args)
{
int i, argc = 0;
char *token;
token = strtok(str," \t\n");
for(i=0; token!=NULL;i++)
{
args[i] = token;
printf("args[%d] = %s\n", i, args[i]);
token = strtok(NULL, " \t\n");
argc++;
}
return argc;
}
void display_strings(char **p)
{
if (p == NULL) return;
while(*p != NULL){
printf("%s\n",*p);
p++;
}
}
int history(char *hist[], int current){
int i = current;
int hist_num = 1;
do {
if (hist[i]) {
printf("%4d %s\n", hist_num, hist[i]);
hist_num++;
}
i = (i + 1) % BUFSIZE;
} while (i != current);
return 0;
}
int main(void){
char *args[MAX_WORD_IN_LINE];
char buffer[BUFSIZE];
char *hist[BUFSIZE];
int i,current=0;
pid_t pid;
int argc;
for(i=0;i<BUFSIZE;i++)
hist[i]= NULL;
while(1) {
memset(args,0,MAX_WORD_IN_LINE);
printf("osh> ");
fgets(buffer, BUFSIZE, stdin);
argc = tokenize(buffer, args);
//display_strings(args);
// skip on empty command
if (argc == 0) continue;
if (strcmp(args[0],"quit") == 0) break;
else if (strcmp(args[0], "hello") == 0) printf("Hello there. How are you?\n");
else if (strcmp(args[0],"history")==0) history(hist,current);
else {
pid = fork();
if (pid == 0) {
hist[current]=strdup(args[0]);
current++;
execvp(args[0], args);
return 0;
}

You need to make a copy of the string that args[0] points to when you save it in hist. Currently, you're just assigning the pointer to the current args[0], and it will be overwritten by the next command. When you print the history, you'll just get the last command repeatedly. So use:
hist[current] = strdup(args[0]);

Related

Issue with libreadline when completing an upper case directory

this is a piece of a shell that I'm creating. I'm having some trouble using libreadline, because when the shell gets loaded and I try to cd in a directory using autocompletion (so pressing TAB), after I press enter I access the directory but I get some strange output before another prompt is printed. I noticed that this happens only when the name of the directory starts with an upper case letter.
Example: "user:: ~ % cd Github" <-- written pressing tab to autocomplete Github
Next prompt is: "8b�/�user :: Github %"
I really cannot understand why, this is something really strange for me.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <signal.h>
#include <readline/history.h>
#include <readline/readline.h>
#include "flush.h"
#include "env.h"
#include "fget.h"
char * flush_builtins[] =
{
"cd",
"help",
"exit",
"ver",
"fget"
};
int flush_num_builtins() {
return sizeof(flush_builtins) / sizeof(char *);
}
int (*flush_func[]) (char **) =
{
&flush_cd,
&help,
&exit_flush,
&ver,
&fget
};
static int flush_startp(char **args)
{
pid_t pid;
int status;
pid = fork();
if (pid == 0)
{
if (execvp(args[0], args) == -1)
{
fprintf(stderr, "flush: command not found\n");
}
exit(1);
}
else if (pid < 0)
{
fprintf(stderr, "flush: command not found\n");
}
else
{
do
{
waitpid(pid, &status, WUNTRACED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
return 1;
}
static int flush_exec(char **args)
{
int i;
if (args[0] == NULL)
{
return 1;
}
for (i = 0; i < flush_num_builtins(); i++)
{
if (strcmp(args[0], flush_builtins[i]) == 0) {
return (*flush_func[i])(args);
}
}
return flush_startp(args);
}
static char * flush_read(void)
{
fflush(stdout);
char *line_read = malloc(sizeof(char) * LINE_BUF);
char *prompt = malloc(sizeof(char) * LINE_BUF);
char *current, buffer[TOK_BUF];
current = getcwd(buffer, TOK_BUF);
strcat(prompt, get_user());
strcat(prompt, " :: ");
if (strcmp(current, get_home()) == 0)
{
strcat(prompt, "~");
}
else
{
strcat(prompt, get_cwd());
}
strcat(prompt, " % ");
line_read = readline(prompt);
if (line_read && *line_read)
{
add_history(line_read);
}
return line_read;
free(prompt);
free(line_read);
free(current);
}
static char **flush_getargs(char * line)
{
int bufsize = TOK_BUF;
int i = 0;
char **tokens = malloc(bufsize * sizeof(char *));
char **token;
if (!tokens)
{
fprintf(stderr, "allocation error\n");
exit(1);
}
token = strtok(line, DELIM);
while (token != NULL)
{
tokens[i] = token;
i++;
token = strtok(NULL, DELIM);
}
tokens[i] = NULL;
return tokens;
}
static void flush_loop(void)
{
char *line;
char **args;
int status;
do
{
line = flush_read();
args = flush_getargs(line);
status = flush_exec(args);
free(line);
free(args);
} while (status);
}
static void handler(int num)
{
signal(SIGINT, handler);
flush_loop();
fflush(stdout);
}
int main()
{
init();
signal(SIGINT, handler);
flush_loop();
return 0;
}
You can not use strcat with a non \0 terminated string:
char *prompt = malloc(sizeof(char) * LINE_BUF);
char *current, buffer[TOK_BUF];
current = getcwd(buffer, TOK_BUF);
strcat(prompt, get_user());
Use strcpy instead of strcat, or calloc instead of malloc

executing commands in own shell - C

I have troubles with creating my own shell in C. Here is the code I have so far
#include "interpreter.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <syslog.h>
void readconfig(int *timeout, char *file){
FILE * fp;
char * line = NULL;
size_t len = 0;
char * token;
fp = fopen(CONFIG, "r");
if (fp == NULL)
{
*timeout = DEFAULTTIME;
}
else
{
while ((getline(&line, &len, fp)) != -1){
token = strtok(line, TOKEN);
if ((strcmp(token,TIME_PERIOD) == 0)){
*timeout = atoi(strtok(NULL, TOKEN));
}
if ((strcmp(token,HISTORY)==0)){
strcpy(file,trim_command(strtok(NULL, TOKEN)));
}
}
}
}
int waitPeriod(pid_t pid){
if(pid) {
int stat_val;
pid_t child_pid;
int time = 0;
while(time < TIME_PERIOD){
child_pid = waitpid(pid, &stat_val, WNOHANG);
if (child_pid == pid){
break;
} else if (child_pid == 0) {
time++;
sleep(1);
}
}
if (time == TIME_PERIOD){
printf("Process ended. Execution time was over. \n");
kill(pid, SIGINT);
if (kill(pid, 0) == 0){
kill(pid, SIGKILL);
}
}
if(WIFEXITED(stat_val)) {
return WEXITSTATUS(stat_val);
}
return 0;
} else {
return -1;
}
}
void splitCommand(char ** parameters, char * command, int count){
char * cm = strtok(command, " ");
int i = 0;
while (cm != NULL){
parameters[i] = malloc(strlen(cm) * sizeof(char *));
parameters[i] = cm;
i++;
cm = strtok (NULL, " ");
}
i++;
parameters[i] = NULL;
}
int getParamsCount(char command[]){
int i;
int count = 1;
int com_length = strlen(command);
for(i=0; i<com_length; i++){
if (command[i] == ' '){
count++;
}
}
return count;
}
void getHistory(FILE * history_file, char ** history_commands){
char line[MAX_INPUT];
int i = 0;
int j;
rewind(history_file);
while (fgets(line, MAX_INPUT, history_file)!= NULL){
history_commands[i] = malloc(strlen(line) * sizeof(char *));
history_commands[i] = strdup(line);
for(j=0; j<MAX_INPUT; j++){
if (history_commands[i][j] == '\n'){
history_commands[i][j] = '\0';
break;
}
}
i++;
}
}
int getNumberOfRows(FILE * history_file){
rewind(history_file);
int lines = 0;
char ch;
while(!feof(history_file)){
ch = fgetc(history_file);
if(ch == '\n'){
lines++;
}
}
return lines;
}
void printCommands(char ** history_commands, int lines){
int i = 0;
int j = 0;
for(j = i; j < lines; j++){
printf("[%d] %s\n", j, history_commands[j]);
}
}
int runCommand(pid_t pid, char * command, char ** parameters, int child){
int count = 0;
switch(pid) {
case -1 :
return -1;
case 0 :
count = getParamsCount(command);
parameters = malloc((count+1) * sizeof(char *));
splitCommand(parameters, command, count);
if (strncmp("cd", parameters[0], 2) == 0){
chdir(parameters[1]);
} else {
execvp(parameters[0], parameters[0]);
}
free(parameters);
return 0;
default :
child = waitPeriod(pid);
printf("Child status: %d\n", child);
command[0] = 0;
free(command);
return 0;
}
}
char * trim_command(char * string){
int l = strlen(string);
int i;
for (i = 0; i<l; i++){
if (string[i] == '\n'){
string[i] = '\0';
}
}
return string;
}
int main(){
char * command;
FILE * history;
char cwd[MAX_INPUT];
pid_t pid = 0;
int child = 0;
int number_of_rows = 0;
int count = 0;
char ** history_commands;
char ** parameters[10];
printf(" Safe comand line interpreter \n");
printf(" Type \"quit\" to cancel interpreter or command \n");
printf(" Type \"history\" to show full command history \n");
printf(" Type \"history number\" to execute command from history \n");
printf("________________________________________________________________________________________\n");
sleep(1);
history = fopen(HISTORY, "a+");
if (history == NULL){
printf("Could not open history file\n");
return -1;
}
while(1){
getcwd(cwd, sizeof(cwd));
printf("Command: [%d]%s : ", child, cwd);
command = malloc(MAX_INPUT * sizeof(char *));
fgets(command, MAX_INPUT, stdin);
trim_command(command);
if (strncmp(QUIT, command, 4) == 0) {
fclose(history);
return EXIT_SUCCESS;
} else if (strncmp("history", command, 7) == 0) {
number_of_rows = getNumberOfRows(history);
history_commands = malloc(number_of_rows * sizeof(char *));
getHistory(history, history_commands);
count = getParamsCount(command);
if (strcmp("history", command) == 0){
printf("HISTORY OF COMMANDS\n");
printCommands(history_commands, number_of_rows);
} else {
char * cm = strtok(command, " ");
cm = strtok(NULL, " ");
int x;
x = atoi(cm);
if (x >= number_of_rows){
printf("Command does not exist\n");
continue;
}
command = strdup(history_commands[x]);
count = getParamsCount(command);
trim_command(command);
fprintf(history, "%s\n", command);
pid = fork();
runCommand(pid, command, parameters, child);
}
} else if (command[0] != 0){
fprintf(history, "%s\n", command);
pid = fork();
runCommand(pid, command, parameters, child);
}
}
fclose(history);
return 0;
}
The problem is, it doesn't execute cd command. When I comment malloc and free lines in runCommand method, cd command starts working, but every other command without parameter is not working...
could somebody help me with this?

Can't solve Segmentation fault (core dumped) in c

we are writing a program that has to mimic the Linux shell.
It is consisted of some parts. Every part does what the previous part did, plus something extra.
Part one runs single commands like ls, pwd etc. No parameters no
redirection.
Part two runs single commands plus redirection.
This is where we are stuck.. We compile myShell 2 without errors. But when we are typing any command we get the segmentation fault.
We're sorry for writing almost all out code here(myShell 1 not included), we just wanted to make sure you have everything you need to tell us where we are wrong.
functions.h
#ifndef FUNCTIONS_H
#define FUNCTIONS_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#define max 260
extern int argCounter(char *argLine,char *delim);
extern void myExec(char *argLine,int howMany,char *delim);
extern char **argArray(char* argLine,int howMany,char *args[],char *delim);
void myExecRedir(char **tokens,char* argLine, int howMany);
#endif
functions.c
#include "functions.h"
int argCounter(char *argLine,char *delim)
{
char *temp;
memcpy(temp,argLine,strlen(argLine));
char *pointer = strtok(temp, delim);
int counter = 0;
while (pointer != NULL)
{
counter++;
pointer = strtok(NULL, delim);
}
return counter;
}
void myExec(char *argLine,int howMany,char *delim)
{
char temp[max];
memset(temp,0,max);
char *args[howMany];
argLine[strlen(argLine)-1] = '\0';
//argArray breaks the argLine and returns an array that contains each argument
argArray(argLine,howMany,args,delim);
execvp(args[0],args);
perror("ERROR: wrong command!");
}
char **argArray(char *argLine,int howMany,char *args[],char *delim)
{
args[howMany] = NULL;
char *pointer = strtok(argLine, delim);
int counter = 0;
while (pointer != NULL)
{
args[counter]=pointer;
counter++;
pointer = strtok(NULL, delim);
}
return args;
}
void myExecRedir(char **tokens,char* argLine, int howMany)
{
char *delim3="<";
char *delim4=">";
int howManyIn= argCounter(argLine,delim3);
int howManyOut= argCounter(argLine,delim4);
if(howManyOut= howManyIn)
{
int fdin = open(tokens[1],O_RDWR);
int fdout = open(tokens[2],O_RDWR);
if(dup2(fdin,fdout) >= 0)
{
tokens[1]=NULL;
tokens[2]=NULL;
execvp(tokens[0],tokens);
}
else
{
printf("ERROR in dup2\n");
}
}
else if(howManyIn== 0) //means we only have > redirection
{
int fdout = open(tokens[1],O_RDWR);
if(dup2(2,fdout) >= 0)
{
tokens[2]=NULL;
execvp(tokens[0],tokens);
}
else
{
printf("ERROR in dup2\n");
}
}
else //means we only have redirection
{
int fdin = open(tokens[1],O_RDWR);
if(dup2(fdin,1) >= 0)
{
tokens[2]=NULL;
execvp(tokens[0],tokens);
}
else
{
printf("ERROR in dup2\n");
}
}
}
myShell2.c
#include "functions.h"
int main()
{
printf("myshell2>");
pid_t pid,waitPid;
//WE TRIED WITHOU ALLOCATING MEMORY AS WELL
char *argLine = (char *)malloc(max);
char **args = (char **)malloc(max);
char **args2 =( char **)malloc(max);
char **temp = (char **)malloc(max);
char *delim="><";
char *delim2=" ";
int i,howMany,howMany2,status;
while(fgets(argLine,max,stdin) != NULL)
{
howMany= argCounter(argLine,delim);//howMany redirections
args=argArray(argLine,howMany,args,delim);
if (howMany == 1)//means we are at myShell 1
{
howMany2= argCounter(argLine,delim2);
if(howMany2 ==1)//checking if the command has any parameters (like ls -l)
{
printf("myshell2>");
pid = fork();
if (pid < 0)
{
perror("ERROR: Fork failed.\n");
return -1;
}
else if(pid == 0)
{
myExec(args[0],howMany2,delim2);
perror("ERROR: Child should never arrive here.\n");
}
else
{
waitPid = wait(&status);
if (waitPid == -1)
{
perror("ERROR: Waitpid failed.\n");
return -1;
}
}
}
else
{
printf("ERROR: Wrong number of Arguments!\n");//can't run on myshell 2
return(0);
}
}
//means we have redirection (< or >)
for (i=0; i<howMany; i++)
{
argArray(args[i],2,args2,delim2);//args2 contains the tokens without spaces(delim2)
temp[i] = args2[0];
howMany2 = argCounter(args[i],delim2);
if(howMany2 > 1) // eg. ls -l should not run here
{
printf("ERROR: Wrong number of Arguments!\n");//myShell3 should be running this
return(0);
}
}
printf("myshell2>");
pid = fork();
if (pid < 0)
{
perror("ERROR: Fork failed.\n");
return -1;
}
else if(pid == 0)
{
myExecRedir(temp,argLine,howMany);
perror("ERROR: Child should never arrive here.\n");
}
else
{
waitPid = wait(&status);
if (waitPid == -1)
{
perror("ERROR: Waitpid failed.\n");
return -1;
}
}
}
}
Thank you in advance.
char *temp;
memcpy(temp,argLine,strlen(argLine));
char *pointer = strtok(temp, delim);
...
is wrong, you need to reserve space with malloc:
size_t len = strlen(argline);
char *temp = malloc(len + 1);
if (temp == NULL) return 0;
memcpy(temp, argLine, len);
/* NUL-terminate the string */
temp[len] = '\0';
char *pointer = strtok(temp, delim);
...
free(temp);
or you can use the non-standard function (but available on many implementations) strdup:
char *temp = strdup(argline);
if (temp == NULL) return 0;
char *pointer = strtok(temp, delim);
...
free(temp);
char **args = (char **)malloc(max);
is also wrong, if you need to reserve space for n pointers to char use:
char **args = malloc(sizeof(*args) * n); /* don't cast malloc */
or
char **args = malloc(sizeof(char *) * n);

Char ** function not quite working outside of function

So I have created a char** variable called myargv which should act like an array that stores strings at each index. I have a function that returns a char** to the myargv and the function seems to work fine when I print everything out from within, but when I try to print out stuff from the myargv from main, it doesn't work anymore.... Can anyone help me?
char **findArgs(char *line)
{
int i = 0;
char **temp, *tokTemp;
char **myargv;
tokTemp = strtok(line, " ");
myargv = malloc(sizeof(*myargv));
while (tokTemp != NULL)
{
if (strcmp(tokTemp, ">") == 0 || strcmp(tokTemp, "<") == 0 || strcmp(tokTemp, ">>") == 0)
{
break;
}
else
{
myargv[i] = malloc(strlen(tokTemp) + 1);
//myargv[i] = malloc(sizeof(char)*strlen(tokTemp));
strcpy(myargv[i], tokTemp);
//printf("myargv[%d] = %s \n", i, myargv[i]);
temp = realloc(myargv, (i+2)*sizeof(*myargv));
if (temp != NULL)
{
myargv = temp;
}
tokTemp = strtok(NULL, " ");
i++;
}
}
myargv[i] = NULL;
//printf("myargv[0] = %s\n", myargv[0]);
return myargv;
}
int main(int argc, char *argv[], char *env[])
{
int cmdInt, pid, status, i = 0, ioNumber = 0;
char input[64], lineBUFFER[64], lineBUFFER2[64], lineBUFFER3[64], lineBUFFER4[64], homePath[64], fileName[64], cmdPathFINAL[64];
char *cmd;
char **myargv, **cmdPath;
int myFile;
while(1)
{
printf("command: ");
gets(input);
strcpy(lineBUFFER, input);
strcpy(lineBUFFER2, input);
strcpy(lineBUFFER3, input);
strcpy(lineBUFFER4, input);
cmd = strtok(lineBUFFER3, " ");
cmdInt = findCommand(lineBUFFER2);
ioNumber = ioCheck(lineBUFFER4, fileName);
//printf("ioCheck = %d \n", ioNumber);
//printf("Filename: %s \n", fileName);
myargv = findArgs(lineBUFFER);
//printf("myargv[0] = %s\n", myargv[0]);
findHome(env, homePath);
//printf("Home path = %s\n", homePath);
switch(cmdInt)
{
case 0 :
if (myargv[1] == NULL)
{
chdir(homePath);
}
else
{
//printf("1st argument: %s, 2nd argument: %s, 3rd argument: %s \n", myargv[1], myargv[2], myargv[3]);
chdir(myargv[1]);
}
break;
case 1 :
exit(1);
break;
default :
pid = fork();
if (pid == 0)
{
//printf("Parent %d waits for child %d to die. \n", getpid(), pid);
pid = wait(&status);
printf("dead child = %d, how = %04x \n", pid, status);
exit(100);
}
else
{
ioNumber = ioCheck(lineBUFFER4, fileName);
//printf("ioCheck = %d \n", ioNumber);
//printf("Filename: %s \n", fileName);
cmdPath = getPath2(env);
//printf("cmdPath[0] = %s\n", cmdPath[0]);
findPath(cmd, cmdPath, cmdPathFINAL);
printf("Command Path = %s\n", cmdPathFINAL);
if (ioNumber == 1)
{
close(0);
myFile = open(fileName, O_RDONLY);
}
else if (ioNumber == 2)
{
close(1);
myFile = open(fileName, O_WRONLY|O_CREAT, 0644);
}
else if (ioNumber == 3)
{
close(1);
myFile = open(fileName, O_WRONLY|O_APPEND);
}
execve(cmdPathFINAL, myargv, env);
//printf("child %d dies by exit () \n", getpid());
exit(100);
}
break;
}
}
if (ioNumber == 1 || ioNumber == 2 || ioNumber == 3)
{
close(myFile);
}
return 0;
}
The following works on both Window and SuSE linux 10.4 x86_64 kernel 2.6.16. There are two versions of the parser: getArgs and getArgs2. Didn't give the code a thorough review, but hopefully it will help you.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int getArgs(const char *line, char *args[], int argc)
{
int len, i = 0;
const char* delims = " ";
char *ltok = strdup(line);
char *tok = strtok(ltok, delims);
for (; tok != NULL; i++) {
if (strchr("><|", *tok) != NULL) /* not sure why this test is needed for CLI */
break;
if (args != NULL && i < argc) {
args[i] = strdup(tok);
}
tok = strtok(NULL, delims);
}
free(ltok);
return i;
}
int getArgs2(const char *line, char **args, int argc)
{
int len, i = 0;
const char *p, *q;
const char *delims = " ";
p = line;
while (strchr(delims, *p) != NULL && *p != '\0')
p++;
q = p;
while (strchr(delims, *q) == NULL && *q != '\0')
q++;
for (; q > p; i++) {
if (strchr("><|", *p) != NULL) /* not sure why this test is needed for CLI */
break;
len = q-p;
if (args != NULL && i < argc) {
args[i] = (char *)malloc(len + 1);
strncpy(args[i], p, len)[len] = '\0';
}
p = q;
while (strchr(delims, *p) != NULL && *p != '\0')
p++;
q = p;
while (strchr(delims, *q) == NULL && *q != '\0')
q++;
}
return i;
}
int main(int argc, char *argv[])
{
char line[256], *q;
char **args;
int count, n;
for(;;) {
printf("command: ");
if (fgets(line, sizeof(line)/sizeof(line[0]), stdin) == NULL)
break;
q = line;
while (isspace(*q))
q++;
if (*q == '\0')
break;
while (*q != '\0' && *q != '\n' && *q != '\r')
q++;
*q = '\0';
for(count = 0, q = line; *q != '\0'; q++)
if (*q == ' ')
count++;
printf("Input command: %d character(s), %d space(s) for \"%s\"\n", strlen(line), count, line);
count = getArgs(line, NULL, 0);
if (count > 0) {
args = (char **)malloc(sizeof(char *)*count);
count = getArgs(line, args, count);
} else {
args = NULL;
}
printf("Parsed %d arg(s) from line\n", count);
printf("--------------------------------------\n");
for (n = 0; n < count; n++) {
printf("%d: %s\n", n+1, args[n]);
free(args[n]);
}
free(args);
}
return 0;
}

Problem with a feature in a shell program

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);}
}
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].
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.
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.

Resources