Print out a given argument files content in C - c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv){
char** alllines;
int size=0;
if(argc < 2){
}else{
for(int i = 0; i < argc; i++){
FILE* fp;
unsigned int bufferSize = 1024;
char* line = malloc(sizeof(char)*bufferSize);
char* filename = argv[i];
fp = fopen(filename, "r");
if (fp == NULL)
exit(EXIT_FAILURE);
while (getline(&line, &bufferSize, fp) != -1){
printf("%s", line);
}
fclose(fp);
if (line)
free(line);
exit(EXIT_SUCCESS);
}
}
return(0);
}
Here's how I compile and run the code:
gcc program.c
Here's how I run it:
./a.exe test.txt
Here's the test file(it's in the same directory as the c file):
12345
asddfhdfh
abcdefgh
765431
Here's what it returns:
MZÉ$
Here's what it should return:
12345
asddfhdfh
abcdefgh
765431

Related

basic usage of pthread function with return value

I am trying to create a thread that can read the number of lines in a file when called from main.c
main.c
#include <stdio.h>
#define MAX_FILE_NAME 100
#include "t_func.h"
#include <pthread.h>
int main(){
int linecount;
pthread_t thread_id;
FILE *fh = fopen("/home/usr154/out.log", "r");
pthread_create(&thread_id, NULL, count_lines,&fh);
pthread_join(thread_id, (void **) linecount);
printf("lines: %d \n", linecount);
}
t_func.h
#include <stdlib.h>
#include <stdio.h>
int count_lines(int *fh){
char c;
int count =0;
if (fh == NULL)
{
printf("Could not open file %s", fh);
return 0;
}
for (c = getc(fh); c != EOF; c = getc(fh))
if (c == '\n')
count++;
fclose(fh);
return count;
}
I am facing 2 problems (or more), file pointer not being accepted and the return value not being handled, any help is much appreciated (I am new to C programming).
MAX_FILE_NAME was not used.
Manage resource in same scope. I choose to do in main() here which in this case include fopen(), error check, and fclose()
Changed signature on *count_lines() to match what pthread_create() expects.
Changed type of c from char to int.
Changed behavior to take file on command line to avoid having to create the file that code expects.
I am getting a warning warning: cast to pointer from integer of different size for return (void *) count; with gcc -Wall -Wextra. Is there a better way to return a value? Other than global variable, pass in arg with an out parameter for the value, or allocating something in the thread.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
void *count_lines(void *arg) {
FILE *fh = (FILE *) arg;
int c;
int count = 0;
while((c = getc(fh)) != EOF) {
if(c == '\n') count++;
}
return (void *) count;
}
int main(int argc, char *argv[]) {
pthread_t thread_id;
if(argc != 2) {
printf("usage: %s path_of_flie\n", argv[0]);
return 1;
}
FILE *fh = fopen(argv[1], "r");
if(!fh) {
printf("Could not open file %s", argv[1]);
return 1;
}
pthread_create(&thread_id, NULL, count_lines, fh);
int linecount;
pthread_join(thread_id, (void **) &linecount);
fclose(fh);
printf("lines: %d \n", linecount);
}
and running the program on itself it returns:
lines: 32

Reading a file character by character using system calls in c

I have no idea how to use system calls but after some search on internet I came up with this code. Can you please correct my code ?
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
char ch;
int file;
open(file, "input.txt", O_RDONLY);
read(file, ch, 1);
while (ch != '\0')
{
printf("%c", ch);
fseek(file, 1, SEEK_CUR);
read(file, ch, 1);
}
return 0;
}
you are almost right in doing, dont need to use fseek inside ,it will be automatically moved.
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int retVal = 0;
unsigned char ch;
int fdr = open(argv[1],O_RDONLY);
if( fdr )
{
while(read(fdr,&ch,1) == 1)
printf("%c", ch);
retVal = 0;
}
else
{
printf("File open failed\n");
retVal = -1;
}
return retVal;
}

How to use execvp() to execute a command

