mirror of
https://github.com/curl/curl.git
synced 2026-04-24 01:42:13 +03:00
Backtrack on previous change that aimed to solve the wrong `share.h` being included. It turns out it did not fix this issue. At the same time it introduced relative header filenames and the need to include the same headers differently depending on the source files' location, reducing readability and editability. Replace this method by re-adding curl's lib source directory to the header path and addressing headers by the their full, relative name to that base directory. Aligning with this method already used in src and tests. With these advantages: - makes includes easier to read, recognize, grep, sort, write, and copy between sources, - syncs the way these headers are included across curl components, - avoids the ambiguity between system `schannel.h`, `rustls.h` vs. local headers using the same names in `lib/vtls`, - silences clang-tidy `readability-duplicate-include` checker, which detects the above issue, Ref: https://clang.llvm.org/extra/clang-tidy/checks/readability/duplicate-include.html - possibly silences TIOBE coding standard warnings: `6.10.2.a: Don't use relative paths in #include statements.` - long shot: it works well with concatenated test sources, for clang-tidy-friendly custom unity builds. Ref: #20667 Slight downside: it's not enforced. If there happens to be a collision between a local `lib/*.h` header and a system one, the solution is to rename (possibly with its `.c` counterpart) into the `curl_` namespace. This is also the method used by curl in the past. Also: - curlx/inet_pton: reduce scope of an include. - toolx/tool_time: apply this to an include, and update VS project files accordingly. Also dropping unnecessary lib/curlx header path. - clang-tidy: enable `readability-duplicate-include`. Follow-up to3887069c66#19676 Follow-up to625f2c1644#16991 #16949 Closes #20623
292 lines
6.7 KiB
C
292 lines
6.7 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 "curlx/dynbuf.h"
|
|
#include "curl_printf.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 idx = s->leng;
|
|
size_t a = s->allc;
|
|
size_t fit = len + idx + 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(idx < 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(!idx);
|
|
/* 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) {
|
|
void *p = curlx_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[idx], mem, len);
|
|
s->leng = idx + 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));
|
|
curlx_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);
|
|
DEBUGASSERT(strcmp(fmt, "%s")); /* use curlx_dyn_add instead */
|
|
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;
|
|
}
|