]> git.pond.sub.org Git - empserver/blob - doc/coding
Clean up some trailing whitespace
[empserver] / doc / coding
1                 Guidelines for Writing Empire Code
2
3              compiled and edited by Markus Armbruster
4
5 Preface
6 -------
7
8 Empire is an old program, and the age shows in places.  It took a lot
9 of people a lot of effort to write it.  Chances are that some of them
10 were smarter than you and me.  Treat the code with the respect it
11 deserves.
12
13 These guidelines are just that: guidelines.  Not law.  There's no
14 Empire Coding Police.  People hacked on Empire code long before I knew
15 it existed, and I hope they still will when I fade into Empire
16 history.  But there's substantial experience behind these guidelines,
17 so don't dismiss them cavalierly.
18
19 Here's our goal: algorithmic clarity.  All the rules and guidelines
20 are subservient to it.  If you'd have to obfuscate your code to
21 satisfy the letter of some guideline, don't!
22
23 Mind, I said `clarity', not `self-realization' or `expression of your
24 individuality'.  Dave Pare wrote:
25
26   Be invisible.  When you make a change, think not about marking your
27   place in history, or about showing off how much nicer your two-space
28   tabs are than those old, icky eight-space tabs that the stupid
29   empire hackers of old used, but think instead about the aesthetics
30   of the whole.  The resulting lines of code should flow smoothly from
31   the beginning of the procedure to the end.  Empire is 60,000 lines
32   of code.  If you're the general case, you're only changing fifty
33   lines, so be aware of that.
34
35 Some guidelines are more serious than others.  When I use words like
36 `is', `shall' or `must', I mean it.  When I write `should', it's a
37 recommendation.
38
39 Many guidelines concern style, i.e. they involve matters of taste.
40 That's how it has to be.  Uniformity of style is important for
41 clarity.
42
43 These guidelines don't attempt to be exhaustive.  More complete
44 guidelines that are mostly compatible with Empire can be found at
45 http://www.jetcafe.org/~jim/c-style.html
46
47
48 Source tree organization
49 ------------------------
50
51 FIXME
52
53
54 Code formatting
55 ---------------
56
57     In My Egotistical Opinion, most people's C programs should be
58     indented six feet downward and covered with dirt."
59         -- Blair P. Houghton
60
61 Over the years, enough Empire coders lacked the good taste to preserve
62 the style of the original Empire code in their changes, and thus
63 turned the source code into an unreadable mess.  In 2003, we fed it to
64 GNU indent.
65
66 We tried to restore things to the original style, mostly.  There is
67 one noteable change: basic indentation is now four spaces.  Restoring
68 the original eight spaces would have resulted in many more long lines,
69 which would have to be broken by indent.  Since indent isn't good at
70 breaking lines tastefully, we reluctantly chose four instead.
71
72 FIXME mention src/scripts/intend-emp, even better: convert it into an
73 indent profile and mention that.
74
75 If you use Emacs, `stroustrup' indentation style produces satisfactory
76 results.  The command `c-set-style', normally bound to `C-c .', lets
77 you set the style for the current buffer.  Set variable
78 `c-default-style' to "stroustrup" to switch to this style for all
79 buffers.
80
81 Tab character use
82
83 Whether you use tab characters or not doesn't really matter that much,
84 but tab stops are every eight characters, period.
85
86 Indentation, placement of braces, function name
87
88 Basic indentation is four spaces.  The opening brace goes on the same
89 line as `if', `struct', etc.  Put `else' and do loops' `while' one the
90 same line as the closing brace.  You are encouraged to leave out
91 syntactically optional braces.  Don't indent case labels.
92
93 Example:
94
95         if (is_fubar())
96             despair();
97         else {
98             do {
99                 char ch = getchar();
100                 switch (ch) {
101                 case EOF:
102                     return;
103                 case '\n':
104                     break;
105                 default:
106                     grind_along(ch);
107                 }
108             } while (happy());
109         }
110
111 In a function definition, the return type, function name and the
112 braces must all start on a new line, unindented, like this:
113
114         type
115         name(arguments)
116         {
117             body
118         }
119
120 This does not apply to function declarations.
121
122 Breaking long lines
123
124 Line length should not exceed 75 characters.  Break such lines at a
125 logical place, preferably before an operator with low precedence.
126 Line up the continuation line with the innermost unclosed parenthesis,
127 if there is one, else indent it four spaces.
128
129 Example:
130
131         FIXME
132
133 Bad example:
134
135         FIXME
136
137 Blank lines
138
139 Use blank lines to separate different things.  Functions must be
140 separated by a blank line.  You are encouraged to insert a blank line
141 between a block's declarations and statements.
142
143 Spaces
144
145 There is a space after `for', `if', and `while'.  If `for' and `while'
146 are followed by `;' (empty loop body) on the same line, there is a
147 space before the `;'.  There is no space between the function name and
148 the `(', but there is a space after each `,'.  There should be no
149 space between type cast operator and operand.  There is no extra space
150 after '(' and before ')'.
151
152 Example:
153
154         for (p = s; *p; ++p) ;
155         printf("%ld\n", (long)(p-s));
156
157 Comments
158
159 The function comment describing what a function does goes directly
160 above the definition.
161
162 Comments to the right of code should start in column 32 if possible
163 (counting from zero).
164
165 Comment lines should be indented exactly like the code the belong to.
166
167 You are encouraged to format multi-line comments like this:
168
169         /*
170          * Please use complete sentences, with proper grammer,
171          * capitalization and punctuation.  Use two spaces between
172          * sentences.
173          */
174
175 But please avoid elaborate boxes like this:
176
177         /***********************************************************
178          * Such decorations are a waste of time, hard to edit, and *
179          * ugly, too.                                              *
180          ***********************************************************/
181
182 Do not use
183
184         // C++/C99 comments
185
186 because they are not portable C89.
187
188
189 Conditional compilation
190
191 Unless the conditional code is very short, please comment it like
192 this:
193
194         #ifdef FOO
195         ...
196         #endif /* FOO */
197
198         #ifdef BAR
199         ...
200         #else  /* !BAR */
201         ...
202         #endif /* !BAR */
203
204
205 Style
206 -----
207
208 Names
209
210 DoNotUseStudlyCaps!  Stick to lower_case and use underscores.  Upper
211 case is for macros and enumeration constants.
212
213 File names should not differ in case only, since not all file systems
214 distinguish case.  Best stick to lower case.  Avoid funny characters
215 in file names.  This includes space.
216
217 Preprocessor
218
219 Like many good things, the preprocessor is best used sparingly.
220 Especially conditional compilation.
221
222 Do not use the preprocessor to `improve' the syntax of C!
223
224 Macro names should be ALL_CAPS to make them stand out.  Otherwise,
225 they can be mistaken for objects or functions.  This is bad, because
226 `interesting' behavior can hide inside macros, like not evaluating
227 arguments, or changing them.  Exception: if a function-like macro
228 behaves exactly like a function, then you may use a lower case name.
229
230 Parameters that can take expression arguments must be parenthesized in
231 the expansion.  If the expansion is an expression, it should be
232 parenthesized as well.
233
234 You are encouraged to use enumeration constants instead of macros when
235 possible.  The existing code doesn't, but it makes sense all the same.
236
237 Comments
238
239 Every file should have a file comment FIXME
240
241 Every function should have a function comment that describes what it
242 does.  FIXME elaborate.  Writing such comments helps both future
243 maintainers and yourself: if it's too hard to write a concise function
244 comment, then your function is likely too complicated and could use a
245 redesign.
246
247 The existing code has very little useful comments, and it'll likely
248 take us years to fix it.  Please don't make it harder than it already
249 is.
250
251 Declarations
252
253 Do not declare system functions yourself; include the appropriate
254 system header.
255
256 Use prototypes, not old-style function declarations.
257
258 To get the best use of C's type checking, each function or variable
259 with external linkage should have exactly one declaration, in some
260 header file, and that declaration must be in scope at the definition.
261 No other declarations should exist.  In particular, please include the
262 appropriate header instead of just declaring stuff again.  The code
263 used to be full of this kind of junk, and it was quite some work to
264 clean it up.
265
266 Forward declarations of static functions should all go in one place
267 near the beginning of the file.
268
269 If you want a typedef name in addition to a structure or union tag,
270 give it the same name, like this:
271
272         typedef struct foo foo;
273
274 Yes, this is incompatble with C++.  Reducing the number of names for
275 the same thing is more useful than compatibility to a programming
276 language we don't use.
277
278 Please don't hide away pointers with typedefs, like this:
279
280        typedef struct foo *foop;
281
282 When I see `foo *', I *know* what it is.  When I see `foop', I have to
283 look it up.
284
285 Booleans
286
287 Do not use increment operators to set a variable to logical true!  It
288 obfuscates the purpose, and narrow variables could even overflow.
289 Just assign 1.  A lot of cleanup remains to be done there.
290
291 Null pointer constant
292
293 Please use NULL for clarity, not just 0.
294
295 Type casts
296
297 Casting pointers to and from `void *' clutters the code and serves no
298 purpose (repeat after me: C is not C++).  It is also unsafe, because
299 the cast suppresses type warnings.
300
301 Casting function values to void clutters the code and serves little
302 purpose (repeat after me: C is not Pascal).
303
304 Casting an argument to the type of the parameter clutters the code and
305 serves no purpose (repeat after me: ISO C is not K&R C).
306
307 Factor out common code
308
309 Do not gratuitiously duplicate code!  Ken Stevens said it well, and
310 it's as relevant as ever:
311
312   Cut-and-Paste coding is by far the biggest problem that the current
313   Empire suffers from.  This is how cut-and-paste coding happens.  Joe
314   Shmuck decides that he wants to add a new function to the server.
315   So he goes hunting through the server to find some already existing
316   code which does something similar to what he wants to do.  This is
317   good.  You should always write new code to imitate old code.  What
318   is bad is when Joe Shmuck decides to simply "copy" 200 lines of code
319   from the old function into his new function, and then just change a
320   couple of little things here and there to suit his needs.  This
321   method, known as Cut-and-Paste coding is the fastest and easiest way
322   to code.  However, it results in a server that is impossible to
323   maintain.  What Joe _should_ have done, is "move" the 200 lines of
324   code into a new _third_ function which the first two both call.
325   This is called writing a "general solution" to handle both cases.
326   Most of my work in the Empire2 project consisted in cleaning up
327   after a bunch of Joe Shmucks.
328
329
330 Portability
331 -----------
332
333 FIXME C89, POSIX
334
335 FIXME sizes, printf formats
336
337 FIXME reserved names
338
339 FIXME conditional compilation is a last resort
340
341
342 Robustness
343 ----------
344
345 Error checking
346
347 Check error conditions meticulously.  The existing code is bad enough
348 at this, please don't make it worse.
349
350 FIXME what to do on error
351
352 Sanity checking
353
354 In many places, the code checks for conditions that should not happen,
355 and then tries to recover.  This is sound defensive programming.
356 Please use CANT_HAPPEN() and CANT_REACH() for this purpose, because
357 they log the error condition, and optionally abort the program, or
358 write out a core dump.  This is called an "oops".
359
360 Buffer overruns
361
362 FIXME
363
364 Thread safety
365
366 Thread stacks cannot grow.  If you use too much automatic storage, you
367 can overrun the stack with disastrous consequences.  FIXME elaborate
368
369 Empire uses non-preemptive threads: a thread runs until it yields the
370 processor.  This simplifies programming, but there are still traps to
371 avoid.  Yielding the processor is an explicit thread operation, and
372 whether a thread operation yields is documented in empthread.h.
373 However, the operation may be buried in library code.
374
375 In particular, player input may yield.  Player output may yield only
376 if it goes to the current player, and his last command doesn't have
377 the C_MOD flag.  You can use this to simplify command code: set C_MOD
378 if you don't want to worry about yield on output.  This is commonly
379 done for commands that modify game state.
380
381 Be careful with static storage.  Read-only data is fine.  More than
382 one thread writing static data is problematic, but there are safe
383 uses.  For instance, a static scratch buffer that is never used across
384 `yields' is safe.
385
386 Yielding the processor invalidates *all* the game state you copied
387 into variables.  You have to reread and possibly recheck.  See below.
388
389 Accessing game state
390
391 Game state consists of several sets of objects, e.g. sectors, ships,
392 bmaps, ...  Each set is fully held in memory and backed by a file in
393 the data directory.
394
395 There are several ways to access an object in set FOO:
396
397 * You can get a pointer to the object (not a copy!) with getFOOp().
398
399   This is inherently dangerous, because it allows you to update the
400   object in memory without updating the disk file.  It's used mostly
401   in update code, where it pays major performance dividends, but there
402   are uses in other places.  Whether they are wise is debatable.
403
404   Obviously, the object can change when you let another thread run.
405   This is not an issue in update code, because it never yields.
406
407 * You can get a copy with getFOO() and write it back with putFOO().
408
409   Putting updates both the object in memory and the disk file.
410
411   Any change to the object invalidates the copy.  Putting such an
412   invalid copy will clobber the change(s) that invalidated it,
413   possibly resulting in corrupted game state.  The code oopses on such
414   puts, but it can't repair the damage.
415
416   There are two common ways to invalidate a copy: calling a function
417   that updates the object you copied (unless it does that through your
418   copy), and yielding the processor, which lets other threads update
419   the object you copied.
420
421   Therefore, you have to reget after a possible invalidation, and deal
422   with changes.  In particular, if you checked whether the object is
423   suitable for a task, you need to check again after regetting it.  If
424   you can afford to bail out when something changed, use
425   check_FOO_ok().
426
427   Function comments should state what objects the function can update.
428   Unfortunately, they generally don't.
429
430   It's best to keep puts close to gets, both in runtime and in the
431   source code.
432
433 * Bmaps have special access functions.
434
435   Each country has two bmaps: the working bmap and the true bmap.
436   Unfortunately, the bmap code calls the former `bmap' and the latter
437   `map'.
438
439   You update bmaps with map_set().  This doesn't write through to the
440   file; instead, it returns non-zero when the update changed anything.
441   In that case, you must write bmaps to disk with writemap() before
442   you yield.  If you only updated the working bmap, then you can call
443   writebmap() instead.
444
445 Reading player input
446
447 Reading player input can fail, and you must check for that.
448 Neglecting it can break the interrupt feature for players (normally
449 Ctrl-C), and produce extra prompts that could confuse clients.  Even
450 worse is neglecting it in a loop that terminates only when input is
451 read successfully.
452
453 When reading input fails, you should normally abort the command with
454 status RET_SYN.  There are exceptions, e.g. when aborting a pinpoint
455 bombing run over the target.
456
457 Some functions to read player input return a special error value you
458 can check, e.g. recvclient(), prmptrd() and uprmptrd() return a
459 negative value, getstring() and getstarg() return NULL.
460
461 Others return the same error value for failed read and for successful
462 read of input that is invalid.  Then you need to check
463 player->aborted; if it is set after a read, the read failed.
464
465
466 git
467 ---
468
469 Commit related changes together, unrelated changes separately.
470
471 Write meaningfull commit messages.  Start with a single short line
472 (ideally less than 50 characters) summarizing the change, followed by
473 a blank line and then a more thorough description.
474
475 The purpose of the change log is not to explain how the code works;
476 that should be done in the source code itself.  It's to explain *why*
477 you made the change, and what is affected by it.
478
479 Don't change whitespace gratuitiously, say just because your editor
480 screws up tabs.  Such changes make it much harder to figure out who
481 changed what and when.
482
483 \f
484 Historical guidelines, superseded by the above
485
486
487 Remarks from Dave Pare:
488
489 And now, a few editorial remarks on my views on Good Techniques for
490 Modifying Existing Software:
491
492 My safari through the hot and bug-ridden jungle that Empire has become
493 has given me some new insights on the modification of large software
494 packages.  My adventure has prompted me to propose some simple coding
495 guidelines for those dreaming of hacking on the code:
496
497 1) Be invisible.  When you make a change, think not about marking your
498 place in history, or about showing off how much nicer your two-space
499 tabs are than those old, icky eight-space tabs that the stupid empire
500 hackers of old used, but think instead about the asethetics of the whole.
501 The resulting lines of code should flow smoothly from the beginning of the
502 procedure to the end.  Empire is 60,000 lines of code.  If you're the
503 general case, you're only changing fifty lines, so be aware of that.
504
505 2) Procedurize.  If you find yourself in a triple-nested loop, or a five
506 hundred line procedure, perhaps it's because you need to split some of
507 that code off into a procedure.  In general, if you've got more than two
508 levels of tabs (or indentations), or more than one or two major loops in
509 a procedure, something may well be amiss.
510
511
512 Sasha Mikheev on indentation:
513
514 The empire indentation style can be achived by using
515 indent -orig -i8 foo.c
516
517 or in old c-mode emacs (versions before 19.29):
518 ;add this to .emacs
519 (setq c-indent-level 8)
520 (setq c-continued-statement-offset 8)
521 (setq c-argdecl-indent 8)
522 (setq c-brace-offset -8)
523 (setq c-label-offset -8)
524
525
526 Further comments by Ken Stevens:
527
528 1) Global variables
529 The only variables which should be global are constants.  If you write
530 a routine which changes a global variable, then you will corrupt the
531 data when two different players run that routine at the same time.
532
533 2) Portability.
534 The following code:
535                 char    a;
536         #ifdef FOO
537                 unsigned char b;
538         #endif FOO
539 Should be rewritten as:
540                 s_char  a;
541         #ifdef FOO
542                 u_char  b;
543         #endif /* FOO */
544
545 AIX has different conventions for signed chars, and IRIX requires the
546 /* comments */ after #endif.
547
548 3) Cut-and-Paste
549 Cut-and-Paste coding is by far the biggest problem that the current
550 Empire suffers from.  This is how cut-and-paste coding happens.  Joe
551 Shmuck decides that he wants to add a new function to the server.  So
552 he goes hunting through the server to find some already existing code
553 which does something similar to what he wants to do.  This is good.
554 You should always write new code to imitate old code.  What is bad is
555 when Joe Shmuck decides to simply "copy" 200 lines of code from the old
556 function into his new function, and then just change a couple of
557 little things here and there to suit his needs.  This method, known as
558 Cut-and-Paste coding is the fastest and easiest way to code.  However,
559 it results in a server that is impossible to maintain.  What Joe
560 _should_ have done, is "move" the 200 lines of code into a new _third_
561 function which the first two both call.  This is called writing a
562 "general solution" to handle both cases.  Most of my work in the
563 Empire2 project consisted in cleaning up after a bonch of Joe Shmucks.
564 I took repeated code and "consolidated" it into general function
565 libraries.
566
567 4) Good style.
568 Just to add to Dave's "Be Invisible" motto, I'd like to give a little
569 example to illustrate some basic do's and don'ts for coding style:
570
571 The following function has bad style:
572
573 double att_combat_eff(com,own)
574 struct combat *com;
575 natid own;{
576   double str;
577   double eff=1.0;
578   if(com->type==EF_SECTOR)
579   {
580     eff=com->eff/100.0;
581     if(com->own==own){
582       str=com->sct_dcp->d_ostr;
583     }else{
584 str=com->sct_dcp->d_dstr;eff=2.0+(str-2.0)*eff;
585     }else if(com->type==EF_SHIP&&com->own!=own)
586       eff=(1.0+com->shp_mcp->m_armor/100.0);
587   return eff;}
588
589 Here is the same function written with "good" style:
590
591 double
592 att_combat_eff(com, own)
593         struct  combat *com;
594         natid   own;
595 {
596         double  eff = 1.0;
597         double  str;
598
599         if (com->type == EF_SECTOR) {
600                 eff = com->eff / 100.0;
601                 if (com->own == own)
602                         str = com->sct_dcp->d_ostr;
603                 else
604                         str = com->sct_dcp->d_dstr;
605                 eff = 2.0 + (str - 2.0) * eff;
606         } else if (com->type == EF_SHIP && com->own != own)
607                 eff = (1.0 + com->shp_mcp->m_armor / 100.0);
608
609         return eff;
610 }
611
612 These are all the things I fixed when changing the bad to the good:
613 - Function names should always start a new line (so you can search for them)
614 - There should always be a space after a ","
615 - Function arguments should be indented 8 spaces
616 - There should always be a tab after a type declaration
617 - Opening function bracket should be on a line by itself
618 - Indentation should be 8 spaces
619 - There should always be a space on both sides of every operator
620 - There should always be a space after if, for, while, switch
621 - The opening bracket should be on the same line as the if
622 - There should always be a space on either side of a {
623 - There should always be a new line after a ;
624 - The closing function bracket should be on a line by itself