зеркало из https://github.com/mozilla/gecko-dev.git
279 строки
6.3 KiB
C
279 строки
6.3 KiB
C
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include "mozilla/Assertions.h"
|
|
#include "cpr_types.h"
|
|
#include "cpr_string.h"
|
|
#include "cpr_strings.h"
|
|
|
|
/* From cpr_stdlib.h */
|
|
#ifdef CPR_STRING_USE_FALLIBLE_MALLOC
|
|
#define cpr_malloc(a) malloc(a)
|
|
#define cpr_calloc(a, b) calloc(a, b)
|
|
#define cpr_realloc(a, b) realloc(a, b)
|
|
#define cpr_free(a) free(a)
|
|
#else
|
|
#include "mozilla/mozalloc.h"
|
|
|
|
#define cpr_malloc(a) moz_xmalloc(a)
|
|
#define cpr_calloc(a, b) moz_xcalloc(a, b)
|
|
#define cpr_realloc(a, b) moz_xrealloc(a, b)
|
|
#define cpr_free(a) free(a)
|
|
#endif
|
|
|
|
/**
|
|
* sstrncpy
|
|
*
|
|
* This is Cisco's *safe* version of strncpy. The string will always
|
|
* be NUL terminated (which is not ANSI compliant).
|
|
*
|
|
* Parameters: s1 - first string
|
|
* s2 - second string
|
|
* max - maximum length in octets to concat.
|
|
*
|
|
* Return: Pointer to the *end* of the string
|
|
*
|
|
* Remarks: Modified to be explicitly safe for all inputs.
|
|
* Also return the number of characters copied excluding the
|
|
* NUL terminator vs. the original string s1. This simplifies
|
|
* code where sstrncat functions follow.
|
|
*/
|
|
unsigned long
|
|
sstrncpy (char *dst, const char *src, unsigned long max)
|
|
{
|
|
unsigned long cnt = 0;
|
|
|
|
if (dst == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
if (src) {
|
|
while ((max-- > 1) && (*src)) {
|
|
*dst = *src;
|
|
dst++;
|
|
src++;
|
|
cnt++;
|
|
}
|
|
}
|
|
|
|
#if defined(CPR_SSTRNCPY_PAD)
|
|
/*
|
|
* To be equivalent to the TI compiler version
|
|
* v2.01, SSTRNCPY_PAD needs to be defined
|
|
*/
|
|
while (max-- > 1) {
|
|
*dst = '\0';
|
|
dst++;
|
|
}
|
|
#endif
|
|
*dst = '\0';
|
|
|
|
return cnt;
|
|
}
|
|
|
|
/**
|
|
* sstrncat
|
|
*
|
|
* This is Cisco's *safe* version of strncat. The string will always
|
|
* be NUL terminated (which is not ANSI compliant).
|
|
*
|
|
* Parameters: s1 - first string
|
|
* s2 - second string
|
|
* max - maximum length in octets to concatenate
|
|
*
|
|
* Return: Pointer to the *end* of the string
|
|
*
|
|
* Remarks: Modified to be explicitly safe for all inputs.
|
|
* Also return the end vs. the beginning of the string s1
|
|
* which is useful for multiple sstrncat calls.
|
|
*/
|
|
char *
|
|
sstrncat (char *s1, const char *s2, unsigned long max)
|
|
{
|
|
if (s1 == NULL)
|
|
return (char *) NULL;
|
|
|
|
while (*s1)
|
|
s1++;
|
|
|
|
if (s2) {
|
|
while ((max-- > 1) && (*s2)) {
|
|
*s1 = *s2;
|
|
s1++;
|
|
s2++;
|
|
}
|
|
}
|
|
*s1 = '\0';
|
|
|
|
return s1;
|
|
}
|
|
|
|
/*
|
|
* flex_string
|
|
*/
|
|
|
|
/*
|
|
* flex_string_init
|
|
*
|
|
* Not thread-safe
|
|
*/
|
|
void flex_string_init(flex_string *fs) {
|
|
fs->buffer_length = FLEX_STRING_CHUNK_SIZE;
|
|
fs->string_length = 0;
|
|
fs->buffer = cpr_malloc(fs->buffer_length);
|
|
fs->buffer[0] = '\0';
|
|
}
|
|
|
|
/*
|
|
* flex_string_free
|
|
*
|
|
* Not thread-safe
|
|
*/
|
|
void flex_string_free(flex_string *fs) {
|
|
fs->buffer_length = 0;
|
|
fs->string_length = 0;
|
|
cpr_free(fs->buffer);
|
|
fs->buffer = NULL;
|
|
}
|
|
|
|
/* For sanity check before alloc */
|
|
#define FLEX_STRING_MAX_SIZE (10 * 1024 * 1024) /* 10MB */
|
|
|
|
/*
|
|
* flex_string_check_alloc
|
|
*
|
|
* Allocate enough chunks to hold the new minimum size.
|
|
*
|
|
* Not thread-safe
|
|
*/
|
|
void flex_string_check_alloc(flex_string *fs, size_t new_min_length) {
|
|
if (new_min_length > fs->buffer_length) {
|
|
/* Oversize, allocate more */
|
|
|
|
/* Sanity check on allocation size */
|
|
if (new_min_length > FLEX_STRING_MAX_SIZE) {
|
|
MOZ_CRASH();
|
|
}
|
|
|
|
/* Alloc to nearest chunk */
|
|
fs->buffer_length = (((new_min_length - 1) / FLEX_STRING_CHUNK_SIZE) + 1) * FLEX_STRING_CHUNK_SIZE;
|
|
|
|
fs->buffer = cpr_realloc(fs->buffer, fs->buffer_length);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* flex_string_append
|
|
*
|
|
* Not thread-safe
|
|
*/
|
|
void flex_string_append(flex_string *fs, const char *more) {
|
|
fs->string_length += strlen(more);
|
|
|
|
flex_string_check_alloc(fs, fs->string_length + 1);
|
|
|
|
sstrncat(fs->buffer, more, fs->buffer_length - strlen(fs->buffer));
|
|
}
|
|
|
|
/*
|
|
* va_copy is part of the C99 spec but MSVC doesn't have it.
|
|
*/
|
|
#ifndef va_copy
|
|
#define va_copy(d,s) ((d) = (s))
|
|
#endif
|
|
|
|
/*
|
|
* flex_string_vsprintf
|
|
*
|
|
* Not thread-safe
|
|
*/
|
|
void flex_string_vsprintf(flex_string *fs, const char *format, va_list original_ap) {
|
|
va_list ap;
|
|
int vsnprintf_result;
|
|
|
|
va_copy(ap, original_ap);
|
|
vsnprintf_result = vsnprintf(fs->buffer + fs->string_length, fs->buffer_length - fs->string_length, format, ap);
|
|
va_end(ap);
|
|
|
|
/* Special case just for Windows where vsnprintf is broken
|
|
and returns -1 if buffer too large unless you size it 0. */
|
|
if (vsnprintf_result < 0) {
|
|
va_copy(ap, original_ap);
|
|
vsnprintf_result = vsnprintf(NULL, 0, format, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
if (fs->string_length + vsnprintf_result >= fs->buffer_length) {
|
|
/* Buffer overflow, resize */
|
|
flex_string_check_alloc(fs, fs->string_length + vsnprintf_result + 1);
|
|
|
|
/* Try again with new buffer */
|
|
va_copy(ap, original_ap);
|
|
vsnprintf_result = vsnprintf(fs->buffer + fs->string_length, fs->buffer_length - fs->string_length, format, ap);
|
|
va_end(ap);
|
|
MOZ_ASSERT(vsnprintf_result > 0 &&
|
|
(size_t)vsnprintf_result < (fs->buffer_length - fs->string_length));
|
|
}
|
|
|
|
if (vsnprintf_result > 0) {
|
|
fs->string_length += vsnprintf_result;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* flex_string_sprintf
|
|
*
|
|
* Not thread-safe
|
|
*/
|
|
void flex_string_sprintf(flex_string *fs, const char *format, ...) {
|
|
va_list ap;
|
|
|
|
va_start(ap, format);
|
|
flex_string_vsprintf(fs, format, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
|
|
|
|
/* From cpr_linux_string.c */
|
|
/**
|
|
* cpr_strdup
|
|
*
|
|
* @brief The CPR wrapper for strdup
|
|
|
|
* The cpr_strdup shall return a pointer to a new string, which is a duplicate
|
|
* of the string pointed to by "str" argument. A null pointer is returned if the
|
|
* new string cannot be created.
|
|
*
|
|
* @param[in] str - The string that needs to be duplicated
|
|
*
|
|
* @return The duplicated string or NULL in case of no memory
|
|
*
|
|
*/
|
|
char *
|
|
cpr_strdup (const char *str)
|
|
{
|
|
char *dup;
|
|
size_t len;
|
|
|
|
if (!str) {
|
|
return (char *) NULL;
|
|
}
|
|
|
|
len = strlen(str);
|
|
if (len == 0) {
|
|
return (char *) NULL;
|
|
}
|
|
len++;
|
|
|
|
dup = cpr_malloc(len * sizeof(char));
|
|
if (!dup) {
|
|
return (char *) NULL;
|
|
}
|
|
(void) memcpy(dup, str, len);
|
|
return dup;
|
|
}
|