Related
A simple program that takes an input file specified at the terminal, and alters the text to be reversed. How can the <stdio.h> functions be converted to only linux system calls? (I assume using only libraries like <unistd.h>)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* concat(const char *str1, const char *str2)
{
char *answer = malloc(strlen(str1) + strlen(str2) + 1);
strcpy(answer, str1);
strcat(answer, str2);
return answer;
}
int main(int argc, char** argv) {
FILE * fp;
char * line = NULL;
size_t len = 0;
fp = fopen(argv[1], "r");
if (fp == NULL){
perror("\nError ");
exit(1);
}
char *rev1 = "rev ";
char *rev2 = {argv[1]};
char *rev3 = concat(rev1,rev2);
system(rev3);
fclose(fp);
return 0;
}
Thank you for any help. Company only wants me to use system calls for some reason, this internship is not going great!
don't understand how to properly implement [read and write]
Assuming you mean call them (not implement them), the catch with read and write is that they may read or write less than requested, so you have to call them in a loop.
size_t to_write = strlen(str);
while (to_write) {
ssize_t written = write(fd, str, to_write);
if (written < 0) {
perror(NULL);
exit(1);
}
str += written;
to_write -= written;
}
Reading works the same way if you know how much you need to read or if you're trying to read an entire file. (To read the entire file, read chunks until read returns 0. Factors of 8*1024 are nice chunk sizes.)
Otherwise, it gets far more complicated. How do you know how much to read before you read it? If you want to read a line, for example, you have no idea how long the line is until you encounter the terminating line feed. You could read a character at a time, but that's very inefficient. You could do like like stdio does and use a buffer that holds the excess. At which point you might as well use stdio.
//#include<stdio.h> not used
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
char* swap(const char *one, const char *two)
{
char *result = malloc(strlen(one) + strlen(two) + 1);
strcpy(result, one);
strcat(result, two);
return result;
}
int main(int argc, char** argv) {
if (argc != 2){
printf("Error, wrong number of arguments!\n");
exit(1);
}
int fd = open(argv[1], O_RDONLY); //<------------------<
char * line = NULL;
size_t len = 0;
char *string1 = "rev ";
char *string2 = {argv[1]};
char *result = swap(string1,string2);
system(result);
return 0;
}
I am looking to create an array of pointers to strings read from a file in C. However when I try to print out the strings copied to stdout, the last line of the file is always left out.
The program also sometimes experiences a segmentation fault which I haven't been able to completely eliminated. It happens about 2 out of 5 times.
Here is my input.c code:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "input.h"
#define MAXLINES 5000
void writelines(char *arr[], int l);
char *read_lines[MAXLINES];
void get_input(const char *fp) {
FILE *contents;
char *line;
char *temp;
size_t len;
ssize_t read;
int i;
i = 0;
contents = fopen(fp, "r");
if (contents == NULL)
exit(EXIT_FAILURE);
while ((read = getline(&line, &len, contents)) != -1) {
if ((temp = (char *) malloc(strlen(line) + 1)) == NULL) {
printf("Could not allocate required memory.");
exit(EXIT_FAILURE);
}
else {
line[strlen(line) - 1] = '\0';
strcpy(temp, line);
read_lines[i++] = temp;
}
}
fclose(contents);
free(line);
free(temp);
writelines(read_lines, i);
exit(EXIT_SUCCESS);
}
void writelines(char *arr[], int l) {
int i;
for (i = 0; i < l; i++) {
printf("%s\n", arr[i]);
}
}
My main.c file is:
#include <stdio.h>
#include "input.h"
int main(int argc, char *argv[]) {
if (argc == 1)
printf("Please provide a valid source code file.\n");
else
get_input(*(++argv));
return 0;
}
I compile using gcc main.c input.c -Wall with no warnings or errors.
Using gdb I can confirm that the process runs normally.
When it experiences a segmentation fault, the back trace shows a call to strlen that apparently fails.
from the documentation:
If *lineptr is NULL, then getline() will allocate a buffer for storing the line, which should be freed by the user program. (In this case, the value in *n is ignored.)
but in your case you're passing an uninitialized value to getline the first time, so getline thinks it can write to that illegal location and this is undefined behaviour (which explains the "It happens about 2 out of 5 times" thing)
The first fix should be to initialize line:
char *line = NULL;
then, why are you creating a copy of line, and you're not freeing line (memory leak) and you're not resetting it to NULL. So next time getline reuses the previous buffer, which may not be long enough to hold the next line.
The fix is just to store the line:
read_lines[i++] = line;
then set line = NULL so getline allocates the proper len for next line. And drop the malloc code, it's useless.
fixed part (you don't need to pass pointer on len it is ignored):
line = NULL;
while ((read = getline(&line, NULL, contents)) != -1) {
read_lines[i++] = line;
line[strcspn(line, "\n")] = 0; // strip off linefeed if there's one
line = NULL;
}
(linefeed strip adapted from Removing trailing newline character from fgets() input)
The reason why I would want to do this is because I want to read from a file line-by-line, and for each line check whether it matches a regex. I am using the getline() function, which puts the line into a char * type variable. I am trying to use regexec() to check for a regex match, but this function wants you to provide the string to match as a const char *.
So my question is, can I create a const char * from a char *? Or perhaps is there a better way to approach the problem I'm trying to solve here?
EDIT: I was requested to provide an example, which I didn't think about and apologise for not giving one in the first place. I did read the answer by #chqrlie before writing this. The following code gives a segmentation fault.
#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdbool.h>
#include <regex.h>
int main() {
FILE * file = fopen("myfile", "r");
char * line = NULL;
size_t len = 0;
ssize_t read;
regex_t regex;
const char * regexStr = "a+b*";
if (regcomp(®ex, regexStr, 0)) {
fprintf(stderr, "Could not compile regex \"%s\"\n", regexStr);
exit(1);
}
while ((read = getline(&line, &len, file)) != -1) {
int match = regexec(®ex, line, 0, NULL, 0);
if (match == 0) {
printf("%s matches\n", line);
}
}
fclose(file);
return 0;
}
char * can be converted to const char * without any special syntax. The const in this type means that the data pointed by the pointer will no be modified via this pointer.
char array[] = "abcd"; // modifiable array of 5 bytes
char *p = array; // array can be modified via p
const char *q = p; // array cannot be modified via q
Here are some examples:
int strcmp(const char *s1, const char *s2);
size_t strlen(const char *s);
char *strcpy(char *dest, const char *src);
As you can see, strcmp does not modify the strings it receives pointers to, but you can of course pass regular char * pointers to it.
Similarly, strlen does not modify the string, and strcpy modifies the destination string but not the source string.
EDIT: You problem has nothing to do with constness conversion:
You do not check the return value of fopen(), the program produces a segmentation fault on my system because myfile does not exist.
You must pass REG_EXTENDED to compile a regex with the newer syntax such asa+b*
Here is a corrected version:
#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <regex.h>
int main() {
FILE *file = fopen("myfile", "r");
char *line = NULL;
size_t len = 0;
ssize_t read;
regex_t regex;
const char *regexStr = "a+b*";
if (file == NULL) {
printf("cannot open myfile, using stdin\n");
file = stdin;
}
if (regcomp(®ex, regexStr, REG_EXTENDED)) {
fprintf(stderr, "Could not compile regex \"%s\"\n", regexStr);
exit(1);
}
while ((read = getline(&line, &len, file)) != -1) {
int match = regexec(®ex, line, 0, NULL, 0);
if (match == 0) {
printf("%s matches\n", line);
}
}
fclose(file);
return 0;
}
I'm trying to implement a basic shell, I have several functions within it that deal with strings, trying to find file names, implement something equivalent to *argv[] and so on.
I have strings in main(), which are passed to a function to be populated. Next the program returns to main(), which passes the strings to another function to be acted upon.
I was debugging with lldb and found that I was successfully populating the strings with the correct values in the first function but upon exiting the function, re-entering main() the output_str string was NULL again. I thought strings, since they point to space in memory would retain values. They seem to for all but one case, when flag = 1 in the code below.
I can't figure out what's happening as the values seem to only be lost after the final } of the function.
Edited to add complete code, hope it isn't too large.
The code works with say, cat input.txt but not with cat input.txt>output.txt when I try to redirect the output from stdout to a file
Thank you for your help in advance.
Here is the function .c file:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
void sig_handler(int signo)
{
if (signo == SIGINT)
{
fprintf(stdout, "\n");
fflush(stdout);
}
}
int check_redirect(char *line, int flag)
{
int n = 0;
if (line == NULL) return (flag);
else
{
do
{
if (line[n] == '>') flag = 1;
n++;
}while (line[n] != '\0');
}
return (flag);
}
void string_breakdown(char *line, char **output_str, int count, char* temp, char *filename, int *f, int *saved_stdout, int flag, int debug)
{
char *sep = " \n";
char *delim = ">\n";
if (line != NULL)
{
temp = strtok(line, delim);
while (temp != NULL)
{
output_str[count] = temp;
if (debug) fprintf(stderr, "1:%s\n2:%s\n3:%s\n", line, temp, output_str[count]);
count++;
output_str = realloc (output_str, (count + 1) * sizeof (char *) );
temp = strtok(NULL, delim);
}
if (flag)
{
count = 0;
strcpy(filename, output_str[1]);
output_str[1] = NULL;
*saved_stdout = dup(1);
*f = open(filename , O_WRONLY|O_CREAT|O_TRUNC, 0666);
dup2(*f, 1);
temp = strtok(*output_str[0], sep);
while (temp != NULL)
{
output_str[count] = temp;
//if (debug) fprintf(stderr, "1:%s\n2:%s\n3:%s\n", line, temp, output_str[count]);
count++;
output_str = realloc (output_str, (count + 1) * sizeof (char *));
temp = strtok(NULL, sep);
}
}
else
{
count = 0;
temp = strtok(line, sep);
while (temp != NULL)
{
output_str[count] = temp;
if (debug) fprintf(stderr, "1:%s\n2:%s\n3:%s\n", line, temp, output_str[count]);
count++;
output_str = realloc (output_str, (count + 1) * sizeof (char *));
temp = strtok(NULL, sep);
}
}
}
}
void com_exec(char *line, char **output_str, char *filename, int *f, int *saved_stdout, int flag, int debug)
{
char *command = malloc(sizeof(char *));
command = output_str[0];
char *name = "HOME";
int ret_val = 0;
pid_t child_pid;
int child_status;
if (command == NULL);
else if (strcmp("cd", command) == 0)
{
if (output_str[1] == NULL) output_str[1] = getenv(name);
ret_val = 0;
ret_val = chdir(output_str[1]);
if (ret_val) perror(NULL);
}
else
{
child_pid = fork ();
if (child_pid == 0)
{
if (debug)
{
system(line);
fprintf(stderr, "Post System Pre Exec\n1:%s\n2:%s\n3:%s\n", line, output_str[0], command);
sleep(2);
}
execvp(command, output_str);
if (flag)
{
close(*f);
dup2(*saved_stdout, 1);
close(*saved_stdout);
}
fprintf (stdout, "Unknown command\n");
exit (0);
}
else
{
if (flag)
{
close(*f);
dup2(*saved_stdout, 1);
close(*saved_stdout);
}
signal(SIGINT, sig_handler);
usleep(500000);
//Parent process waits for child to finish
if (debug) fprintf (stderr, "parent waiting\n");
wait(&child_status);
waitpid(child_pid, &child_status, 0);
signal(SIGINT, SIG_DFL);
}
}
Here is the functions .h file:
#ifndef SHELL_H_INCLUDED
#define SHELL_H_INCLUDED
void sig_handler(int signo);
int prompt(char *line, size_t len, ssize_t read);
int check_redirect(char *line, int flag);
void string_breakdown(char *line, char **output_str, int count, char* temp, char *filename, int *f, int *saved_stdout, int flag, int debug);
void com_exec(char *line, char **output_str, char *filename, int *f, int *saved_stdout, int flag, int debug);
#endif // LINKLAYER_H_INCLUDED
Below is main.c, where the function is called.
#include <unistd.h>
#include <time.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include "shell.h"
int main(void)
{
int debug = 0;
char *line = NULL;
size_t len = 0;
ssize_t read = 0;
int flag = 0;
int f = 0;
int saved_stdout = 0;
do
{
flag = 0;
//read = prompt(line, len, read);
char buffer[15];
time_t now = time(NULL);
strftime(buffer, 15, "[%d/%m %H:%M]", localtime(&now) );
fprintf(stdout, "%s # ", buffer);
signal(SIGINT, SIG_IGN);
read = getline (&line, &len, stdin);
signal(SIGINT, SIG_DFL);
flag = check_redirect(line, flag);
char **output_str = malloc(sizeof(char *));
int count = 0;
char* temp = NULL;
char *filename = malloc(sizeof(char *));
string_breakdown(line, output_str, count, temp, filename, &f, &saved_stdout, flag, debug); // function call of problem function
com_exec(line, output_str, filename, &f, &saved_stdout, flag, debug);
} while (read != EOF);
if (debug) fprintf(stderr, "parent exiting\n");
else fprintf(stdout, "\n");
return 0;
}
output_str = realloc (output_str, (count + 1) * sizeof (char *) );
This line re-assigns the value of the the local parameter variable output_str, but the new value in no way makes it back to the caller of the string_breakdown function - meaning that the pointer it has will probably be left dangling, and will cause problems when used ("undefined behavior", manifesting in strange program behavior or crashing).
You need to understand that within the function, output_str is a local variable. You can change its value, but that won't affect the value of any variable in the caller.
You call the function from main:
string_breakdown(line, output_str, count, temp, filename, &f, &saved_stdout, flag, debug); // The call of the above function
main also uses output_str as the variable name, but again, this is a different variable. One variable is local to main, the other is local to string_breakdown, even though they share the same name. Due to the realloc call above, the pointer value in main's output_str will most likely be invalid on return from string_breakdown, because it is not updated to point to the newly allocated memory. That's why you are "losing" the string values on return from the function - the output_str variable in main is no longer actually pointing to the array of strings, which has been moved to a different location via realloc.
Typically you resolve this kind of problem by adding another level of indirection, changing the output_str parameter from a char ** to a char ***:
void string_breakdown(char *line, char ***output_str, int count, char* temp, char *filename, int *f, int *saved_stdout, int flag, int debug)
and
(*output_str)[count] = temp;
and
*output_str = realloc (*output_str, (count + 1) * sizeof (char *) );
and so on. You need to adjust the call in main as well:
string_breakdown(line, &output_str, count, temp, filename, &f, &saved_stdout, flag, debug); // The call of the above function
Because you are passing a pointer to main's output_str variable, the called function is now able to modify its value.
You should also understand that string_breakdown as written modifies the string which the line parameter points to. That's because it uses strtok, and strtok replaces delimiters with nul bytes as it processes the string. So, it is odd that you pass this modified line buffer to com_exec after processing it with string_breakdown.
I get several warnings when I try to compile your code; main.c uses fprintf but doesn't #include <stdio.h>, and uses malloc but doesn't #include <stdlib.h>.
your realloc does nothing.
you mean *output_ptr = realloc....
actually it does something, but its really bad
this is also wrong
output_str[count] = temp;
and this
filename = output_str[1];
you need to distinguish - a pointer to your buffer, a pointer to the pointer to your buffer.
char * buffer = *output_str; // to remove the confusion
strcpy(&buffer[count], temp); // assigning pointers doesnt copy things
filename = buffer[1]; // is hat what you mean - filename is one char
I've got a problem reading a couple of lines from a read-only FIFO. In particular, I have to read two lines — a number n, followed by a \n and a string str — and my C program should write str in a write-only FIFO for n times. This is my attempt.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
char *readline(int fd);
int main(int argc, char** argv) {
int in = open(argv[1], O_RDONLY);
mkfifo(argv[2], 0666);
int out = open(argv[2] ,O_WRONLY);
char *line = (char *) malloc(50);
int n;
while (1) {
sscanf(readline(in), "%d", &n);
strcpy(line, readline(in));
int i;
for (i = 0; i < n; i++) {
write(out, line, strlen(line));
write(out, "\n", 1);
}
}
close(in);
close(out);
return 0;
}
char *readline(int fd) {
char *c = (char *) malloc(1);
char line[50];
while (read(fd, c, 1) != 0) {
if (strcmp(c, "\n") == 0) {
break;
}
strcat(line, c);
}
return line;
}
The code is working properly, but it puts a random number of newlines after the last string repetition. Also, this number changes at each execution.
Could someone please give me any help?
Besides the facts that reading character wise and and comparing two characters using "string" comparsion both is far from being efficient, readline() returns a pointer to memory being declared local to readline(), that is line[50] The memory gets deallocated as soon as readline() returns, so accessing it afterwards invokes undefine behaviour.
One possibility to fix this is to declare the buffer to read the line into outside readline() and pass a reference to it down like so:
char * readline(int fd, char * line, size_t size)
{
if ((NULL != line) && (0 < size))
{
char c = 0;
size_t i = 0;
while (read(fd, &c, 1) >0)
{
if ('\n' == c) or (size < i) {
break;
}
line[i] = c;
++i;
}
line [i] = 0;
}
return line;
}
And then call it like this:
char * readline(int fd, char * line, size_t size);
int main(void)
{
...
char line[50] = "";
...
... readline(in, line, sizeof(line) - 1) ...
I have not tried running your code, but in your readline function you have not terminated the line with null ('\0') character. once you hit '\n' character you just breaking the while loop and returning the string line. Try adding '\0' character before returning from the function readline.
Click here for more info.
Your code did not work on my machine, and I'd say you're lucky to get any meaningful results at all.
Here are some problems to consider:
readline returns a locally defined static char buffer (line), which will be destroyed when the function ends and the memory it once occupied will be free to be overwritten by other operations.
If line was not set to null bytes on allocation, strcat would treat its garbage values as characters, and could possibly try to write after its end.
You allocate a 1-byte buffer (c), I suspect, just because you need a char* in read. This is unnecessary (see the code below). What's worse, you do not deallocate it before readline exits, and so it leaks memory.
The while(1) loop would re-read the file and re-print it to the output fifo until the end of time.
You're using some "heavy artillery" - namely, strcat and memory allocation - where there are simpler approaches.
Last, some C standard versions may require that you declare all your variables before using them. See this question.
And here's how I modified your code. Note that, if the second line is longer than 50 characters, this code may also not behave well. There are techniques around the buffer limit, but I don't use any in this example:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
char *readline(int fd, char * buffer);
int main(int argc, char** argv) {
int in = open(argv[1], O_RDONLY);
int out;
int n;
int i;
char line[50];
memset(line, 0, 50);
mkfifo(argv[2], 0666);
out = open(argv[2] ,O_WRONLY);
sscanf(readline(in, line), "%d", &n);
strcpy(line, readline(in, line));
for (i = 0; i < n; i++) {
write(out, line, strlen(line));
write(out, "\n", 1);
}
close(in);
close(out);
return 0;
}
char *readline(int fd, char * buffer) {
char c;
int counter = 0;
while (read(fd, &c, 1) != 0) {
if (c == '\n') {
break;
}
buffer[counter++] = c;
}
return buffer;
}
This works on my box as you described. Compiled with GCC 4.8.2 .