So I'm trying to create a custom shell for my school project. My method was to create child process, and have that process execute the command using the execvp() function that my professor briefly mentioned in class that we are meant to use. Here's my code, as always, any help is appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#define MAX_LINE 80
int main(int argc, char *argv[])
{
char *input = (char*)malloc(MAX_LINE*sizeof(char));
int should_run = 1;
while(should_run){
printf("osh>");
fflush(stdout);
pid_t pid;
pid = fork();
if(pid < 0){
printf("error with creating chiled process");
return 0;
}
if(pid == 0){
fgets(input, MAX_LINE, stdin);
char *token = strtok(input," ");
if(execvp(token[0], token) < 0){
printf("Error in execution.");
return(0);
}
//should_run = 0;
}
waitpid(pid, 1, 0);
}
return 0;
}
The prototype of execvp is
int execvp(const char *file, char *const argv[]);
It expects a pointer to char as the first argument, and a NULL-terminated
pointer to an array of char*. You are passing completely wrong arguments.
You are passing a single char as first argument and a char* as the second.
Use execlp instead:
int execlp(const char *file, const char *arg, ...
/* (char *) NULL */);
So
char *token = strtok(input," \n");
if(token == NULL)
{
fprintf(stderr, "only delimiters in line\n");
exit(1);
}
if(execlp(token, token, NULL) < 0){
fprintf(stderr, "Error in execution: %s\n", strerror(errno));
exit(1);
}
Also the convention in UNIX is to print error messages to stderr and a process with an error should
have an exit status other than 0.
As Pablo's states, you are passing the wrong arguments to execvp().
You can consider coding by yourself a function (char **strsplit(char *str, char delim)) which takes a string and split it into smaller pieces, returning an array of strings.
Also don't ignore compiler's warnings, they tell you a lot of things, and I suggest you to compile with gcc -Wall -Wextra -Werror to get almost any possible error in your program.
I tell you this because waitpid() takes as second argument a pointer to integer, to get an update of the status of the forked program. With this status you how the program exited (normally, segf, bus error...), you can use it to print an error if something went wrong.
You can consider using execv() instead (I know I'm going off topic, but you can learn useful things doing this), and find by yourself the correct executable(s).
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#define MAX_LINE 255
char **strsplit(char *str, char delim);
char *strjoin(char const *s1, char const *s2);
int isexec(char *path)
{
struct stat buf;
lstat(path, &buf);
if (S_ISREG(buf.st_mode) && (S_IXUSR & buf.st_mode))
return (1);
return (0);
}
static char *find_exec_readdir(char *paths, char *cmd)
{
DIR *dir;
struct dirent *dirent;
char *exec;
exec = NULL;
if ((dir = opendir(paths)) != NULL)
{
while ((dirent = readdir(dir)) != NULL)
{
if (!strcmp(dirent->d_name, cmd))
{
exec = strdup(dirent->d_name);
break ;
}
}
if (closedir(dir))
dprintf(2, "Failed closing dir.\n");
}
return (exec);
}
char *find_exec(char *cmd, char **paths)
{
char *exec;
char *path;
char *tmp;
int i;
i = -1;
exec = NULL;
path = NULL;
if ((cmd[0] == '.' || cmd[0] == '/'))
{
if (isexec(cmd))
return (strdup(cmd));
return (NULL);
}
while (paths[++i])
if ((exec = find_exec_readdir(paths[i], cmd)) != NULL)
{
tmp = strjoin(paths[i], "/");
path = strjoin(tmp, exec);
free(tmp);
free(exec);
break ;
}
return (path);
}
int handle_return_status(int status)
{
int sig;
int i;
if (!WIFEXITED(status) && WIFSIGNALED(status))
{
sig = WTERMSIG(status);
i = -1;
while (++i <= 13)
{
if (print_signal_error(sig))
{
return (-1);
}
}
dprintf(2, "Process terminated with unknown signal: %d\n", sig, NULL);
return (-1);
}
return (0);
}
int main(int argc, char *argv[])
{
char *input = NULL;
char **command = NULL;
int should_run = 1;
int status = 0;
(void)argc;
(void)argv;
if ((input = (char*)malloc(MAX_LINE*sizeof(char))) == NULL)
return (dprintf(2, "Failed to malloc, abort.\n"));
while(should_run){
printf("osh> ");
fflush(stdout);
pid_t pid;
pid = fork();
if(pid < 0)
return (dprintf(2, "error with creating chiled process\n"));
if(pid == 0){
fgets(input, MAX_LINE, stdin);
command = strsplit(input, ' ');
command[0] = find_exec(command[0], strsplit(getenv("PATH"), ':'));
if(execv(command[0], &command[1]) < 0)
return (dprintf(2, "Error in execution.\n"));
//should_run = 0;
}
waitpid(pid, &status, 0);
handle_ret_status(status);
}
return 0;
}

C - Reading a File from Command Line?

Suppose I had a file that I wanted to read.
./a.out file // where file is a argument
The Program being:
//program.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char ch, file_name[25] = argv[1]; //??? Is the issue here?
FILE *fp;
fp = fopen(file_name,"r");
if( fp == NULL )
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
printf("The contents of %s file are :\n", file_name);
while( ( ch = fgetc(fp) ) != EOF )
printf("%c",ch);
fclose(fp);
return 0;
}
EDITED:
When compiling with gcc
gcc program.c
program.c: file not recognized: File format not recognized
Is the error Im getting.
//program.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define SIZEBUF 1024
int main(int argc, char *argv[])
{
int fd;
char buffer[SIZEBUF];
if (argc < 2)
{
printf("Missing file\n");
return (EXIT_FAILURE);
}
fd = open(argv[1], O_RDONLY);
if (fd == -1)
{
printf("Some error occured\n");
return (EXIT_FAILURE);
}
printf("The contents of %s file are :\n", argv[1]);
while(read(fd, buffer, SIZEBUF) > 0 )
printf("%s", buffer);
close(fd);
return (EXIT_SUCCESS);
}
Try this.
Yes.
But if you're in doubt, you could try printing the things in argv.

