summaryrefslogtreecommitdiff
path: root/CODING_STYLE
blob: e0df3f1b40251890e0165f00f3c12bb72cab2a44 (plain)
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
Tumbler Coding Style
====================

This document intends to give information about the coding style to be
used when contributing code to tumbler. It does not claim to be
complete. Parts of it are taken or inspired from the Clutter coding
style document.

An example of a good coding style (from the perspective of this
document) is tumblerd/tumbler-service.c. In the following, the most
important requirements for writing consistent code for tumbler are 
explained.

Table of Contents:
  * Line Width
  * Whitespace
  * Indentation and Braces
  * Functions and Braces
  * Empty Lines
  * Variable Declarations
  * Assertions
  * More on Conditions
  * Header Files
  * Loops and Loop Termination


Line Width
==========

The maximum line width for source files is 90 characters. This limit may
be exceeded when there is no way around it. Accepted ways to wrap long
lines caused by function calls are

  result = some_function_with_a_very_long_name (first_parameter,
                                                second_parameter,
                                                third_parameter);

and

  long_result_variable =
    some_function_with_a_very_long_name (first_parameter,
                                         second_parameter,
                                         third_parameter);

where the result variable name is too long to fit the function call
into the 90 characters limit even when wrapping the parameters.

Do not separate the function name from its arguments like this:

  /* bad */
  some_function_with_a_long_name
    (long_argument_name1, long_argument_name2);

Instead, consider using shorter variable names as aliases:

  /* good */
  short1 = long_argument_name1;
  short2 = long_argument_name2;
  some_function_with_a_long_name (short1, short2);

The line width limit of 90 characters does not apply to header files.
However the alignment and parameter indentation rules explained in the
section "Functions and Braces" still apply to header files.


Whitespace
==========

Always insert a space before a parenthesis but never after or
between the opening or closing parenthesis and a parameter.

  /* good */
  if (condition)
    foo (argument1, argument2);

  /* bad */
  if(condition)
    foo(argument1, argument2);

  /* bad */
  if ( condition )
    foo ( argument1, argument 2 );


Indentation and Braces
======================

Use spaces only, tabs are not allowed. The indentation for each level is
2 spaces in addition to the previous level. Braces add another level of
indentation. Valid indentations and uses of braces are:

Single-line statements:

  /* good */
  if (condition)
    single_line_statement ();

Multiple statements:

  /* good */
  if (condition)
    {
      a_statement ();
      another_statement ();
    }

Multiple and single statements:

  /* good */
  if (condition)
    {
      a_statement ();
      another_statement ();
    }
  else
    {
      one_more_statement ();
    }

Do and while loops:

  /* good */
  while (foo)
    {
      bar ();
    }

  /* good */
  do
    {
      bar ();
    }
  while (foo);

Switch statements:

  /* good */
  switch (condition)
    {
    case FOO:
      do_something ();
      break;
    case BAR:
      do_something_else ();
      break;
    default:
      do_whatever_you_need_to_do ();
      break;
    }

  /* bad */
  switch (condition) {
    case FOO:
      do_something ();
      break;
  }

  /* bad */
  switch (condition)
    {
      case FOO:
        do_something ();
        break;
    }

  /* bad */
  switch (condition)
    {
    case FOO: do_something ();
      break;
    }

  /* bad */
  switch (condition)
    {
      case FOO:
      do_something ();
      break;
    }

Nested if statements:

  /* good */
  if (condition) 
    {
      /* here the same rules as on the top level apply again */
      if (another_condition)
        single_statement ();
      else if (yet_another_condition)
        another_single_statement ();
    }

Do not put curly braces into the same line as the condition:
  
  /* bad */
  if (condition) {
     ...
  }

Do not asymmetrically use and not use braces:

  /* bad */
  if (condition)
    {
      /* multiple statements */
    }
  else
    single_statement ();

If there are multiple conditions in a single if statement spread across
more than one line, always use curly braces:

  /* good */
  if (condition1
      && condition2)
  {
    /* multiple or single statement(s) */
  }


Functions and Braces
====================

Braces in function definitions are not indented. Parameters are to be
wrapped and aligned so that the end results looks like this:

Function declarations:

  /* good */
  static gchar   *some_type_your_function             (SomeType *object,
                                                       int       another parameter,
                                                       gchar   **and_another_one);
  static gboolean some_type_some_longer_function_name (SomeType *object);

