
/** @file  psString.c
 *
 * -*- mode: C; c-basic-indent: 4; tab-width: 8; indent-tabs-mode: nil -*-
 * vim: set cindent ts=8 sw=4 expandtab:
 *
 *  @brief Contains the definition of string utility functions
 *
 *  String utility functions defined shall provide basic string copying
 *  capabilities while using the preferred memory management utilities.
 *
 *  @author Eric Van Alst, MHPCC
 *
 *  @version $Revision: 1.21.6.2 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2006-01-21 23:44:37 $
 *
 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
 */

#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "psString.h"
#include "psMemory.h"
#include "psError.h"

#include "psErrorText.h"

psString psStringCopy(const char *string)
{
    // Allocate memory using psAlloc function
    // Copy input string to memory just allocated
    // Return the copy
    // Pass through NULL values
    return string ? strcpy(psAlloc(strlen(string) + 1), string) : NULL;
}

psString psStringNCopy(const char *string, unsigned int nChar)
{
    char *returnValue = NULL;

    // Check the number of characters to copy is non-negative
    if (nChar == UINT_MAX) {
        // Log error message and return NULL
        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
                PS_ERRORTEXT_psString_NCHAR_NEGATIVE,
                nChar);
        return NULL;
    }
    // Allocate memory using psAlloc function - nChar bytes
    // Copy input string to memory allocated up to nChar characters
    // Return the copy
    // Pass through NULL values
    returnValue =
              string ? strncpy(psAlloc((size_t) nChar + 1), string, (size_t) nChar)
              : NULL;

    // Ensure the last byte is NULL character
    returnValue[nChar] = '\0';

    // Return the string pointer
    return returnValue;
}

// XXX EAM : since 'dest' is on the memory system, this probably should be:
//   ssize_t psStringAppend(psString *dest, const char *format, ...)
ssize_t psStringAppend(char **dest, const char *format, ...)
{
    va_list         args;
    size_t          length;             // complete string length (sans \0)
    size_t          oldLength;          // original string length (sans \0)
    ssize_t         tailLength;         // length of string to append

    if (!dest || !format) {
        return 0;
    }

    if (!*dest) {
        *dest = psStringCopy("");
        oldLength = 0;
    } else {
        // size of existing string
        oldLength = strlen(*dest);
    }

    // find the size of the string to append
    va_start(args, format);
    // C99 guarentees vsnprintf() to work as expected with size = 0
    tailLength = vsnprintf(*dest, 0, format, args);
    va_end(args);

    // if the new tail is zero length, return the length of the old string.  if
    // it's a format error, return the error code.
    if (tailLength < 1) {
        return tailLength == 0 ? oldLength : tailLength;
    }

    // new string length (sans \0)
    length = oldLength + tailLength;

    // realloc string to string + tail + \0
    *dest = psRealloc(*dest, length + 1);

    // append tail + \0
    va_start(args, format);
    vsnprintf(*dest + oldLength, tailLength + 1, format, args);
    va_end(args);

    return length;
}

ssize_t psStringPrepend(char **dest, const char *format, ...)
{
    va_list         args;
    size_t          length;             // complete string length (sans \0)
    ssize_t         headLength;         // length of string to prepend
    char            *oldDest;           // copy of original string

    if (!dest || !format) {
        return 0;
    }

    if (!*dest) {
        // makes the string backup and concatination pointless
        *dest = psStringCopy("");
        length = 0;
    } else {
        // size of existing string
        length = strlen(*dest);
    }

    // find the size of the string to prepend
    va_start(args, format);
    // C99 guarentees vsnprintf() to work as expected with size = 0
    headLength = vsnprintf(*dest, 0, format, args);
    va_end(args);

    // if the new head is zero length, return the length of the old string.  if
    // it's a format error, return the error code.
    if (headLength < 1) {
        return headLength == 0 ? length : headLength;
    }

    // backup original string
    oldDest = psStringCopy(*dest);

    // new string length (sans \0)
    length += headLength;

    // realloc string to head + string + \0
    *dest = psRealloc(*dest, length + 1);

    // copy the new head to the beginning of string
    va_start(args, format);
    vsnprintf(*dest, length + 1, format, args);
    va_end(args);

    // append the original string
    strncat(*dest, oldDest, length + 1);

    psFree(oldDest);

    return length;
}

/*** psLine not yet released ***/
# if (0)
    static void psLineFree (psLine *line)
{

    if (line == NULL)
        return;

    psFree (line->line);
    return;
}

// allocate a psLine structrue
psLine *psLineAlloc (int Nline)
{

    psLine *line;
    line = psAlloc (sizeof(psLine));
    psMemSetDeallocator(line, (psFreeFunc) psLineFree);

    line->Nline = 0;
    line->NLINE = Nline;
    line->line = psAlloc (Nline);
    return (line);
}

bool psLineInit (psLine *line)
{
    if (line == NULL)
        return (false);
    line->Nline = 0;
    return (true);
}

bool psLineAdd (psLine *line, char *format, ...)
{

    int Nchar;
    va_list ap;

    if (line == NULL)
        return (false);

    int nMax = line->NLINE - line->Nline;

    va_start (ap, format);
    Nchar = vsnprintf (&line->line[line->Nline], nMax, format, ap);
    line->Nline += PS_MIN (nMax - 1, Nchar);
    va_end (ap);

    if (Nchar >= nMax)
        return (false);
    return (true);
}
# endif