Global variable not staying set, maybe caused by fork()

I'm trying to write a very very simple unix shell in C, and I have the basics of what I need working, except support for a history command. I have a global 2D char array that holds the history of all entered commands. Commands are added before the fork() system call, and I was originally printing out the value of the history global array after strings were added, and they were printing out correctly, so I'm not sure why it doesn't print out when the command "history" is used at the shell.
Thank to anyone who takes a look.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "myhistory.h"
int BUFFER_SIZE = 1024;
char history[100][80];
int command_index = 0;
int main(int argc, char *argv[]){
int status = 0;
int num_args;
pid_t pid;
while(1){
char *buffer_input, *full_input;
char command[BUFFER_SIZE];
char *args[BUFFER_SIZE];
printf("myshell> ");
buffer_input = fgets(command, 1024, stdin);
full_input = malloc(strlen(buffer_input)+1);
strcpy(full_input, buffer_input);
if (command_index >= 100) {
command_index = 0;
}
strncpy(history[command_index], full_input, strlen(full_input) + 1);
command_index += 1;
parse_input(command, args, BUFFER_SIZE, &num_args);
//check exit and special command conditions
if (num_args==0)
continue;
if (!strcmp(command, "quit" )){
exit(0);
}
if(!strcmp(command, "history")){
int i;
fprintf(stderr,"%d\n",(int)pid);
for(i = 0; i < command_index; i++){
fprintf(stdout, "%d: %s\n",i+1,history[command_index]);
}
continue;
}
errno = 0;
pid = fork();
if(errno != 0){
perror("Error in fork()");
}
if (pid) {
pid = wait(&status);
} else {
if( execvp(args[0], args)) {
perror("executing command failed");
exit(1);
}
}
}
return 0;
}
void parse_input(char *input, char** args,
int args_size, int *nargs){
char *buffer[BUFFER_SIZE];
buffer[0] = input;
int i = 0;
while((buffer[i] = strtok(buffer[i], " \n\t")) != NULL){
i++;
}
for(i = 0; buffer[i] != NULL; i++){
args[i] = buffer[i];
}
*nargs = i;
args[i] = NULL;
}
Change:
fprintf(stdout, "%d: %s\n",i+1,history[command_index]);
to:
fprintf(stdout, "%d: %s\n",i+1,history[i]);

Resources