/**----------------------------------------------------------------------------\
| Split a string into an array of strings. |
+------------------------------------------------------------------------------+
| Usage: |
| char **strings = explode("Explode me!"); |
| while(*strings) printf("%s\n", *strings++); |
| |
| Result: |
| Explode |
| me! |
+---------+---------+--------+-------------------------------------------------+
| @param | char* | input | string to be turned into an array. |
| @param | char* | delim | Delimiter which will split the string. |
| @return | char** | result | Array of strings. |
\---------+---------+--------+------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* explode() arguments. */
typedef struct {
const char *input;
const char *delim;
} explode_args;
/* explode() macro. */
#define explode(...) explode((explode_args){__VA_ARGS__})
/* explode() function. */
char** (explode)(explode_args arg){
/* Required argument. */
if(!sizeof arg.input) return NULL;
/* Default delimiter argument. */
arg.delim = (arg.delim && arg.delim[0] != '\0') ? arg.delim : " ";
/* Input string is the same as the delimiter. */
if(arg.input == arg.delim) return NULL;
/* Tokenize string. */
char *token = strtok(strdup(arg.input), arg.delim);
/* Build array. */
char **result = malloc(sizeof(*result));
int count = 0;
while(1){
/* Append array with next word. */
result[count++] = token ? strdup(token) : token;
if(!token) break;
/* Get next word. */
token = strtok(NULL, arg.delim);
/* Enlarge array. */
size_t size_new = ((size_t)count + 1) * sizeof(*result);
char **result_new = realloc(result, size_new);
if(result_new == NULL){
printf("Unable to allocate %u bytes at: %p.\n", (int)size_new, (void*)&result);
free(result);
continue;
}
result = result_new;
}
/* Done. */
return result;
}
/**----------------------------------------------------------------------------\
| Example usage. |
\-----------------------------------------------------------------------------*/
#include <unistd.h>
char *readline();
int main(int argc, char **argv){
/* Get a string from the user. */
printf("Please enter a string (or leave blank to show example):\n");
char *input = readline();
/* Remove trailing LF/CRLF. */
size_t length = strlen(input);
while(length && ((input[length - 1] == '\n') || (input[length - 1] == '\r'))){
input[length - 1] = '\0';
length = strlen(input);
}
/* Default string if nothing is entered. */
if(input[0] == '\0'){
input = strdup("Explode me; this is an example of an array of strings made from a single exploded string!");
if(input == NULL){
printf("Unable to allocate memory at: %p.\n", (void*)&input);
return 1;
}
}
/* Get a delimiter from the user. */
printf("Please enter a delimiter (or leave blank to use space):\n");
char *delim = readline();
/* Remove trailing LF/CRLF. */
length = strlen(delim);
while(length && ((delim[length - 1] == '\n') || (delim[length - 1] == '\r'))){
delim[length - 1] = '\0';
length = strlen(delim);
}
/* Explode string. */
char **strings = explode(input, delim);
/* Cleanup. */
if(input[0] != '\0') free(input);
if(delim[0] != '\0') free(delim);
/* Print array of strings. */
int i = 0;
printf("[\n");
do{
/* Output. */
printf(" \"%s\"", strings[i]);
if(strings[i] != '\0') printf(", ");
printf("\n");
/* Cleanup. */
free(strings[i]);
}while(strings[i++] != '\0');
printf("]");
/* Cleanup. */
free(strings);
/* Done. */
sleep(10);
return 0;
}
/**----------------------------------------------------------------------------\
| Utility function for example usage. |
| Read user input character-by-character dynamically. |
\-----------------------------------------------------------------------------*/
char *readline(){
char *output = "";
while(1){
/* Get character. */
char character = fgetc(stdin);
if(character == '\n') break;
/* Get string. */
char *original = output;
/* Convert into mutable C-string pointer. */
char *append = strdup((char*)&character);
/* Get strings' lengths. */
size_t original_size = strlen(original);
size_t append_size = strlen(append);
/* Ensure we captured only one character; append NUL byte. */
if(append_size > 1){
append[1] = '\0';
append_size = 1;
}
/* Allocate memory for output string. */
output = malloc(original_size + append_size + 1);
/* Write string to memory. */
memcpy(output, original, original_size);
memcpy(output + original_size, append, append_size + 1);
}
return output;
}