You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
457 lines
18 KiB
457 lines
18 KiB
4 years ago
|
Coding style guidelines for transcode
|
||
|
-------------------------------------
|
||
|
|
||
|
== Syntax ==
|
||
|
|
||
|
* Lines must not be longer than 79 columns, and should be kept to 75
|
||
|
columns or less when feasible.
|
||
|
|
||
|
* The basic indentation unit is four columns.
|
||
|
|
||
|
* Tab characters (ASCII 0x09) must not be used for indentation or alignment
|
||
|
of source code, and should be avoided in other cases (such as in strings)
|
||
|
where possible. Tabs should not be assumed to have any particular width.
|
||
|
|
||
|
* Comments should use standard C style (/*...*/); however, C++ style (//)
|
||
|
is permissible for inline comments (comments placed on the same line as
|
||
|
code). Comments on their own lines should start at the same indentation
|
||
|
level as the surrounding code; inline comments should, if feasible, line
|
||
|
up with other nearby inline comments. Multi-line comments should begin
|
||
|
with a single "*" on the second and subsequent lines, aligned with the
|
||
|
"*" in the "/*" on the first line; the final "*/" should be placed on the
|
||
|
same line as the last line of comment text, unless doing so would cause
|
||
|
that line to exceed 79 characters. However, for lengthy comments it is
|
||
|
also acceptable to place the initial "/*" and trailing "*/" on their own
|
||
|
lines. Examples:
|
||
|
|
||
|
/*
|
||
|
* This is a lengthy multiline comment, perhaps a function header,
|
||
|
* with the comment delimiters placed on their own lines.
|
||
|
*/
|
||
|
void myfunction()
|
||
|
{
|
||
|
int var1; // Inline comment about var1
|
||
|
double variable2; // Inline comment about var2
|
||
|
|
||
|
/* This is a shorter multiline comment about what the next bit of
|
||
|
* code will do. */
|
||
|
first();
|
||
|
/* This is a single-line comment */
|
||
|
second();
|
||
|
}
|
||
|
|
||
|
* Every function should be preceded by a header in the following format
|
||
|
which describes the purpose of the function.
|
||
|
|
||
|
/**
|
||
|
* function_name: The purpose/behavior of the function, in detail.
|
||
|
* (Replace "function_name" by the function's name.)
|
||
|
*
|
||
|
* Parameters:
|
||
|
* param: Description of `param'.
|
||
|
* param2: Description of `param2'. Note that parameters are
|
||
|
* right-aligned to the colon.
|
||
|
* Return value:
|
||
|
* A description of the value returned by the function. If the
|
||
|
* the function's return type is void, write "None."
|
||
|
* Preconditions:
|
||
|
* A list of everything the function assumes to be true. Use C-style
|
||
|
* expressions (such as "ptr != NULL") where possible. If there are no
|
||
|
* preconditions, write "None." This section may be omitted if there
|
||
|
* are no preconditions.
|
||
|
* Postconditions:
|
||
|
* A list of everything the function guarantees to be true when it
|
||
|
* returns, or "None." This section may be omitted if no
|
||
|
* postconditions are specified.
|
||
|
* Side effects:
|
||
|
* Any effects the function has that are not mentioned in the function
|
||
|
* description (such as the effect of strtok() destroying its source
|
||
|
* string), or "None." This section may be omitted if there are no
|
||
|
* side effects.
|
||
|
*/
|
||
|
|
||
|
* Only one statement is allowed per line. Statements (including the empty
|
||
|
statement ";") may not be written on the same line as a control keyword
|
||
|
(if, for, or while).
|
||
|
|
||
|
* Spaces are placed between binary operators and their operands, except for
|
||
|
the member-reference operators "->" and "."; spaces are not placed
|
||
|
between unary operators and their operands. However, spaces may be
|
||
|
omitted around binary operators when doing so would improve readability.
|
||
|
Examples:
|
||
|
|
||
|
i = j * 2;
|
||
|
structure->field++;
|
||
|
result += i*60 + (j+59)/60;
|
||
|
|
||
|
* Parentheses are required when && and || (or two or more of &, |, and ^)
|
||
|
are used in the same expression to explicitly indicate the order of
|
||
|
evaluation; do not rely on the default order of evaluation.
|
||
|
|
||
|
* Parentheses following the control statements "if", "for", and "while" are
|
||
|
preceded by a space. Parentheses following function or macro calls are
|
||
|
not preceded by a space. Example:
|
||
|
|
||
|
if (flag)
|
||
|
function();
|
||
|
|
||
|
* Spaces are placed after the comma of each parameter to a function or
|
||
|
macro; however, they may be omitted in function calls which are
|
||
|
themselves parameters to a function or macro, or when including them
|
||
|
would make the line exceed 79 columns in length (and removing them does
|
||
|
not harm the readability of the code). Spaces are also placed after the
|
||
|
semicolons in a for statement. Spaces are not placed after the opening
|
||
|
parenthesis or before the closing parenthesis of a function/macro call or
|
||
|
control statement. Examples:
|
||
|
|
||
|
function(param1, param2);
|
||
|
function(param1, strchr(string,'/'), param3);
|
||
|
for (i = 0; i < count; i++) ...
|
||
|
|
||
|
* Opening braces of control statement blocks go on the same line as the
|
||
|
control statement (if, for, etc.) associated with the block; function
|
||
|
blocks and "naked blocks" (those not associated with any control
|
||
|
statement or function) have the opening brace alone on a line, indented
|
||
|
to the same level as the surrounding code. Closing braces are indented
|
||
|
to the same level as the line containing the opening brace. Examples:
|
||
|
|
||
|
if (flag) {
|
||
|
/* indented code goes here */
|
||
|
...
|
||
|
}
|
||
|
|
||
|
int function(int param1, char *param2)
|
||
|
{
|
||
|
/* indented code goes here */
|
||
|
...
|
||
|
/* start of a naked block */
|
||
|
{
|
||
|
int foo;
|
||
|
...
|
||
|
}
|
||
|
}
|
||
|
|
||
|
* If an if statement is longer than one line, it should be broken at
|
||
|
logical operators (&& or ||); the operator should be placed at the
|
||
|
beginning of the next line, and should be indented to show which term the
|
||
|
operator belongs with. The closing parenthesis for the if statement and
|
||
|
the subsequent open brace should be alone on a line, aligned with the
|
||
|
first line of the if statement. (Braces are required in this case.)
|
||
|
Conditions for for and while statements should never span multiple lines,
|
||
|
though a for statement may be broken at the semicolons if necessary.
|
||
|
Examples:
|
||
|
|
||
|
if (ok && (strcmp(option, "option-name-1") == 0
|
||
|
|| strcmp(option, "option-name-2") == 0)
|
||
|
) {
|
||
|
...
|
||
|
}
|
||
|
|
||
|
if (!init_first()
|
||
|
|| !init_second()
|
||
|
|| !init_third()
|
||
|
|| !init_fourth()
|
||
|
) {
|
||
|
/* This example outdents the || by three spaces
|
||
|
* to make the terms line up. */
|
||
|
...
|
||
|
}
|
||
|
|
||
|
for (node = first_node(list, LISTTYPE_MYLIST); node != NULL;
|
||
|
node = next_node(list, LISTTYPE_MYLIST))
|
||
|
) {
|
||
|
...
|
||
|
}
|
||
|
|
||
|
* An else followed by an if is considered to be a single keyword, "else if".
|
||
|
The if part should always be placed on the same line as and immediately
|
||
|
following the else; the else if should never be split up onto two lines,
|
||
|
nor should braces be used around the if block. The exception to this is
|
||
|
when the else and if refer to two conceptually distinct sets of
|
||
|
conditions, in which case the if block should be enclosed by braces and
|
||
|
indented. Example:
|
||
|
|
||
|
res = check_password( /* ... */ );
|
||
|
if (res == 0) {
|
||
|
...
|
||
|
} else if (res == 1) {
|
||
|
/* "else if" on a single line */
|
||
|
...
|
||
|
} else {
|
||
|
if (otherflag) {
|
||
|
/* "if" condition is different from "else"
|
||
|
* condition, thus separate */
|
||
|
...
|
||
|
}
|
||
|
}
|
||
|
|
||
|
* Braces are always placed around the body of a control statement (if, for,
|
||
|
etc.). The one exception, aside from the case of else if mentioned
|
||
|
above, is a statement for which the body, as well as the bodies of any
|
||
|
else if or else statements for an if statement, are all one statement in
|
||
|
length and do not contain any nested control statements; in this case
|
||
|
braces are optional (but recommended if any of the statements span
|
||
|
multiple lines). Examples:
|
||
|
|
||
|
for (i = 0; i < count; i++)
|
||
|
function(i);
|
||
|
|
||
|
while (!done) {
|
||
|
/* Braces required because of the nested "if" */
|
||
|
if (do_stuff())
|
||
|
done = 1;
|
||
|
}
|
||
|
|
||
|
if (state == 0) {
|
||
|
a = b;
|
||
|
} else if (state == 1) {
|
||
|
/* Every if/else body gets braces because this body
|
||
|
* has two statements */
|
||
|
b += a;
|
||
|
a = 0;
|
||
|
} else {
|
||
|
state = 0;
|
||
|
}
|
||
|
|
||
|
* When using multiply-nested control statements, or a single control
|
||
|
statement which has a long block, the closing brace of the block should
|
||
|
be followed by a comment indicating what control statement the block
|
||
|
belongs to. This should usually be the content of the control statement,
|
||
|
but may be abbreviated as long as its meaning is clear. If a long if
|
||
|
block is followed by an else clause, the else should likewise be
|
||
|
documented. Examples:
|
||
|
while (i < count) {
|
||
|
...
|
||
|
} /* while (i < count) */
|
||
|
|
||
|
if (flag) {
|
||
|
...
|
||
|
} else { /* !flag */
|
||
|
...
|
||
|
} /* if (flag) */
|
||
|
|
||
|
for (node = first; node != NULL; node = node->;next) {
|
||
|
...
|
||
|
} /* for all nodes */
|
||
|
|
||
|
* Case labels for a switch should be indented half of a normal indentation
|
||
|
unit (two columns) from the line containing the switch with which they
|
||
|
are associated; statements associated with a case should be indented a
|
||
|
full unit from the line containing the switch (half a unit from the
|
||
|
case). If a case requires its own block, such as when it declares its
|
||
|
own local variables, the opening brace is placed after the colon on the
|
||
|
case line. Example:
|
||
|
switch (variable) {
|
||
|
case 123: {
|
||
|
int foo;
|
||
|
...
|
||
|
break;
|
||
|
} /* case 123 */
|
||
|
default:
|
||
|
...
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
* When a case in a switch block does not contain a break (or return)
|
||
|
statement and deliberately "falls through" to the next case, a comment to
|
||
|
this effect should be made at the bottom of the case. Example:
|
||
|
switch (state) {
|
||
|
case 0:
|
||
|
...
|
||
|
/* fall through */
|
||
|
case 1:
|
||
|
...
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
* Structured type initializers should use C99-style named initializers, to
|
||
|
avoid bugs resulting from initialization of incorrect fields if the
|
||
|
structure definition is changed. This is particularly important if the
|
||
|
structure definition is in a different source file, such as a header
|
||
|
file. Example:
|
||
|
struct foo {
|
||
|
int bar;
|
||
|
double quux;
|
||
|
int have_quux;
|
||
|
};
|
||
|
...
|
||
|
struct foo myfoo = {
|
||
|
.bar = 1,
|
||
|
.have_quux = 0,
|
||
|
};
|
||
|
|
||
|
|
||
|
== Semantics ==
|
||
|
|
||
|
* Functions should not be overly long or complex; as a rule of thumb, if a
|
||
|
function has more than four levels of indentation then it should probably
|
||
|
be broken up into separate functions.
|
||
|
|
||
|
* Do not use binary operators to perform arithmetic operations. In
|
||
|
particular, never use bit-shift operators in place of multiplication or
|
||
|
division by powers of two. (Modern compilers are smart enough to convert
|
||
|
arithmetic expressions like "x/2" to a bit-shift operation; moreover,
|
||
|
right shift and division give different results on negative numbers.)
|
||
|
Binary operators should only be used when operating on bitmasks or other
|
||
|
values where there is a need to extract or modify particular bits,
|
||
|
independent of the value of the variable as a whole.
|
||
|
|
||
|
* Always use the increment and decrement operators (++ and --) as postfix
|
||
|
operators, except in expressions that require prefix usage.
|
||
|
|
||
|
* Avoid nesting assignment expressions (including increment and decrement
|
||
|
operations) within other expressions, to the extent that extracting the
|
||
|
assignment operation would not unduly complicate the code. In the
|
||
|
following example, separating the strtok() call and its comparison would
|
||
|
require changing the structure of the loop completely, so the example is
|
||
|
acceptable as is:
|
||
|
|
||
|
while ((s = strtok(NULL, " \t\r\n")) != NULL) {
|
||
|
...
|
||
|
}
|
||
|
|
||
|
* Do not use an assignment expression as the condition in an "if", "while",
|
||
|
or "for" test; explicitly compare the result of the assignment against 0
|
||
|
or NULL, as appropriate.
|
||
|
|
||
|
* Do not use the result of a logical expression (operators &&, ||, ==,
|
||
|
etc.) as an operand in an arithmetic or binary expression.
|
||
|
|
||
|
* Always use NULL, not 0, in pointer comparisons. For character
|
||
|
comparisons, use 0 when checking for the null terminator at the end of a
|
||
|
string; use '\0' only if the intent is to check for the ASCII character
|
||
|
NUL as part of a string. Do not use '\0' with variables declared as type
|
||
|
int8_t or uint8_t, even though these types are usually equivalent to char
|
||
|
and unsigned char.
|
||
|
|
||
|
* The construct "!!expression" should not be used. Use "expression != 0"
|
||
|
(for characters or integers) or "expression != NULL" (for pointers)
|
||
|
instead.
|
||
|
|
||
|
* All exported functions must be prototyped in a header file.
|
||
|
|
||
|
* When declaring a function that takes no parameters, use "(void)" instead
|
||
|
of "()", since the latter does not declare a prototype in C. Example:
|
||
|
|
||
|
int function(void) /* Function that takes no parameters */
|
||
|
{
|
||
|
...
|
||
|
}
|
||
|
|
||
|
* Do not use the "inline" keyword. Most compilers can determine
|
||
|
automatically when inlining a function will be beneficial, and will do
|
||
|
so (if told to optimize) even without the "inline"; older compilers may
|
||
|
not understand "inline" at all.
|
||
|
|
||
|
* Functions should check all parameters for validity. However, in cases
|
||
|
where it is clear that a parameter is valid (for example, because the
|
||
|
function is only called by one other function under specific
|
||
|
circumstances), it is acceptable to assume the parameter is valid if that
|
||
|
assumption is listed as a precondition in the function's header.
|
||
|
|
||
|
* Variables should be declared in the innermost block which completely
|
||
|
encloses all uses of the variable. However, a loop counter in a nested
|
||
|
loop may be declared at a higher level if there are no other loop-local
|
||
|
variables at the appropriate level. Examples:
|
||
|
|
||
|
int function(int limit)
|
||
|
{
|
||
|
int foo = 0; /* used throughout the function */
|
||
|
int i; /* used in a top-level loop */
|
||
|
int j; /* used in a nested loop, no other locals */
|
||
|
|
||
|
for (i = 0; i < limit; i++) {
|
||
|
/* No loop-local variables here, so j is declared above */
|
||
|
for (j = 0; j < 3; j++) {
|
||
|
int x, y; /* only used inside the loop body */
|
||
|
otherfunction(i, j, &x, &y);
|
||
|
foo += x * y;
|
||
|
}
|
||
|
}
|
||
|
return foo;
|
||
|
}
|
||
|
|
||
|
* The goto statement should not be used except in error handling situations
|
||
|
where it will help avoid multiple levels of if nesting or other awkward
|
||
|
code. Labels for goto should be outdented half of an indentation unit
|
||
|
from the surrounding code (i.e., indented two columns less than the
|
||
|
surrounding code).
|
||
|
|
||
|
* assert() must not be used. If a sanity check fails, the program should
|
||
|
either recover as best it can or, if recovery is impossible, print a
|
||
|
meaningful error message and exit gracefully.
|
||
|
|
||
|
|
||
|
== Identifier naming ==
|
||
|
|
||
|
* Global variables (including variables declared static at the file level)
|
||
|
and type names should use mixed upper- and lower-case, with an upper-case
|
||
|
letter at the beginning of each distinct word in the name (including the
|
||
|
first).
|
||
|
|
||
|
* Preprocessor constants and macros should use all upper-case letters, with
|
||
|
an underscore between distinct words in the name.
|
||
|
|
||
|
* Structure names and local variables should use all lower-case letters,
|
||
|
with an underscore between distinct words in the name.
|
||
|
|
||
|
* Structure names for structures with an associated type name (i.e., from
|
||
|
typedef) should be given the same name as the type, except with all
|
||
|
letters in lowercase and followed by an underscore. Example:
|
||
|
typedef struct mytype_ MyType;
|
||
|
struct mytype_ {
|
||
|
MyType *next, *prev;
|
||
|
...
|
||
|
};
|
||
|
|
||
|
* Names should be descriptive. For global variables, preprocessor macros
|
||
|
and constants, type names, and structure names, names should generally
|
||
|
consist of one or more full words. For local variables, short names and
|
||
|
abbreviations are permitted as long as it is clear what the variables are
|
||
|
used for. In general, one-letter local variable names should not be used
|
||
|
other than the following:
|
||
|
* c: character
|
||
|
* f: file pointer (FILE *)
|
||
|
* i, j, k: integers (usually counters)
|
||
|
* n, p, q: integers (p may also be a pointer variable)
|
||
|
* s: string
|
||
|
* t: string or temporary variable
|
||
|
* x, y, z: integers (usually position variables)
|
||
|
|
||
|
|
||
|
== Transcode-specific features ==
|
||
|
|
||
|
* Always include config.h (if HAVE_CONFIG_H is defined) before including
|
||
|
any system includes, since config.h defines symbols such as
|
||
|
_FILE_OFFSET_BITS which can affect system includes. The following files
|
||
|
also include config.h:
|
||
|
transcode.h
|
||
|
aclib/aclib.h
|
||
|
avilib/avilib.h
|
||
|
avilib/wavlib.h
|
||
|
libtc/libtc.h
|
||
|
libtcaudio/tcaudio.h
|
||
|
libtcvideo/tcvideo.h
|
||
|
|
||
|
* All code which may be called from the main transcode executable
|
||
|
(including modules, libraries, the tcdecode/tcextract/etc. subprograms,
|
||
|
and their component source files) should use one of the tc_log_XXX()
|
||
|
macros from libtc for output intended to be seen by the user, including
|
||
|
debugging messages. There are four log levels available, and they
|
||
|
should be used as follows:
|
||
|
* tc_log_error()
|
||
|
For unrecoverable errors which cause the operation to abort.
|
||
|
* tc_log_warn()
|
||
|
For recoverable errors or other situations which may indicate
|
||
|
a problem but do not cause the operation to abort.
|
||
|
* tc_log_info()
|
||
|
For ordinary informational messages.
|
||
|
* tc_log_msg()
|
||
|
For debugging messages and less important informational
|
||
|
messages.
|
||
|
NEVER use printf() or any other functions which write to stdout for
|
||
|
these purposes.
|
||
|
|
||
|
* Do not use "\t" in strings for aligning text; use the proper number of
|
||
|
spaces instead.
|