This function str_join() is an updated version of my earlier function str_join() [Found here: https://codereview.stackexchange.com/questions/270759/str-join-function-not-present-in-standard-c-library].
This version has all bugs fixed and has incorporated some review comments.
Syntax: char *str_join(unsigned int skip_null_and_empty_input_strings, const char *delim, long num_args, ...);
The description of the function str_join() is in the header file - "str_join.h".
The code is below:
str_join.c
#include "str_join.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
/* The description of the function str_join() is in the header file - "str_join.h" */
char *str_join(unsigned int skip_null_and_empty_input_strings, const char *delim, long num_args, ...)
{
va_list valist;
long i = 0;
size_t iica = 0; // iica - index into character array
size_t len = 0;
size_t delim_len = 0;
size_t total_len = 0;
long num_delim_to_concat = -1;
char *new_char_array = NULL;
char *temp = NULL;
if (num_args <= 0)
return NULL;
if (delim) {
delim_len = strlen(delim);
}
va_start(valist, num_args);
for (i = 0; i < num_args; i++) {
temp = va_arg(valist, char *);
if (skip_null_and_empty_input_strings) {
if ((!temp) || (!*temp))
continue;
}
if ((!temp) || (!*temp))
len = 0;
else
len = strlen(temp);
total_len = total_len + len;
num_delim_to_concat = num_delim_to_concat + 1;
if (num_delim_to_concat > 0)
total_len = total_len + delim_len;
}
va_end(valist);
if (total_len == 0)
return NULL;
total_len = total_len + 1; // 1 extra for terminating null byte
new_char_array = malloc(total_len);
if (!new_char_array)
return NULL;
va_start(valist, num_args);
for (i = 0; i < num_args; i++) {
temp = va_arg(valist, char *);
if (skip_null_and_empty_input_strings) {
if ((!temp) || (!*temp))
continue;
}
if ((!temp) || (!*temp))
len = 0;
else
len = strlen(temp);
memmove(&(new_char_array[iica]), temp, len);
iica = iica + len;
if (num_delim_to_concat > 0) {
memmove(&(new_char_array[iica]), delim, delim_len);
iica = iica + delim_len;
num_delim_to_concat = num_delim_to_concat - 1;
}
}
va_end(valist);
new_char_array[iica] = 0;
return new_char_array;
} // end of str_join
str_join.h
#ifndef STR_JOIN_H
#define STR_JOIN_H
/*
* char *str_join(unsigned int skip_null_and_empty_input_strings, const char *delim, long num_args, ...):
*
* Parameters:
*
* num_args: number of variable arguments that are passed to this function
* excluding the 'delim' string.
* ...: Variable number of "char *" pointers.
*
* Description:
*
* Function str_join() concatenates all the strings/character arrays passed
* to it. If 'delim' is not NULL or not empty then between every two strings,
* the 'delim' string is concatenated.
*
* If skip_null_and_empty_input_strings is zero then this means that NULL/empty
* strings should be considered valid strings for the purpose of concatenating
* 'delim' string - this means that if there is a NON-NULL/non-empty string
* in the variable arguments list which is then followed or preceded by a
* NULL/empty string then one 'delim' string will be concatenated between
* NON-NULL/non-empty string and NULL/empty string. This can be useful in
* case columns of a database are concatenated to form a record which will
* then be written in a file - so here, a column containing NULL/empty value
* will be represented as empty by having two consecutive 'delim' strings.
*
* If skip_null_and_empty_input_strings is non-zero then this means that
* NULL/empty strings should be skipped and no 'delim' string should be
* concatenated for them.
*
* Function str_join() allocates a new character array whose size is equal
* to the sum of the lengths of all strings passed to it plus 1 (extra 1
* for terminating null byte). It then concatenates all the strings passed
* to it (these strings are separated by 'delim' string but please see above
* for NULL/empty strings) into the newly allocated character array and then
* returns the pointer to the newly allocated character array. If memory
* allocation fails then NULL is returned.
*
* It is the responsibility of the caller to free the allocated memory (that
* is, to free the returned pointer from this function).
*/
char *str_join(unsigned int skip_null_and_empty_input_strings, const char *delim, long num_args, ...);
#endif
test_str_join.c
#include "str_join.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int mystrcmp(const char *result, const char *expected);
void verify_result(char *result, const char *expected, int line_num, const char *file_name);
int mystrcmp(const char *result, const char *expected)
{
if ((!result) && (!expected))
return 0;
else if ((!result) || (!expected))
return 1;
else
return strcmp(result, expected);
} // end of mystrcmp
void verify_result(char *result, const char *expected, int line_num, const char *file_name)
{
int ret_val = -1;
printf("\n");
if (result) printf("Result = \"%s\"\n", result); else printf("Result = NULL\n");
if (expected) printf("Expected = \"%s\"\n", expected); else printf("Expected = NULL\n");
ret_val = mystrcmp(result, expected);
free(result);
if (ret_val != 0) {
printf("Test case failed. Check the test case just before line number %d in file \"%s\".\n", line_num, file_name);
printf("\nExiting ..\n\n");
exit(1);
} else {
printf("Test case passed.\n");
}
} // end of verify_result
int main(void)
{
char *result = NULL;
char *expected = NULL;
result = str_join(0, "-", 0);
expected = NULL;
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-", 0, "abc");
expected = NULL;
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-", 0, "");
expected = NULL;
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-", 0, NULL);
expected = NULL;
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-", 1, "abc");
expected = "abc";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-", 1, "");
expected = NULL;
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-", 1, NULL);
expected = NULL;
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-", 2, "abc", "123");
expected = "abc-123";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-", 2, "abc", "");
expected = "abc-";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-", 2, NULL, "abc");
expected = "-abc";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-", 2, "", NULL);
expected = "-";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-", 3, "abc", "123", "fgh");
expected = "abc-123-fgh";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-", 3, "", "123", "fgh");
expected = "-123-fgh";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-", 3, "abc", NULL, "fgh");
expected = "abc--fgh";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-", 3, "abc", "123", "");
expected = "abc-123-";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-", 3, NULL, "NULL", "");
expected = "-NULL-";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-", 3, "abc", "", NULL);
expected = "abc--";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-", 3, "", NULL, "abc");
expected = "--abc";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-?-", 4, "a", "b", "cd", "e");
expected = "a-?-b-?-cd-?-e";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-?-", 4, "a", NULL, "cd", "e");
expected = "a-?--?-cd-?-e";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-?-", 4, "a", "", "cd", "");
expected = "a-?--?-cd-?-";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "-?-", 10, "1", "2", "3", "4", "5", "6", "7", "8", "9", "10");
expected = "1-?-2-?-3-?-4-?-5-?-6-?-7-?-8-?-9-?-10";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "", 4, "a", "b", "cd", "e");
expected = "abcde";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, NULL, 4, "a", NULL, "cd", "e");
expected = "acde";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, NULL, 4, "a", "", "cd", "");
expected = "acd";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(0, "", 10, "1", "2", "3", "4", "5", "6", "7", "8", "9", "10");
expected = "12345678910";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-", 0);
expected = NULL;
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-", 0, "abc");
expected = NULL;
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-", 0, "");
expected = NULL;
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-", 0, NULL);
expected = NULL;
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-", 1, "abc");
expected = "abc";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-", 1, "");
expected = NULL;
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-", 1, NULL);
expected = NULL;
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-", 2, "abc", "123");
expected = "abc-123";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-", 2, "abc", "");
expected = "abc";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-", 2, NULL, "abc");
expected = "abc";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-", 2, "", NULL);
expected = NULL;
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-", 3, "abc", "123", "fgh");
expected = "abc-123-fgh";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-", 3, "", "123", "fgh");
expected = "123-fgh";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-", 3, "abc", NULL, "fgh");
expected = "abc-fgh";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-", 3, "abc", "123", "");
expected = "abc-123";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-", 3, NULL, "NULL", "");
expected = "NULL";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-", 3, "abc", "", NULL);
expected = "abc";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-", 3, "", NULL, "abc");
expected = "abc";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-?-", 4, "a", "b", "cd", "e");
expected = "a-?-b-?-cd-?-e";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-?-", 4, "a", NULL, "cd", "e");
expected = "a-?-cd-?-e";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-?-", 4, "a", "", "cd", "");
expected = "a-?-cd";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "-?-", 10, "1", "2", "3", "4", "5", "6", "7", "8", "9", "10");
expected = "1-?-2-?-3-?-4-?-5-?-6-?-7-?-8-?-9-?-10";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "", 4, "a", "b", "cd", "e");
expected = "abcde";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, NULL, 4, "a", NULL, "cd", "e");
expected = "acde";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, NULL, 4, "a", "", "cd", "");
expected = "acd";
verify_result(result, expected, __LINE__, __FILE__);
result = str_join(1, "", 10, "1", "2", "3", "4", "5", "6", "7", "8", "9", "10");
expected = "12345678910";
verify_result(result, expected, __LINE__, __FILE__);
printf("\n------------------------------------\n");
printf("Success: All test cases have passed.\n");
printf("------------------------------------\n\n");
} // end of main