In addition to the previous instructions, check PRs for coding style.
- applies to C source code in src/ directory
- 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
- file names, function and type names, and global variables have the
njs_prefix
size_t
njs_utf8_length(u_char *p, size_t n)
{
u_char c, *last;
size_t len;
last = p + n;
for (len = 0; p < last; len++) {
c = *p;
if (c < 0x80) {
p++;
continue;
}
if (njs_utf8_decode(&p, last - p) > 0x10ffff) {
/* invalid UTF-8 */
return n;
}
}
return len;
}
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.
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>
#endifHeader files should include the so called "header protection":
#ifndef _NJS_VM_H_INCLUDED_
#define _NJS_VM_H_INCLUDED_
...
#endif /* _NJS_VM_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 start from njs_ or NJS_ prefix. 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 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 }Conditions are inside parentheses, negation is outside:
#if (NJS_HAVE_OPENSSL)
...
#elif (NJS_HAVE_QUICKJS)
...
#elif (NJS_HAVE_ADDR2LINE)
...
#else /* default */
...
#endif /* NJS_HAVE_OPENSSL */Type names end with the _t suffix. A defined type name is separated by at least two spaces:
typedef uint8_t njs_vmcode_t;Structure types are defined using typedef. Inside structures, member types and names are aligned:
typedef struct {
size_t length;
u_char *start;
} njs_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 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;Each structure member is declared on its own line. The asterisk (*) in pointer declarations is aligned with the field name, not the type:
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;Enumerations have types ending with _t:
typedef enum {
NJS_NULL,
NJS_UNDEFINED,
NJS_BOOLEAN,
NJS_NUMBER,
NJS_STRING,
NJS_SYMBOL
} njs_value_type_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:
u_char *rv, *p;
njs_vm_t *vm;
njs_uint_t i, j, k;
njs_parser_t *parser;
njs_value_t *values;
unsigned int len;
njs_generator_t *generator;
struct sockaddr *sa;
const unsigned char *data;
u_char text[NJS_STRING_MAX_LENGTH];Static and global variables may be initialized on declaration:
static njs_str_t njs_string_constructor = njs_str("String");
static njs_uint_t mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
static uint32_t njs_crc32_table16[] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
...
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};There is a bunch of commonly used type/name combinations:
u_char *p, *start, *end;
njs_int_t ret;
njs_vm_t *vm;
njs_value_t *value;
njs_parser_t *parser;
njs_function_t *function;
njs_generator_t *generator;All functions (even static ones) should have prototypes. Prototypes include argument names. Long prototypes are wrapped with a single indentation on continuation lines:
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 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 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,
njs_token_type_t token)
{
...
}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:
njs_printf(vm, "parser: %V at %uz",
&token->text, parser->lexer->start);
value = njs_mp_alloc(vm->mem_pool,
parser->scope->items * sizeof(njs_value_t));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);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.u.string = &parser->lexer->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 = njs_utf8_decode((const u_char **) &start, end);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 (type == NJS_NULL
|| type == NJS_UNDEFINED
|| type == NJS_BOOLEAN
|| type == NJS_NUMBER
|| type == NJS_STRING)
{
...
}
parser->error = "unexpected token "
"in expression";As a last resort, it is possible to wrap an expression so that the continuation line ends at position 79:
values = njs_mp_alloc(vm->mem_pool, sizeof(njs_value_t)
+ count * sizeof(njs_object_prop_t));The above rules also apply to sub-expressions, where each sub-expression has its own indentation level:
if (((parser->scope->type & NJS_SCOPE_FUNCTION)
|| generator->context)
&& !vm->options.backtrace
&& parser->scope->nesting_level > 1)
{
...
}Sometimes, it is convenient to wrap an expression after a cast. In this case, the continuation line is indented:
value = (njs_value_t *)
((u_char *) prop - offsetof(njs_object_prop_t, value));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 (value->type == NJS_NULL) {
result = njs_value_undefined;
goto done;
} else if (value->type == NJS_UNDEFINED) {
result = njs_value_null;
goto done;
} else {
result = njs_value_to_string(vm, value);
if (result == NULL) {
goto error;
} else {
goto done;
}
}Similar formatting rules are applied to do and while loops:
while (p < end && *p == ' ') {
p++;
}
do {
parser->node = current;
parser = parser->parent;
} while (parser);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 NJS_TOKEN_FUNCTION:
parser->state = njs_parser_function;
break;
case NJS_TOKEN_VAR:
parser->state = njs_parser_var;
break;
default:
parser->state = njs_parser_statement;
break;
}Most for loops are formatted like this:
for (i = 0; i < parser->scope->items; i++) {
...
}
for (prop = njs_object_prop(object);
prop < njs_object_prop_end(object);
prop = njs_object_prop_next(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 = njs_mp_alloc(vm->mem_pool, i * sizeof(njs_value_t));
if (values == NULL) {
goto failed;
}
parser->values = i;
...
return NJS_OK;
failed:
njs_mp_free(vm->mem_pool, values);
return NJS_ERROR;- applies to C source code in nginx/ directory
- 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
- file names, function and type names, and global variables have the
ngx_or more specific prefix such asngx_http_andngx_mail_
size_t
ngx_utf8_length(u_char *p, size_t n)
{
u_char c, *last;
size_t len;
last = p + n;
for (len = 0; p < last; len++) {
c = *p;
if (c < 0x80) {
p++;
continue;
}
if (ngx_utf8_decode(&p, last - p) > 0x10ffff) {
/* invalid UTF-8 */
return n;
}
}
return len;
}
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.
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>
#endifHeader files should include the so called "header protection":
#ifndef _NGX_PROCESS_CYCLE_H_INCLUDED_
#define _NGX_PROCESS_CYCLE_H_INCLUDED_
...
#endif /* _NGX_PROCESS_CYCLE_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 start from ngx_ or NGX_ (or more specific) prefix. 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:
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 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;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:
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 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
};There is a bunch of commonly used type/name combinations:
u_char *rv;
ngx_int_t rc;
ngx_conf_t *cf;
ngx_connection_t *c;
ngx_http_request_t *r;
ngx_peer_connection_t *pc;
ngx_http_upstream_srv_conf_t *us, *uscf;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 ngx_inline macro should be used instead of inline:
static ngx_inline void ngx_cpuid(uint32_t i, uint32_t *buf);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'));
r->exten.data = &r->uri.data[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 (ch) {
case '!':
looked = 2;
state = ssi_comment0_state;
break;
case '<':
copy_end = p;
break;
default:
copy_end = p;
looked = 0;
state = ssi_start_state;
break;
}Most for loops are formatted like this:
for (i = 0; i < ccf->env.nelts; i++) {
...
}
for (q = ngx_queue_head(locations);
q != ngx_queue_sentinel(locations);
q = ngx_queue_next(q))
{
...
}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 (cl = *busy; cl->next; cl = cl->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) {
u->err = "host not found";
goto failed;
}
u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t));
if (u->addrs == NULL) {
goto failed;
}
u->naddrs = i;
...
return NGX_OK;
failed:
freeaddrinfo(res);
return NGX_ERROR;