forked from freeciv/freeciv
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CodingStyle
657 lines (480 loc) · 21.6 KB
/
CodingStyle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
============================================================================
Freeciv Coding Style Guide
============================================================================
If you want to hack Freeciv, and want your patches to be accepted, it helps
to follow some simple style rules. Yes, some of these are a bit nit-picky,
but wars are fought over the silliest things ...
- This style is used for all code in Freeciv. Freeciv gtk-clients use
this style, not gtk style.
- Freeciv is mostly programmed in C, C89 with some C99 features.
Qt parts are programmed in C++. Even C++ parts should have mostly
consistent style with C parts, so where not otherwise noted, this
guide applies to C++ parts too. Headers that are included to both
C and C++ source files follow C style.
- C++-style comments (i.e., // comments) should be used for
single-line comments in C++ code. They may be used in C code.
- C++11 Lambda Expressions are allowed in C++ code, and encouraged for short
callbacks in Qt slot connections.
- Declaring variables in the middle of the scope is forbidden, unless
one of the following is true.
1) You are using C99 dynamic arrays and you need to check the size
of the array before you declare it.
2) Variable in question is declared only conditionally to some preprocessor
macro, and there's separate code block similarly conditional to the same
macro that would use it. In that case it's ok to declare the variable
inside the macro guarded block that is using it.
- C99 Compound Literals are allowed in C code, and are encouraged for struct
and union values that are only used once.
- Where variable is logically boolean, 'bool' type should be used even in
C code. To make sure that the type is defined, include utility/support.h.
In C code boolean values are uppercase macros 'TRUE' and 'FALSE'.
In C++ code lowercase boolean values 'true' and 'false' should be used.
- Functions that take no arguments should be declared and defined with
'void' argument list in C code, and empty argument list in C++ code.
C:
int no_arguments(void);
C++:
int no_arguments();
- Use K&R indentation style with indentation 2 (if in doubt, use "indent -kr
-i2 -l77", but beware that that will probably mangle the _() macros used
to mark translated strings and the brace style for iteration macros).
- Do not re-indent areas of code you are not modifying or creating.
- Here are the most important formatting rules:
- Lines are at most 77 characters long, including the terminating newline.
- The tab width is 8 spaces for tabs that already exist in the source code
(this is just so that old code will appear correctly in your editor).
However, tabs should be avoided in newly written code.
- The indentation is 2 spaces per level for all new code; do not use tabs
for any kind of indentation. The one exception to this is if you are
just adding one line to a set of lines that are already indented with
some strange mix of tabs and spaces; in this case you may use the same
indentation as the surrounding lines.
- Do not add more than 2 empty lines between any sections in the code.
- Spaces are inserted before and after operators: instead of "int a,b,c;"
use "int i, j, k;" and instead of
if(foo<=bar){
c=a+b;
}
use
if (foo <= bar) {
c = a + b;
}
Note the space between "if" and the bracket.
- Switch statement case labels are aligned with the enclosing "switch":
switch (value) {
case MY_VALUE1:
do_some_stuff(value);
break;
case MY_VALUE2:
{
int value2 = value + 5;
do_some_other_stuff(value2);
}
break;
}
- If case of a switch is supposed to continue to the next case,
explicitly mark it so by using fc__fallthrough; This also avoids
compiler warning about missing break; when such warnings are enabled.
switch (value) {
case MY_VALUE1:
do_some_stuff(value);
fc__fallthrough; /* break; intentionally left out */
case MY_VALUE2:
{
int value2 = value + 5;
do_some_other_stuff(value2);
}
break;
}
- In the rare case that you actually use goto, the label should be all
capitals and "out-dented" in the block in which it is contained:
static int frob(int n)
{
int i, j;
for (i = 0; i < n; i++) {
for (j = i; j < n; j++) {
if (some_condition(i, j)) {
goto EXIT_LOOP;
}
}
}
EXIT_LOOP:
return 123;
}
- If a function prototype exceeds 77 characters on one line, you should
put the return value type and storage specifier on the line immediately
above it:
static const struct incredibly_long_structure_name *
get_a_const_struct_incredibly_long_structure_name(int id);
- If arguments in a function prototype or a function call cause the line
to exceed 77 characters, they should be placed on the following line and
lined up with spaces to the column after the '(':
void some_function(const struct another_really_long_name *arln,
int some_other_argument);
- If the line is still too long for some reason, you may place the
arguments two indentation levels on the next line:
a_very_awkward_long_function_name(some_argument,
"A really long string that would have to be cut up.");
But you should try to avoid this situation, either by naming your
functions/types/variables more succinctly, or by using helper variables
or functions to split the expression over a number of lines.
- An empty line should be placed between two separate blocks of code.
- Place operators at the beginning of a line, not at the end. It should be
if ((a
&& b)
|| c) {
instead of
if ((a &&
b) ||
c) {
============================================================================
Comments
============================================================================
- All comments should have proper English grammar, spelling and punctuation,
but you should not capitalize names of identifiers (variables, types,
functions, etc.) used in the code. If using plain identifiers in sentences
would be confusing to the reader, you should put the names in quotes.
- Every function should have a comment header. The comment should look like
the example below, indented by two spaces. It should be above the
function's implementation, not the prototype. Note "*//**" in the end
of the beginning line for the doxygen.
Doxygen "@param" and "@return" documentation is recommended
to be added for new functions, or when existing header is being touched.
/************************************************************************//**
The description of the function should be here. Also describe what is
expected of the arguments if it is not obvious. Especially note down any
non-trivial assumptions that the function makes.
Do _not_ introduce a new function without some sort of comment.
@param base value to add to
@return final value
****************************************************************************/
int the_function_starts_here(int base)
{
return base + 2;
}
- One line comments should be indented correctly and placed above the code
being commented upon:
int x;
/* I am a single line comment. */
x = 3;
- For multiline comments, asterisks should be placed in front of the comment
line like so:
/* I am a multiline
* comment, blah
* blah blah. */
- If you need to comment a declared variable, it should be as such:
struct foo {
int bar; /* bar is used for ...
* in ... way. */
int blah; /* blah is used for ... . */
};
Or if the comment is very long, it may be placed above the field
declaration, as in the one-line or multi-line comment cases.
- Comments in conditionals: if you need a comment to show program flow, it
should be below the if or else:
if (is_barbarian(pplayer)) {
x++;
} else {
/* If not barbarian... */
x--;
}
- Comments to translators are placed before the N_(), _(), Q_() or PL_()
marked string, and are preceded by "TRANS:". . They must be on the same or
immediately previous line to the gettext invocation. These comments are
copied to the translator's file. Use them whenever you think the
translators may need some more information:
/* TRANS: Do not translate "commandname". */
printf(_("commandname <arg> [-o <optarg>]"));
============================================================================
Declaring Variables
============================================================================
- Avoid static and global variables if at all possible. When you absolutely
do need them, minimize the number of times they are referenced in the code
(e.g. use a helper function to wrap their access).
- Variables should be declared in the innermost block possible, i.e., they
should not be visible where they are not needed.
- Never initialize variables with values that make no sense as their
value in case they get used. If there's no sensible initialization
value for a variable, leave it uninitialized. This allows various
tools to detect if such a variable ever gets used without assigning
proper value to it.
- Variables can be initialized as soon as they are declared:
int foo(struct unit *punit)
{
int x = punit->x;
int foo = x;
char *blah;
/* Etc. */
(But you should generally check arguments to functions before using them,
unless you are absolutely sure that pointers are not NULL, etc.)
- After variables are declared, there should be an empty line before the
rest of the function body.
- Merging declarations: variables do not have to be declared one per line;
however, they should only be grouped by similar function.
int foo(struct city *pcity)
{
int i, j, k;
int total, cost;
int build = pcity->shield_stock;
}
- When declaring a pointer, there should be a space before '*' and no space
after, except if it is a second '*'.
struct unit *find_random_unit(struct unit **array, size_t num)
{
struct unit *const *prand = array + fc_rand(num);
return *prand;
}
instead of
struct unit* find_random_unit(struct unit* *array, size_t num)
{
struct unit * const* prand = array + fc_rand(num);
return *prand;
}
============================================================================
Bracing
============================================================================
- Function braces begin and end in the first column:
int foo(void)
{
return 0;
}
instead of
int foo(void) {
return 0;
}
- Use extra braces for iteration macros. Note that the "*_iterate_end;"
should be placed on the same line as the end brace:
unit_list_iterate(pcity->units_supported, punit) {
kill(punit);
} unit_list_iterate_end;
- In switch statements, braces should only be placed where needed, i.e. to
protect local variables.
- Braces shall always be used after conditionals, loops, etc.:
if (x == 3) {
return;
}
and
if (x == 3) {
return 1;
} else {
return 0;
}
not
if (x == 3)
return 1; /* BAD! */
============================================================================
Enumerators
============================================================================
- First of all, reread comment about the switch statement indentations and
braces.
- Avoid the usage of magic values (plain hard-coded value, such as 0 or -1)
and prefer the usage of enumerators. If an enumeration cannot be defined
for any reason, then define a macro for this value.
- Avoid storing magic values in external processes. For example, savegames
shouldn't contain any enumerators as magic numbers. They should be saved
as strings, to keep compatibility when their definition is changed. For
doing this, there are some tools in utility/specenum_gen.h; have a look at
it.
- Avoid the usage of the default case in switch statements, if possible. The
default case removes the warning of the compiler when a value is missing
in a switch statement.
============================================================================
Including Headers
============================================================================
- Order include files consistently: all includes are grouped together.
These groups are divided by an empty line. The order of these groups is as
follows:
1) fc_config.h (see below)
2) system include files which are OS-independent (part of C-standard or
POSIX)
3) system include files which are OS-dependent or conditional includes
4) include files from utility/
5) include files from common/
6) include files from client/
7) include files from server/ and ai/
8) include the header corresponding to the current c source file after
all other headers.
Each group is sorted in alphabetic order. This helps to avoid adding
unnecessary or duplicated include files.
Always set a comment to determine the location of the following headers
before every group.
It is very important that '#include <fc_config.h>' is at the top of
every .c file (it need not be included from .h files). Some definitions in
fc_config.h will affect how the code is compiled, without which you can end
up with bad and untraceable memory bugs.
#ifdef HAVE_CONFIG_H
#include <fc_config.h>
#endif
#include <stdlib.h>
/* utility */
#include "log.h"
/* common */
#include "game.h"
#include "myfileheader.h"
- For headers within a subdirectory path, the common rule is to set them
in an additional group, after the same group (don't forget the location
comment).
/* common */
#include "game.h"
/* common/aicore */
#include "pf_tools.h"
However, there is an exception to this. The last group is always the one
we are working on. So, if we are working on the common part, the order
should be:
/* common/aicore */
#include "pf_tools.h"
/* common */
#include "game.h"
Same observations with ai/ and server/. When working on the server/
directory, the order should be:
/* ai */
#include "daitools.h"
/* server */
#include "srv_main.h"
and working on the ai/ directory:
/* server */
#include "srv_main.h"
/* ai */
#include "daitools.h"
- Do not include headers in other headers if at all possible. Use forward
declarations for pointers to structs:
struct connection;
void a_function(struct connection *pconn);
instead of
#include "connection.h"
void a_function(struct connection *pconn);
- Of course, never include headers of non-linked parts of the code. For
example, never include client/ headers into a server/ file. Also, in the
client/ directory, GUI specific headers are never included. Always, use
the common set of headers defined in client/include/.
============================================================================
Object-Oriented Programming
============================================================================
Freeciv is not really object-oriented programming, but last written parts
seems to tend to there. Also, there are more and more parts which are
modular, so there are some observations to do:
- Any function or member of a module must be prefixed by the name of this
module, or an abbreviation of it (but use the same prefix for all members
please!). Never set the module name as suffix!
/* Super mega cool module! */
void smc_module_init(void);
void smc_module_free(void);
not
/* Super mega cool module! */
void smc_module_init(void);
void sm_cool_free(void);
neither
/* Super mega cool module! */
void init_smc_module(void);
void free_smc_module(void);
- A function which allocates memory for a pointer variable should use the
suffix '_new'. The memory is freed by a corresponding function with the
suffix '_destroy'.
{
struct test *t = test_new();
/* Do something. */
test_destroy(t);
}
- The suffix '_init' should be used for functions which initialize some
static data. The name of the corresponding function to deinitialize stuff
should use the suffix '_free' (see server/settings.c or common/map.c).
{
struct astring str;
astr_init(&str);
/* Do something. */
astr_free(&str);
}
============================================================================
Low level functions
============================================================================
utility/support.[ch] module contains low level functions that should be used
instead of ones from c-library or other sources. Most of those functions
have the 'fc_' prefix in their name. They are more portable (i.e always
available with the freeciv source code) and often more secure than the
functions available natively.
- Instead of fopen(), use fc_fopen()
- Instead of localtime(), use fc_localtime()
- Instead of strncmp(), use fc_strncmp()
- Instead of strcasecmp(), use fc_strcasecmp()
- Instead of strlcat() or strncat(), use fc_strlcat()
============================================================================
Miscellaneous
============================================================================
- If an empty statement is needed, you should put an explanatory comment
in an empty block (i.e. {}):
while (*i++) {
/* Do nothing. */
}
- Use the postfix operator instead of the prefix operator when either will
work. That is, write "a++" instead of "++a".
- Strive to make your code re-entrant (thread/recursion safe), as long as
this does not make the implementation too cumbersome or involved.
- Strive to make your code modular: make it independent from other parts of
the codebase, and assume as little as possible about the circumstances in
which it is used.
- Strive to avoid code duplication: if some part of the code is repeated in
several places, factor it out into a helper function.
- Try to use static inline functions and const data instead of macros.
- If helper functions internal to freeciv are added, prefix their names
with 'fc_'. Do not use 'my_' because it is also used by MySQL and could
be included in some libs.
- Do not use assert() or die(); instead use the macros defined within
utility/log.h:
fc_assert(condition)
fc_assert_ret(condition)
fc_assert_ret_val(condition, val)
fc_assert_action(condition, action_on_failure)
fc_assert_exit(condition, action_on_failure)
fc_assert_msg(condition, message, ...)
fc_assert_ret_msg(condition, message, ...)
fc_assert_ret_val_msg(condition, val, message, ...)
fc_assert_action_msg(condition, action_on_failure, message, ...)
fc_assert_exit_msg(condition, action_on_failure, message, ...)
This way error conditions can be handled gracefully while still enforcing
invariants you expect not to be violated in the code.
(By default execution will continue with a warning, but it can be made
to halt by specifying the '-F' option to the client or server.)
int foo_get_id(const struct foo *pfoo)
{
fc_assert_ret_val(pfoo != NULL, -1);
return pfoo->id;
}
- Do not put multiple conditions in the same fc_assert*() statement:
fc_assert(pfoo != NULL);
fc_assert(pfoo->id >= 0);
instead of
fc_assert(pfoo != NULL && pfoo->id >= 0);
- Never include functionality also otherwise necessary inside fc_assert*().
Such functionality would be missing from release builds where asserts
are disabled. If you want to assert return value of a critical function
call, make the call outside assert and place the return value to variable
and then assert value of that variable.
- For strings containing multiple sentences, use a single space after periods
(not two, not zero, just one).
- If you use a system specific feature, do not add #ifdef __CRAY__ or
something like that. Rather write a check for that feature for
configure.ac, and use a meaningful macro name in the source.
- Always prototype global functions in the appropriate header file. Local
functions should always be declared as static. To catch these and some
other problems please use the following warning options "-Wall
-Wpointer-arith -Wcast-align -Wmissing-prototypes -Wmissing-declarations
-Wstrict-prototypes -Wnested-externs -Wl,--no-add-needed" if you use gcc.
- Always check compilation with the configure option --enable-debug set.
- Header files should be compatible with C++ but code (.c) files need not
be. This means some C++ keywords (like "this" or "class") may not be used
in header files. It also means casts on void pointers (which should be
avoided in C files) must be used in headers.
- To assign null pointer, or to compare against one, use 'nullptr' in C++ code
In C code that's going to get backported to freeciv-3.2 or even older,
'NULL' must be used. In freeciv-3.3, and later, 'nullptr' can be used.
- If you send patches, use "diff -u" (or "diff -r -u"). "git diff" works
correctly without extra parameters.
For further information, see:
<https://www.freeciv.org/wiki/How_to_Contribute>.
Also, name patch files descriptively (e.g. "fix-foo-bug-0.patch" is good,
but "freeciv.patch" is not).
- When doing a "diff" for a patch, be sure to exclude unnecessary files by
using the "-X" argument to "diff". E.g.:
% diff -ruN -Xdiff_ignore freeciv_git freeciv >/tmp/fix-foo-bug-0.patch
A suggested "diff_ignore" file is included in the Freeciv distribution.
============================================================================