mirror of
https://github.com/joel16/uofw.git
synced 2024-11-27 13:30:33 +00:00
393 lines
10 KiB
Plaintext
393 lines
10 KiB
Plaintext
This document is about the preferred uOFW coding style. Please stick to the style
|
|
presented in this guide to make working on uOFW as a team easier.
|
|
Thank you.
|
|
|
|
1) Indentation:
|
|
|
|
Indentations are 4 bytes wide. The reason behind this is to visibly show
|
|
where a block starts and where it ends.
|
|
|
|
Example:
|
|
|
|
if (condition) {
|
|
doX();
|
|
doY();
|
|
}
|
|
|
|
Don't put multiple statements on a single line:
|
|
|
|
/* bad */
|
|
if (condition) doX();
|
|
|
|
For switch blocks, don't indent the "case"s and "default"s but only their content.
|
|
In example:
|
|
|
|
switch (type) {
|
|
case 'A':
|
|
break;
|
|
}
|
|
|
|
2) Breaking long lines:
|
|
|
|
Make sure to not write code lines longer than 120 characters. If necessary, break lines exceeding the 120
|
|
characters limit like below:
|
|
|
|
SCE_MODULE_INFO("sceController_Service", SCE_MODULE_KERNEL | SCE_MODULE_NO_STOP | SCE_MODULE_SINGLE_LOAD |
|
|
SCE_MODULE_SINGLE_START, 1, 1);
|
|
|
|
This applies to functions as well.
|
|
|
|
Long if-lines (same as while-, for-lines) are broken into several lines like this:
|
|
|
|
if (a == 1 ||
|
|
b == 2)
|
|
doSomething();
|
|
|
|
|
|
3) Placing Braces and Spaces:
|
|
|
|
Put the opening brace last on the line, and put the closing brace first, thusly:
|
|
|
|
if (condition) {
|
|
doX();
|
|
doY();
|
|
}
|
|
|
|
This applies to all non-function code blocks (if, switch, for, while).
|
|
Furthermore, it is used when using typedef or array/structure initialization.
|
|
|
|
However, don't put braces where only one branch exists with just one single
|
|
statement.
|
|
Reason: The indentation is already visible and thus there is no need for braces.
|
|
|
|
if (condition)
|
|
doX();
|
|
|
|
If there are two or more branches, use braces this way:
|
|
|
|
if (condition) {
|
|
doX();
|
|
doZ();
|
|
} else if (otherCondition) {
|
|
doA();
|
|
doB();
|
|
} else {
|
|
doY();
|
|
doW();
|
|
}
|
|
|
|
And don't put braces when the block contents are only one line long, the same way
|
|
as above:
|
|
|
|
if (condition) {
|
|
doX();
|
|
doZ();
|
|
} else if (otherCondition)
|
|
doY();
|
|
else
|
|
doW();
|
|
|
|
For functions, put the opening brace first on a new line and the closing brace
|
|
first on the last line:
|
|
|
|
void function(void)
|
|
{
|
|
doSomethingCool();
|
|
}
|
|
|
|
Space policy:
|
|
|
|
Put a space after these keywords: if, switch, case, do, while, for, return.
|
|
|
|
switch (number) {
|
|
case 1:
|
|
doThis();
|
|
break;
|
|
case 2:
|
|
doThat();
|
|
break;
|
|
default:
|
|
doStandard();
|
|
break;
|
|
}
|
|
|
|
Don't put spaces after keywords not mentioned above.
|
|
|
|
Put spaces before and after arithmetic operators (+, -, *, /, %), shift operators,
|
|
binary operators (&, |, ^), comparison & operation operators.
|
|
|
|
Example:
|
|
|
|
if ((a + (b << 2)) > 4)
|
|
doSomeMagic();
|
|
|
|
Consequently, don't put spaces before and after prefix/postfix operators (++/--),
|
|
or after unary operators like &, *, !, ~.
|
|
Furthermore, no spaces around structure member operators (. and ->).
|
|
|
|
The sizeof compile-time unary operator is special. Use a space after it only when
|
|
taking the size of an object, don't use a space (but parentheses!) when taking
|
|
the size of a data type.
|
|
|
|
sizeof object; -> (sizeof variable;)
|
|
|
|
sizeof(type name); -> (sizeof(u32);)
|
|
|
|
Declaring a pointer is made by adjoining the unary operator '*' to the data name
|
|
and not the type name:
|
|
|
|
s8 *ptr;
|
|
|
|
When declaring a pointer to a function, this way suffices:
|
|
|
|
s32 (*funcPtr)(void);
|
|
|
|
4) Type using:
|
|
|
|
Don't use type's like (unsigned) short, (unsigned) int as their size is NOT
|
|
the same on all machines.
|
|
Use instead:
|
|
|
|
8 bit signed/unsigned data size -> s8/u8
|
|
16 bit signed/unsigned data size -> s16/u16
|
|
32 bit signed/unsigned data size -> s32/u32
|
|
64 bit signed/unsigned data size -> s64/u64
|
|
|
|
s8 applies to arrays of characters as well, obviously:
|
|
|
|
s8 project[] = "uOFW";
|
|
|
|
Also use these data types for casts, when necessary.
|
|
|
|
When declaring a structure type using a typedef, do it this way:
|
|
|
|
typedef struct {
|
|
s32 x;
|
|
s32 y;
|
|
} Point;
|
|
|
|
and not:
|
|
|
|
/* bad */
|
|
typedef struct _Point {
|
|
s32 x;
|
|
s32 y;
|
|
} Point;
|
|
|
|
Except if defining the structure itself is needed, in example if the structure references itself.
|
|
In that case, use:
|
|
typedef struct Point {
|
|
struct Point *next;
|
|
} Point;
|
|
|
|
5) Naming:
|
|
|
|
Use simple, short names, easy to understand. For local variables, it is even okay
|
|
to use a variable name consisting of only one letter:
|
|
|
|
/* bad */
|
|
u8 loopCounter;
|
|
|
|
/* good */
|
|
u8 i;
|
|
|
|
Another common example is the use of temporary variables. Just name them "tmp",
|
|
this is clearly understandable and does its job. Don't try making the program
|
|
harder to understand than necessary.
|
|
|
|
If you encounter a local variable and you don't know what it represents, name
|
|
it "unk". If there are more unknown variables within one function, name them
|
|
like this:
|
|
|
|
s32 unk1;
|
|
s32 unk2;
|
|
...
|
|
|
|
This applies for unknown structure members too. Note that if there are a few
|
|
different structures in the same file, using different "styles" (like unk1 or
|
|
unk001 or unk_1..) can be useful so the member name can be replaced easily in all
|
|
the file.
|
|
|
|
For global variables, use descriptive names. Here, the variables' names
|
|
matter and not primarily the name length.
|
|
In order to clearly distinguish global variables from local variables
|
|
(especially helpful in large functions), use a "g_" prefix for global's.
|
|
|
|
/* global mutexId */
|
|
s32 g_MutexId;
|
|
|
|
Don't use underscores in variable names, except for the "g_" prefix for globals.
|
|
Instead, use capital letters.
|
|
|
|
/* Bad */
|
|
u32 is_uofw_cool;
|
|
|
|
/* Good */
|
|
u32 isUofwCool = 1; /* Indeed. */
|
|
|
|
6) Don't use magic numbers!
|
|
|
|
Using magic numbers is bad, as only the author of the C file in which they occur
|
|
will know (for a little while) what they express.
|
|
Instead, use a #define statement or an enumeration to give numbers a meaningful name.
|
|
|
|
The approach is to give hardware important #defines a "PSP_" prefix and general #defines shared with
|
|
other files a "SCE_" prefix, as in "SCE_MODULE_KERNEL".
|
|
|
|
Hardware-important example #define from ctrl.c:
|
|
|
|
/* This is bad, what SYSCON transmit command does 7 represent? */
|
|
g_Ctrl.sysPacket[0].tx_cmd = 7;
|
|
|
|
Thus, we have the following #define in syscon.h:
|
|
#define PSP_SYSCON_CMD_GET_KERNEL_DIGITAL_KEY 7
|
|
|
|
/* Aha, "7" stands for a data tranfer of all digital buttons (no analog pad data). */
|
|
ctrl.sysPacket[0].tx_cmd = PSP_SYSCON_CMD_GET_KERNEL_DIGITAL_KEY;
|
|
|
|
The same goes for return codes. uOFW's error file is located in
|
|
/uOFW/trunk/include/common/error.h. Use the defined errors instead of magic numbers.
|
|
|
|
A similar approach for for/while-loops:
|
|
|
|
/* This is bad code */
|
|
u32 g_Array[10];
|
|
|
|
u32 i;
|
|
for (i = 0; i < 10; i++)
|
|
g_Array[i] = 0;
|
|
|
|
/* Good code */
|
|
#define ARRAY_SIZE 10
|
|
|
|
u32 g_Array[ARRAY_SIZE];
|
|
|
|
u32 i;
|
|
for (i = 0; i < ARRAY_SIZE; i++)
|
|
g_Array[i] = 0;
|
|
|
|
|
|
7) Structure initialization:
|
|
|
|
Assume we have the following structure:
|
|
|
|
typedef struct {
|
|
s32 x;
|
|
s32 y;
|
|
} Point;
|
|
|
|
The initialization of a Point variable looks like this:
|
|
|
|
Point p = {
|
|
.x = 20,
|
|
.y = 12
|
|
};
|
|
|
|
Directly assigning the structure members is very helpful, especially in large
|
|
structure initializations, as this will help us to keep track of which structure
|
|
member has been initialized with what value.
|
|
|
|
Use the sizeof operator when a structure has a 'size' field to be filled with the
|
|
structure size (sizeof(structureType);)
|
|
|
|
|
|
8) Accessing hardware registers:
|
|
|
|
Hardware registers are stored in memory starting at 0xBC000000 and are _special_
|
|
compared to global variables. They have to be written synchronously, which means
|
|
you have to tell the compiler that it can't invert two hardware operations.
|
|
|
|
If you want to load from/store to a hardware register, use the HW(addr) macro.
|
|
|
|
u32 hwRegTmp;
|
|
|
|
hwRegTmp = HW(0xBC000000);
|
|
HW(0xBC000000) = 1;
|
|
|
|
|
|
9) Comments:
|
|
|
|
All exported functions of a module and important data structures as well as
|
|
#defines shared among .c files have to be put into a header file used as a module documentation.
|
|
|
|
Exported functions are commented like this:
|
|
|
|
/**
|
|
* Purpose of <exportedFunction>.
|
|
*
|
|
* @param a Description of parameter a.
|
|
* @param b Description of parameter b.
|
|
*
|
|
* @return 0 on success.
|
|
*/
|
|
u32 exportedFunction(u32 a, u32 b);
|
|
|
|
Note: "0 on success." implies that the function returns less than zero on error.
|
|
We do that because all the exported functions return less than zero on error. If
|
|
the function always returns 0, just use "@return 0.".
|
|
|
|
Structure members are commented like this (same for enumerations):
|
|
|
|
typedef struct {
|
|
/** The X-axis value of a point. */
|
|
s32 x;
|
|
/** The Y-axis value of a point. */
|
|
s32 y;
|
|
} Point;
|
|
|
|
In the module's .c file(s), use "/*" instead of "/**" and only add
|
|
parameter description if the purpose of the parameters is unclear without
|
|
additional description.
|
|
|
|
/*
|
|
* Purpose of <sum>.
|
|
*
|
|
* Returns the sum of a and b.
|
|
*/
|
|
static s32 sum(s32 a, s32 b);
|
|
|
|
Here, everything about the parameters a and b is obvious, so there is no need for
|
|
explaining them.
|
|
Also note that we use "Returns..." instead of "@return" for header functions.
|
|
|
|
Comments inside of functions:
|
|
|
|
When necessary, comment hard-to-understand code parts, explaining WHAT the code is doing.
|
|
The reader of the .c file probably knows a lot less than you (as you reversed the module)
|
|
about the module. Thus, make sure that those readers will understand what is going on.
|
|
|
|
One line comments will look like this:
|
|
|
|
/* My comment. */
|
|
|
|
Longer comments differ from short comments:
|
|
|
|
/*
|
|
* My comment, which is too long
|
|
* to fit in one line.
|
|
*/
|
|
|
|
Use "//" for temporary comments such as "//TODO: " or address comments like
|
|
sceKernelCpuResumeIntr(suspendFlag); //0x000020A8
|
|
|
|
Make sure to use enough address comments to be able to fix every line in in your
|
|
reversed code file fast and easily. Keep a local copy of your reversed code files
|
|
with included address comments and, optionally, TODO-comments, and upload a file version
|
|
WITHOUT address-, TODO-comments to the uOFW svn, as soon as your module fully works.
|
|
|
|
10) Switches:
|
|
|
|
Put a break at the end of each "case" and at the end of the "default".
|
|
Don't skip lines between the different labels ("case"s and "default"s).
|
|
In example:
|
|
switch (type) {
|
|
case 1:
|
|
do1();
|
|
break;
|
|
case 2:
|
|
do2();
|
|
break;
|
|
default:
|
|
doDefault();
|
|
break;
|
|
} |