Function definitions:

  /* good */
  static gchar *
  some_type_your_function (SomeType *object,
                           int       another_parameter,
                           gchar   **and_another_one)
  {
    /* declarations */
    /* assertions */
    /* actual code */
  }

Do not declare functions like this:

  /* bad */
  static gchar *some_type_your_function (SomeType *object,
                                         int another parameter,
                                         gchar **and_another_one);
  static gboolean some_type_some_longer_function_name (SomeType *object);

Or like this:

  /* bad */
  static gchar *some_type_your_function (SomeType *object, int another parameter, gchar **and_another_one);
  static gboolean some_type_some_longer_function_name (SomeType *object);


Empty Lines
===========

Between declarations of groups of structs, enums, functions, static
variables and macros there have to be three empty lines to make the
different items easier to spot and distinguish. There also have to be
three empty lines between function definitions.

Also, when declaring data structures, use newlines to separate logical
sections of member variables:

  struct _TumblerService
  {
    /* thumbnailers and preferred thumbnailers */
    GHashTable *thumbnailers;
    GHashTable *preferred_thumbnailers;

    /* cached supported URIs and MIME types */
    gchar     **mime_types;
    gchar     **uri_schemes;

    /* protection against threads */
    GMutex     *mutex;
  };


Variable Declarations
=====================

Variables may only be declared at the top of a function. Variable
declarations in blocks (code surrounded by braces) are not allowed.

Declarations follow special alignment and sorting rules. The sorting
order of declarations is determined by:

  1. number of characters of the variable type
  2. ascending alphabetical order of the type (case-insensitive)
  3. ascending alphabetical order of the variable name

Here is an example of how a variable declaration sequence has to
look like:

  TumblerSpecializedThumbnailer *thumbnailer;
  const gchar * const           *mime_types;
  const gchar                   *static_name;
  gboolean                       result = FALSE;
  GFile                         *file;
  gchar                         *dynamic_name;
  guint                          index;
  guint                          n;


Assertions
==========

In order to make it easier to detect broken code paths, assertions in
the form of g_return_if_fail() and g_return_val_if_fail() statements are
used in almost all methods. When implementing new methods in your code,
please make sure to check the input parameters for type incompatiblities
or memory corruption.


More on Conditions
==================

Do not check boolean values for equality like this:

  /* bad */
  if (condition == TRUE)
    ...

Instead, just do it like this:

  /* good */
  if (condition)
    ...

Be explicit when checking pointers however:

  /* good */
  if (some_pointer == NULL)
    ...

  /* good */
  if (some_pointer != NULL)
    ...

Do not simply do it like this:

  /* bad */
  if (some_pointer)
    ...

If you have so many conditions in an if statement that you need to split
them up into multiple lines, the logical operatiors should always be
placed at the beginning of the line, like this:

  /* good */
  if (condtion1 
      || condition 2
      || condition 3)
  {
    ...
  }

Don't place the logical operators at the end of the line:

  /* bad */
  if (condition1 || 
      condition2 ||
      conidition3)
  {
    ...
  }


Header Files
============

Header files should always include the following code in addition to the
license header (example for tumbler-data-structure.h):

  #ifndef __TUMBLER_DATA_STRUCTURE_H__
  #define __TUMBLER_DATA_STRUCTURE_H__

  #include <something-that-also-includes-glib-object.h>

  G_BEGIN_DECLS

  ...

  G_END_DECLS

  #endif /* !__TUMBLER_DATA_STRUCTURE_H__ */



Loops and Loop Termination
==========================

When writing loops, try to avoid break statements. Instead of breaking
on some condition move the condition into the loop header to make more
clear when the loop is supposed to be terminated.

So, instead of doing

  /* bad */
  for (n = 0; n < some_value; ++n)
    {
      if (some_other_condition)
        break;

      ...
    }

do it like this:

  /* good */
  for (n = 0; !some_other_condition && n < some_value; ++n)
    {
      ...
    }

If the loop header exceeds the 90 character limit per line, split it up
into multiple lines (in which case you are required to add curly braces 
of course):

  /* good */
  for (n = 0;
       !some_other_condition && n < some_value; 
       ++n)
    {
      ...
    }

Try to avoid while loops where you can. Some GLib data structures
such as iterators encourage the use of while loops. In those cases it's
ok not to use for loops.