mirror of
https://github.com/curl/curl.git
synced 2026-04-14 13:01:42 +08:00
Move curlx_ functions into its own subdir. The idea is to use the curlx_ prefix proper on these functions, and use these same function names both in tool, lib and test suite source code. Stop the previous special #define setup for curlx_ names. The printf defines are now done for the library alone. Tests no longer use the printf defines. The tool code sets its own defines. The printf functions are not curlx, they are publicly available. The strcase defines are not curlx_ functions and should not be used by tool or server code. dynbuf, warnless, base64, strparse, timeval, timediff are now proper curlx functions. When libcurl is built statically, the functions from the library can be used as-is. The key is then that the functions must work as-is, without having to be recompiled for use in tool/tests. This avoids symbol collisions - when libcurl is built statically, we use those functions directly when building the tool/tests. When libcurl is shared, we build/link them separately for the tool/tests. Assisted-by: Jay Satiro Closes #17253
299 lines
6.9 KiB
C
299 lines
6.9 KiB
C
/***************************************************************************
|
|
* _ _ ____ _
|
|
* Project ___| | | | _ \| |
|
|
* / __| | | | |_) | |
|
|
* | (__| |_| | _ <| |___
|
|
* \___|\___/|_| \_\_____|
|
|
*
|
|
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
|
*
|
|
* This software is licensed as described in the file COPYING, which
|
|
* you should have received as part of this distribution. The terms
|
|
* are also available at https://curl.se/docs/copyright.html.
|
|
*
|
|
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
|
* copies of the Software, and permit persons to whom the Software is
|
|
* furnished to do so, under the terms of the COPYING file.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
* SPDX-License-Identifier: curl
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "../curl_setup.h"
|
|
#include "dynbuf.h"
|
|
#include "../curl_printf.h"
|
|
#ifdef BUILDING_LIBCURL
|
|
#include "../curl_memory.h"
|
|
#endif
|
|
#include "../memdebug.h"
|
|
|
|
#define MIN_FIRST_ALLOC 32
|
|
|
|
#ifdef DEBUGBUILD
|
|
#define DYNINIT 0xbee51da /* random pattern */
|
|
#endif
|
|
|
|
/*
|
|
* Init a dynbuf struct.
|
|
*/
|
|
void curlx_dyn_init(struct dynbuf *s, size_t toobig)
|
|
{
|
|
DEBUGASSERT(s);
|
|
DEBUGASSERT(toobig);
|
|
DEBUGASSERT(toobig <= MAX_DYNBUF_SIZE); /* catch crazy mistakes */
|
|
s->bufr = NULL;
|
|
s->leng = 0;
|
|
s->allc = 0;
|
|
s->toobig = toobig;
|
|
#ifdef DEBUGBUILD
|
|
s->init = DYNINIT;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* free the buffer and re-init the necessary fields. It does not touch the
|
|
* 'init' field and thus this buffer can be reused to add data to again.
|
|
*/
|
|
void curlx_dyn_free(struct dynbuf *s)
|
|
{
|
|
DEBUGASSERT(s);
|
|
DEBUGASSERT(s->init == DYNINIT);
|
|
Curl_safefree(s->bufr);
|
|
s->leng = s->allc = 0;
|
|
}
|
|
|
|
/*
|
|
* Store/append an chunk of memory to the dynbuf.
|
|
*/
|
|
static CURLcode dyn_nappend(struct dynbuf *s,
|
|
const unsigned char *mem, size_t len)
|
|
{
|
|
size_t indx = s->leng;
|
|
size_t a = s->allc;
|
|
size_t fit = len + indx + 1; /* new string + old string + zero byte */
|
|
|
|
/* try to detect if there is rubbish in the struct */
|
|
DEBUGASSERT(s->init == DYNINIT);
|
|
DEBUGASSERT(s->toobig);
|
|
DEBUGASSERT(indx < s->toobig);
|
|
DEBUGASSERT(!s->leng || s->bufr);
|
|
DEBUGASSERT(a <= s->toobig);
|
|
DEBUGASSERT(!len || mem);
|
|
|
|
if(fit > s->toobig) {
|
|
curlx_dyn_free(s);
|
|
return CURLE_TOO_LARGE;
|
|
}
|
|
else if(!a) {
|
|
DEBUGASSERT(!indx);
|
|
/* first invoke */
|
|
if(MIN_FIRST_ALLOC > s->toobig)
|
|
a = s->toobig;
|
|
else if(fit < MIN_FIRST_ALLOC)
|
|
a = MIN_FIRST_ALLOC;
|
|
else
|
|
a = fit;
|
|
}
|
|
else {
|
|
while(a < fit)
|
|
a *= 2;
|
|
if(a > s->toobig)
|
|
/* no point in allocating a larger buffer than this is allowed to use */
|
|
a = s->toobig;
|
|
}
|
|
|
|
if(a != s->allc) {
|
|
/* this logic is not using Curl_saferealloc() to make the tool not have to
|
|
include that as well when it uses this code */
|
|
void *p = realloc(s->bufr, a);
|
|
if(!p) {
|
|
curlx_dyn_free(s);
|
|
return CURLE_OUT_OF_MEMORY;
|
|
}
|
|
s->bufr = p;
|
|
s->allc = a;
|
|
}
|
|
|
|
if(len)
|
|
memcpy(&s->bufr[indx], mem, len);
|
|
s->leng = indx + len;
|
|
s->bufr[s->leng] = 0;
|
|
return CURLE_OK;
|
|
}
|
|
|
|
/*
|
|
* Clears the string, keeps the allocation. This can also be called on a
|
|
* buffer that already was freed.
|
|
*/
|
|
void curlx_dyn_reset(struct dynbuf *s)
|
|
{
|
|
DEBUGASSERT(s);
|
|
DEBUGASSERT(s->init == DYNINIT);
|
|
DEBUGASSERT(!s->leng || s->bufr);
|
|
if(s->leng)
|
|
s->bufr[0] = 0;
|
|
s->leng = 0;
|
|
}
|
|
|
|
/*
|
|
* Specify the size of the tail to keep (number of bytes from the end of the
|
|
* buffer). The rest will be dropped.
|
|
*/
|
|
CURLcode curlx_dyn_tail(struct dynbuf *s, size_t trail)
|
|
{
|
|
DEBUGASSERT(s);
|
|
DEBUGASSERT(s->init == DYNINIT);
|
|
DEBUGASSERT(!s->leng || s->bufr);
|
|
if(trail > s->leng)
|
|
return CURLE_BAD_FUNCTION_ARGUMENT;
|
|
else if(trail == s->leng)
|
|
return CURLE_OK;
|
|
else if(!trail) {
|
|
curlx_dyn_reset(s);
|
|
}
|
|
else {
|
|
memmove(&s->bufr[0], &s->bufr[s->leng - trail], trail);
|
|
s->leng = trail;
|
|
s->bufr[s->leng] = 0;
|
|
}
|
|
return CURLE_OK;
|
|
|
|
}
|
|
|
|
/*
|
|
* Appends a buffer with length.
|
|
*/
|
|
CURLcode curlx_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
|
|
{
|
|
DEBUGASSERT(s);
|
|
DEBUGASSERT(s->init == DYNINIT);
|
|
DEBUGASSERT(!s->leng || s->bufr);
|
|
return dyn_nappend(s, mem, len);
|
|
}
|
|
|
|
/*
|
|
* Append a null-terminated string at the end.
|
|
*/
|
|
CURLcode curlx_dyn_add(struct dynbuf *s, const char *str)
|
|
{
|
|
size_t n;
|
|
DEBUGASSERT(str);
|
|
DEBUGASSERT(s);
|
|
DEBUGASSERT(s->init == DYNINIT);
|
|
DEBUGASSERT(!s->leng || s->bufr);
|
|
n = strlen(str);
|
|
return dyn_nappend(s, (const unsigned char *)str, n);
|
|
}
|
|
|
|
/*
|
|
* Append a string vprintf()-style
|
|
*/
|
|
CURLcode curlx_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
|
|
{
|
|
#ifdef BUILDING_LIBCURL
|
|
int rc;
|
|
DEBUGASSERT(s);
|
|
DEBUGASSERT(s->init == DYNINIT);
|
|
DEBUGASSERT(!s->leng || s->bufr);
|
|
DEBUGASSERT(fmt);
|
|
rc = curlx_dyn_vprintf(s, fmt, ap);
|
|
|
|
if(!rc)
|
|
return CURLE_OK;
|
|
else if(rc == MERR_TOO_LARGE)
|
|
return CURLE_TOO_LARGE;
|
|
return CURLE_OUT_OF_MEMORY;
|
|
#else
|
|
char *str;
|
|
str = curl_mvaprintf(fmt, ap); /* this allocs a new string to append */
|
|
|
|
if(str) {
|
|
CURLcode result = dyn_nappend(s, (const unsigned char *)str, strlen(str));
|
|
free(str);
|
|
return result;
|
|
}
|
|
/* If we failed, we cleanup the whole buffer and return error */
|
|
curlx_dyn_free(s);
|
|
return CURLE_OUT_OF_MEMORY;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Append a string printf()-style
|
|
*/
|
|
CURLcode curlx_dyn_addf(struct dynbuf *s, const char *fmt, ...)
|
|
{
|
|
CURLcode result;
|
|
va_list ap;
|
|
DEBUGASSERT(s);
|
|
DEBUGASSERT(s->init == DYNINIT);
|
|
DEBUGASSERT(!s->leng || s->bufr);
|
|
va_start(ap, fmt);
|
|
result = curlx_dyn_vaddf(s, fmt, ap);
|
|
va_end(ap);
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Returns a pointer to the buffer.
|
|
*/
|
|
char *curlx_dyn_ptr(const struct dynbuf *s)
|
|
{
|
|
DEBUGASSERT(s);
|
|
DEBUGASSERT(s->init == DYNINIT);
|
|
DEBUGASSERT(!s->leng || s->bufr);
|
|
return s->bufr;
|
|
}
|
|
|
|
char *curlx_dyn_take(struct dynbuf *s, size_t *plen)
|
|
{
|
|
char *ptr = s->bufr;
|
|
DEBUGASSERT(s);
|
|
DEBUGASSERT(s->init == DYNINIT);
|
|
*plen = s->leng;
|
|
s->bufr = NULL;
|
|
s->leng = 0;
|
|
s->allc = 0;
|
|
return ptr;
|
|
}
|
|
|
|
/*
|
|
* Returns an unsigned pointer to the buffer.
|
|
*/
|
|
unsigned char *curlx_dyn_uptr(const struct dynbuf *s)
|
|
{
|
|
DEBUGASSERT(s);
|
|
DEBUGASSERT(s->init == DYNINIT);
|
|
DEBUGASSERT(!s->leng || s->bufr);
|
|
return (unsigned char *)s->bufr;
|
|
}
|
|
|
|
/*
|
|
* Returns the length of the buffer.
|
|
*/
|
|
size_t curlx_dyn_len(const struct dynbuf *s)
|
|
{
|
|
DEBUGASSERT(s);
|
|
DEBUGASSERT(s->init == DYNINIT);
|
|
DEBUGASSERT(!s->leng || s->bufr);
|
|
return s->leng;
|
|
}
|
|
|
|
/*
|
|
* Set a new (smaller) length.
|
|
*/
|
|
CURLcode curlx_dyn_setlen(struct dynbuf *s, size_t set)
|
|
{
|
|
DEBUGASSERT(s);
|
|
DEBUGASSERT(s->init == DYNINIT);
|
|
DEBUGASSERT(!s->leng || s->bufr);
|
|
if(set > s->leng)
|
|
return CURLE_BAD_FUNCTION_ARGUMENT;
|
|
s->leng = set;
|
|
s->bufr[s->leng] = 0;
|
|
return CURLE_OK;
|
|
}
|