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 &lt; last; len++) {
+
+        c = *p;
+
+        if (c &lt; 0x80) {
+            p++;
+            continue;
+        }
+
+        if (ngx_utf8_decode(&amp;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 &lt;ngx_config.h>
+#include &lt;ngx_core.h>
+#include &lt;ngx_http.h>
+
+#include &lt;libxml/parser.h>
+#include &lt;libxml/tree.h>
+#include &lt;libxslt/xslt.h>
+
+#if (NGX_HAVE_EXSLT)
+#include &lt;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 &amp;&amp; !(NGX_TEST_BUILD_DEVPOLL)) \
+       || (NGX_HAVE_EVENTPORT &amp;&amp; !(NGX_TEST_BUILD_EVENTPORT)))
+...
+#elif (NGX_HAVE_EPOLL &amp;&amp; !(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\"",
+               &amp;h->key, &amp;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 &lt;&lt; 4) + (ch - '0'));
+</programlisting>
+<programlisting>
+r->exten.data = &amp;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 &amp; NGX_HTTP_UPSTREAM_FT_UPDATING)
+     || c->stale_updating) &amp;&amp; !r->background
+    &amp;&amp; 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 &lt; last &amp;&amp; *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 '&lt;':
+    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 &lt; 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>