| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- Cairo coding style.
- This document is intended to be a short description of the preferred
- coding style for the cairo source code. Good style requires good
- taste, which means this can't all be reduced to automated rules, and
- there are exceptions.
- We want the code to be easy to understand and maintain, and consistent
- style plays an important part in that, even if some of the specific
- details seem trivial. If nothing else, this document gives a place to
- put consistent answers for issues that would otherwise be arbitrary.
- Most of the guidelines here are demonstrated by examples, (which means
- this document is quicker to read than it might appear given its
- length). Most of the examples are positive examples that you should
- imitate. The few negative examples are clearly marked with a comment
- of /* Yuck! */. Please don't submit code to cairo that looks like any
- of these.
- Indentation
- -----------
- Each new level is indented 4 more spaces than the previous level:
- if (condition)
- do_something ();
- This may be achieved with space characters or a combination of tab
- characters and space characters. It may not be achieved with tab
- characters exclusively (see below).
- Tab characters
- --------------
- The tab character must always be interpreted according to its
- traditional meaning:
- Advance to the next column which is a multiple of 8.
- With this definition, even levels of indentation can be achieved with
- a sequence of tab characters, while odd levels of indentation may
- begin with a sequence of tab character but must end with 4 space
- characters.
- Some programmers have been misled by certain text editors into
- thinking that 4-space indentation can be achieved with tab characters
- exclusively by changing the meaning of tab character to be "advance to
- the next column which is a multiple of 4". Code formatted in this way,
- making an assumption of a fictitious 4-character-tab will not be
- accepted into cairo.
- The rationale here is that tabs are used in the code for lining things
- up other than indentation, (see the Whitespace section below), and
- changing the interpretation of tab from its traditional meaning will
- break this alignment.
- Braces
- ------
- Most of the code in cairo uses bracing in the style of K&R:
- if (condition) {
- do_this ();
- do_that ();
- } else {
- do_the_other ();
- }
- but some of the code uses an alternate style:
- if (condition)
- {
- do_this ();
- do_that ();
- }
- else
- {
- do_the_other ();
- }
- and that seems just fine. We won't lay down any strict rule on this
- point, (though there should be some local consistency). If you came
- here hoping to find some guidance, then use the first form above.
- If all of the substatements of an if statement are single statements,
- the optional braces should not usually appear:
- if (condition)
- do_this ();
- else
- do_that ();
- But the braces are mandatory when mixing single statement and compound
- statements in the various clauses. For example, do not do this:
- if (condition) {
- do_this ();
- do_that ();
- } else /* Yuck! */
- do_the_other ();
- And of course, there are exceptions for when the code just looks
- better with the braces:
- if (condition) {
- /* Note that we have to be careful here. */
- do_something_dangerous (with_care);
- }
- if (condition &&
- other_condition &&
- yet_another)
- {
- do_something ();
- }
- And note that this last example also shows a situation in which the
- opening brace really needs to be on its own line. The following looks awful:
- if (condition &&
- other_condition &&
- yet_another) { /* Yuck! */
- do_something ();
- }
- As we said above, legible code that is easy to understand and maintain
- is the goal, not adherence to strict rules.
- Whitespace
- ----------
- Separate logically distinct chunks with a single newline. This
- obviously applies between functions, but also applies within a
- function or block and can even be used to good effect within a
- structure definition:
- struct _cairo_gstate {
- cairo_operator_t op;
- double tolerance;
- /* stroke style */
- double line_width;
- cairo_line_cap_t line_cap;
- cairo_line_join_t line_join;
- double miter_limit;
- cairo_fill_rule_t fill_rule;
- double *dash;
- int num_dashes;
- double dash_offset;
- ...
- }
- Use a single space before a left parenthesis, except where the
- standard will not allow it, (eg. when defining a parameterized macro).
- Don't eliminate newlines just because things would still fit on one
- line. This breaks the expected visual structure of the code making it
- much harder to read and understand:
- if (condition) foo (); else bar (); /* Yuck! */
- Do eliminate trailing whitespace (space or tab characters) on any
- line. Also, avoid putting initial or final blank lines into any file,
- and never use multiple blank lines instead of a single blank line.
- Do enable the default git pre-commit hook that detect trailing
- whitespace for you and help you to avoid corrupting cairo's tree with
- it. Do that as follows:
- chmod a+x .git/hooks/pre-commit
- You might also find the git-stripspace utility helpful which acts as a
- filter to remove trailing whitespace as well as initial, final, and
- duplicate blank lines.
- As a special case of the bracing and whitespace guidelines, function
- definitions should always take the following form:
- void
- my_function (argument)
- {
- do_my_things ();
- }
- And function prototypes should similarly have the return type (and
- associated specifiers and qualifiers) on a line above the function, so
- that the function name is flush left.
- Break up long lines (> ~80 characters) and use whitespace to align
- things nicely. For example the arguments in a long list to a function
- call should all be aligned with each other:
- align_function_arguments (argument_the_first,
- argument_the_second,
- argument_the_third);
- And as a special rule, in a function prototype, (as well as in the
- definition), whitespace should be inserted between the parameter types
- and names so that the names are aligned:
- void
- align_parameter_names_in_prototypes (const char *char_star_arg,
- int int_arg,
- double *double_star_arg,
- double double_arg);
- Note that parameters with a * prefix are aligned one character to the
- left so that the actual names are aligned.
- Managing nested blocks
- ----------------------
- Long blocks that are deeply nested make the code very hard to
- read. Fortunately such blocks often indicate logically distinct chunks
- of functionality that are begging to be split into their own
- functions. Please listen to the blocks when they beg.
- In other cases, gratuitous nesting comes about because the primary
- functionality gets buried in a nested block rather than living at the
- primary level where it belongs. Consider the following:
- foo = malloc (sizeof (foo_t));
- if (foo) { /* Yuck! */
- ...
- /* lots of code to initialize foo */
- ...
- return SUCCESS;
- }
- return FAILURE;
- This kind of gratuitous nesting can be avoided by following a pattern
- of handling exceptional cases early and returning:
- foo = malloc (sizeof (foo_t));
- if (foo == NULL)
- return FAILURE;
- ...
- /* lots of code to initialize foo */
- ...
- return SUCCESS;
- The return statement is often the best thing to use in a pattern like
- this. If it's not available due to additional nesting above which
- require some cleanup after the current block, then consider splitting
- the current block into a new function before using goto.
- Memory allocation
- -----------------
- Because much of cairo's data consists of dynamically allocated arrays,
- it's very easy to introduce integer overflow issues whenever malloc()
- is called. Use the _cairo_malloc2(), _cairo_malloc3(), and
- _cairo_malloc2_add1 macros to avoid these cases; these macros check
- for overflow and will return NULL in that case.
- malloc (n * size) => _cairo_malloc_ab (n, size)
- e.g. malloc (num_elts * sizeof(some_type)) =>
- _cairo_malloc2 (num_elts, sizeof(some_type))
- malloc (a * b * size) => _cairo_malloc_abc (a, b, size)
- e.g. malloc (width * height * 4) =>
- _cairo_malloc3 (width, height, 4)
- malloc (n * size + k) => _cairo_malloc_ab_plus_c (n, size, k)
- e.g. malloc (num * sizeof(entry) + sizeof(header)) =>
- _cairo_malloc2k (num, sizeof(entry), sizeof(header))
- In general, be wary of performing any arithmetic operations in an
- argument to malloc. You should explicitly check for integer overflow
- yourself in any more complex situations.
- Mode lines
- ----------
- So given the rules above, what is the best way to simplify one's life as
- a code monkey? Get your editor to do most of the tedious work of
- beautifying your code!
- As a reward for reading this far, here are some mode lines for the more
- popular editors:
- /*
- * vim:sw=4:sts=4:ts=8:tw=78:fo=tcroq:cindent:cino=\:0,(0
- * vim:isk=a-z,A-Z,48-57,_,.,-,>
- */
- TODO
- ----
- Write rules for common editors to use this style. Also cleanup/unify
- the modelines in the source files.
|