curl/curl
Patterns and conventions
curl is mature C code with extremely consistent style. New code is expected to match the existing patterns. The authoritative style guide is docs/CODE_STYLE.md (rendered at https://curl.se/dev/code-style.html); this page distills the patterns you will most often need to read or write.
Language target
- C89. No
//comments outside conditional debug code, noinlinekeyword, no flexible array members, no_Generic, no compound literals in initializers, no variable declarations after statements (in production code paths). - 64-bit integer types must work —
curl_off_tis the project's portable signed 64-bit type, defined ininclude/curl/system.h. stdint.his required (the project enforcesuint32_tetc. vialib/curl_setup.h).
Symbol naming
| Visibility | Prefix | Example |
|---|---|---|
| Public API | curl_ (lowercase) |
curl_easy_init |
| Public macro | CURL_ / CURLOPT_ |
CURLOPT_URL |
| Internal, cross-file | Curl_ |
Curl_resolv |
| Single-file | static (no prefix) |
static rc_t parse_uri(...) |
This is enforced in part by scripts/checksrc.pl and by symbol-visibility flags (CURL_EXTERN).
Error handling
Every function that can fail returns one of:
CURLcode— for libcurl easy-style functions (defined ininclude/curl/curl.h)CURLMcode— for multi-style functionsCURLUcode,CURLHcode,CURLSHcode,CURLcsType— for the URL, header, share, and cipher subsystems
The convention is CURLE_OK = 0 for success; non-zero is an error. There are no exceptions, no longjmp, no errno-style globals. Functions that "cannot fail" return void.
CURLcode result = some_curl_call(data, ...);
if(result)
goto fail;
...
fail:
/* free locally allocated state */
return result;goto fail is idiomatic for cleanup; there is one cleanup label per function.
Memory
- Use
Curl_safefree(defined inlib/curl_setup.h) to free and null in one step. - Use
Curl_dyn_*(the dynbuf API inlib/curlx/dynbuf.c) for growable string/byte buffers — neverrealloc(buf, n)directly. - Use
Curl_bufq_*(lib/bufq.c) for byte queues when you need flow control. - Allocations through
malloc/callocare wrapped at debug-build time bylib/memdebug.cso leaks are caught in CI.
Containers
| Container | API | Source |
|---|---|---|
| Linked list | Curl_llist_* |
lib/llist.c |
| Hash | Curl_hash_* |
lib/hash.c |
| Splay tree | Curl_splay* |
lib/splay.c |
| Bit set (small unsigned ints) | Curl_uint_bset_* |
lib/uint-bset.c |
| Sparse bit set | Curl_uint_spbset_* |
lib/uint-spbset.c |
| Hash of unsigned int → ptr | Curl_uint_hash_* |
lib/uint-hash.c |
| Table indexed by unsigned int | Curl_uint_tbl_* |
lib/uint-table.c |
Avoid introducing new container types. The existing ones are tested by unit tests in tests/unit/.
Strings
lib/curlx/dynbuf.hfor assembled output.lib/curlx/strparse.hfor non-allocating parsing of structured ASCII (numbers, words, headers).Curl_strcase*(lib/strcase.c) for case-insensitive comparison — never usestrcasecmpdirectly because it is not portable.mprintf.cis curl's own printf with strict 64-bit handling.aprintfandmaprintfallocate;msnprintfis the safe sized variant. Format strings are checked byscripts/checksrc.pl.
Headers
Each .c file starts with #include "curl_setup.h" so every other include and macro sees the same configuration. Cross-platform/conditional compile lives in curl_setup.h. Every public-API user includes <curl/curl.h> only.
Build conditionals
curl supports many feature toggles via CURL_DISABLE_* and USE_* macros:
#ifndef CURL_DISABLE_HTTP
/* HTTP support compiled in */
#endif
#ifdef USE_OPENSSL
/* OpenSSL TLS backend */
#endifThe full list is in lib/curl_setup.h (CURL_DISABLE_*) and configure.ac / CMakeLists.txt (USE_*). Each new optional feature gets its own toggle.
Connection filters and protocol handlers
- A new transport goes in as a new
struct Curl_cftype(lib/cfilters.h) plus acf_*_createconstructor. See Connection filters. - A new protocol goes in as a new
const struct Curl_protocol(lib/protocol.h) registered in the scheme dispatch inlib/url.c. - Both must be guardable by
CURL_DISABLE_*macros and gated inMakefile.incandCMakeLists.txt.
Tests, docs, options come together
When adding an easy_setopt option, you touch all of:
include/curl/curl.h— newCURLOPT_*enum valuelib/easyoptions.candlib/setopt.c— argument-type table and dispatchlib/url.c— initial handling, oftenlib/urldata.h— storage instruct Curl_easy::setdocs/libcurl/opts/CURLOPT_*.md— the man-page sourcedocs/libcurl/opts/Makefile.inc— register the new filetests/data/test<N>— at least one functional testtests/libtest/lib<N>.c— when neededRELEASE-NOTESanddocs/CHANGES.md— automatic viascripts/release-notes.pl
This many touch points sounds heavy but is the source of curl's reputation for backward compatibility.
What not to do
- Don't introduce C99/C11/C23 features unless gated behind
#if. - Don't change public ABI. Adding fields to public structs needs a SONAME bump (last bumped in 2006, you do not want to be the one).
- Don't reformat unrelated code in your patch. Drive-by reformatting fragments git-blame.
- Don't use
// commentsin production code. - Don't
#includesystem headers directly fromlib/*.c; go throughcurl_setup.h.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.