Skip to content

Commit 02d27f6

Browse files
authored
Merge pull request libgit2#5482 from pks-t/pks/coding-style
docs: add documentation for our coding style
2 parents d08f72e + ffb6a57 commit 02d27f6

File tree

1 file changed

+364
-0
lines changed

1 file changed

+364
-0
lines changed

docs/coding-style.md

Lines changed: 364 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,364 @@
1+
# libgit2 Coding Style
2+
3+
This documentation describes the preferred coding style for the libgit2 project.
4+
While not all parts of our code base conform to this coding style, the outlined
5+
rules are what we aim for.
6+
7+
Note that in no case do we accept changes that convert huge parts of the code
8+
base to use our coding style. Instead, it is encouraged to modernize small parts
9+
of code you're going to modify anyway for a given change you want to introduce.
10+
A good rule to follow is the Boy Scout Rule: "Leave the campground cleaner than
11+
you found it."
12+
13+
## C Coding Style
14+
15+
The following sections define the coding style for all code files and headers.
16+
17+
### Indentation and Alignment
18+
19+
Code is indented by tabs, where a tab is 8 spaces. Each opening scope increases
20+
the indentation level.
21+
22+
```c
23+
int foobar(int void)
24+
{
25+
if (condition)
26+
doit();
27+
/* Body */
28+
}
29+
```
30+
31+
Switch statements have their `case`s aligned with the `switch` keyword. Case
32+
bodies are indented by an additional level. Case bodies should not open their
33+
own scope to declare variables.
34+
35+
```c
36+
switch (c) {
37+
case 'a':
38+
case 'b':
39+
return 0;
40+
default:
41+
return -1;
42+
}
43+
```
44+
45+
Multi-line conditions should be aligned with the opening brace of the current
46+
statement:
47+
48+
```c
49+
if (one_very_long_condition(c) &&
50+
another_very_long_condition(c))
51+
doit();
52+
```
53+
54+
### Spaces
55+
56+
There must be no space between the function and its arguments, arguments must be
57+
separated by a space:
58+
59+
```c
60+
int doit(int first_arg, int second_arg);
61+
doit(1, 2);
62+
```
63+
64+
For any binary or ternary operators, the arguments and separator must be
65+
separated by a space:
66+
67+
```c
68+
1 + 2;
69+
x ? x : NULL;
70+
```
71+
72+
Unary operators do not have a space between them and the argument they refer to:
73+
74+
```c
75+
*c
76+
&c
77+
```
78+
79+
The `sizeof` operator always must not have a space and must use braces around
80+
the type:
81+
82+
```
83+
sizeof(int)
84+
```
85+
86+
There must be a space after the keywords `if`, `switch`, `case`, `do` and
87+
`while`.
88+
89+
### Braces
90+
91+
Functions must have their opening brace on the following line:
92+
93+
```c
94+
void foobar(void)
95+
{
96+
doit();
97+
}
98+
```
99+
100+
For conditions, braces should be placed on the same line as the condition:
101+
102+
```c
103+
if (condition(c)) {
104+
doit();
105+
dothat();
106+
}
107+
108+
while (true) {
109+
doit();
110+
}
111+
```
112+
113+
In case a condition's body has a single line, only, it's allowed to omit braces,
114+
except if any of its `else if` or `else` branches has more than one line:
115+
116+
```c
117+
if (condition(c))
118+
doit();
119+
120+
if (condition(c))
121+
doit();
122+
else if (other_condition(c))
123+
doit();
124+
125+
/* This example must use braces as the `else if` requires them. */
126+
if (condition(c)) {
127+
doit();
128+
} else if (other_condition(c)) {
129+
doit();
130+
dothat();
131+
} else {
132+
abort();
133+
}
134+
```
135+
136+
### Comments
137+
138+
Comments must use C-style `/* */` comments. C++-style `// `comments are not
139+
allowed in our codebase. This is a strict requirement as libgit2 tries to be
140+
compliant with the ISO C90 standard, which only allows C-style comments.
141+
142+
Single-line comments may have their opening and closing tag on the same line:
143+
144+
```c
145+
/* This is a short comment. */
146+
```
147+
148+
For multi-line comments, the opening and closing tag should be empty:
149+
150+
```c
151+
/*
152+
* This is a rather long and potentially really unwiedly but informative
153+
* multiline comment that helps quite a lot.
154+
*/
155+
```
156+
157+
Public functions must have documentation that explain their usage, internal
158+
functions should have a comment. We use Docurium to generate documentation
159+
derived from these comments, which uses syntax similar to Doxygen. The first
160+
line should be a short summary of what the function does. More in-depth
161+
explanation should be separated from that first line by an empty line.
162+
Parameters and return values should be documented via `@return` and `@param`
163+
tags:
164+
165+
```c
166+
/*
167+
* Froznicate the string.
168+
*
169+
* Froznicate the string by foobaring its internal structure into a more obvious
170+
* translation. Note that the returned string is a newly allocated string that
171+
* shall be `free`d by the caller.
172+
*
173+
* @param s String to froznicate
174+
* @return A newly allocated string or `NULL` in case an error occurred.
175+
* /
176+
char *froznicate(const char *s);
177+
```
178+
179+
### Variables
180+
181+
Variables must be declared at the beginning of their scope. This is a strict
182+
requirement as libgit2 tries to be compliant with the ISO C90 standard, which
183+
forbids mixed declarations and code:
184+
185+
```c
186+
void foobar(void)
187+
{
188+
char *c = NULL;
189+
int a, b;
190+
191+
a = 0;
192+
b = 1;
193+
194+
return c;
195+
}
196+
```
197+
198+
### Naming
199+
200+
Variables must have all-lowercase names. In case a variable name has multiple
201+
words, words should be separated by an underscore `_` character. While
202+
recommended to use descriptive naming, common variable names like `i` for
203+
indices are allowed.
204+
205+
All public functions must have a `git` prefix as well as a prefix indicating
206+
their respective subsystem. E.g. a function that opens a repository should be
207+
called `git_repository_open()`. Functions that are not public but declared in
208+
an internal header file for use by other subsystems should follow the same
209+
naming pattern. File-local static functions must not have a `git` prefix, but
210+
should have a prefix indicating their respective subsystem.
211+
212+
All structures declared in the libgit2 project must have a `typedef`, we do not
213+
use `struct type` variables. Type names follow the same schema as functions.
214+
215+
### Error Handling
216+
217+
The libgit2 project mostly uses error codes to indicate errors. Error codes are
218+
always of type `int`, where `0` indicates success and a negative error code
219+
indicates an error case. In some cases, positive error codes may be used to
220+
indicate special cases. Returned values that are not an error code should be
221+
returned via an out parameter. Out parameters must always come first in the list
222+
of arguments.
223+
224+
```c
225+
int doit(const char **out, int arg)
226+
{
227+
if (!arg)
228+
return -1;
229+
*out = "Got an argument";
230+
return 0;
231+
}
232+
```
233+
234+
To avoid repetitive and fragile error handling in case a function has resources
235+
that need to be free'd, we use `goto out`s:
236+
237+
```c
238+
int doit(char **out, int arg)
239+
{
240+
int error = 0;
241+
char *c;
242+
243+
c = malloc(strlen("Got an argument") + 1);
244+
if (!c) {
245+
error = -1;
246+
goto out;
247+
}
248+
249+
if (!arg) {
250+
error = -1;
251+
goto out;
252+
}
253+
254+
strcpy(c, "Got an argument")
255+
*out = c;
256+
257+
out:
258+
if (error)
259+
free(c);
260+
return error;
261+
}
262+
```
263+
264+
When calling functions that return an error code, you should assign the error
265+
code to an `error` variable and, in case an error case is indicated and no
266+
custom error handling is required, return that error code:
267+
268+
```c
269+
int foobar(void)
270+
{
271+
int error;
272+
273+
if ((error = doit()) < 0)
274+
return error;
275+
276+
return 0;
277+
}
278+
```
279+
280+
When doing multiple function calls where all of the functions return an error
281+
code, it's common practice to chain these calls together:
282+
283+
```c
284+
int doit(void)
285+
{
286+
int error;
287+
288+
if ((error = dothis()) < 0 ||
289+
(error = dothat()) < 0)
290+
return error;
291+
292+
return 0;
293+
}
294+
```
295+
296+
## CMake Coding Style
297+
298+
The following section defines the coding style for our CMake build system.
299+
300+
### Indentation
301+
302+
Code is indented by tabs, where a tab is 8 spaces. Each opening scope increases
303+
the indentation level.
304+
305+
```cmake
306+
if(CONDITION)
307+
doit()
308+
endif()
309+
```
310+
311+
### Spaces
312+
313+
There must be no space between keywords and their opening brace. While this is
314+
the same as in our C codebase for function calls, this also applies to
315+
conditional keywords. This is done to avoid the awkward-looking `else ()`
316+
statement.
317+
318+
```cmake
319+
if(CONDITION)
320+
doit()
321+
else()
322+
dothat()
323+
endif()
324+
```
325+
326+
### Case
327+
328+
While CMake is completely case-insensitive when it comes to function calls, we
329+
want to agree on a common coding style for this. To reduce the danger of
330+
repetitive strain injuries, all function calls should be lower-case (NB: this is
331+
not currently the case yet, but introduced as a new coding style by this
332+
document).
333+
334+
Variables are written all-uppercase. In contrast to functions, variables are
335+
case-sensitive in CMake. As CMake itself uses upper-case variables in all
336+
places, we should follow suit and do the same.
337+
338+
Control flow keywords must be all lowercase. In contrast to that, test keywords
339+
must be all uppercase:
340+
341+
```cmake
342+
if(NOT CONDITION)
343+
doit()
344+
elseif(FOO AND BAR)
345+
dothat()
346+
endif()
347+
```
348+
349+
### Targets
350+
351+
CMake code should not use functions that modify the global scope but prefer
352+
their targeted equivalents, instead. E.g. instead of using
353+
`include_directories()`, you must use `target_include_directories()`. An
354+
exception to this rule is setting up global compiler flags like warnings or
355+
flags required to set up the build type.
356+
357+
### Dependencies
358+
359+
Dependencies should not be discovered or set up in the main "CMakeLists.txt"
360+
module. Instead, they should either have their own module in our top-level
361+
"cmake/" directory or have a "CMakeLists.txt" in their respective "deps/"
362+
directory in case it is a vendored library. All dependencies should expose
363+
interface library targets that can be linked against with
364+
`target_link_libraries()`.

0 commit comments

Comments
 (0)