Home | History | Annotate | Download | only in docs
      1 # curl C code style
      2 
      3 Source code that has a common style is easier to read than code that uses
      4 different styles in different places. It helps making the code feel like one
      5 single code base. Easy-to-read is a very important property of code and helps
      6 making it easier to review when new things are added and it helps debugging
      7 code when developers are trying to figure out why things go wrong. A unified
      8 style is more important than individual contributors having their own personal
      9 tastes satisfied.
     10 
     11 Our C code has a few style rules. Most of them are verified and upheld by the
     12 `lib/checksrc.pl` script. Invoked with `make checksrc` or even by default by
     13 the build system when built after `./configure --enable-debug` has been used.
     14 
     15 It is normally not a problem for anyone to follow the guidelines, as you just
     16 need to copy the style already used in the source code and there are no
     17 particularly unusual rules in our set of rules.
     18 
     19 We also work hard on writing code that are warning-free on all the major
     20 platforms and in general on as many platforms as possible. Code that obviously
     21 will cause warnings will not be accepted as-is.
     22 
     23 ## Naming
     24 
     25 Try using a non-confusing naming scheme for your new functions and variable
     26 names. It doesn't necessarily have to mean that you should use the same as in
     27 other places of the code, just that the names should be logical,
     28 understandable and be named according to what they're used for. File-local
     29 functions should be made static. We like lower case names.
     30 
     31 See the [INTERNALS](INTERNALS.md) document on how we name non-exported
     32 library-global symbols.
     33 
     34 ## Indenting
     35 
     36 We use only spaces for indentation, never TABs. We use two spaces for each new
     37 open brace.
     38 
     39     if(something_is_true) {
     40       while(second_statement == fine) {
     41         moo();
     42       }
     43     }
     44 
     45 ## Comments
     46 
     47 Since we write C89 code, `//` comments are not allowed. They weren't
     48 introduced in the C standard until C99. We use only `/*` and `*/` comments:
     49 
     50     /* this is a comment */
     51 
     52 ## Long lines
     53 
     54 Source code in curl may never be wider than 79 columns and there are two
     55 reasons for maintaining this even in the modern era of very large and high
     56 resolution screens:
     57 
     58 1. Narrower columns are easier to read than very wide ones. There's a reason
     59    newspapers have used columns for decades or centuries.
     60 
     61 2. Narrower columns allow developers to easier show multiple pieces of code
     62    next to each other in different windows. I often have two or three source
     63    code windows next to each other on the same screen - as well as multiple
     64    terminal and debugging windows.
     65 
     66 ## Braces
     67 
     68 In if/while/do/for expressions, we write the open brace on the same line as
     69 the keyword and we then set the closing brace on the same indentation level as
     70 the initial keyword. Like this:
     71 
     72     if(age < 40) {
     73       /* clearly a youngster */
     74     }
     75 
     76 You may omit the braces if they would contain only a one-line statement:
     77 
     78     if(!x)
     79       continue;
     80 
     81 For functions the opening brace should be on a separate line:
     82 
     83     int main(int argc, char **argv)
     84     {
     85       return 1;
     86     }
     87 
     88 ## 'else' on the following line
     89 
     90 When adding an `else` clause to a conditional expression using braces, we add
     91 it on a new line after the closing brace. Like this:
     92 
     93     if(age < 40) {
     94       /* clearly a youngster */
     95     }
     96     else {
     97       /* probably grumpy */
     98     }
     99 
    100 ## No space before parentheses
    101 
    102 When writing expressions using if/while/do/for, there shall be no space
    103 between the keyword and the open parenthesis. Like this:
    104 
    105     while(1) {
    106       /* loop forever */
    107     }
    108 
    109 ## Use boolean conditions
    110 
    111 Rather than test a conditional value such as a bool against TRUE or FALSE, a
    112 pointer against NULL or != NULL and an int against zero or not zero in
    113 if/while conditions we prefer:
    114 
    115     result = do_something();
    116     if(!result) {
    117       /* something went wrong */
    118       return result;
    119     }
    120 
    121 ## No assignments in conditions
    122 
    123 To increase readability and reduce complexity of conditionals, we avoid
    124 assigning variables within if/while conditions. We frown upon this style:
    125 
    126     if((ptr = malloc(100)) == NULL)
    127       return NULL;
    128 
    129 and instead we encourage the above version to be spelled out more clearly:
    130 
    131     ptr = malloc(100);
    132     if(!ptr)
    133       return NULL;
    134 
    135 ## New block on a new line
    136 
    137 We never write multiple statements on the same source line, even for very
    138 short if() conditions.
    139 
    140     if(a)
    141       return TRUE;
    142     else if(b)
    143       return FALSE;
    144 
    145 and NEVER:
    146 
    147     if(a) return TRUE;
    148     else if(b) return FALSE;
    149 
    150 ## Space around operators
    151 
    152 Please use spaces on both sides of operators in C expressions.  Postfix `(),
    153 [], ->, ., ++, --` and Unary `+, - !, ~, &` operators excluded they should
    154 have no space.
    155 
    156 Examples:
    157 
    158     bla = func();
    159     who = name[0];
    160     age += 1;
    161     true = !false;
    162     size += -2 + 3 * (a + b);
    163     ptr->member = a++;
    164     struct.field = b--;
    165     ptr = &address;
    166     contents = *pointer;
    167     complement = ~bits;
    168     empty = (!*string) ? TRUE : FALSE;
    169 
    170 ## Column alignment
    171 
    172 Some statements cannot be completed on a single line because the line would
    173 be too long, the statement too hard to read, or due to other style guidelines
    174 above. In such a case the statement will span multiple lines.
    175 
    176 If a continuation line is part of an expression or sub-expression then you
    177 should align on the appropriate column so that it's easy to tell what part of
    178 the statement it is. Operators should not start continuation lines. In other
    179 cases follow the 2-space indent guideline. Here are some examples from libcurl:
    180 
    181 ~~~c
    182     if(Curl_pipeline_wanted(handle->multi, CURLPIPE_HTTP1) &&
    183        (handle->set.httpversion != CURL_HTTP_VERSION_1_0) &&
    184        (handle->set.httpreq == HTTPREQ_GET ||
    185         handle->set.httpreq == HTTPREQ_HEAD))
    186       /* didn't ask for HTTP/1.0 and a GET or HEAD */
    187       return TRUE;
    188 ~~~
    189 
    190 ~~~c
    191   case CURLOPT_KEEP_SENDING_ON_ERROR:
    192     data->set.http_keep_sending_on_error = (0 != va_arg(param, long)) ?
    193                                            TRUE : FALSE;
    194     break;
    195 ~~~
    196 
    197 ~~~c
    198     data->set.http_disable_hostname_check_before_authentication =
    199       (0 != va_arg(param, long)) ? TRUE : FALSE;
    200 ~~~
    201 
    202 ~~~c
    203   if(option) {
    204     result = parse_login_details(option, strlen(option),
    205                                  (userp ? &user : NULL),
    206                                  (passwdp ? &passwd : NULL),
    207                                  NULL);
    208   }
    209 ~~~
    210 
    211 ~~~c
    212         DEBUGF(infof(data, "Curl_pp_readresp_ %d bytes of trailing "
    213                      "server response left\n",
    214                      (int)clipamount));
    215 ~~~
    216 
    217 ## Platform dependent code
    218 
    219 Use `#ifdef HAVE_FEATURE` to do conditional code. We avoid checking for
    220 particular operating systems or hardware in the #ifdef lines. The HAVE_FEATURE
    221 shall be generated by the configure script for unix-like systems and they are
    222 hard-coded in the config-[system].h files for the others.
    223 
    224 We also encourage use of macros/functions that possibly are empty or defined
    225 to constants when libcurl is built without that feature, to make the code
    226 seamless. Like this style where the `magic()` function works differently
    227 depending on a build-time conditional:
    228 
    229     #ifdef HAVE_MAGIC
    230     void magic(int a)
    231     {
    232       return a + 2;
    233     }
    234     #else
    235     #define magic(x) 1
    236     #endif
    237 
    238     int content = magic(3);
    239