MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame^] | 1 | The LPMud gamedriver is by nature the result of the cooperative work |
| 2 | of multiple programmers, often separated by large oceans and years |
| 3 | of time. In order to keep the appearance of the driver source consistent |
| 4 | (and with that maintainable), the following guidelines should be followed |
| 5 | for all code contributions. |
| 6 | |
| 7 | For a quick start in how good driver source should look like, take |
| 8 | a look at comm.{c,h}, object.{c,h} and mapping.{c.h}. |
| 9 | |
| 10 | The guidelines have a strong emphasis on code layout and commenting, |
| 11 | stemming from the fact that proper layout and comments gave the |
| 12 | incentive for LDMud in the first place. Right now, 50% of all lines |
| 13 | are comments, and that has been proven to be a Good Thing. |
| 14 | |
| 15 | Any reader of the "real programmers don't write comments"-school |
| 16 | of thought is asked to take his or her incompetence elsewhere. |
| 17 | |
| 18 | |
| 19 | Language |
| 20 | -------- |
| 21 | The language is ISO Standard C (also known as 'C89' or 'ANSI C'). |
| 22 | Common compiler extensions or features from the new C99 standard are |
| 23 | permitted if their addition is transparent for other C89 compilers. |
| 24 | For example: the 'inline' keyword permitted through the use of the |
| 25 | INLINE macro; so are the Metrowerks-pragmas and GNU-attributes. Not |
| 26 | permitted are GNU's local functions. |
| 27 | |
| 28 | System/Platform specifics are to be detected by the configure script |
| 29 | and provided with transparent implementations in port.{c,h} (or for |
| 30 | module-specific dependencies in the respective modules). |
| 31 | |
| 32 | Adherence to the Standard has the following implications: |
| 33 | |
| 34 | - All functions must be fully prototyped. |
| 35 | - Standard types like size_t, ssize_t or ptrdiff_t are to be used |
| 36 | whereever possible. |
| 37 | - Unixisms like |
| 38 | { |
| 39 | a = malloc(20); |
| 40 | b = malloc(20); |
| 41 | c = b-a; |
| 42 | } |
| 43 | are not legal and shouldn't be used. |
| 44 | - Don't make assumptions about the size of the base types (e.g. |
| 45 | a char might have more than 8 bits). If such an assumption |
| 46 | is unavoidable, comment it clearly and if possible add a test |
| 47 | to raise a compile or runtime error if the assumption is not met. |
| 48 | |
| 49 | |
| 50 | Style |
| 51 | ----- |
| 52 | All modules (.c-files) have to have their interface in an accompaning |
| 53 | .h-file. The header file must be guarded against repeated inclusion |
| 54 | with the normal |
| 55 | #ifndef HEADERNAME_H |
| 56 | #define HEADERNAME_H 1 |
| 57 | ... |
| 58 | #endif /* HEADERNAME_H */ |
| 59 | construct. To use a module, its headerfile must be included - no random |
| 60 | 'extern' declarations. |
| 61 | |
| 62 | Every module must include "driver.h" which in turn includes the |
| 63 | portability headers and provides common defines. |
| 64 | |
| 65 | Use the driver-provided types and macros like Bool or p_int. |
| 66 | |
| 67 | Code should be written defensively and readable. This is not the IOCCC. |
| 68 | |
| 69 | No magic numbers - use #defines to give them names. |
| 70 | |
| 71 | Add sanity checks where useful. If the checks are costly, enclose |
| 72 | them in a #ifdef DEBUG...#endif bracket. |
| 73 | |
| 74 | Comment questionable code or opportunities for possible extensions with a |
| 75 | 'TODO: ...' comment. For multiline comments, use 'TODO::' on the second |
| 76 | and following lines (this makes reading a grep easier). |
| 77 | |
| 78 | Comment temporary debug code with a 'DEBUG:' comment. Similar, debug |
| 79 | output should always begin with 'DEBUG:'. |
| 80 | |
| 81 | Variable identifiers should start with a lowercase letter, function |
| 82 | identifiers may start with upper or lowercase, constant identifiers |
| 83 | should start with an uppercase letter. Macro identifiers should be |
| 84 | all UPPERCASE, other identifiers may be under_scored or SkudlyCaps. |
| 85 | Hungarian notation is accepted only in a very light form: pFoo for |
| 86 | pointers, ppFoo for pointer to pointers, iFoo for integer types, |
| 87 | sFoo for string pointers, aFoo for complex types - you get the |
| 88 | idea. But no alpzsFoo and friends. |
| 89 | |
| 90 | f_xxx() function names are reserved for efun implementations. |
| 91 | typedef'd typenames should end in _t (e.g. 'mapping_t'), struct |
| 92 | names should end in _s (e.g. 'struct instrs_s'). |
| 93 | |
| 94 | Indentation is 4 spaces per level. No tab characters anywhere! |
| 95 | |
| 96 | The indentation style is a variant of the 'Allman style': |
| 97 | |
| 98 | if (foo) |
| 99 | { |
| 100 | ...body... |
| 101 | } /* if (foo) */ |
| 102 | |
| 103 | Note the comment at the closing brace! |
| 104 | |
| 105 | One line bodies may be written as |
| 106 | |
| 107 | if (foo) body; |
| 108 | |
| 109 | or |
| 110 | |
| 111 | if (foo) |
| 112 | body; |
| 113 | |
| 114 | _if_ it improves the readability. |
| 115 | |
| 116 | Similar, the typical layout of a function is: |
| 117 | |
| 118 | static int |
| 119 | function_name ( arg1 , arg2) |
| 120 | |
| 121 | /* Twiddle <arg1> with <arg2> and return the result. |
| 122 | */ |
| 123 | |
| 124 | { |
| 125 | .... |
| 126 | } /* function_name() */ |
| 127 | |
| 128 | If an expression (argument list, ...) extends over several, the first |
| 129 | literal element on a line should be an operator or syntactical marker: |
| 130 | |
| 131 | if (condition1 |
| 132 | && ( condition2 |
| 133 | || condition3) |
| 134 | ) |
| 135 | |
| 136 | printf( "..." |
| 137 | , arg1, arg2, arg3 |
| 138 | ); |
| 139 | |
| 140 | Be generous with whitespace - both horizontal and vertical. |
| 141 | |
| 142 | [ The reasoning behind this style is to use the language elements |
| 143 | to create strong visual structures for the eyes to follow. By doing so, |
| 144 | the structure of the program becomes obvious without much |
| 145 | conscious thought. |
| 146 | ] |
| 147 | |
| 148 | |
| 149 | Commenting |
| 150 | ---------- |
| 151 | The comments also follow the idea of giving strong visual clues of |
| 152 | how the program is structured. |
| 153 | |
| 154 | Horizontal lines should be created as |
| 155 | |
| 156 | /*------...-------*/ |
| 157 | /*======...=======*/ |
| 158 | /* - - -... - - - */ |
| 159 | |
| 160 | The '---' line is the normal separator between the components of a |
| 161 | source file (includes, variable declarations, macro declarations, |
| 162 | the separate functions). The '===' line can be used to separate |
| 163 | larger sections of a source file (e.g. the lowlevel routines from |
| 164 | the efun implementations). '- -' lines, which usally span less than |
| 165 | the whole line, can be used to subdivide large functions (though then |
| 166 | it's often better to split the function into several small ones). |
| 167 | |
| 168 | A '***' line is reserved for the end of every source file. |
| 169 | |
| 170 | A '/* --- Subsection --- */' is also good to separate subsections. |
| 171 | |
| 172 | Vertical lines are to be constructed as |
| 173 | |
| 174 | /* |
| 175 | * |
| 176 | */ |
| 177 | |
| 178 | No box comments. |
| 179 | |
| 180 | Every function must have a head comment explaining the meaning |
| 181 | of the arguments, what the function does, and the possible results. |
| 182 | For efun implementations, this comment should be identical to the |
| 183 | man page. |
| 184 | |
| 185 | Within a function, every variable should be commented as |
| 186 | |
| 187 | int foo; /* short comment */ |
| 188 | int bar; |
| 189 | /* long comment which doesn't fit on one line. |
| 190 | */ |
| 191 | |
| 192 | The major steps in a function should be preceeded by a comment |
| 193 | explaining them. Also, wherever a critical design decision has |
| 194 | been made, a comment should line out the whats and whys: |
| 195 | |
| 196 | /* Duplicate the stored arguments for the function call. |
| 197 | * (It's tempting to use the stored arguments directly |
| 198 | * in the last pass; however it's not guaranteed that |
| 199 | * the last pass actually comes this far.) |
| 200 | */ |
| 201 | |
| 202 | |
| 203 | A typical file layout, commentwise, looks like this: |
| 204 | |
| 205 | /*------------------------------------------------------ |
| 206 | * Gamedriver Bouncing module. |
| 207 | * |
| 208 | * <reserved for future copyright notice> |
| 209 | *------------------------------------------------------ |
| 210 | * 'Big picture' description of the module and its |
| 211 | * relation to the other gamedriver parts. |
| 212 | * |
| 213 | * Tricky design discussions also belong in here. |
| 214 | *------------------------------------------------------ |
| 215 | */ |
| 216 | |
| 217 | #include "driver.h" |
| 218 | #include "typedefs.h" |
| 219 | |
| 220 | #include <stdlib.h> |
| 221 | |
| 222 | #include "bounce.h" |
| 223 | #include "backend.h" |
| 224 | |
| 225 | /*--------------------------------------------------------*/ |
| 226 | |
| 227 | /* --- User information --- */ |
| 228 | interactive_t *all_bouncers[MAX_PLAYERS]; |
| 229 | |
| 230 | /* --- Statistics --- */ |
| 231 | |
| 232 | p_int number_of_calls; |
| 233 | |
| 234 | /*--------------------------------------------------------*/ |
| 235 | void |
| 236 | add_bouncer (interactive_t *bouncer) |
| 237 | |
| 238 | /* This function adds <bouncer> to the all_bouncers[]. |
| 239 | */ |
| 240 | { |
| 241 | int i; /* search index */ |
| 242 | |
| 243 | .... |
| 244 | } /* add_bouncer() */ |
| 245 | |
| 246 | /**********************************************************/ |
| 247 | |