Mercurial > hg > nginx-site
changeset 2153:ccc41545bf55
Extended code style description.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Mon, 23 Apr 2018 15:47:07 +0300 |
parents | a226918def86 |
children | ebc9fb8139e4 |
files | xml/en/docs/contributing_changes.xml xml/en/docs/dev/development_guide.xml |
diffstat | 2 files changed, 660 insertions(+), 28 deletions(-) [+] |
line wrap: on
line diff
--- a/xml/en/docs/contributing_changes.xml Tue Apr 17 18:36:58 2018 +0300 +++ b/xml/en/docs/contributing_changes.xml Mon Apr 23 15:47:07 2018 +0300 @@ -9,7 +9,7 @@ <article name="Contributing Changes" link="/en/docs/contributing_changes.html" lang="en" - rev="3"> + rev="4"> <section id="getting_sources" name="Getting Sources"> @@ -29,31 +29,11 @@ <section id="formatting_changes" name="Formatting Changes"> <para> -Changes should be formatted according to the code style used by nginx. -Code formatting should not rely on such editor features like syntax -highlighting or automatic line breaking. -Below are some basic rules: -<list type="bullet"> - -<listitem> -maximum text width is 80 characters -</listitem> - -<listitem> -indentation is four spaces -</listitem> - -<listitem> -no tabs -</listitem> - -<listitem> -logical code blocks in a file are separated with two empty lines -</listitem> - -</list> -Examine how existing nginx sources are formatted and mimic this style -in your code. +Changes should be formatted according to the +<link doc="../docs/dev/development_guide.xml" id="code_style">code style</link> +used by nginx. +Sometimes, there is no clear rule; in such cases +examine how existing nginx sources are formatted and mimic this style. Changes will more likely be accepted if style corresponds to the surrounding code. </para>
--- a/xml/en/docs/dev/development_guide.xml Tue Apr 17 18:36:58 2018 +0300 +++ b/xml/en/docs/dev/development_guide.xml Mon Apr 23 15:47:07 2018 +0300 @@ -9,7 +9,7 @@ <article name="Development guide" link="/en/docs/dev/development_guide.html" lang="en" - rev="3"> + rev="4"> <section name="Introduction" id="introduction"> @@ -3513,7 +3513,7 @@ <listitem> <literal>NGX_CONF_BLOCK</literal> — Directive is a block, that is, it can -contain other directives within its opening and closing curly braces, or even +contain other directives within its opening and closing braces, or even implement its own parser to handle contents inside. </listitem> @@ -6605,4 +6605,656 @@ </section> + +<section name="Code style" id="code_style"> + +<section name="General rules" id="code_style_general_rules"> + +<para> +<list type="bullet"> + +<listitem> +maximum text width is 80 characters +</listitem> + +<listitem> +indentation is 4 spaces +</listitem> + +<listitem> +no tabs, no trailing spaces +</listitem> + +<listitem> +list elements on the same line are separated with spaces +</listitem> + +<listitem> +hexadecimal literals are lowercase +</listitem> + +<listitem> +file names, function and type names, and global variables have the +<literal>ngx_</literal> or more specific prefix such as +<literal>ngx_http_</literal> and <literal>ngx_mail_</literal> +</listitem> + +</list> + +<programlisting> +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, n) > 0x10ffff) { + /* invalid UTF-8 */ + return n; + } + } + + return len; +} +</programlisting> + +</para> + +</section> + + +<section name="Files" id="code_style_files"> + +<para> +A typical source file may contain the following sections separated by +two empty lines: + +<list type="bullet"> +<listitem> +copyright statements +</listitem> + +<listitem> +includes +</listitem> + +<listitem> +preprocessor definitions +</listitem> + +<listitem> +type definitions +</listitem> + +<listitem> +function prototypes +</listitem> + +<listitem> +variable definitions +</listitem> + +<listitem> +function definitions +</listitem> + +</list> +</para> + +<para> +Copyright statements look like this: +<programlisting> +/* + * Copyright (C) Author Name + * Copyright (C) Organization, Inc. + */ +</programlisting> +If the file is modified significantly, the list of authors should be updated, +the new author is added to the top. +</para> + +<para> +The <literal>ngx_config.h</literal> and <literal>ngx_core.h</literal> files +are always included first, followed by one of +<literal>ngx_http.h</literal>, <literal>ngx_stream.h</literal>, +or <literal>ngx_mail.h</literal>. +Then follow optional external header files: +<programlisting> +#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 +</programlisting> + +</para> + +<para> +Header files should include the so called "header protection": +<programlisting> +#ifndef _NGX_PROCESS_CYCLE_H_INCLUDED_ +#define _NGX_PROCESS_CYCLE_H_INCLUDED_ +... +#endif /* _NGX_PROCESS_CYCLE_H_INCLUDED_ */ +</programlisting> +</para> + +</section> + + +<section name="Comments" id="code_style_comments"> +<para> +<list type="bullet"> + +<listitem> +“<literal>//</literal>” comments are not used +</listitem> + +<listitem> +text is written in English, American spelling is preferred +</listitem> + +<listitem> +multi-line comments are formatted like this: +<programlisting> +/* + * The red-black tree code is based on the algorithm described in + * the "Introduction to Algorithms" by Cormen, Leiserson and Rivest. + */ +</programlisting> +<programlisting> +/* find the server configuration for the address:port */ +</programlisting> +</listitem> + +</list> +</para> + +</section> + + +<section name="Preprocessor" id="code_style_preprocessor"> +<para> +Macro names start from <literal>ngx_</literal> or <literal>NGX_</literal> +(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: +<programlisting> +#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 } +</programlisting> +Conditions are inside parentheses, negation is outside: +<programlisting> +#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 */ +</programlisting> +</para> +</section> + + +<section name="Types" id="code_style_types"> + +<para> +Type names end with the “<literal>_t</literal>” suffix. +A defined type name is separated by at least two spaces: +<programlisting> +typedef ngx_uint_t ngx_rbtree_key_t; +</programlisting> +</para> + +<para> +Structure types are defined using <literal>typedef</literal>. +Inside structures, member types and names are aligned: +<programlisting> +typedef struct { + size_t len; + u_char *data; +} ngx_str_t; +</programlisting> +Keep alignment identical among different structures in the file. +A structure that points to itself has the name, ending with +“<literal>_s</literal>”. +Adjacent structure definitions are separated with two empty lines: +<programlisting> +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; +</programlisting> +Each structure member is declared on its own line: +<programlisting> +typedef struct { + ngx_uint_t hash; + ngx_str_t key; + ngx_str_t value; + u_char *lowcase_key; +} ngx_table_elt_t; +</programlisting> +</para> + +<para> +Function pointers inside structures have defined types ending +with “<literal>_pt</literal>”: +<programlisting> +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; +</programlisting> +</para> + +<para> +Enumerations have types ending with “<literal>_e</literal>”: +<programlisting> +typedef enum { + ngx_http_fastcgi_st_version = 0, + ngx_http_fastcgi_st_type, + ... + ngx_http_fastcgi_st_padding +} ngx_http_fastcgi_state_e; +</programlisting> +</para> + +</section> + + +<section name="Variables" id="code_style_variables"> + +<para> +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: +<programlisting> +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]; +</programlisting> +</para> + +<para> +Static and global variables may be initialized on declaration: +<programlisting> +static ngx_str_t ngx_http_memcached_key = ngx_string("memcached_key"); +</programlisting> + +<programlisting> +static ngx_uint_t mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +</programlisting> + +<programlisting> +static uint32_t ngx_crc32_table16[] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + ... + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c +}; +</programlisting> +</para> + +<para> +There is a bunch of commonly used type/name combinations: +<programlisting> +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; +</programlisting> +</para> +</section> + + +<section name="Functions" id="code_style_functions"> + +<para> +All functions (even static ones) should have prototypes. +Prototypes include argument names. +Long prototypes are wrapped with a single indentation on continuation lines: +<programlisting> +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); +</programlisting> +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: +<programlisting> +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) +{ + ... +} +</programlisting> +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: +<programlisting> +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 *)); +</programlisting> +The <literal>ngx_inline</literal> macro should be used instead of +<literal>inline</literal>: +<programlisting> +static ngx_inline void ngx_cpuid(uint32_t i, uint32_t *buf); +</programlisting> +</para> + +</section> + + +<section name="Expressions" id="code_style_expressions"> + +<para> +Binary operators except “<literal>.</literal>” and “<literal>−></literal>” +should be separated from their operands by one space. +Unary operators and subscripts are not separated from their operands by spaces: +<programlisting> +width = width * 10 + (*fmt++ - '0'); +</programlisting> +<programlisting> +ch = (u_char) ((decoded << 4) + (ch - '0')); +</programlisting> +<programlisting> +r->exten.data = &r->uri.data[i + 1]; +</programlisting> +</para> + +<para> +Type casts are separated by one space from casted expressions. +An asterisk inside type cast is separated with space from type name: +<programlisting> +len = ngx_sock_ntop((struct sockaddr *) sin6, p, len, 1); +</programlisting> +</para> + +<para> +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: +<programlisting> +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) +{ + ... +} +</programlisting> +<programlisting> +p->temp_file->warn = "an upstream response is buffered " + "to a temporary file"; +</programlisting> +As a last resort, it is possible to wrap an expression so that the +continuation line ends at position 79: +<programlisting> +hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t) + + size * sizeof(ngx_hash_elt_t *)); +</programlisting> +The above rules also apply to sub-expressions, +where each sub-expression has its own indentation level: +<programlisting> +if (((u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING) + || c->stale_updating) && !r->background + && u->conf->cache_background_update) +{ + ... +} +</programlisting> +Sometimes, it is convenient to wrap an expression after a cast. +In this case, the continuation line is indented: +<programlisting> +node = (ngx_rbtree_node_t *) + ((u_char *) lr - offsetof(ngx_rbtree_node_t, color)); +</programlisting> +</para> + +<para> +Pointers are explicitly compared to +<literal>NULL</literal> (not <literal>0</literal>): + +<programlisting> +if (ptr != NULL) { + ... +} +</programlisting> +</para> + +</section> + + +<section name="Conditionals and Loops" id="code_style_conditionals_and_loops"> + +<para> +The “<literal>if</literal>” 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 “<literal>else if</literal> / <literal>else</literal>”. +Usually, there is an empty line before the +“<literal>else if</literal> / <literal>else</literal>” part: +<programlisting> +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; + } +} +</programlisting> +</para> + +<para> +Similar formatting rules are applied to “<literal>do</literal>” +and “<literal>while</literal>” loops: +<programlisting> +while (p < last && *p == ' ') { + p++; +} +</programlisting> + +<programlisting> +do { + ctx->node = rn; + ctx = ctx->next; +} while (ctx); +</programlisting> +</para> + +<para> +The “<literal>switch</literal>” 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 “<literal>case</literal>” keywords are lined up with +“<literal>switch</literal>”: +<programlisting> +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; +} +</programlisting> +</para> + +<para> +Most “<literal>for</literal>” loops are formatted like this: +<programlisting> +for (i = 0; i < ccf->env.nelts; i++) { + ... +} +</programlisting> +<programlisting> +for (q = ngx_queue_head(locations); + q != ngx_queue_sentinel(locations); + q = ngx_queue_next(q)) +{ + ... +} +</programlisting> +If some part of the “<literal>for</literal>” statement is omitted, +this is indicated by the “<literal>/* void */</literal>” comment: +<programlisting> +for (i = 0; /* void */ ; i++) { + ... +} +</programlisting> +A loop with an empty body is also indicated by the +“<literal>/* void */</literal>” comment which may be put on the same line: +<programlisting> +for (cl = *busy; cl->next; cl = cl->next) { /* void */ } +</programlisting> +An endless loop looks like this: +<programlisting> +for ( ;; ) { + ... +} +</programlisting> +</para> + +</section> + + +<section name="Labels" id="code_style_labels"> + +<para> +Labels are surrounded with empty lines and are indented at the previous level: +<programlisting> + 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; +</programlisting> +</para> +</section> + +</section> + </article>