lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <CAFf+5zgGuaQG=v+Fs5qgqbcfq+rAbuaz3OZm=mqLK6VpCQMsZw@mail.gmail.com>
Date: Mon, 16 Jun 2025 12:52:49 +0530
From: Amit <amitchoudhary0523@...il.com>
To: linux-kernel@...r.kernel.org
Subject: Concatenate multiple strings (Four files: str_join.c, str_join.h,
 test_str_join.c, and ReadMe.txt).

Concatenate multiple strings (Four files: str_join.c, str_join.h,
test_str_join.c, and ReadMe.txt).

-------------
str_join.c
-------------

/*
 * License:
 *
 * This file has been released under "unlicense" license
 * (https://unlicense.org).
 *
 * This is free and unencumbered software released into the public domain.
 *
 * Anyone is free to copy, modify, publish, use, compile, sell, or distribute
 * this software, either in source code form or as a compiled binary, for any
 * purpose, commercial or non-commercial, and by any means.
 *
 * For more information about this license, please visit - https://unlicense.org
 */

/*
 * Author: Amit Choudhary
 * Email: amitchoudhary0523 AT gmail DOT com
 */

#include "str_join.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

char *str_join(int skip_null_and_empty_strings, const char *delim,
               int num_args, ...)
{

    va_list valist;
    int 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;
    int 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_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_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 function str_join()

-------------
str_join.h
-------------

/*
 * License:
 *
 * This file has been released under "unlicense" license
 * (https://unlicense.org).
 *
 * This is free and unencumbered software released into the public domain.
 *
 * Anyone is free to copy, modify, publish, use, compile, sell, or distribute
 * this software, either in source code form or as a compiled binary, for any
 * purpose, commercial or non-commercial, and by any means.
 *
 * For more information about this license, please visit - https://unlicense.org
 */

/*
 * Author: Amit Choudhary
 * Email: amitchoudhary0523 AT gmail DOT com
 */

#ifndef _STR_JOIN_H_
#define _STR_JOIN_H_

/*
 * char *str_join(int skip_null_and_empty_strings, const char *delim,
 *                int num_args, ...):
 *
 * Function str_join() concatenates all the strings passed to it. If 'delim' is
 * not NULL and not empty then the 'delim' is concatenated between every two
 * strings.
 *
 * Argument 'num_args' is the total number of strings passed to this function.
 *
 * This function expects that all arguments after 'num_args' should be either
 * pointers to null-terminated strings or a mix of null-terminated strings,
 * NULL, and empty strings. Any other type(s) of argument may make this function
 * behave strangely and this function may even crash also.
 *
 * If 'skip_null_and_empty_strings' is true 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_strings' is not true then this means that
 * NULL/empty strings should be skipped and no 'delim' string should be
 * concatenated for them.
 *
 * This function 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 the
 * terminating null character). 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 necessary to check the return value of this function for NULL before
 * proceeding ahead.
 *
 * The memory for the returned string is allocated using malloc(), so it is the
 * user's responsibility to free this memory.
 */
char *str_join(int skip_null_and_empty_strings, const char *delim,
               int num_args, ...);

#endif

-------------------
test_str_join.c
-------------------

/*
 * License:
 *
 * This file has been released under "unlicense" license
 * (https://unlicense.org).
 *
 * This is free and unencumbered software released into the public domain.
 *
 * Anyone is free to copy, modify, publish, use, compile, sell, or distribute
 * this software, either in source code form or as a compiled binary, for any
 * purpose, commercial or non-commercial, and by any means.
 *
 * For more information about this license, please visit - https://unlicense.org
 */

/*
 * Author: Amit Choudhary
 * Email: amitchoudhary0523 AT gmail DOT com
 */

#include "str_join.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static int mystrcmp(const char *result, const char *expected);
static void verify_result(char *result, const char *expected, int line_num,
                          const char *file_name);

int main(void)
{

    char *result = NULL;
    char *expected = NULL;

    printf("\n");
    printf("-----------------------------\n");
    printf("Running automated test cases.\n");
    printf("-----------------------------\n");

    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");

    return 0;

} // end of function main()

static int mystrcmp(const char *result, const char *expected)
{

    if ((!result) && (!expected)) {
        return 0;
    } else if ((!result) || (!expected)) {
        return 1;
    }

    return strcmp(result, expected);

} // end of function mystrcmp()

static 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 the line"
               " number %d in the file \"%s\".\n", line_num, file_name);
        printf("\nExiting ..\n\n");
        exit(1);
    } else {
        printf("Test case passed.\n");
    }

    return;

} // end of function verify_result()

----------------
ReadMe.txt
----------------

File "str_join.c" implements a function called str_join() that concatenates all
the strings passed to it. The signature of this function is:

        char *str_join(int skip_null_and_empty_strings, const char *delim,
                       int num_args, ...)

Function str_join() concatenates all the strings passed to it. If 'delim' is not
NULL and not empty then the 'delim' is concatenated between every two strings.

Argument 'num_args' is the total number of strings passed to this function.

This function expects that all arguments after 'num_args' should be either
pointers to null-terminated strings or a mix of null-terminated strings, NULL,
and empty strings. Any other type(s) of argument may make this function behave
strangely and this function may even crash also.

If 'skip_null_and_empty_strings' is true 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_strings' is not true then this means that NULL/empty
strings should be skipped and no 'delim' string should be concatenated for them.

This function 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 the terminating null
character). 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 necessary to check the return value of this function for NULL before
proceeding ahead.

The memory for the returned string is allocated using malloc(), so it is the
user's responsibility to free this memory.

---- End of ReadMe ----

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