1 | This document describes guidelines for code which is to be |
---|
2 | incorporated into the Athena source tree. Here are the areas covered: |
---|
3 | |
---|
4 | Conventions for C code |
---|
5 | Conventions for shell scripts |
---|
6 | Software engineering practices |
---|
7 | Symbol namespaces |
---|
8 | Portability considerations for code we maintain |
---|
9 | Portability considerations for code we release |
---|
10 | Portability considerations for code we get from third parties |
---|
11 | |
---|
12 | Conventions for C code |
---|
13 | ---------------------- |
---|
14 | |
---|
15 | If you are working on an existing module which does not follow these |
---|
16 | conventions, be consistent with the existent source code rather than |
---|
17 | these conventions. |
---|
18 | |
---|
19 | You should follow the section on "Writing C" in the Gnu coding |
---|
20 | standards (available in emacs info under "standards"), with the |
---|
21 | following changes: |
---|
22 | |
---|
23 | * When making a function call, do not put a space before the |
---|
24 | open parenthesis. Do put spaces before the open parenthesis |
---|
25 | after "while", "if", or "for", though. |
---|
26 | |
---|
27 | * When defining a function, do not drop to the next line for |
---|
28 | the name of the function; put the function name on the same |
---|
29 | line as the return type. |
---|
30 | |
---|
31 | * Don't insert form feed characters into source files to |
---|
32 | divide programs into pages. |
---|
33 | |
---|
34 | * Ignore the sections on "Portability between System Types" |
---|
35 | and "Portability between CPUs"; see the sections on |
---|
36 | portability in this file instead. Also ignore the section |
---|
37 | on "Internationalization." |
---|
38 | |
---|
39 | * In the section "Calling System Functions," ignore everything |
---|
40 | about string functions. These days you can assume that |
---|
41 | using "#include <string.h>", strchr(), and strrchr() will |
---|
42 | work on just about all platforms. |
---|
43 | |
---|
44 | You can use "M-x set-c-style" "GNU" in emacs to have emacs take care |
---|
45 | of the gnu-style indentation for you. (This is the default on Athena |
---|
46 | if you haven't set it to something else in your .emacs.) Remember to |
---|
47 | drop to the next line before each open brace. |
---|
48 | |
---|
49 | When writing return statements, do not put parentheses around the |
---|
50 | return value; just write "return foo;". (This convention is not |
---|
51 | specified in the Gnu coding standards, but is consistent with the |
---|
52 | examples in the standards.) |
---|
53 | |
---|
54 | Put braces around the bodies of control constructs (if, while, for, |
---|
55 | do, switch) if they are more than one line long. |
---|
56 | |
---|
57 | Each C source file should begin with an MIT copyright statement, a |
---|
58 | comment describing what the file does, and a line: |
---|
59 | |
---|
60 | static char rcsid[] = "$Id$"; |
---|
61 | |
---|
62 | Each C header file should begin with: |
---|
63 | |
---|
64 | /* $Id$ */ |
---|
65 | |
---|
66 | followed by an MIT copyright statement and a comment describing what |
---|
67 | the file does. MIT copyright statements may be omitted for source |
---|
68 | code which is not distributed outside of MIT. |
---|
69 | |
---|
70 | The preferred convention for comments is |
---|
71 | |
---|
72 | /* comment text */ |
---|
73 | |
---|
74 | for one line comments, and |
---|
75 | |
---|
76 | /* comment text line 1 |
---|
77 | * comment text line 2 |
---|
78 | */ |
---|
79 | |
---|
80 | for multi-line comments. (To make "M-q" in Emacs leave the closing |
---|
81 | "*/" on a line by itself, set the variable c-hanging-comment-ender-p |
---|
82 | to nil.) As recommended in the Gnu coding standards, your comments |
---|
83 | should normally be complete, capitalized sentences ending with a |
---|
84 | period. |
---|
85 | |
---|
86 | Write prototypes for all of your functions. Include argument names in |
---|
87 | your prototypes, to help the reader understand what they mean. |
---|
88 | |
---|
89 | Conventions for shell scripts |
---|
90 | ----------------------------- |
---|
91 | |
---|
92 | Use /bin/sh to write shell scripts, not csh. |
---|
93 | |
---|
94 | Begin each shell script with: |
---|
95 | |
---|
96 | #!/bin/sh |
---|
97 | # $Id$ |
---|
98 | |
---|
99 | followed by an MIT copyright if the shell script will be distributed |
---|
100 | outside of MIT. |
---|
101 | |
---|
102 | Use two spaces for indentation. Avoid putting the result or |
---|
103 | alternative parts of an if statement on the same line as the "if" or |
---|
104 | "else". Avoid creating lines longer than 79 characters. Write case |
---|
105 | statements according to the format: |
---|
106 | |
---|
107 | case expression in |
---|
108 | pattern) |
---|
109 | statements |
---|
110 | ;; |
---|
111 | esac |
---|
112 | |
---|
113 | Environment variable names should be in all capitals; shell variable |
---|
114 | names should be in all lowercase. Avoid writing ${varname} for |
---|
115 | variable expansion except when necessary; just write $varname. In |
---|
116 | most cases, if you intend to expand a variable as a single word, you |
---|
117 | should write "$varname" with double quotes. This is not necessary in |
---|
118 | the switch expression of a case statement or in variable assignments, |
---|
119 | though. |
---|
120 | |
---|
121 | Test expressions in shell scripts can be a mine field of ungraceful |
---|
122 | failures if the variables being tested are empty, contain spaces or |
---|
123 | glob characters, or begin with a dash. To handle all such corner |
---|
124 | cases gracefully without adding unnecessary hair, use the following |
---|
125 | test expressions: |
---|
126 | |
---|
127 | To test if a variable is... Write |
---|
128 | --------------------------- ----- |
---|
129 | empty -z "$varname" |
---|
130 | non-empty -n "$varname" |
---|
131 | equal to a literal literal = "$varname" |
---|
132 | equal to another variable "x$varname" = "x$othervarname" |
---|
133 | set "${varname+set}" = set |
---|
134 | not set "${varname+set}" != set |
---|
135 | |
---|
136 | Software engineering practices |
---|
137 | ------------------------------ |
---|
138 | |
---|
139 | The following software engineering practices are strongly encouraged: |
---|
140 | |
---|
141 | * Restricting the operations which can access a given type of |
---|
142 | data object, and grouping them together. |
---|
143 | |
---|
144 | * Documenting data invariants (i.e. conditions on the |
---|
145 | representations of data objects which are assumed to always |
---|
146 | be true) and the meaning of data representations. |
---|
147 | |
---|
148 | * Documenting non-obvious requirements and effects of |
---|
149 | procedures. |
---|
150 | |
---|
151 | * Use of prototypes for all functions. |
---|
152 | |
---|
153 | * Automated testing of both program components ("unit |
---|
154 | testing") and whole programs ("integration testing"). |
---|
155 | |
---|
156 | The following software engineering practices are discouraged: |
---|
157 | |
---|
158 | * Use of global variables. Remember that the complexity of |
---|
159 | any function's interface is increased by the global |
---|
160 | variables it uses, even if that doesn't show up in the |
---|
161 | function prototype. Global variables are marginally |
---|
162 | acceptable to represent configuration parameters determined |
---|
163 | by command-line arguments or a configuration file, but even |
---|
164 | then it is preferable to find an alternative. |
---|
165 | |
---|
166 | * Use of global process state. You should avoid using |
---|
167 | alarm(), and you should avoid using getuid() or getenv() |
---|
168 | inside libraries or other "deep" interfaces. Code that uses |
---|
169 | global process state tends to interact poorly with other |
---|
170 | code in large programs. |
---|
171 | |
---|
172 | Symbol namespaces |
---|
173 | ----------------- |
---|
174 | |
---|
175 | If you are writing a library, you should pick a prefix for your |
---|
176 | library. You should ensure that all symbols which interact with the |
---|
177 | application's namespace (both at link time and on inclusion of the |
---|
178 | header file) begin with your prefix (or the all-caps form of your |
---|
179 | prefix, in the case of preprocessor symbols and enumeration constants) |
---|
180 | followed by an underscore. Symbols which are not intended for use by |
---|
181 | the application should begin with your prefix followed by two |
---|
182 | underscores. |
---|
183 | |
---|
184 | For instance, if your prefix is "hes", then functions exported to the |
---|
185 | user should begin with "hes_" (e.g. "hes_resolve"). Functions used |
---|
186 | internally by the library should begin with "hes__" |
---|
187 | (e.g. "hes__resolve" for the internal resolver function). |
---|
188 | Preprocessor symbols intended for use by the application should begin |
---|
189 | with "HES_" (e.g. "HES_ER_OK"); preprocessor symbols not intended for |
---|
190 | use by the application should begin with "HES__" (e.g. |
---|
191 | "HES__HESIOD_H", used to protect hesiod.h from multiple |
---|
192 | inclusion). |
---|
193 | |
---|
194 | Names of structures should begin with your prefix, but structure |
---|
195 | fields don't need to. Strictly speaking, structure fields interact |
---|
196 | with the user's namespace because the user might have "#define"'d them |
---|
197 | to something before including your header file, but applications |
---|
198 | generally shouldn't be "#define"ing lots of lowercase symbols, so this |
---|
199 | is not a real worry. |
---|
200 | |
---|
201 | Portability considerations for code we maintain |
---|
202 | ----------------------------------------------- |
---|
203 | |
---|
204 | In general, your code should assume a POSIX-compliant and ANSI |
---|
205 | C-compliant development environment, except to work around specific |
---|
206 | bugs in platforms we care about. |
---|
207 | |
---|
208 | You should use Autoconf to handle portability concerns; see the file |
---|
209 | "build-system" in this directory for how a package in the athena |
---|
210 | hierarchy should use autoconf. If you must perform an operating |
---|
211 | system test (because you are using a plain Makefile, typically for |
---|
212 | something in the packs hierarchy), do it in two steps; for instance: |
---|
213 | |
---|
214 | #define HAVE_STRERROR |
---|
215 | #if defined(sun) && !defined(SOLARIS) |
---|
216 | /* SunOS 4.1.3_U1 doesn't have strerror(). Use sys_errlist |
---|
217 | * instead. */ |
---|
218 | #undef HAVE_STRERROR |
---|
219 | #endif |
---|
220 | |
---|
221 | #ifndef HAVE_STRERROR |
---|
222 | extern const char *const sys_errlist[]; |
---|
223 | #define strerror(x) (sys_errlist[x]) |
---|
224 | #endif |
---|
225 | |
---|
226 | This way, if the source tree is ever converted to use feature tests, |
---|
227 | the person porting the code will know exactly what needs to be tested |
---|
228 | for. If you can anticipate the preprocessor symbol which would be |
---|
229 | used with Autoconf (as in this example), that's even better. Note |
---|
230 | particularly the comment instead the operating system test; it should |
---|
231 | specify: |
---|
232 | |
---|
233 | * What special consideration is needed for that operating |
---|
234 | system. |
---|
235 | |
---|
236 | * The version number of the operating system for which this |
---|
237 | approach was determined to be necessary. |
---|
238 | |
---|
239 | This will help future maintainers determine if one can eliminate the |
---|
240 | special consideration altogether when an OS upgrade has happened. |
---|
241 | |
---|
242 | Following is a list of appropriate preprocessor symbols to use to |
---|
243 | detect platforms we care about, when using plain Makefiles: |
---|
244 | |
---|
245 | SunOS: #if defined(sun) && !defined(SOLARIS) |
---|
246 | Solaris: #ifdef SOLARIS |
---|
247 | IRIX #ifdef sgi |
---|
248 | Linux: #ifdef linux |
---|
249 | NetBSD: #ifdef __NetBSD__ |
---|
250 | or #include <sys/param.h> and #ifdef BSD4_4 |
---|
251 | if applicable to all BSD 4.4 systems. |
---|
252 | |
---|
253 | SOLARIS is not automatically defined by the compiler on Solaris |
---|
254 | systems; we make sure it's defined when we build code not using |
---|
255 | autoconf. There are no reliable automatically defined constants for |
---|
256 | Solaris systems. |
---|
257 | |
---|
258 | For some highly non-portable operations you may need to do a platform |
---|
259 | test even when using Autoconf. In that case, use AC_CANONICAL_HOST |
---|
260 | rather than the above ifdefs. |
---|
261 | |
---|
262 | Portability considerations for code we release |
---|
263 | ---------------------------------------------- |
---|
264 | |
---|
265 | All of the standards in the previous section apply; however, we |
---|
266 | generally care about more platforms for code we release to the outside |
---|
267 | works. It is discouraged, but acceptable, to care about platforms |
---|
268 | which are not POSIX-compliant. Code that cares about such platforms |
---|
269 | should determine whether the platform supports POSIX interfaces by |
---|
270 | using AC_CHECK_HEADERS(unistd.h) to determine whether it can #include |
---|
271 | <unistd.h>, and then checking whether _POSIX_VERSION is defined. Such |
---|
272 | code should always use POSIX interfaces rather than less portable |
---|
273 | interfaces when they are available. |
---|
274 | |
---|
275 | Portability considerations for code we get from third parties |
---|
276 | ------------------------------------------------------------- |
---|
277 | |
---|
278 | The overriding principle for code obtained from third parties is to |
---|
279 | make as few changes as possible. A lot of third-party code has a very |
---|
280 | bad approach to portability, or cares about a lot of platforms we |
---|
281 | don't care about. You should attempt to follow the portability |
---|
282 | approach used by the rest of the program, such as it may be. Ideally, |
---|
283 | any changes you make should be made in such a manner that they can be |
---|
284 | incorporated into the source tree maintained by the third party. |
---|