source: trunk/doc/standards @ 9541

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