| | 1 | To keep the code as portable as possible, follow these rules. All these |
| | 2 | "don't"s may seem brain-damaged, but there's really no other way to keep |
| | 3 | the code compileable on old and/or brain-damaged compilers. |
| | 4 | |
| | 5 | These rules are not a panacea, mind you. The intention is to make the |
| | 6 | code as portable as *possible*, so that any compiler-incompatibilities |
| | 7 | are easier to fix. They don't give a "100% portability guarantee." |
| | 8 | |
| | 9 | Furthermore, I'm no portability-wizard. These rules are a combination |
| | 10 | of my own and (most importantly) other people's experiences. If you |
| | 11 | have ideas regarding portability, please contact the maintainer. |
| | 12 | |
| | 13 | If you spot any code that does not follow these rules, please report it |
| | 14 | as a bug and/or send a patch. An exception to this are the files in the |
| | 15 | tads2/ and tads3/ directories; they are read-only. Don't touch them. |
| | 16 | Any changes made to them will be lost next time FrobTADS gets in sync |
| | 17 | with the TADS base code. Problems in any of these files should only be |
| | 18 | reported, not fixed. |
| | 19 | |
| | 20 | Sidenote: If you're looking for object oriented programming guidelines, |
| | 21 | forget it. FrobTADS is object based, not object oriented. It uses C++ |
| | 22 | mostly as a "better C". Classes and objects are only used to make |
| | 23 | things simpler, not with OOP in mind. |
| | 24 | |
| | 25 | OK, here goes: |
| | 26 | |
| | 27 | |
| | 28 | The "common.h" header file |
| | 29 | ========================== |
| | 30 | |
| | 31 | In new source files, always, Always, ALWAYS, #include "common.h" as the |
| | 32 | first header. Everywhere; both in C and C++ sources, in headers and |
| | 33 | *.c/*.cc/*.cpp files. |
| | 34 | |
| | 35 | |
| | 36 | 'and', 'or' and 'not' |
| | 37 | ===================== |
| | 38 | |
| | 39 | If you prefer these keywords over the usual '&&', '||' and '!' operators |
| | 40 | (I do), just use them as if they were available everywhere. You must |
| | 41 | always #include "common.h" for this to work. This only applies to C++ |
| | 42 | code of course. Don't use these keywords in C (they *are* in the C++ |
| | 43 | standard, even if old compilers don't support them, but not in ANSI C). |
| | 44 | |
| | 45 | |
| | 46 | C++ template library |
| | 47 | ==================== |
| | 48 | |
| | 49 | Don't use the C++ standard library. That means no <iostream>, no |
| | 50 | <vector>, no <algorithm>, no <string>, no fun. |
| | 51 | |
| | 52 | |
| | 53 | #including standard C-headers in C++ |
| | 54 | ==================================== |
| | 55 | |
| | 56 | Don't use new-style C++ includes to include C-library headers. Do this: |
| | 57 | |
| | 58 | #include <string.h> |
| | 59 | |
| | 60 | rather than this: |
| | 61 | |
| | 62 | #include <cstring> |
| | 63 | |
| | 64 | |
| | 65 | Namespaces |
| | 66 | ========== |
| | 67 | |
| | 68 | Don't use namespaces. |
| | 69 | |
| | 70 | |
| | 71 | for-loops |
| | 72 | ========= |
| | 73 | |
| | 74 | Don't rely on the modern semantics of for-loops. Don't do this: |
| | 75 | |
| | 76 | for (int i = 0; i < frob; ++i) { |
| | 77 | // ... |
| | 78 | } |
| | 79 | // ... |
| | 80 | for (int i = 0; [...] |
| | 81 | |
| | 82 | as it will only compile on modern compilers. Do this instead: |
| | 83 | |
| | 84 | int i; |
| | 85 | for (i = 0; i < frob; ++i) [...] |
| | 86 | for (i = 0; [...] |
| | 87 | |
| | 88 | This compiles on both modern and old compilers. If you really need a |
| | 89 | variable that expires after the loop, use this: |
| | 90 | |
| | 91 | {for (int i = 0; i < frob; ++i) { |
| | 92 | // ... |
| | 93 | }} |
| | 94 | |
| | 95 | Attention! If you have an old compiler, don't do this: |
| | 96 | |
| | 97 | for (int i = 0; [...] |
| | 98 | for (i = 0; [...] |
| | 99 | |
| | 100 | as it will *only* work with *old* compilers. Modern compilers can't |
| | 101 | compile this code. |
| | 102 | |
| | 103 | |
| | 104 | C++ casts |
| | 105 | ========= |
| | 106 | |
| | 107 | Don't use static_cast<> and friends. Do this instead: |
| | 108 | |
| | 109 | static_cast(foo)(bar) |
| | 110 | dynamic_cast(frob*)(baz) |
| | 111 | reinterpret_cast(const xyzzy*)(plugh) |
| | 112 | |
| | 113 | This will work on every compiler (as long as you #include "common.h" in |
| | 114 | your sources). On modern compilers, this: |
| | 115 | |
| | 116 | static_cast(int)(bar) |
| | 117 | |
| | 118 | will be macro-transformed into: |
| | 119 | |
| | 120 | static_cast<int>(bar) |
| | 121 | |
| | 122 | while on old compilers, it will become: |
| | 123 | |
| | 124 | (int)(bar) |
| | 125 | |
| | 126 | |
| | 127 | Exception handling |
| | 128 | ================== |
| | 129 | |
| | 130 | Don't use exception handling. There's a portable exception-framework in |
| | 131 | the TADS 3 base code (transparently utilizing labels and gotos through |
| | 132 | macros); you might want to use it if you really can't do without exception |
| | 133 | handling. |
| | 134 | |
| | 135 | |
| | 136 | Templates |
| | 137 | ========= |
| | 138 | |
| | 139 | Don't use templates. Don't try to work around this by emulating them |
| | 140 | with macros; you'll just shoot yourself in the foot (and since this is |
| | 141 | C++, this will blow away your whole leg). |
| | 142 | |
| | 143 | |
| | 144 | Non-standard compiler features |
| | 145 | ============================== |
| | 146 | |
| | 147 | Don't use compiler-specific non-ANSI features; not everyone has GCC |
| | 148 | installed. You should always compile with GCC's "-ansi -pedantic" |
| | 149 | switches (both C and C++). Note that "-ansi -pedantic" cannot check |
| | 150 | your code for full ANSI correctness; they are only meant to catch |
| | 151 | obvious blunders. |
| | 152 | |
| | 153 | |
| | 154 | Non-ANSI/ISO functions |
| | 155 | ====================== |
| | 156 | |
| | 157 | If you feel like using a non-ANSI function (for example a BSD one), use |
| | 158 | it, but provide a working ANSI-only fall-back, as is already done with |
| | 159 | some functions in src/missing.[h/cc]. Also look at the implementation |
| | 160 | of os_get_sys_clock_ms() in src/oscurses.cc on how to handle portability |
| | 161 | issues. |
| | 162 | |
| | 163 | Generally, if such a function has equivalent ones in other standards, |
| | 164 | just check for them in "configure.ac" and structure your code to use the |
| | 165 | information the configuration script detects. |
| | 166 | |
| | 167 | |
| | 168 | Filenames |
| | 169 | ========= |
| | 170 | Don't use filenames longer than 14 characters. I'm not talking about |
| | 171 | DOS (which has the 8+3 limit). There are some Unices that have this |
| | 172 | limitation. |