source: trunk/doc/standards @ 12062

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