mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-07-08 21:31:51 +00:00
387 lines
9.3 KiB
C
Executable File
387 lines
9.3 KiB
C
Executable File
/* 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/. */
|
|
|
|
#define __STRINGLIB_INTERNAL__
|
|
|
|
#include "cpr_types.h"
|
|
#include "cpr_stdlib.h"
|
|
#include "cpr_stdio.h"
|
|
#include "cpr_string.h"
|
|
#include "cpr_stddef.h"
|
|
#include "cpr_locks.h"
|
|
#include "string_lib.h"
|
|
#include "phone_debug.h"
|
|
#include "debug.h"
|
|
|
|
|
|
#define STRING_SIGNATURE (('S'<<8)|'T')
|
|
#define STR_TO_STRUCT(str) ((string_block_t *)((str) - (offsetof(string_block_t,data))))
|
|
#define STRUCT_TO_STR(sbt) ((const char *) (sbt)->data)
|
|
|
|
static string_t empty_str;
|
|
static int strlib_is_string(string_t str);
|
|
|
|
/*
|
|
* Function: strlib_malloc
|
|
*
|
|
* PARAMETERS:const char* : string which is to be malloc'ed
|
|
int : length of string or -1
|
|
*
|
|
* DESCRIPTION:strlib_malloc : creates a new string and returns a const char*
|
|
* to the new string. Size of String is equal to length specified or actual
|
|
* length of the string when length is specified as -1(LEN_UNKNOWN)
|
|
*
|
|
* RETURNS: Pointer to malloc'ed string
|
|
*
|
|
*/
|
|
string_t
|
|
strlib_malloc (const char *str, int length, const char *fname, int line)
|
|
{
|
|
string_block_t *temp;
|
|
int size;
|
|
|
|
// if specified length is unknown or invalid... then calculate it
|
|
// Length < 0 is not expected, but since length is an int, it could
|
|
// theoritically be negative. [ This check accounts for that, and
|
|
// avoids a static analysis warning related to same ]
|
|
if ((length == LEN_UNKNOWN) || (length < 0)) {
|
|
length = strlen(str);
|
|
}
|
|
|
|
size = sizeof(string_block_t) + length + 1;
|
|
temp = (string_block_t *) cpr_malloc(size);
|
|
|
|
if (!temp) {
|
|
err_msg("Error: Strlib_Malloc() Failed. Requested Size = %d\n", size);
|
|
return (string_t) 0;
|
|
}
|
|
|
|
temp->refcount = 1;
|
|
temp->length = (uint16_t) length;
|
|
temp->signature = STRING_SIGNATURE;
|
|
temp->fname = fname;
|
|
temp->line = line;
|
|
/* There used to be memcpy here which will walk off the end of */
|
|
/* str pointer which is a bad thing to do */
|
|
sstrncpy(temp->data, str, length + 1);
|
|
temp->data[length] = '\0';
|
|
|
|
return STRUCT_TO_STR(temp);
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: strlib_copy
|
|
*
|
|
* PARAMETERS:string_t : string whose ref count is to be incremented
|
|
*
|
|
* DESCRIPTION:just increments the reference count of the string.
|
|
* It is not like conventional strcpy as far as implementation
|
|
* is concerned, but effectivly when user calls strlib_copy he gets
|
|
* private copy which cannot be modified by any other function.
|
|
* String should be modified only by calling strlib_open
|
|
* which checks for the refcount and if its more than 1 allocates new string.
|
|
*
|
|
* RETURNS: string_t: string whose ref count is incremented
|
|
*
|
|
*/
|
|
string_t
|
|
strlib_copy (string_t str)
|
|
{
|
|
string_block_t *temp;
|
|
|
|
if (!strlib_is_string(str)) {
|
|
return (NULL);
|
|
}
|
|
|
|
temp = STR_TO_STRUCT(str);
|
|
|
|
/*
|
|
* Refcount is limited to USHRT_MAX since refcount is
|
|
* of type uint16_t.
|
|
*/
|
|
if ((temp->refcount < 0xffff) && (str != empty_str)) {
|
|
temp->refcount++;
|
|
}
|
|
|
|
return STRUCT_TO_STR(temp);
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: strlib_update
|
|
*
|
|
* PARAMETERS:string_t : destination string
|
|
* const char* : source string
|
|
*
|
|
* DESCRIPTION:like strcpy but returns const char* to a string in pool
|
|
*
|
|
* RETURNS: string_t:Pointer to a new string
|
|
*
|
|
*/
|
|
string_t
|
|
strlib_update (string_t destination, const char *source,
|
|
const char *calling_fname, int line)
|
|
{
|
|
const char *fname = "strlib_udpate";
|
|
string_t ret_str;
|
|
|
|
/* Bogus destination */
|
|
if (!destination) {
|
|
/* Should never happen, so report it */
|
|
err_msg("%s: Destination String is invalid: %s:%d", fname,
|
|
calling_fname, line);
|
|
/* bad input, bad output */
|
|
return NULL;
|
|
}
|
|
|
|
/* Bogus source */
|
|
if (!source) {
|
|
/* Should never happen, so report it and return something */
|
|
err_msg("%s: Source String is invalid: %s:%d", fname,
|
|
calling_fname, line);
|
|
strlib_free(destination);
|
|
return strlib_empty();
|
|
}
|
|
|
|
if (source[0] == '\0') {
|
|
/* Source is NULL string, use string empty */
|
|
strlib_free(destination);
|
|
return strlib_empty();
|
|
}
|
|
|
|
ret_str = strlib_malloc(source, LEN_UNKNOWN, calling_fname, line);
|
|
|
|
if (!ret_str) {
|
|
/*
|
|
* If a malloc error occurred, give them back what they had.
|
|
* It's not right, but it's better than nothing.
|
|
*/
|
|
ret_str = destination;
|
|
} else {
|
|
strlib_free(destination);
|
|
}
|
|
|
|
return (ret_str);
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: strlib_append
|
|
*
|
|
* PARAMETERS: string_t : oringinal string
|
|
* const char* : to be appended string
|
|
*
|
|
* DESCRIPTION:this function will append a string to the original string,
|
|
* makes a duplicate of the string and returns it.
|
|
*
|
|
* RETURNS: Appended string (string_t) or NULL if failure
|
|
*
|
|
*/
|
|
string_t
|
|
strlib_append (string_t str, const char *toappend_str,
|
|
const char *fname, int line)
|
|
{
|
|
int curlen;
|
|
char *buf;
|
|
|
|
/* Should never happen */
|
|
if (!str) {
|
|
return NULL;
|
|
}
|
|
|
|
curlen = strlen(str);
|
|
/* not really an open, rather more like modify */
|
|
buf = strlib_open(str, curlen + strlen(toappend_str) + 1, fname, line);
|
|
/*
|
|
* Validate returned value, but buf could be equal to str (buf == str)
|
|
* so there still may be issues.
|
|
*/
|
|
if (buf) {
|
|
strcpy(buf + curlen, toappend_str);
|
|
return buf;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: strlib_free
|
|
*
|
|
* PARAMETERS: string_t : string to which reference is to be removed
|
|
*
|
|
* DESCRIPTION:It will remove the node containing the string from the linked
|
|
* list if its refcount is 0 else it will decrement the refcount.
|
|
*
|
|
* RETURNS: none
|
|
*
|
|
*/
|
|
void
|
|
strlib_free (string_t str)
|
|
{
|
|
string_block_t *temp;
|
|
|
|
if ((!strlib_is_string(str)) || (str == empty_str)) {
|
|
return;
|
|
}
|
|
|
|
temp = STR_TO_STRUCT(str);
|
|
temp->refcount--;
|
|
if (temp->refcount == 0) {
|
|
temp->signature = 0;
|
|
cpr_free(temp);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: strlib_open
|
|
*
|
|
* PARAMETERS: string_t : string to be modified
|
|
* int : length of string to be modified
|
|
*
|
|
* DESCRIPTION:User will call open when he wants to modify the string. If
|
|
* length of string after modification is going to be = < original string
|
|
* return to him pointer to original string, else a new string is malloced
|
|
* for user and a pointer to it is send to him.
|
|
*
|
|
* RETURNS: char* to modifiable string
|
|
*
|
|
*/
|
|
char *
|
|
strlib_open (string_t str, int length, const char *fname, int line)
|
|
{
|
|
char *ret_str;
|
|
string_block_t *temp;
|
|
|
|
if (!strlib_is_string(str)) {
|
|
return (NULL);
|
|
}
|
|
|
|
temp = STR_TO_STRUCT(str);
|
|
|
|
if ((temp->refcount == 1) && (length <= temp->length)) {
|
|
ret_str = (char *) str;
|
|
} else {
|
|
ret_str = (char *) strlib_malloc(str, length, fname, line);
|
|
if (!ret_str) {
|
|
/*
|
|
* If a malloc error occurred, give them back what they had.
|
|
* It's not right, but it's better than nothing.
|
|
*/
|
|
ret_str = (char *) str;
|
|
} else {
|
|
strlib_free(str);
|
|
}
|
|
}
|
|
|
|
return (ret_str);
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: strlib_close
|
|
*
|
|
* PARAMETERS:char* : string to be made unmodifiable
|
|
*
|
|
* DESCRIPTION:Just returns const char* for the string, so that user
|
|
* does not change it by mistake
|
|
*
|
|
* RETURNS:string_t: pointer to same string
|
|
*
|
|
*/
|
|
string_t
|
|
strlib_close (char *str)
|
|
{
|
|
if (!strlib_is_string(str)) {
|
|
return (NULL);
|
|
}
|
|
return (str);
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: strlib_is_string
|
|
*
|
|
* PARAMETERS: string_t : string which is to be validated
|
|
*
|
|
* DESCRIPTION:Checks whether the signature for the provided string is valid
|
|
*
|
|
* RETURNS: static int
|
|
*
|
|
*/
|
|
int
|
|
strlib_is_string (string_t str)
|
|
{
|
|
string_block_t *temp;
|
|
|
|
if (str == NULL) {
|
|
err_msg("Strlib Error: strlib_is_tring passed invalid string\n");
|
|
return (0);
|
|
}
|
|
|
|
temp = STR_TO_STRUCT(str);
|
|
|
|
if (temp->signature == STRING_SIGNATURE) {
|
|
return (1);
|
|
} else {
|
|
err_msg("Strlib Error: strlib_is_tring passed invalid string\n");
|
|
return (0);
|
|
}
|
|
|
|
}
|
|
|
|
int
|
|
strlib_test_memory_is_string (void *mem)
|
|
{
|
|
string_block_t *temp;
|
|
|
|
if (!mem) {
|
|
return FALSE;
|
|
}
|
|
|
|
temp = (string_block_t *) mem;
|
|
if (temp->signature == STRING_SIGNATURE) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Function: strlib_empty
|
|
*
|
|
* PARAMETERS: None
|
|
*
|
|
* DESCRIPTION:strlib_empty will be called by user when he wants
|
|
* to initialize his string to '/0' or "". It is not same as initializing
|
|
* it to NULL. if(str) will evaluate to true if str = strlib_empty().
|
|
* Correct way to check for empty string will be to do if (str[0] == '\0') or
|
|
* if (str[0] == "")
|
|
*
|
|
* RETURNS: Pointer to empty_str
|
|
*/
|
|
string_t
|
|
strlib_empty (void)
|
|
{
|
|
string_block_t *temp;
|
|
static boolean empty_str_init = FALSE;
|
|
|
|
if (empty_str_init == FALSE) {
|
|
empty_str = strlib_malloc("", LEN_UNKNOWN, __FILE__, __LINE__);
|
|
temp = STR_TO_STRUCT(empty_str);
|
|
temp->refcount = 0xffff;
|
|
empty_str_init = TRUE;
|
|
}
|
|
return (empty_str);
|
|
}
|
|
|
|
void
|
|
strlib_init (void)
|
|
{
|
|
(void) strlib_empty(); // force it to allocate the empty string buffer
|
|
}
|