Open-Source Wikis

/

curl

/

How to contribute

/

Patterns and conventions

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, no inline keyword, 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_t is the project's portable signed 64-bit type, defined in include/curl/system.h.
  • stdint.h is required (the project enforces uint32_t etc. via lib/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 in include/curl/curl.h)
  • CURLMcode — for multi-style functions
  • CURLUcode, 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 in lib/curl_setup.h) to free and null in one step.
  • Use Curl_dyn_* (the dynbuf API in lib/curlx/dynbuf.c) for growable string/byte buffers — never realloc(buf, n) directly.
  • Use Curl_bufq_* (lib/bufq.c) for byte queues when you need flow control.
  • Allocations through malloc/calloc are wrapped at debug-build time by lib/memdebug.c so 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.h for assembled output.
  • lib/curlx/strparse.h for non-allocating parsing of structured ASCII (numbers, words, headers).
  • Curl_strcase* (lib/strcase.c) for case-insensitive comparison — never use strcasecmp directly because it is not portable.
  • mprintf.c is curl's own printf with strict 64-bit handling. aprintf and maprintf allocate; msnprintf is the safe sized variant. Format strings are checked by scripts/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 */
#endif

The 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 a cf_*_create constructor. See Connection filters.
  • A new protocol goes in as a new const struct Curl_protocol (lib/protocol.h) registered in the scheme dispatch in lib/url.c.
  • Both must be guardable by CURL_DISABLE_* macros and gated in Makefile.inc and CMakeLists.txt.

Tests, docs, options come together

When adding an easy_setopt option, you touch all of:

  1. include/curl/curl.h — new CURLOPT_* enum value
  2. lib/easyoptions.c and lib/setopt.c — argument-type table and dispatch
  3. lib/url.c — initial handling, often
  4. lib/urldata.h — storage in struct Curl_easy::set
  5. docs/libcurl/opts/CURLOPT_*.md — the man-page source
  6. docs/libcurl/opts/Makefile.inc — register the new file
  7. tests/data/test<N> — at least one functional test
  8. tests/libtest/lib<N>.c — when needed
  9. RELEASE-NOTES and docs/CHANGES.md — automatic via scripts/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 // comments in production code.
  • Don't #include system headers directly from lib/*.c; go through curl_setup.h.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Patterns and conventions – curl wiki | Factory