I am trying to write a function that gets multiple lines if ends with \
and just stop if don't have that. I am very new with C so having trouble to do it.
So something like
User input:
Hello, I am blablabla \
I like bablabla \
My favorite color is (stop here)
But in my current function when the user press enter is over and just the first line is saved.
I know that I need to check if in the end have a backslash just keep going and appending, I am just not sure how to do that using getline.
char *getCommand(void){
char* line; //string from user
ssize_t linesize = 0;
//getting command from user if reaches end of file exit or if something went wrong to read file.
if(getline(&line, &linesize, stdin)==-1){
if(feof(stdin)){
exit(0);
}
else{
fprintf(stderr, "Error reading the command: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
}
return line;
}
CodePudding user response:
What your code is basically doing is reading one line. Few things to note:
feof(stdin)
is wrong.getline()
dynamically allocates a string, so you need to free it yourself.
That said, you can implement it this way:
// Returns the number of commands read, -1 if it fails
int getCommand(char **commands, int max_commands)
{
int i, num_cmds = 0;
for (i = 0; i < max_commands; i ) {
char *line = NULL; // This must be initialized to NULL
ssize_t linesize = 0;
if(getline(&line, &linesize, stdin) == -1)
return -1;
line[strcspn(line, "\n")] = '\0'; // Replace \n with a null-terminator
commands[i] = line;
num_cmds ;
if (!strchr(line, '\\')) // if the line doesn't contain a \ then exit
return num_cmds;
}
return num_cmds;
}
commands
is an array of strings that will hold your commands. max_commands
is the maximum number of commands your array may hold (i.e. its size).
You can use it this way:
int main(void)
{
const int max_commands = 120;
char *commands[max_commands];
int num_cmds = getCommand(commands, max_commands);
if (num_cmds == -1) {
fprintf(stderr, "Error reading commands\n");
return 1;
}
int i;
for (i = 0; i < num_cmds; i ) {
printf("command %d: %s\n", i 1, commands[i]);
free(commands[i]); // clear memory allocated by getline
}
}
Given your input as an example, here is what you will get:
Hello, I am blablabla \
I like bablabla \
My favorite color is
command 1: Hello, I am blablabla \
command 2: I like bablabla \
command 3: My favorite color is
EDIT: If the \
needs to be at the end of the line, then replace if (!strchr(line, '\\'))
with
if (line[strlen(line)-1] != '\\')
.
CodePudding user response:
You can use this code to solve your problem, I opted to use scanf
instead of getline
, but the final working is the same:
#include <stdio.h>
#include <stdlib.h>
// Set limit to line
#define LINE_BUFFER 1024
// Get length a string
unsigned int length(const char * str) {
int count = 0;
while (str[count] != '\0') count ;
return count;
}
// Concatenate two strings to a target variable (dest)
int concat(const char * src_1, const char * src_2, char * dest, size_t sizeof_dest) {
// Get lengths from sources
unsigned int src_1_length = length(src_1);
unsigned int src_2_length = length(src_2);
// Calculate minimum length for dest
unsigned int dst_length = src_1_length src_2_length;
if(sizeof_dest < dst_length)
// Has no minimum length for concatenation
return -1;
int index = 0;
for(int i = 0; i < src_1_length; i ) {
index ;
dest[i] = src_1[i];
}
for(int i = 0; i < src_2_length; i ) dest[index i] = src_2[i];
return 0;
}
// Read multiline
char * getCommand() {
char * command = NULL;
while(1) {
char line[LINE_BUFFER];
scanf("%[^\n]s", line);
fflush(stdin);
// Get line length
unsigned int line_length = length(line);
// Checking last character
// zero - false
// nonzero - true
char has_slash = line[line_length - 1] == '\\' ? 1 : 0;
// Update slash to breakline
if(has_slash) line[line_length - 1] = '\n';
if(command == NULL) {
command = (char *) malloc(line_length * sizeof(char));
// Copy line to command
for(int i = 0; i < line_length; i ) command[i] = line[i];
} else {
// Concatenate command with current line for command update
unsigned int command_length = length(command);
unsigned int tmp_command_length = line_length command_length;
char tmp_command[tmp_command_length];
if(concat(command, line, tmp_command, sizeof(tmp_command)) != 0) {
printf("Error in concatenating '%s' with '%s'\n", command, line);
}
// Free memory from old command
free(command);
// Allocating memory for new updated command
command = (char *) malloc(tmp_command_length * sizeof(char));
// Copy command plus current line to new command
for(int i = 0; i < tmp_command_length; i ) command[i] = tmp_command[i];
}
if(!has_slash) break;
}
return command;
}
Click here to access the code repository on Github if you want to improve or fix something. Your collaboration is very welcome.
Quick example of implementation:
Let's assume this is the main file (main.c)
// IMPORTANT: Paste the code above here
// ...
int main() {
char * command = getCommand();
// Print result
printf("\n---- BEGIN ---\n");
printf("\n%s\n", command);
printf("\n---- END ---\n");
// Always clear data allocated in heap memory
free(command);
return 1;
}
Now let's compile the file via terminal, you can use the gcc or clang compilers. In this example I will use clang
.
$ clang main.c -o getcommand
(if you are using gcc, just change the clang
to gcc
)
Run the compiled file:
$ ./getcommand
Right after type your test text
Hello, I am blablabla \
I like blablabla \
My favorite color is
The output should be as follows:
---- BEGIN ---
Hello, I am blablabla
I like blablabla
My favorite color is
---- END ---