/* @file  psString.h
 *
 * @brief string utility functions
 *
 * String utility functions defined shall provide basic string copying
 * capabilities.
 *
 * @author EAM, IfA
 * @author Eric Van Alst, MHPCC
 * @author David Robbins, MHPCC
 *
 * @version $Revision: 1.36 $ $Name: not supported by cvs2svn $
 * @date $Date: 2007-02-03 05:35:30 $
 *
 * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
 */

#ifndef PS_STRING_H
#define PS_STRING_H

/// @addtogroup SysUtils System Utilities
/// @{

#include <sys/types.h>
#include <stdarg.h>
#include "psType.h"
#include "psList.h"

/** This macro will convert the argument to a quoted string */
#define PS_STRING(S)  #S

/** This macro returns a (static buffer containing) "file:line" */
const char *p_psFileLine(const char *file, int line);
#define PS_FILE_LINE p_psFileLine(__FILE__,__LINE__)

/** Allocates a new psString.
 *
 *  @return psString:       Newly allocated string of length n.
 */
psString psStringAlloc(
    long nChar                         ///< Size of psString to allocate.
);

/** Checks the type of a particular pointer.
 *
 *  Uses the appropriate deallocation function in psMemBlock to check the ptr datatype.
 *
 *  @return bool:       True if the pointer matches a psString structure, false otherwise.
 */
bool psMemCheckString(
    psPtr ptr                          ///< the pointer whose type to check
);

/** Copies the input string
 *
 *  This function shall allocate memory to the length of the input string plus
 *  one and copy the input string to the newly allocated memory.  If 'string'
 *  is 'NULL' then 'NULL' is returned.
 *
 *  @return psString:      Copy of input string
 */
psString psStringCopy(
    const char *string                 ///< Input string of characters to copy
);

/** Copies the input string up to the specified number of characters
 *
 *  This function shall allocate memory to the length specified by nChar
 *  plus one and copy the input string to the newly allocated memory.
 *  This function will only copy nChar bytes from the input to new string,
 *  so if the input string is larger than nChar characters the copied
 *  string will be a substring of the input string.  If the input string
 *  is smaller than nChar bytes then the remaining bytes allocated will
 *  be set to NULL.  If 'string' is 'NULL' then 'NULL' is returned.
 *
 *  @return  psString:   Copy of input string
 */
psString psStringNCopy(
    const char *string,                ///< Input string of characters to copy
    unsigned int nChar                 ///< Number of bytes to allocate for string copy
);

/** Appends a format onto a string
 *
 * This function shall allocate a new string if dest is NULL.  dest shall be
 * automatically extended to the size of the new string.
 *
 * @return ssize_t:     The length of the new string (excluding '\0')
 */
#ifdef __GNUC__
ssize_t psStringAppend(
    char **dest,                        ///< existing string
    const char *format,                 ///< format to append
    ...                                 ///< format arguments
) __attribute__((format(printf, 2, 3)));
#else // __GNUC__
ssize_t psStringAppend(
    char **dest,                        ///< existing string
    const char *format,                 ///< format to append
    ...                                 ///< format arguments
);
#endif // __GNUC__

/** Appends a format onto a string
 *
 * This function shall allocate a new string if dest is NULL.  dest shall be
 * automatically extended to the size of the new string.
 *
 * @return ssize_t:     The length of the new string (excluding '\0')
 */
ssize_t psStringAppendV(
    char **dest,                        ///< existing string
    const char *format,                 ///< format to append
    va_list ap                          ///< va_list of format arguments
);

/** Prepends a format onto a string
 *
 * This function shall allocate a new string if dest is NULL.  dest shall be
 * automatically extended to the size of the new string.
 *
 * @return ssize_t:     The length of the new string (excluding '\0')
 */
#ifdef __GNUC__
ssize_t psStringPrepend(
    char **dest,                        ///< existing string
    const char *format,                 ///< format to append
    ...                                 ///< format arguments
) __attribute__((format(printf, 2, 3)));
# else // __GNUC__

    ssize_t psStringPrepend(
        char **dest,                        ///< existing string
        const char *format,                 ///< format to append
        ...                                 ///< format arguments
    );
#endif // __GNUC__

/** Prepends a format onto a string
 *
 * This function shall allocate a new string if dest is NULL.  dest shall be
 * automatically extended to the size of the new string.
 *
 * @return ssize_t:     The length of the new string (excluding '\0')
 */
ssize_t psStringPrependV(
    char **dest,                        ///< existing string
    const char *format,                 ///< format to append
    va_list ap                          ///< va_list of format arguments
);

/** Procedure to split the input string into a psList of psStrings.
 *
 *  The string is split at any one of the characters in splitters.  Split
 *  strings of zero length should not be included in the output list.
 *
 *  @return psList*:    The list of (split) psStrings.
 */
psList *psStringSplit(
    const char *string,                ///< String to split
    const char *splitters,             ///< Characters on which to split
    bool multipleAreSignificant        ///< Are multiple occurences significant?
);

/** Procedure to split the input string into a psArray of psStrings.
 *
 *  The string is split at any one of the characters in splitters.  Split
 *  strings of zero length should not be included in the output list.
 *
 *  @return psArray*:       The array of (split) psStrings.
 */
psArray *psStringSplitArray(
    const char *string,                ///< String to split
    const char *splitters,             ///< Characters on which to split
    bool multipleAreSignificant        ///< Are multiple occurences significant?
);

// Given the input string, search for all copies of the key, and replace with the replacement value
// the input string may be freed if not needed
/** Procedure to search an input string and substitute strings where desired.
 *
 *  The input string is searched for all instances of the key, which is then replaced with
 *  the replacement value wherever found.  The input string may be freed if not needed.
 *
 *  @return ssize_t:      the length of the new string (excluding '\0')
 */
ssize_t psStringSubstitute (
    psString *input,                    ///< ptr to input string to be modified
    const char *replace,                ///< replacement value
    const char *key                     ///< string to be replaced in input
);

// strip whitespace from head and tail of string
/** Procedure to strip the whitespace from the head and tail of a string.
 *
 *  @return size_t:         Number of whitespaces removed.
 */
size_t psStringStrip(
    char *string                       ///< input string to be stripped.
);

/// Given a CVS keyword string, strip off the CVS-specific keyword to get the value
psString psStringStripCVS(const char *string, ///< The string, something like "$CVSKEYWORD: Value$"
                          const char *tagName ///< The name of the tag to remove, something like "CVSKEYWORD"
                         );

#define PS_ASSERT_STRING_NON_EMPTY(NAME, RVAL) \
if (!(NAME) || strlen(NAME) == 0) { \
    psError(PS_ERR_BAD_PARAMETER_VALUE, true, \
            "Error: String %s is NULL or empty.", \
            #NAME); \
    return(RVAL); \
}

#ifndef DOXYGEN
#if NO_STRCASESTR
// this means that the system's libc does not provide strcasestr()
#define strcasestr(...) p_psstrcasestr(__VA_ARGS__)
extern char *p_psstrcasestr (const char *haystack, const char *needle)
    __THROW __attribute_pure__ __nonnull ((1, 2));
#endif // if NO_STRCASESTR
#endif // ifndef DOXYGEN

/// @}
#endif // #ifndef PS_STRING_H
