Trying make a custom shell in c that executes (among others) this command
ls -l >> text.txt
Now this used to work, but after changes in getArgs() it either loops endlessly printing success messages without creating a file, or terminates abnormally.
Here is the immediately relevant code
else if(option == 3){
directory=" ";
if(A[0]=='.' || A[0]=='/'){
directory="./";
}
getArgs(&A,args,directory,&size);
for(i=0;i<size;i++){
printf("arg[%d] : %s\n",i,args[i]);
}
directory=concat(directory,args[0]);
printf("directory %s\n",directory );
fp = open(args[3],O_RDWR | O_CREAT|O_TRUNC,S_IRWXU);
pid=fork();
if(pid==0){
com = args[0];
dup2(fp,STDOUT_FILENO);
readCommand(args,directory,com,0);
return 1;
}
waitpid(-1,&status,0);
dup2(output,STDOUT_FILENO);
if(WIFEXITED(status)){
printf("Data successfully saved in file");
}else{
printf("Abnormal termination\n");
}
close(fp);
close(output);
clean(args);
}
Here is the mylib.c file including getArgs()
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include "mylib.h"
#define MAX_SIZE 50
void getArgs(char **A,char *args[10], char *directory,int *sizeA){
int i,j,num,slash,size;
char *token,*s,*dummy;
trim(*A,&size);
*A=(char*)realloc(*A,(size) * sizeof(char*));
token = strtok (*A, " ");
num=0;
while (token != NULL)
{
args[num] = token;
token = strtok (NULL, " ");
num++;
}
s=args[0];
for(i=num;i<10;i++){
args[i]="\0";
}
if(*A[0]=='.' || *A[0]=='/'){
for(i=0;*args[i]!='\0';i++){
if(args[0][i]=='/'){
slash=i;
}
}
slash+=1;
j=0;
if(*A[0]=='.'){
memmove(args[0], (args[0])+slash, strlen(args[0]));
}
else if(*A[0]=='/'){
memmove(args[0], (args[0])+slash, strlen(args[0]));
}
}
*sizeA=num;
}
//resets args array
void clean(char *args[10]){
int i;
for(i=0;i<10;i++){
args[i] = '\0';
}
}
//reads and executes command
void readCommand(char *args[10],char *directory,char *com, int i){
if(execl(directory, args[i],args[i+1], NULL)==-1){
execl("/bin/sh", "/bin/sh", "-c", com, NULL);
perror("execlp");
}
else{
execl(directory, args[0],args[1],args[2],args[3],args[4], NULL); //max number of args=4
perror("execlp");
}
}
//concatenates 2 strings
char* concat(const char *s1, const char *s2)
{
const size_t len1 = strlen(s1);
const size_t len2 = strlen(s2);
char *result = malloc(len1 + len2 + 1);
memcpy(result, s1, len1);
memcpy(result + len1, s2, len2 + 1);
return result;
}
//trims the /n from the argument
void trim(char *A,int *size) {
int i=0;
do{
*size=i;
if(A[i]=='\n'){
A[i]='\0';
}
i++;
}while(A[i]!='\n');
}
Related
Ive been trying various ways to get my program to work. regardless of weather i try argv1 or argv2 first, the second one will segmentation fault. even if i try to print SOURCE2DEFINE or argv[2] AFTER a move() it will segmentation fault. i cannot move both files trying to run move twice will result in a segmentation fault. im assuming that it has to be something to do with pointers and allocation.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#define SOURCEDEFINE argv[1]
#define SOURCE2DEFINE argv[2]
#define DESTDEFINE argv[argc - 1]
#define ARGCDEFINE argc
#define COMMANDDEFINE argv[0]
int getIndex(char, char*);
char* fileGetName(char*);
void move(char*, char*);
void copy(char*, char*);
int main(int argc, char** argv)
{
printf("Test Argc: %d\n", argc);
int lengthArray = argc-2;
printf("Test Length: %d\n", lengthArray);
printf(" command %s\n", COMMANDDEFINE);
printf("%s\n", DESTDEFINE);
if(strcmp("./copy", COMMANDDEFINE) == 0)
{
// copy(source, dest);
}
else if(strcmp("./move", COMMANDDEFINE) == 0)
{
int i = 1;
printf("Test 1: %s\n", argv[i]);
printf("Test 2: %s\n", argv[argc-1]);
move(SOURCEDEFINE, DESTDEFINE);
printf("%s Filename debug \n", SOURCE2DEFINE);
move(SOURCE2DEFINE, DESTDEFINE);
// i++;
}
return 0;
}
void moveMultiple(int argc, char** argv){
int index = 1;
while(argv[index] != NULL){
if(index < argc - 1){
move(argv[index],argv[argc - 1]);
index++;
}
}
}
void move(char *source, char* dest)
{
printf("Running Move\n");
// FILE *s = fopen(source, "r");
// FILE *s;
//FILE *s = fopen(source, "r");
strcat(dest, fileGetName(source));
int l = link(source, dest);
//if(s == NULL)
if(l)
{
printf("Error, File Not Found");
perror("Link");
fflush(stdout);
exit(1);
}
remove(source);
}
void copy(char *source, char* dest)
{
printf("Running Copy\n");
strcat(dest, fileGetName(source));
int l = link(source, dest);
//if(s == NULL)
if(l)
{
printf("Error, File Not Found");
perror("Link");
fflush(stdout);
exit(1);
}
}
char* fileGetName(char *filename)
{
int i = 0;
int length = strlen(filename);
char *catString;
int index = getIndex('/', filename);
index--;
memcpy(catString,&filename[index], length);
return catString;
}
int getIndex(char i, char *s)
{
printf("Running getIndex\n");
int index = -1;
for(int l =0; l<strlen(s); l++){
if(s[l] == i) {
index = l;
}
}
return index;
}
Your move method changes dest (which is really argv[i]), and overwrites the memory after it: strcat(dest, fileGetName(source));. This destroys the other parameter and probably some other things. Don't write strings into memory you don't own.
I'm writing a function that should read a string of unknown length. I can use read, malloc, open, close and my own library that behaves like a normal one. It includes functions from the standard library and a few additional.
The problem is that fill_append() copies string from gnl->buf to *line incorrectly. In addition to copying the string itself, it adds other characters. Functions with ft_ prefix work accurately.
int fill_append(t_gnl* gnl, char** line)
{
char* append;
int index;
char* sub;
char* tmp;
append = ft_strchr(gnl->buf, '\n');
if (append == NULL)
{
*line = ft_strdup(gnl->buf);
return (0);
}
index = (int)(append - gnl->buf);
sub = ft_strsub(gnl->buf, 0, index);
tmp = ft_strnew(ft_strlen(*line) + ft_strlen(sub) + 1);
ft_strcpy(tmp, *line);
ft_strcat(tmp, sub);
*line = tmp;
// tmp = (char *)malloc(ft_strlen(*line) + ft_strlen(sub) + 1);
// memcpy(tmp, *line, ft_strlen(*line));
// memcpy(tmp + ft_strlen(*line), sub, ft_strlen(sub) + 1);
// *line = tmp;
gnl->buf = ft_strdup(&gnl->buf[index + 1]);
return (1);
}
int read_fd(t_gnl* gnl, char** line)
{
int bsize;
char* tmp;
while ((bsize = read(gnl->fd, gnl->buf, BUFF_SIZE)))
{
gnl->buf[bsize] = '\0';
if (ft_strchr(gnl->buf, '\n') == NULL)
{
tmp = *line;
*line = ft_strjoin(*line, gnl->buf);
free(tmp);
free(gnl->buf);
gnl->buf = ft_strnew(BUFF_SIZE);
}
else
return (fill_append(gnl, line));
}
if (bsize == 0 && *line[0] == 0)
{
free(gnl->buf);
return (0);
}
return (1);
}
int get_next_line(const int fd, char** line)
{
static t_gnl* gnl;
if (fd < 0 || line == NULL)
return (-1);
*line = ft_strnew(0);
if (gnl)
if (gnl->buf)
if (fill_append(gnl, line))
return (1);
if (!gnl)
gnl = (t_gnl*)malloc(sizeof(t_gnl));
gnl->buf = ft_strnew(BUFF_SIZE);
gnl->fd = fd;
return (read_fd(gnl, line));
}
For example, with input is sfesefsefsefwefsefsefsef
sfesefsefsefwefsefsefsef function returns sfesefsefsefwefsefsefsef1
sfesefsefsefwefsefsefsef!
Header:
#ifndef GET_NEXT_LINE_H
#define GET_NEXT_LINE_H
#define BUFF_SIZE 150
#include <unistd.h>
#include <stdlib.h>
#include "libft/libft.h"
typedef struct s_gnl
{
char* buf;
int fd;
} t_gnl;
int get_next_line(const int fd, char** line);
#endif
Main:
#include <stdlib.h>
#include <fcntl.h>
#include "get_next_line.h"
#include "libft/libft.h"
int main(void)
{
int fd;
char* line;
fd = open("gnl.txt", O_RDONLY);
while (get_next_line(fd, &line))
{
ft_putendl(line);
ft_strdel(&line);
}
close(fd);
}
I am trying to create a thread and read from stdin inside the thread. In main() have dynamically allocated memory to a 2d array based on the size given as user input. In the thread I am reading from stdin and splitting it using strtok and adding it into the 2d array. I am not sure why there is a segmentation fault, searched SO and I seem to have handled all the cases related to strtok.
This is the program -
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int dimB;
int dimA;
char** buffer;
char* temp;
void *thread(void *threadid){
char *buf;//[30] = {};
size_t len = 0;
ssize_t read;
char *line = NULL;
char *each;
printf("Hello World!.\n");
while ((read = getline(&line, &len, stdin)) != -1) {
printf("%s || \n", line);
each = strtok(line," ,()");
printf("************************%s ", each);
while(each != NULL){
buf = each;
strcpy(buffer[0][0], buf);
printf("%s", buf);
each = strtok(NULL," ,()");
}
}
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
pthread_t tidMpr;
long r;
int i;
dimB = atoi(argv[1]);
dimA = atoi(argv[2]);
pthread_t tidRdr[dimA];
buffer = malloc(dimA * sizeof(char*));
temp = malloc(dimA * dimB * sizeof(char));
for (i = 0; i < dimA; i++) {
buffer[i] = temp + (i * dimB);
}
//Create thread Thread
pthread_create(&tidMpr, NULL, thread, NULL);
free(temp);
free(buffer);
pthread_exit(NULL);
}
The 2d array memory allocation is from this question - How do I work with dynamic multi-dimensional arrays in C?.
I know I am writing everything to buffer[0][0], but that is so that I can store each in a buffer array buffer[0][1], buffer[0][2] later on based on some logic. But that shouldn't be a problem now right?
Also line is printing the correct value, whatever it is reading from stdin. So, probably strtok is the problem.
Another very similar program produces the desired output. This -
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
typedef struct { char action; int score; } Rules;
Rules rules[5] = {{'P',50}, {'L',20}, {'D',-10}, {'C',30}, {'S',40}};
int findScore(Rules* rules, char action){
int i;
for(i=0; i<5; i++){
if(rules[i].action == action)
return rules[i].score;
}
fprintf(stderr, "Action not present! Exiting...\n");
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[]){
FILE *fp;
char inputTuple[30] = {};
char buf[30] = {};
char* oB;
oB = "(";
char* cB;
char* co = ",";
cB = ")";
fp = fopen(argv[1], "r");
int score;
char *each;
size_t len = 0;
ssize_t read;
char * line = NULL;
char *eacharray;
int u = 0;
char *outputTuple;
int pad = 0;
int g;
if (fp == NULL)
exit(EXIT_FAILURE);
while ((read = getline(&line, &len, fp)) != -1) {
each = strtok(line," ,()");
while(each != NULL){
if(u%3 == 0){
outputTuple = (char *) malloc(1 + strlen(each)+ strlen(oB) );
strcpy(outputTuple, oB);
strcat(outputTuple, each);
} else if(u%3 == 1){
char q = *each;
score = findScore(rules, q);
} else if(u%3 == 2){
char * str3 = (char *) malloc(1 + strlen(outputTuple)+ strlen(co) );
strcpy(str3, outputTuple);
strcat(str3, co);
char *str4 = (char *) malloc(1 + strlen(str3)+ strlen(each) );
strcpy(str4, str3);
strcat(str4, each);
for(pad = strlen(each); pad<15; pad++)
strcat(str4," ");
sprintf(buf, "%s,%d)\n", str4, score);
printf("%s", buf);
free(outputTuple);
free(str3);
free(str4);
}
each = strtok(NULL," ,()");
u++;
}
u = 0;
}
fclose(fp);
return 0;
}
Update :
strcpy(buffer[0][0], buf); seems to be the problem. When I comment it, it is producing the output. I dont understand why is that causing a problem.
can you advice me? I have a string from a file. When i see the string on my console, i need to write the word on which i want to change, and output the result in another file. For example: "Hello my girl" the word i want change "girl" on another word "boy". I can use the library
Can you advice me the algorithm which helps me to change the word?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char my_string[256];
char* ptr;
FILE *f;
if ((f = fopen("test.txt", "r"))==NULL) {
printf("Cannot open test file.\n");
exit(1);}
FILE *out;
if((out=fopen("result.txt","w"))==NULL){
printf("ERROR\n");
exit(1);
}
fgets (my_string,256,f);
printf ("result: %s\n",my_string);
ptr = strtok (my_string," ");
while (ptr != NULL)
{
printf ("%s \n",ptr);
ptr = strtok (NULL," ");
}
char old_word [10];
char new_word [10];
char* ptr_old;
char* ptr_new;
printf ("Enter your old word:\n");
ptr_old= gets (old_word);
printf ("Your old word:%s\n",old_word);
printf ("Enter new old word:\n");
ptr_new = gets (new_word);
printf ("Your new word:%s\n",new_word);
fclose(f);
fclose(out);
return 0;
}
i tried to split inputting string into words. Now its dead end.
This code will help you. you have to pass 4 args at runtime.
./a.out "oldword" "newword" "file name from take the old word" "file name where to copy"
$ ./a.out girl boy test.txt result.txt
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int args, char *argv[4])
{
FILE *f1;
FILE *f2;
char *strings=0;
char *newstrings=0;
char *token=NULL;
strings=(char *)malloc(1000);
newstrings=(char *)malloc(1000);
if((strings==NULL)||(newstrings==NULL))
{
printf("Memory allocation was not successfull.");
return 0;
}
if(args<4)
{
puts("Error: Not enough input parameters");
puts("Usage: ./change <oldword> <newword> <infile> <newfile>");
return 0;
}
f1=fopen(argv[3],"r");
f2=fopen(argv[4],"w");
if(f1==NULL)
{
puts("No such file exists");
return 0;
}
while(fgets(strings,1000,f1)!=NULL)
{
if(strstr(strings,argv[1])!=NULL)
{
token=strtok(strings,"\n\t ");
while(token!=NULL)
{
if(strcmp(token,argv[1])==0)
{
strcat(newstrings,argv[2]);
strcat(newstrings," ");
}
else
{
strcat(newstrings,token);
strcat(newstrings," ");
}
token=strtok(NULL,"\n\t ");
}
}
else
{
strcpy(newstrings,strings);
}
fputs(newstrings,f2);
}
free(strings);
free(newstrings);
printf("New file <%s> generated!\n",argv[4]);
fclose(f1);
fclose(f2);
return 0;
}
You can use a function like the shown function in the demonstrative program below
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char * replace(const char *s, const char *src, const char *dsn)
{
size_t n = 0;
size_t src_len = strlen(src);
size_t dsn_len = strlen(dsn);
for (const char *p = s; (p = strstr(p, src)) != NULL; p += src_len)
{
n++;
}
char *result = malloc(strlen(s) + n * (src_len - dsn_len) + 1);
const char *p = s;
char *t = result;
if (n != 0)
{
for (const char *q; (q = strstr(p, src)) != NULL; p = q + src_len)
{
memcpy(t, p, q - p);
t += q - p;
memcpy(t, dsn, dsn_len);
t += dsn_len;
}
}
strcpy(t, p);
return result;
}
int main( void )
{
char s[] = " the girl and boy are relatives";
char *p = replace(s, "girl", "boy");
puts(s);
puts(p);
free(p);
}
The program output is
the girl and boy are relatives
the boy and boy are relatives
#include <stdio.h>
#include <string.h>
int main ()
{
char file_path[40] = { 0 }, stf[255] = { 0 }, rtf[255] = { 0 }, str[255] = { 0 };
FILE* file = NULL;
FILE *e_f;
if((e_f=fopen("result.txt","w"))==NULL){
printf("ERROR\n");
exit(1);
}
do
{
printf("Enter file path: ");
fgets(file_path, 40, stdin);
file_path[strlen(file_path) - 1] = '\0';
file = fopen(file_path, "r+");
}
while(file == NULL);
printf("Enter text to find: ");
fgets(stf, 255, stdin);
stf[strlen(stf) - 1] = '\0';
printf("Enter text to replace: ");
fgets(rtf, 255, stdin);
rtf[strlen(rtf) - 1] = '\0';
while(fgets(str, 255, file) != NULL)
{
char* tmp_ptr = strstr(str, stf);
while(tmp_ptr != NULL)
{
char tmp_str[255];
strcpy(tmp_str, tmp_ptr + strlen(stf));
strcpy(str + strlen(str) - strlen(tmp_ptr), rtf);
strcat(str, tmp_str);
tmp_ptr = strstr(str, stf);
}
printf("%s", str);
}
fclose(file);
fclose(e_f);
return 0;
}
That was i need. Thanks everybody for helping!
I did a function:
#include <stdio.h>
#include <string.h>
#define MAX 50
void Change (char x[], char cx, char nu){
int i;
for(i=0;i<strlen(x);i++) {
if (x[i]==cx){
x[i] = nu;
}
}
}
int main () {
char str[MAX];
char ch;
char new;
printf("Insert the string\n");
scanf("%s",str);
printf("Insert the word that you want to change\n");
scanf(" %c",&ch);
printf("the new word\n");
scanf(" %c",&new);
Change(str, ch, new);
printf("The new word is %s\n",str );
return 0;
}
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