I'm trying to figure out a project for school and I'm pretty close. The goal is to emulate using a terminal, essentially inputting a series of commands with pipes and having them execute correctly.
My current code and output is listed below but the main gist is that I have been able to separate commands and arguments thus far, but when attempting to use an strcat on line 83, I feel to get a segmentation fault.
The lines I attempted to add were:
strcat (allargs, print);
}
printf("\n %s -- ALLARGS\n ", allargs);
What would be the best way to extract a string of all the arguments? As I'm looking to use either execvp or execlp, would there be a better way to go about this?
Thanks!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <wait.h>
#include <sys/types.h>
#include <unistd.h>
// count number of "|" in string
int count_cmds(char *str)
{
int count = 1; // always will be 1 cmd
for (int i = 0; i < strlen(str); i )
{
if (str[i] == '|')
{
count ;
}
}
return count;
}
char *get_token_at(char *command, size_t n, char *delimiter)
{
size_t position = 0;
char *copy = strdup(command);
char *token = strtok(copy, delimiter);
char *output = NULL;
while (token && position < n)
{
token = strtok(NULL, delimiter);
position ;
}
if (token && position == n)
output = strdup(token);
free(copy);
return output;
}
// trim whitespace
char *trimwhitespace(char *str)
{
char *end;
while (isspace(*str))
str ;
if (*str == 0)
return str;
end = str strlen(str) - 1;
while (end > str && isspace(*end))
end--;
// new end of string
*(end 1) = 0;
return str;
}
// count spaces in a string
int count_spaces(char *str)
{
int count = 0;
for (int i = 0; i < strlen(str); i )
{
if (str[i] == ' ')
{
count ;
}
}
return count;
}
int fd[2];
int x;
int execc(char *command, int i)
{
printf("--- NEW CALL TO EXECC ---------------- COMMAND PASSED: %s \t\t\t\t\t\t ---- NUMBER PASSED: %d\n", command, i);
char *text = trimwhitespace((get_token_at(command, i - 1, "|")));
char *textargs = text;
char *allargs = " ";
for (int k = 0; k < count_spaces(textargs); k )
{
char *print = trimwhitespace((get_token_at(textargs, k 1, " ")));
printf("\n %s -- TEXTARG\n ", print);
}
char *cmd_only = get_token_at(text, 0, " ");
printf("\n %s -- cmd only\n ", cmd_only);
int x = fork();
if (x < 0)
{
perror("fork error");
exit(1);
}
// parent
if (x > 0)
{
printf("IN PARTENT -- wait for child\n");
wait(&x);
return x;
}
// child
if (x == 0)
{
printf("NEW CHILD -- exec or call next \n");
dup2(fd[0], STDIN_FILENO);
if (i == 1)
{
dup2(fd[1], STDOUT_FILENO);
}
close(fd[0]);
close(fd[1]);
if (i == 1)
{
char *z1 = trimwhitespace((get_token_at(command, i - 1, "|")));
printf(" i=1 ---------------- \n%s\n %s \n %s ", z1, z1, trimwhitespace((get_token_at(command, i - 1, " "), NULL)));
// execlp(z1,z1, (trimwhitespace(get_token_at(command, i, " ")), NULL)); // if last command, exec
}
else
{
execc(command, --i); // if not last command, recurse
char *z2 = trimwhitespace(get_token_at(command, i - 1, "|"));
printf("i!=1 --------------------\n%s\n %s \n %s ", z2, z2, trimwhitespace((get_token_at(command, i - 1, " "), NULL)));
// execlp(z2,z2, trimwhitespace((get_token_at(command, i, " "), NULL)));
}
// char* z3 = trimwhitespace(get_token_at(command, i-1, "|"));
// printf("%s\n %s \n %s \n",z3,z3, trimwhitespace((get_token_at(command, i-1, " "), NULL)));
// execlp(z3,z3, trimwhitespace((get_token_at(command, i, " "), NULL)));
}
}
int main(int argc, char *argv[])
{
printf(" Enter Command>");
char cmd[50];
fgets(cmd, 50, stdin);
int num_cmds = count_cmds(cmd);
printf("\n");
printf("Command count: %d\n", num_cmds);
execc(cmd, num_cmds);
pipe(fd);
if (pipe(fd) == -1)
{
printf("Error pipe\n");
exit(1);
}
}
./current Enter Command>ls -l | sort -r | grep -h
Command count: 3 --- NEW CALL TO EXECC ---------------- COMMAND PASSED: ls -l | sort -r | grep -h ---- NUMBER PASSED: 3
-h -- TEXTARG
grep -- cmd only IN PARTENT NEW CHILD --- NEW CALL TO EXECC ---------------- COMMAND PASSED: ls -l | sort -r | grep -h ---- NUMBER PASSED: 2
-r -- TEXTARG
sort -- cmd only IN PARTENT NEW CHILD --- NEW CALL TO EXECC ---------------- COMMAND PASSED: ls -l | sort -r | grep -h ---- NUMBER PASSED: 1
-l -- TEXTARG
ls -- cmd only IN PARTENT NEW CHILD
CodePudding user response:
should define allargs
as a char array, not a pointer,
Like this:
char allargs[64] = {0};