/* Editor Settings: expandtabs and use 4 spaces for indentation
* ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
* -*- mode: c, c-basic-offset: 4 -*- */
/*
* Copyright (c) Likewise Software. All rights Reserved.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the license, or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details. You should have received a copy
* of the GNU Lesser General Public License along with this program. If
* not, see .
*
* LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
* TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
* WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
* TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
* LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU
* HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
* TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
* license@likewise.com
*/
/*
* Copyright (C) Likewise Software. All rights reserved.
*
* Module Name:
*
* rtlstring_cstring.c
*
* Abstract:
*
* Base C-style String Functions
*
* Authors: Danilo Almeida (dalmeida@likewise.com)
*
*/
#include "includes.h"
#include
#include
#include
#include
#include
size_t
LwRtlCStringNumChars(
IN PCSTR pszString
)
{
return strlen(pszString);
}
NTSTATUS
LwRtlCStringAllocateFromWC16String(
OUT PSTR* ppszNewString,
IN PCWSTR pszOriginalString
)
{
NTSTATUS status = 0;
PSTR pszNewString = NULL;
if (pszOriginalString)
{
pszNewString = awc16stombs(pszOriginalString);
if (!pszNewString)
{
status = STATUS_INSUFFICIENT_RESOURCES;
GOTO_CLEANUP();
}
}
cleanup:
if (status)
{
LwRtlCStringFree(&pszNewString);
}
*ppszNewString = pszNewString;
return status;
}
NTSTATUS
LwRtlCStringAllocateFromUnicodeString(
OUT PSTR* ppszNewString,
IN PUNICODE_STRING pOriginalString
)
{
NTSTATUS status = 0;
UNICODE_STRING terminatedOriginalString = { 0 };
PWSTR pwszTerminatedString = NULL;
PSTR pszNewString = NULL;
if (LW_RTL_STRING_IS_NULL_TERMINATED(pOriginalString))
{
pwszTerminatedString = pOriginalString->Buffer;
}
else
{
// Since duplicate always does NULL-termination, we can
// safely use the Buffer field as a WC16String.
status = LwRtlUnicodeStringDuplicate(&terminatedOriginalString, pOriginalString);
GOTO_CLEANUP_ON_STATUS(status);
pwszTerminatedString = terminatedOriginalString.Buffer;
}
status = LwRtlCStringAllocateFromWC16String(&pszNewString, pwszTerminatedString);
GOTO_CLEANUP_ON_STATUS(status);
cleanup:
if (!NT_SUCCESS(status))
{
RTL_FREE(&pszNewString);
}
LwRtlUnicodeStringFree(&terminatedOriginalString);
*ppszNewString = pszNewString;
return status;
}
NTSTATUS
LwRtlCStringDuplicate(
OUT PSTR* ppszNewString,
IN PCSTR pszOriginalString
)
{
NTSTATUS status = 0;
int EE = 0;
size_t size = 0;
PSTR pszNewString = NULL;
if (!pszOriginalString)
{
status = STATUS_INVALID_PARAMETER;
GOTO_CLEANUP_ON_STATUS_EE(status, EE);
}
size = (strlen(pszOriginalString) + 1) * sizeof(pszOriginalString[0]);
status = RTL_ALLOCATE(&pszNewString, CHAR, size);
GOTO_CLEANUP_ON_STATUS_EE(status, EE);
memcpy(pszNewString, pszOriginalString, size);
cleanup:
if (status)
{
LwRtlCStringFree(&pszNewString);
}
*ppszNewString = pszNewString;
return status;
}
VOID
LwRtlCStringFree(
IN OUT PSTR* ppszString
)
{
RTL_FREE(ppszString);
}
LW_LONG
LwRtlCStringCompare(
LW_IN LW_PCSTR pString1,
LW_IN LW_PCSTR pString2,
LW_IN LW_BOOLEAN bIsCaseSensitive
)
{
LW_LONG result = 0;
int innerResult = 0;
if (bIsCaseSensitive)
{
innerResult = strcmp(pString1, pString2);
}
else
{
innerResult = strcasecmp(pString1, pString2);
}
if (innerResult > 0)
{
result = 1;
}
else if (innerResult < 0)
{
result = -1;
}
return result;
}
LW_BOOLEAN
LwRtlCStringIsEqual(
LW_IN LW_PCSTR pString1,
LW_IN LW_PCSTR pString2,
LW_IN LW_BOOLEAN bIsCaseSensitive
)
{
return LwRtlCStringCompare(pString1, pString2, bIsCaseSensitive) == 0;
}
/* Replacement for vasprintf */
static
char*
my_vasprintf(
const char* fmt,
va_list ap
)
{
int len;
va_list my_ap;
char* str, *str_new;
/* Some versions of vsnprintf won't accept
a null or zero-length buffer */
str = malloc(1);
if (!str)
{
return NULL;
}
va_copy(my_ap, ap);
len = vsnprintf(str, 1, fmt, my_ap);
/* Some versions of vsnprintf return -1 when
the buffer was too small rather than the
number of characters that would be written,
so we have loop in search of a large enough
buffer */
if (len == -1)
{
int capacity = 16;
do
{
capacity *= 2;
va_copy(my_ap, ap);
str_new = realloc(str, capacity);
if (!str_new)
{
free(str);
return NULL;
}
str = str_new;
len = vsnprintf(str, capacity, fmt, my_ap);
} while (len == -1 || capacity <= len);
str[len] = '\0';
return str;
}
else
{
va_copy(my_ap, ap);
str_new = realloc(str, len+1);
if (!str_new)
{
free(str);
return NULL;
}
str = str_new;
if (vsnprintf(str, len+1, fmt, my_ap) < len)
return NULL;
else
return str;
}
}
NTSTATUS
LwRtlCStringAllocatePrintfV(
OUT PSTR* ppszString,
IN PCSTR pszFormat,
IN va_list Args
)
{
NTSTATUS status = 0;
PSTR pszNewString = NULL;
// TODO -- Memory model? (currenlty using free)
// TODO -- Enhance with %Z, %wZ, etc.
pszNewString = my_vasprintf(pszFormat, Args);
if (pszNewString == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
}
*ppszString = pszNewString;
return status;
}
NTSTATUS
LwRtlCStringAllocatePrintf(
OUT PSTR* ppszString,
IN PCSTR pszFormat,
IN ...
)
{
NTSTATUS status = 0;
va_list args;
va_start(args, pszFormat);
status = LwRtlCStringAllocatePrintfV(ppszString, pszFormat, args);
va_end(args);
return status;
}
static
NTSTATUS
LwRtlCStringAllocateAppendPrintfV(
IN OUT PSTR* ppszString,
IN PCSTR pszFormat,
IN va_list Args
)
{
NTSTATUS status = 0;
PSTR pszAddString = NULL;
PSTR pszNewString = NULL;
PSTR pszResultString = *ppszString;
status = LwRtlCStringAllocatePrintfV(&pszAddString, pszFormat, Args);
GOTO_CLEANUP_ON_STATUS(status);
if (pszResultString)
{
status = LwRtlCStringAllocatePrintf(&pszNewString, "%s%s", pszResultString, pszAddString);
GOTO_CLEANUP_ON_STATUS(status);
LwRtlCStringFree(&pszResultString);
}
else
{
pszNewString = pszAddString;
pszAddString = NULL;
}
pszResultString = pszNewString;
cleanup:
if (status)
{
LwRtlCStringFree(&pszNewString);
}
else
{
*ppszString = pszResultString;
}
LwRtlCStringFree(&pszAddString);
return status;
}
NTSTATUS
LwRtlCStringAllocateAppendPrintf(
IN OUT PSTR* ppszString,
IN PCSTR pszFormat,
...
)
{
NTSTATUS status = 0;
va_list args;
va_start(args, pszFormat);
status = LwRtlCStringAllocateAppendPrintfV(ppszString, pszFormat, args);
va_end(args);
return status;
}