source: trunk/doc/standards @ 17738

Revision 17738, 10.7 KB checked in by ghudson, 22 years ago (diff)
Revert the last two changes, and change the descriptive text to note the real problem, which is variable values equal to "!". ([ ! = ! ] works on Red Hat 7.3 but fails on Solaris 8 and IRIX 6.5.3.) Thanks to jmorzins for pointing this out.
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 two spaces for indentation.  Avoid putting the result or
103alternative parts of an if statement on the same line as the "if" or
104"else".  Avoid creating lines longer than 79 characters.  Write case
105statements according to the format:
106
107        case expression in
108        pattern)
109                statements
110                ;;
111        esac
112
113Environment variable names should be in all capitals; shell variable
114names should be in all lowercase.  Avoid writing ${varname} for
115variable expansion except when necessary; just write $varname.  In
116most cases, if you intend to expand a variable as a single word, you
117should write "$varname" with double quotes.  This is not necessary in
118the switch expression of a case statement or in variable assignments,
119though.
120
121Test expressions in shell scripts can be a mine field of ungraceful
122failures if the variables being tested are empty, contain spaces or
123glob characters, or have a value of "!".  To handle all such corner
124cases gracefully without adding unnecessary hair, use the following
125test 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
136Software engineering practices
137------------------------------
138
139The 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
156The 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
172Symbol namespaces
173-----------------
174
175If you are writing a library, you should pick a prefix for your
176library.  You should ensure that all symbols which interact with the
177application's namespace (both at link time and on inclusion of the
178header file) begin with your prefix (or the all-caps form of your
179prefix, in the case of preprocessor symbols and enumeration constants)
180followed by an underscore.  Symbols which are not intended for use by
181the application should begin with your prefix followed by two
182underscores.
183
184For instance, if your prefix is "hes", then functions exported to the
185user should begin with "hes_" (e.g. "hes_resolve").  Functions used
186internally by the library should begin with "hes__"
187(e.g. "hes__resolve" for the internal resolver function).
188Preprocessor symbols intended for use by the application should begin
189with "HES_" (e.g. "HES_ER_OK"); preprocessor symbols not intended for
190use by the application should begin with "HES__" (e.g.
191"HES__HESIOD_H", used to protect hesiod.h from multiple
192inclusion).
193
194Names of structures should begin with your prefix, but structure
195fields don't need to.  Strictly speaking, structure fields interact
196with the user's namespace because the user might have "#define"'d them
197to something before including your header file, but applications
198generally shouldn't be "#define"ing lots of lowercase symbols, so this
199is not a real worry.
200
201Portability considerations for code we maintain
202-----------------------------------------------
203
204In general, your code should assume a POSIX-compliant and ANSI
205C-compliant development environment, except to work around specific
206bugs in platforms we care about.
207
208You should use Autoconf to handle portability concerns; see the file
209"build-system" in this directory for how a package in the athena
210hierarchy should use autoconf.  If you must perform an operating
211system test (because you are using a plain Makefile, typically for
212something 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
226This way, if the source tree is ever converted to use feature tests,
227the person porting the code will know exactly what needs to be tested
228for.  If you can anticipate the preprocessor symbol which would be
229used with Autoconf (as in this example), that's even better.  Note
230particularly the comment instead the operating system test; it should
231specify:
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
239This will help future maintainers determine if one can eliminate the
240special consideration altogether when an OS upgrade has happened.
241
242Following is a list of appropriate preprocessor symbols to use to
243detect 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
253SOLARIS is not automatically defined by the compiler on Solaris
254systems; we make sure it's defined when we build code not using
255autoconf.  There are no reliable automatically defined constants for
256Solaris systems.
257
258For some highly non-portable operations you may need to do a platform
259test even when using Autoconf.  In that case, use AC_CANONICAL_HOST
260rather than the above ifdefs.
261
262Portability considerations for code we release
263----------------------------------------------
264
265All of the standards in the previous section apply; however, we
266generally care about more platforms for code we release to the outside
267works.  It is discouraged, but acceptable, to care about platforms
268which are not POSIX-compliant.  Code that cares about such platforms
269should determine whether the platform supports POSIX interfaces by
270using AC_CHECK_HEADERS(unistd.h) to determine whether it can #include
271<unistd.h>, and then checking whether _POSIX_VERSION is defined.  Such
272code should always use POSIX interfaces rather than less portable
273interfaces when they are available.
274
275Portability considerations for code we get from third parties
276-------------------------------------------------------------
277
278The overriding principle for code obtained from third parties is to
279make as few changes as possible.  A lot of third-party code has a very
280bad approach to portability, or cares about a lot of platforms we
281don't care about.  You should attempt to follow the portability
282approach used by the rest of the program, such as it may be.  Ideally,
283any changes you make should be made in such a manner that they can be
284incorporated into the source tree maintained by the third party.
Note: See TracBrowser for help on using the repository browser.