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 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.