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