// ========================================================= //
//                                                           //
//   File      : arb_string.h                                //
//   Purpose   : (inlined) string functions using char*      //
//                                                           //
//   Coded by Ralf Westram (coder@reallysoft.de) in Nov 10   //
//   http://www.arb-home.de/                                 //
//                                                           //
// ========================================================= //

// Note: code using std::string should go to arb_stdstring.h
//                           or ../TEMPLATES/arb_stdstr.h

#ifndef ARB_STRING_H
#define ARB_STRING_H

#ifndef ARB_MEM_H
#include "arb_mem.h"
#endif
#ifndef ARB_ASSERT_H
#include "arb_assert.h"
#endif
#ifndef _GLIBCXX_CSTRING
#include <cstring>
#endif

inline char *ARB_strdup(const char *str) {
    char *dup = strdup(str);
    if (!dup) arb_mem::failed_to_allocate(strlen(str));
    return dup;
}

inline char *ARB_strduplen(const char *p, unsigned len) {
    // fast replacement for strdup, if len is known
    //
    // Note: to copy a part of a string -> use ARB_strpartdup or ARB_strndup.

    if (p) {
        char *neu;

        arb_assert(strlen(p) == len);
        // Note: Common reason for failure: a zero-char was manually printed by a GBS_global_string...-function

        ARB_alloc(neu, len+1);
        memcpy(neu, p, len+1);
        return neu;
    }
    return NULp;
}

inline char *ARB_strpartdup(const char *start, const char *end) {
    /* strdup of a part of a string (including 'start' and 'end')
     * 'end' may point behind end of string -> copy only till zero byte
     * if 'start' is NULp   -> return NULp
     * if 'end'   is NULp   -> copy whole string
     * if 'end'=('start'-1) -> return ""
     * if 'end'<('start'-1) -> return NULp
     */

    char *result;
    if (start && end) {
        int len = end-start+1;

        if (len >= 0) {
            const char *eos = (const char *)memchr(start, 0, len);

            if (eos) len = eos-start;
            ARB_alloc(result, len+1);
            memcpy(result, start, len);
            result[len] = 0;
        }
        else {
            result = NULp;
        }
    }
    else { // end = 0 -> return copy of complete string
        result = nulldup(start);
    }

    return result;
}

inline char *ARB_strndup(const char *start, int len) {
    // strdup part of string.
    // copies either 'len' characters or until zero-byte, whichever is shorter.
    //
    // Note: to copy the whole string when length is known -> use ARB_strduplen.
    return start ? ARB_strpartdup(start, start+len-1) : NULp;
}


const char *ARB_date_string(void);
const char *ARB_dateTime_suffix(void);
const char *ARB_keep_string(char *str);

inline const char *ARB_strchrnul(const char *str, int chr) {
#if defined(DARWIN)
    // replacement code for strchrnul:
    char buf[2] = "x";
    buf[0]      = chr;
    return str+strcspn(str, buf);
#else
    return strchrnul(str, chr); // strchrnul is gnu specific
#endif
}

template <typename NUM>
inline const char *plural(NUM val) {
    return "s"+(val == 1);
}
template <> inline const char *plural(float);  // avoid float ("is 1.001 already plural?")
template <> inline const char *plural(double); // avoid double

#else
#error arb_string.h included twice
#endif /* ARB_STRING_H */
