In addition to the previous instructions, please check PRs for style.
- apply general C style for C code in all directories
- apply njs style in the
src/directory, see directory-specific rules below - apply nginx style in the
nginx/directory, see directory-specific rules below
- maximum text width is 80 characters
- indentation is 4 spaces
- no tabs, no trailing spaces
- list elements on the same line are separated with spaces
- hexadecimal literals are lowercase
A typical source file may contain the following sections separated by two empty lines:
- copyright statements
- includes
- preprocessor definitions
- type definitions
- function prototypes
- variable definitions
- function definitions
Copyright statements look like this:
/*
* Copyright (C) Author Name
* Copyright (C) Organization, Inc.
*/
If the file is modified significantly, the list of authors should be updated, the new author is added to the top.
Header files should include the so called "header protection":
#ifndef _HEADER_NAME_H_INCLUDED_
#define _HEADER_NAME_H_INCLUDED_
...
#endif /* _HEADER_NAME_H_INCLUDED_ *///comments are not used- text is written in English, American spelling is preferred
- multi-line comments are formatted like this:
/*
* The red-black tree code is based on the algorithm described in
* the "Introduction to Algorithms" by Cormen, Leiserson and Rivest.
*/
/* find the server configuration for the address:port */Macro names for constants are uppercase. Parameterized macros and macros for initializers are lowercase. The macro name and value are separated by at least two spaces:
#define NGX_CONF_BUFFER 4096
#define ngx_buf_in_memory(b) (b->temporary || b->memory || b->mmap)
#define ngx_buf_size(b) \
(ngx_buf_in_memory(b) ? (off_t) (b->last - b->pos): \
(b->file_last - b->file_pos))
#define ngx_null_string { 0, NULL }Conditions are inside parentheses, negation is outside:
#if (NGX_HAVE_KQUEUE)
...
#elif ((NGX_HAVE_DEVPOLL && !(NGX_TEST_BUILD_DEVPOLL)) \
|| (NGX_HAVE_EVENTPORT && !(NGX_TEST_BUILD_EVENTPORT)))
...
#elif (NGX_HAVE_EPOLL && !(NGX_TEST_BUILD_EPOLL))
...
#elif (NGX_HAVE_POLL)
...
#else /* select */
...
#endif /* NGX_HAVE_KQUEUE */Type names end with the _t suffix. A defined type name is separated by at least two spaces:
typedef ngx_uint_t ngx_rbtree_key_t;Structure types are defined using typedef. Inside structures, member types and names are aligned. The asterisk (*) in pointer declarations is aligned with the field name, not the type:
typedef struct {
size_t len;
u_char *data;
} ngx_str_t;Keep alignment identical among different structures in the file. A structure that points to itself has the name, ending with _s. Adjacent structure definitions are separated with two empty lines:
typedef struct ngx_list_part_s ngx_list_part_t;
struct ngx_list_part_s {
void *elts;
ngx_uint_t nelts;
ngx_list_part_t *next;
};
typedef struct {
ngx_list_part_t *last;
ngx_list_part_t part;
size_t size;
ngx_uint_t nalloc;
ngx_pool_t *pool;
} ngx_list_t;Each structure member is declared on its own line.
typedef ssize_t (*ngx_recv_pt)(ngx_connection_t *c, u_char *buf, size_t size);
typedef ssize_t (*ngx_recv_chain_pt)(ngx_connection_t *c, ngx_chain_t *in,
off_t limit);
typedef ssize_t (*ngx_send_pt)(ngx_connection_t *c, u_char *buf, size_t size);
typedef ngx_chain_t *(*ngx_send_chain_pt)(ngx_connection_t *c, ngx_chain_t *in,
off_t limit);
typedef struct {
ngx_recv_pt recv;
ngx_recv_chain_pt recv_chain;
ngx_recv_pt udp_recv;
ngx_send_pt send;
ngx_send_pt udp_send;
ngx_send_chain_pt udp_send_chain;
ngx_send_chain_pt send_chain;
ngx_uint_t flags;
} ngx_os_io_t;Function pointers inside structures have defined types ending with _pt:
typedef return_type_t (*function_ptr_pt)(param_t *param);
typedef struct {
function_ptr_pt callback;
other_type_t field;
} structure_with_callback_t;Variables are declared sorted by length of a base type, then alphabetically. Type names and variable names are aligned. The type and name "columns" are separated with two spaces. Large arrays are put at the end of a declaration block.
Nginx style (asterisk aligned to the left of the variable name):
u_char *rv, *p;
type_t *ptr;
uint_t i, j, k;
unsigned int len;
struct sockaddr *sa;
complex_type_t *complex;
const unsigned char *data;
very_long_type_name_t *long_name;
u_char text[MAX_LENGTH];Njs style (asterisk aligned on the same column as name):
u_char *rv, *p;
type_t *ptr;
uint_t i, j, k;
unsigned int len;
struct sockaddr *sa;
complex_type_t *complex;
const unsigned char *data;
very_long_type_name_t *long_name;
u_char text[MAX_LENGTH];Static and global variables may be initialized on declaration:
static ngx_str_t ngx_http_memcached_key = ngx_string("memcached_key");
static ngx_uint_t mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
static uint32_t ngx_crc32_table16[] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
...
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};All functions (even static ones) should have prototypes. Prototypes include argument names. Long prototypes are wrapped with a single indentation on continuation lines:
static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_int_t ngx_http_init_phases(ngx_conf_t *cf,
ngx_http_core_main_conf_t *cmcf);
static char *ngx_http_merge_servers(ngx_conf_t *cf,
ngx_http_core_main_conf_t *cmcf, ngx_http_module_t *module,
ngx_uint_t ctx_index);The function name in a definition starts with a new line. The function body opening and closing braces are on separate lines. The body of a function is indented. There are two empty lines between functions:
static ngx_int_t
ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len)
{
...
}
static ngx_int_t
ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt)
{
...
}There is no space after the function name and opening parenthesis. Long function calls are wrapped such that continuation lines start from the position of the first function argument. If this is impossible, format the first continuation line such that it ends at position 79:
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http header: \"%V: %V\"",
&h->key, &h->value);
hc->busy = ngx_palloc(r->connection->pool,
cscf->large_client_header_buffers.num * sizeof(ngx_buf_t *));The inline macro should be used instead of inline:
static inline_macro int_t function_name(const u_char **start, const u_char *end);Binary operators except . and −> should be separated from their operands by one space. Unary operators and subscripts are not separated from their operands by spaces:
width = width * 10 + (*fmt++ - '0');
ch = (u_char) ((decoded << 4) + (ch - '0'));
value->data.string = &text.start[i + 1];Type casts are separated by one space from casted expressions. An asterisk inside type cast is separated with space from type name:
len = ngx_sock_ntop((struct sockaddr *) sin6, p, len, 1);If an expression does not fit into single line, it is wrapped. The preferred point to break a line is a binary operator. The continuation line is lined up with the start of expression:
if (status == NGX_HTTP_MOVED_PERMANENTLY
|| status == NGX_HTTP_MOVED_TEMPORARILY
|| status == NGX_HTTP_SEE_OTHER
|| status == NGX_HTTP_TEMPORARY_REDIRECT
|| status == NGX_HTTP_PERMANENT_REDIRECT)
{
...
}
p->temp_file->warn = "an upstream response is buffered "
"to a temporary file";As a last resort, it is possible to wrap an expression so that the continuation line ends at position 79:
hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t)
+ size * sizeof(ngx_hash_elt_t *));The above rules also apply to sub-expressions, where each sub-expression has its own indentation level:
if (((u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING)
|| c->stale_updating) && !r->background
&& u->conf->cache_background_update)
{
...
}Sometimes, it is convenient to wrap an expression after a cast. In this case, the continuation line is indented:
node = (ngx_rbtree_node_t *)
((u_char *) lr - offsetof(ngx_rbtree_node_t, color));Pointers are explicitly compared to NULL (not 0):
if (ptr != NULL) {
...
}The if keyword is separated from the condition by one space. Opening brace is located on the same line, or on a dedicated line if the condition takes several lines. Closing brace is located on a dedicated line, optionally followed by else if / else. Usually, there is an empty line before the else if / else part:
if (node->left == sentinel) {
temp = node->right;
subst = node;
} else if (node->right == sentinel) {
temp = node->left;
subst = node;
} else {
subst = ngx_rbtree_min(node->right, sentinel);
if (subst->left != sentinel) {
temp = subst->left;
} else {
temp = subst->right;
}
}Similar formatting rules are applied to do and while loops:
while (p < last && *p == ' ') {
p++;
}
do {
ctx->node = rn;
ctx = ctx->next;
} while (ctx);The switch keyword is separated from the condition by one space. Opening brace is located on the same line. Closing brace is located on a dedicated line. The case keywords are lined up with switch:
switch (token) {
case TOKEN_FUNCTION:
state = parse_function;
break;
case TOKEN_VAR:
state = parse_var;
break;
default:
state = parse_statement;
break;
}Most for loops are formatted like this:
for (i = 0; i < count; i++) {
...
}
for (prop = first_prop(object);
prop < last_prop(object);
prop = next_prop(prop))
{
...
}If some part of the for statement is omitted, this is indicated by the /* void */ comment:
for (i = 0; /* void */ ; i++) {
...
}A loop with an empty body is also indicated by the /* void */ comment which may be put on the same line:
for (prop = object->start; prop->next; prop = prop->next) { /* void */ }An endless loop looks like this:
for ( ;; ) {
...
}Labels are surrounded with empty lines and are indented at the previous level:
if (i == 0) {
vm->error = "function not found";
goto failed;
}
values = alloc_function(pool, i * sizeof(type_t));
if (values == NULL) {
goto failed;
}
count = i;
...
return SUCCESS;
failed:
free_function(pool, values);
return ERROR;- file names, function and type names, and global variables have the
njs_prefix - macro names start from
njs_orNJS_prefix
The njs_main.h file is always included first. Then follow optional external header files:
#include <njs_main.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxslt/xslt.h>
#if (NJS_HAVE_EXSLT)
#include <libexslt/exslt.h>
#endif#ifndef _NJS_VM_H_INCLUDED_
#define _NJS_VM_H_INCLUDED_
...
#endif /* _NJS_VM_H_INCLUDED_ */#define NJS_STRING_MAX_LENGTH 0x7fffffff
#define njs_queue_is_empty(queue) ((queue) == (queue)->prev)
#define njs_queue_insert_head(queue, link) \
(link)->next = (queue)->next; \
(link)->next->prev = (link); \
(link)->prev = (queue); \
(queue)->next = (link)
#define njs_null_string { 0, NULL }#if (NJS_HAVE_OPENSSL)
...
#elif (NJS_HAVE_QUICKJS)
...
#elif (NJS_HAVE_ADDR2LINE)
...
#else /* default */
...
#endif /* NJS_HAVE_OPENSSL */typedef uint8_t njs_vmcode_t;
typedef struct {
u_char *start;
u_char *end;
njs_str_t file;
njs_str_t name;
njs_arr_t *lines; /* of njs_vm_line_num_t */
} njs_vm_code_t;
typedef struct njs_queue_link_s njs_queue_link_t;
struct njs_queue_link_s {
njs_queue_link_t *prev;
njs_queue_link_t *next;
};
typedef struct {
njs_queue_link_t head;
} njs_queue_t;Enumerations have types ending with _t:
typedef enum {
NJS_NULL,
NJS_UNDEFINED,
NJS_BOOLEAN,
NJS_NUMBER,
NJS_STRING,
NJS_SYMBOL
} njs_value_type_t;u_char *rv;
njs_int_t rc;
njs_vm_t *vm;
njs_value_t *value;
njs_parser_t *parser;
njs_generator_t *generator;
njs_function_t *function;static njs_int_t njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end);
static njs_int_t njs_parser_statement(njs_parser_t *parser,
njs_parser_node_t *parent);
static njs_int_t njs_generator_function(njs_vm_t *vm,
njs_generator_t *generator, njs_parser_node_t *node);The njs_inline macro should be used instead of inline:
static njs_inline njs_int_t njs_utf8_byte(const u_char ***start, const u_char *end);- file names, function and type names, and global variables have the
ngx_or more specific prefix such asngx_http_andngx_mail_ - macro names start from
ngx_orNGX_(or more specific) prefix
The ngx_config.h and ngx_core.h files are always included first, followed by one of ngx_http.h, ngx_stream.h, or ngx_mail.h. Then follow optional external header files:
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxslt/xslt.h>
#if (NGX_HAVE_EXSLT)
#include <libexslt/exslt.h>
#endif#ifndef _NGX_PROCESS_CYCLE_H_INCLUDED_
#define _NGX_PROCESS_CYCLE_H_INCLUDED_
...
#endif /* _NGX_PROCESS_CYCLE_H_INCLUDED_ */#define NGX_CONF_BUFFER 4096
#define ngx_buf_in_memory(b) (b->temporary || b->memory || b->mmap)
#define ngx_buf_size(b) \
(ngx_buf_in_memory(b) ? (off_t) (b->last - b->pos): \
(b->file_last - b->file_pos))
#define ngx_null_string { 0, NULL }#if (NGX_HAVE_KQUEUE)
...
#elif ((NGX_HAVE_DEVPOLL && !(NGX_TEST_BUILD_DEVPOLL)) \
|| (NGX_HAVE_EVENTPORT && !(NGX_TEST_BUILD_EVENTPORT)))
...
#elif (NGX_HAVE_EPOLL && !(NGX_TEST_BUILD_EPOLL))
...
#elif (NGX_HAVE_POLL)
...
#else /* select */
...
#endif /* NGX_HAVE_KQUEUE */typedef ngx_uint_t ngx_rbtree_key_t;
typedef struct {
size_t len;
u_char *data;
} ngx_str_t;
typedef struct ngx_list_part_s ngx_list_part_t;
struct ngx_list_part_s {
void *elts;
ngx_uint_t nelts;
ngx_list_part_t *next;
};
typedef struct {
ngx_list_part_t *last;
ngx_list_part_t part;
size_t size;
ngx_uint_t nalloc;
ngx_pool_t *pool;
} ngx_list_t;
typedef struct {
ngx_uint_t hash;
ngx_str_t key;
ngx_str_t value;
u_char *lowcase_key;
} ngx_table_elt_t;Function pointers inside structures have defined types ending with _pt:
typedef ssize_t (*ngx_recv_pt)(ngx_connection_t *c, u_char *buf, size_t size);
typedef ssize_t (*ngx_recv_chain_pt)(ngx_connection_t *c, ngx_chain_t *in,
off_t limit);
typedef ssize_t (*ngx_send_pt)(ngx_connection_t *c, u_char *buf, size_t size);
typedef ngx_chain_t *(*ngx_send_chain_pt)(ngx_connection_t *c, ngx_chain_t *in,
off_t limit);
typedef struct {
ngx_recv_pt recv;
ngx_recv_chain_pt recv_chain;
ngx_recv_pt udp_recv;
ngx_send_pt send;
ngx_send_pt udp_send;
ngx_send_chain_pt udp_send_chain;
ngx_send_chain_pt send_chain;
ngx_uint_t flags;
} ngx_os_io_t;Enumerations have types ending with _e:
typedef enum {
ngx_http_fastcgi_st_version = 0,
ngx_http_fastcgi_st_type,
...
ngx_http_fastcgi_st_padding
} ngx_http_fastcgi_state_e;u_char *rv, *p;
ngx_conf_t *cf;
ngx_uint_t i, j, k;
unsigned int len;
struct sockaddr *sa;
const unsigned char *data;
ngx_peer_connection_t *pc;
ngx_http_core_srv_conf_t **cscfp;
ngx_http_upstream_srv_conf_t *us, *uscf;
u_char text[NGX_SOCKADDR_STRLEN];static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_int_t ngx_http_init_phases(ngx_conf_t *cf,
ngx_http_core_main_conf_t *cmcf);
static char *ngx_http_merge_servers(ngx_conf_t *cf,
ngx_http_core_main_conf_t *cmcf, ngx_http_module_t *module,
ngx_uint_t ctx_index);The ngx_inline macro should be used instead of inline:
static ngx_inline void ngx_cpuid(uint32_t i, uint32_t *buf);