Another hurdle for the 5620/630/730 lines of terminals was when I
tried getting software support. Teletype being a mostly a "dumb"
terminal manufacturer never considered them more that a way to have
multilple 80 char x 24 line terminals on one display. I had difficulty
in conveying to them that it was a computer in its own right and you
could program it. The marketing was probably just as limited in scope.
Another blow for the BLIT portion on the terminal came when you
cound get an external cartridge for the 730 that turned it
into an X-terminal. I got mine in 1991 and then rarely used
layers after that.
-B
Norman Wilson's account of the Jerq/Blit etc. is quite
complete and correct, though there was some recycling
of names. 'Jerq' actually was used quite early, when
Pike got interested in bitmap graphics. The name
was a takeoff on the Three Rivers Perq, which he (and I)
saw at Lucasfilm Ltd. while attending an early Usenix.
Blit was the slightly more PC version (suggested either
as part of BitBlt or "Bell Labs Interactive Terminal).
The originals used the Motorola 68000, and part of
the development messup was AT&T Computer systems'
decision to switch to the WE32000 processor with
consequent delay for porting and reworking.
The earliest versions were not quite as wonderful
in practice as Norman suggests for the later ones.
They were built by the Teletype corp. model shop
(in quantity of a few hundred) and downloading
the OS took several minutes at 1200bps--necessary
at startup, since they didn't have a ROM for the whole
thing, just enough for doing a download. They
were also static electricity antennas! Many
is the time that I would shift in my chair, then
touch the keyboard, only to have the terminal
reset itself. I developed the habit of putting my
hand on the heavy steel case before moving around.
On the other hand, the basic idea was architecturally
right (and the later commercial versions were not so
subject to static, and had ROM for the OS). They
were even nicer at 9600bps.
It's good to know that Norman is still using his.
Dennis
> I've been using this window system more or less daily since August 1984,
> though only at home since I left Bell Labs in 1990. (I am using it to
> type this message.)
!
what other hardware and software do you run, if you don't mind my noseyness?
> From: "A.P.Garcia" <apgarcia(a)uwm.edu>
> To: tuhs(a)minnie.tuhs.org
> Subject: [TUHS] c coding standards
> Date: Fri, 11 Oct 2002 01:52:08 +0000
>
> check out this old post I found on Google Groups.
> this kind of stuff makes me giddy. :-)
< 2288 lines deleted >
Not to be overly picky, but aren't there two copies of everything.
carl
--
carl lowenstein marine physical lab u.c. san diego
clowenst(a)ucsd.edu
22. Pike, R. "The Blit: A Multiplexed Graphics Terminal". _AT&T Bell
Laboratories Technical Journal 63_, 8 (Oct. 1984).
Rob described an earlier version of the Blit work in a USENIX talk
at USENIX in January 1982 (Santa Monica CA). So far as I know it
was just a talk, no paper, though he showed a canned demo on video
tape.
For those who don't know it, the Blit (in later versions called the
Jerq; in official product version, the AT&T 5620 DMD terminal, and
later the 630 and 730) is a separate terminal with a bitmapped display,
keyboard, and mouse. The window system runs in the terminal; a
multiplexed-channel protocol (one channel per window) is used to
communicate with the host computer; a (user-mode) multiplexer program
on the host passes data for each channel to and from an appropriate
local process (group), one per channel. Creating a new window in
the terminal tells the multiplexer to create a new process in the host.
By default the window is just a terminal (and the process is a shell),
but it is possible for a host program to download a program into the
terminal (where it can get at the screen and mouse directly) to act
on its behalf just for its own window; that's how graphical programs
work. This often requires programs to be split into front and back
ends, but often that turns out to be a good idea anyway, keeping
user-interface work and file-manipulation and computation separate.
It also means much less communication bandwidth is needed; in fact
the communication line is RS232 (what else would you expect in 1982?).
It worked fine, even at 1200 bps, except when a large graphical front-
end program had to be loaded, but people tended to load such programs
once and keep them running.
I've been using this window system more or less daily since August 1984,
though only at home since I left Bell Labs in 1990. (I am using it to
type this message.) It is Spartan by modern standards--menus are short
and to-the-point, windows are not surrounded by fancy borders and icons,
there is no `desktop' or `graphical user environment'--it's just good
old UNIX in multiple windows, with a terminal window that makes good use
of the mouse for local editing, and provision to run fancier programs
when necessary. It wouldn't work well for graphics-heavy work unless
the communication line could be greatly sped up--a web browser would be
hard to make work well unless all the pictures were left out. But it's
well thought out, with a nice balance between spareness and function. I
still like it better than any other window system I've seen; even Rob's
more recent work in Plan 9 seems to me over-elaborate by comparison. I
also like much better the overall model that the terminal is a client
rather than a server; X11 always seemed inside-out to me.
I am still disappointed that the process of turning the Blit from a
research tool to a salable product was botched so badly. If memory
serves, not only did it take several years longer than it should have
done, but when the 5620 hit the streets in early 1984 it cost a mere
$6000, which even in those days was outrageous for a terminal. (None
of this was Rob's fault so far as I know.) If things had gone better,
the UNIX windowing world might have turned out quite different.
Norman Wilson
Toronto ON
check out this old post I found on Google Groups.
this kind of stuff makes me giddy. :-)
-=-=-=-
Message-ID: <bnews.mit-vax.149>
Newsgroups: net.sources
X-Path: utzoo!decvax!harpo!eagle!mit-vax!mp
From: mit-vax!mp
Date: Tue Jun 29 08:07:31 1982
Subject: C coding standards
X-Google-Info: Converted from the original B-News header
Posted: Sun Jun 27 18:24:20 1982
Received: Tue Jun 29 08:07:31 1982
In my message in net.misc about coding standards, I offered to
send out the Stanford Network Graphics project's C style sheet.
Since almost everyone who responded to my query requested a copy
of that document, I decided to post it to the net.
In fact, thanks to JBrookshire@USC-ECLB, I now have 3 different C style
standards to give you. Each is separated by a line of "*********"s.
Mark Plotnick, MIT
************************************************
INGRES CODING CONVENTIONS FOR C/UNIX PROGRAMMING
University of California, Berkeley
"The Ingres data base system encompasses about 75,000 lines of code
in the programming language `C' and runs on top of the Unix operating system.
Over the past six years, Ingres has evolved into a functionally complete and
usable prototype. Development required 25 to 30 programmer-years by a total
of 19 people, and the systems is now in use at over 125 sites around the world."
Allman, Eric.; and Stonebreaker, Michael "Observations on the
Evolution of a Software System." COMPUTER 15, 6 (June 1982),
27-32.
The following represents the current C coding conventions that have
evolved from and during the development of the Ingres system. This document
has been provided by Joe Kalash of Berkeley <INGVAX.kalash at Berkeley> in
response to a general enquiry distributed via Arpanet BBOARDS.
/*
** CODE_CNVNTNS.C -- A Program to Display the INGRES Coding Style
**
** This hunk of code does virtually nothing of use. Its main
** purpose is to demonstrate the "official" ingres coding style.
**
** This demonstrates comments. There should be a block comment
** at the beginning of every file and/or procedure to explain
** the function of the code. Important information to put here
** includes the parameters of the routines, any options that the
** user may specify, etc.
**
** The first line of the comment should be a one-line description
** of what's going on. The remainder should be more detailed.
** Blank lines should seperate major points in the comments. In
** general, ask yourself the question, "If I didn't know what this
** code was, what it was for, how it fit in, etc., and if I didn't
** even have the documentation for it, would these comments be
** enough for me?"
**
** Some general guidelines for the code:
**
** ***** GENERAL SYNTAX *****
**
** - Commas and semicolons should always be followed by a space.
** Binary operators should be surrounded on both sides by
** spaces. Unary operators should be in direct contact
** with the object that they act on, except for "sizeof",
** which should be seperated by one space.
**
** - Two statements should never go on the same line. This includes
** such things as an if and the associated conditionally
** executed statement.
** In cases such as this, the second half of the if
** should be indented one tab stop more than the if. For
** example, use:
** if (cond)
** statement;
** never:
** if (cond) statement;
** or:
** if (cond)
** statement;
**
** - Braces ({}) should (almost) always be on a line by them-
** selves. Exceptions are closing a do, and terminating
** a struct definition or variable initialization. Braces
** should start at the same indent as the statement with
** which they bind, and code inside the braces should be
** indented one stop further. For example, use:
** while (cond)
** {
** code
** }
** and never:
** while (cond)
** {
** code
** }
** or:
** while (cond) {
** code
** }
** or:
** while (cond)
** {
** code
** }
** or anything else in that line. Braces which match
** should always be at the same tab stop.
**
** - Do statements must always be of the form:
** do
** {
** code;
** } while (cond);
** even if "code" is only one line. This is done so that
** it is clear that the "while" is with a do, rather than
** a standalone "while" which is used for the side effects of
** evaluation of the condition.
**
** - There should always be a space following a keyword (i.e.,
** for, if, do, while, switch, and return), but never
** between a function and the paren preceeding its
** arguments. For example, use:
** if (i == 0)
** exit();
** never:
** if(i == 0)
** exit ();
**
** - Every case in a switch statement (including default) should
** be preceeded by a blank line. The actual word "case" or
** "default" should have the indent of the switch statement plus
** two spaces. It should be followed by a space (not a
** tab) and the case constant. Multiple case labels on
** a single block of code should be on seperate lines, but
** they should not be seperated by blank lines. The
** switch statement should in general be used in place of
** such constructs as:
if (i == 1)
** code1;
** else if (i == 34)
** code2;
** else if (i == -1643)
** code3;
** which can be more succinctly stated as:
** switch (i)
** {
** case 1:
** code1;
** break;
**
** case 34:
** code2;
** break;
**
** case -1643:
** code3;
** break;
** }
** In point of fact the equivalent switch will compile
** extremely efficiently. (Note that if you had some
** instance where you could not use a case, e.g., checking
** for i < 5, else check for j > 3, else whatever, then
** the above ("if") code is in the correct style. However,
** if (i < 5)
** code1;
** else
** if (j > 3)
** code2;
** else
** code3;
** is acceptable.
**
** - A blank line should seperate the declarations and the code
** in a procedure. Blank lines should also be used freely
** between major subsections of your code. The major
** subsections should also have a block comment giving
** some idea of what is about to occur.
**
** ***** PREPROCESSOR USAGE *****
**
** - Fields of #defines and #includes should line up. Use:
** # define ARPA 25
** # define MAXFIELDS 18
** and not:
** #define ARPA 25
** #define MAXFIELDS 18
** Conditional compilation (#ifdef/#endif) should be used
** around all trace information, timing code, and code
** which may vary from version to version of UNIX. See
** the code below for an example of conditional compila-
** tion use.
**
** ***** VARIABLES AND DECLARATIONS *****
**
** - Defined constants (defined with the # define feature) must
** be entirely upper case. The exceptions to this are
** compilation flags, which begin with a lower case "x",
** and some sub-types for parser symbols. In any case,
** the majority of the symbol is upper case.
**
** - Global variables should begin with an upper case letter and
** be otherwise all lower case. Local symbols should be
** entirely lower case. Procedure names are all lower
** case. The only exception to this is the trace routine
** "tTf". You should avoid user non-local symbols (globals
** or # define'd symbols) which are one character only;
** it is impossible to distinguish them. Capitalization
** may be used freely inside global names so long as they
** are primarily lower case; for example, "ProcName" is
** an acceptable name (and preferred over either Proc_name
** or Procname).
**
** - Use descriptive variable names, particularly for global var-
** iables. "IEH3462" tells me nothing; nor does "R". On
** the other hand, "Resultid" tells me quite a lot,
** including what it might be, where I might go to see
** how it is initialized, etc. Try not to use variables
** for multiple purposes. Variable names like "i" are
** acceptable for loop indices & temporary storage
** provided that the value does not have long-term
** semantic value.
**
** - When the storage structure or type of a variable is
** important, always state it explicitly. In particular,
** include "auto" if you are going to take the address
** of something using the ampersand operator (so that
** some wayward programmer doesn't change it to register),
** and declare int parameters as int instead of letting
** them default.
**
** ***** GENERAL COMMENTS *****
**
** - It is quite possible to name a file "printr.c" and then
** put the code for "destroydb" in it. Try to arrange
** the names of your files so that given the name of a
** routine, it is fairly easy to figure out which file
** it is in.
**
** - Sometimes it is really pretty much impossible to avoid doing
** something tricky. In these cases, put in a comment
** telling what you are doing and why you are doing it.
** - Try to write things that are clear and safe, rather than
** things which you think are easier to compile. For
** example, always declare temporary buffers as local,
** rather than as global. This way you can another
** routine accidently when it still had useful info
** in it.
**
** ***** COMMENTS *****
**
** - The importance of comments cannot be overemphasised.
** INGRES is primarily a research vehicle rather than
** a program product. This means that there will be
** many people pouring over your code, trying to
** understand what you have done & modify it to do
** other things. Try to make life easy for them &
** maybe they will be nice to you someday.
**
** - Try to keep an idea of the flow of your program. Put
** block comments at the beginning of major segments,
** and use one-line comments at less major junctures.
** A person viewing your code at ten paces should be
** able to tell where the major segments lay.
**
** - The preferred format for block comments is to begin with
** a line containing slash-star alone, followed by a
** number of lines all beginning star-star containing
** the comment, and terminating with a line containing
** star-slash alone. Comments without the double-star
** at the beginning of each line should be avoided,
** since it makes the comments seemingly disappear into
** the body of the code.
**
** - The beginning of each routine should have a comment block
** in parametric form as demonstrated below. The fields
** "Parameters", "Returns", and "Side Effects" should
** be considered mandatory. Mark parameters as being
** (IN), (IN/OUT), or (OUT) parameters, depending on
** whether the parameter is used only to transmit infor-
** mation into the routine, in and out of the routine,
** or only to return information; the default is (IN).
**
** Remember, it is easy to write totally incomprehensible code in
** C, but we don't go in for that sort of thing. It isn't too
** much harder to write brilliantly clear code, and the code is
** worth a lot more later.
**
** For efficiency reasons, you should always use register variables
** when possible. A simple and extremely effective tip is to define
** a register variable, and assign an oft-used parameter to it,
** since it is particularly inefficient to reference a parameter.
** Another particularly inefficient operation is referencing arrays
** of structures. When possible, define a register pointer to the
** structure, and then say:
** struct xyz structure[MAX];
** register struct xyz *p;
** ...
** for (i = 0; i < MAX; i++)
** {
** p = &structure[i];
** p->x = p->y + p->z;
** (diddle with p->???)
** }
** and not:
** struct xyz structure[MAX];
** ...
** for (i = 0; i < MAX; i++)
** {
** Structure[i].x = Structure[i].y + Structure[i].z;
** (diddle with Structure[i].???)
** }
** Remember, the nice things about register variables is that they
** make your code smaller and they run faster. It is hard to
** lose with registers. There are three restrictions which you
** should be aware of on register variables, however. First,
** The only types which may be registers are int's, char's,
** and pointers. Second, there may only be three register
** variables per subroutine. Third, you may not take the address
** of a register variable (i.e., you may not say "&i" if i is
** typed as a register variable).
**
** Usage:
** example [flags] argument
**
** Positional Parameters:
** argument -- this gets echoed to the standard
** output.
**
** Flags:
** -n -- don't put a newline at the end.
** -x -- don't do anything.
** -b -- echo it with a bell character.
**
** Return Codes:
** 0 -- successful
** else -- failure
**
** Defined Constants:
** XEQ1 -- maximum number of simultaneous equijoins.
**
** Compilation Flags:
** xTRACE -- enable trace information
**
** Trace Flags:
** 5 -- general debug
** 6 -- reserved for future use
** Compilation Instructions:
** cc -n example.c
** mv a.out example
** chmod 755 example
**
** Notes:
** These comments don't apply to the code at all,
** since this is just an example program.
** Also, it is wise to avoid this many comments
** except at the head of main programs and
** at the head of major modules. For example,
** this sort of commenting is appropriate at
** the top of ingres.c (system startup) and
** view.c (virtual view subsystem), but not
** in small utility routines, e.g., length.c.
** This sort of routine should be limited to
** "Parameters:", "Returns:", "Side Effects:",
** and anything else that seems relevant in
** that context.
** A fairly large comment block should exist at the
** top of modules [files] which contain many
** procedures; this block should clarify why
** the procedures are grouped together, that
** is, their common purpose in life. A small
** block should occur at the top of each
** procedure explaining details of that proce-
** dure.
** Procedures should be on seperate pages (use the
** form feed character, control-L).
** A program will help you generate this comment block.
** In ex, go to the line where you want to insert
** a block and say "so /mnt/ingres/comment". It
** will ask you for a block type, e.g., "main"
** for main program, "modfn" for a file which
** contains only one function, "function" or
** "procedure" for a procedure within a module,
** "module" for a module header (e.g., as a
** seperate comment block for a major module
** [check .../qrymod/view.c for an example] or
** in header files.
** SCCS should be considered an essential tool, if only
** to maintain history fields.
**
** Deficiencies:
** It should handle pseudo tty's.
*/
/* the following macro is defined by <sccs.h> */
SCCSID(%W%); /* %W% is replaced by a version number by SCCS */
# define XEQ1 5
struct magic
{
char *name; /* name of symbol */
int type; /* type of symbol, defined in symbol.h */
int value; /* optional value. This is actually
* the value if it is type "integer",
* a pointer to the value if it is a
* string. */
};
struct magic Stuff;
main(argc, argv)
int argc;
char *argv[];
{
register struct magic *r;
register int i;
register int j;
int timebuf[2];
auto int status;
/*
** Note that in the declarations of argc and argv above, all
** parameters to any function should be declared, even if they
** are of type int (which is the default).
*/
r = &Stuff;
/* initialize random # generator */
time(timebuf);
srand(timebuf[1]);
/* scan Stuff structure */
for (i = 0; i < XEQ1; i++)
{
# ifdef xTRACE
if (tTf(5, 13))
printf("switch on type %d\n", r->reltype);
# endif
switch (r->type)
{
case 0:
case 1:
case 3:
/* initialize */
printf("hi\n");
break;
case 2:
/* end of query */
printf("bye\n");
break;
default:
/*
** be sure to print plenty of info on an error;
** "syserr("bad reltype");" would not have been
** sufficient. However, don't make syserr's
** overly verbose; they take much space in the
** object module, and it will probably be
** necessary to look at the code anyway.
*/
syserr("main: bad type %d", r->type);
}
}
/* resist the temptation to say "} else {" */
if (i == 5)
{
i++;
j = 4;
}
else
i--;
/* plot the results */
do
{
i = rand() & 017;
plot(i);
} while (j--);
/* wait for child processes to complete */
wait(&status);
/* end of run, print termination message and exit */
for (i = 0; i < 2; i++)
printf("bye ");
printf("\n");
}
** PLOT -- Plot a Bar-Graph
**
** Does a simple plot on a terminal -- one line's worth.
**
** Parameters:
** n (IN) -- number of asterisks to plot
**
** Returns:
** none
**
** Side Effects:
** none
**
** Deficiencies:
** Should allow scaling.
*/
plot(n)
int n;
{
register int i;
for (i = n; i-- > 0; )
{
printf("*");
}
printf("\n");
}
**************************************************************************
BBN PROGRAMMING STANDARDS FOR C
The following document was provided by Dan Franklin <DAN at BBN=UNIX>
in response to a general enquiry distributed to Arpanet BBOARDS:
Here's a short set of guidelines that represents a combination
of the thoughts of two groups within BBN. I was its last editor.
Hope you find it useful. If you come across something more
comprehensive (which this certainly isn't), I'd appreciate it
if you let me know.
PROGRAMMING STANDARDS AND PRACTICES
FOR THE UNIX COST CENTER
This memo proposes a set of practices that might be followed in
the cost center, in order to have a consistently organized and
written, readable, understandable, and ultimately maintainable
software package. Qualifying each of the items below is an (S)
or (P): the former indicates that, once agreed-upon, the rule
must be adhered to rigorously and consistently--a Standard; the
latter items are more of the flavour of "good programming
Practice"--once agreed-upon, programmers should follow the
practice to the extent that common sense dictates.
1. DOCUMENTATION OF ROUTINE INTERFACES
(S) Every routine should be prefaced by a standard header
which describes the routine and its interface precisely, so that
the routine could be used by someone without reading the code.
The rationale for such a header is that it concentrates the critical document-
ation in one place, making it easy for someone (including the original
designer/coder) to use the routine correctly, and allows for the possibility
of automatically stripping off all headers to form an Internal Documentation
document.
In some cases a routine may do a small amount of processing and then
call another routine. (As an example, a routine may provide a
"special case" interface to another more general routine with
a more cumbersome calling sequence.) In this case, a routine's header
may refer the reader to the header of another routine for further information.
The format suggested is illustrated below: comments are surrounded by
< > symbols. Any item that is irrelevant, e.g., no parameters,
no return value, no error conditions, may be omitted.
/*------------------------ E P R I N T -----------------------------------*/
/* <a brief description of the routine...also, put the routine name in
* caps in the line above. The description should give, in general
* terms, the routine's function, including an overall description of its
* parameters, return values, and effect on global databases. It should also
* describe any error conditions that may occur and be reflected to the
* caller. The return value must be described precisely.>
*/
int eprint(estrucp, istart, ilength)
struct estruct *estructp; /* Pointer to eprint's structure */
int istart; /* Place in structure to start from */
int ilength; /* # things in struct to print */
{
}
Note that each parameter gets its own declaration line, and has a
comment to convey its exact meaning.
Each file in a program or subsystem consisting of multiple files
should start with some additional information, giving (essentially)
the justification for putting all these routines in one file.
That is, it should include a description of the common function
they all perform, the related functions they all perform, the database
they have in common and which is contained only in this file, etc.
In the last case, especially, a detailed description of the database
should be included; otherwise, since the database is not part of any
one routine, it will not get described in any other comment field.
The detailed description may require reading comments associated
with the actual declarations in order to be complete.
This header should include a history list describing all modifications
to functions in this file. Each entry in the list should give the
person, the date, the names of the functions (or database elements)
changed, and the reasons.
For the file containing the main routine of a program, the following
standards should be observed:
1. The main routine should be the first routine in the file.
2. Before the main routine should appear an overall comment field
describing the calling sequence in some detail. Generally, the
program will also be described in a manual page as well; this
comment field need not duplicate the entire contents of the
manual page, but it should include information about the overall
structure of the program which would be useful to a maintainer.
3. The main routine should exit by calling exit(0) explicitly.
All programs, however, must return an exit status of zero on success,
and nonzero on error.
2. FORMATTING
(S) All programs must be indented, at least 4 spaces per
indentation level. Statements at the same nesting level should
be at the same indentation level; statements at deeper nesting
levels should be indented more. (For the purposes of this
standard, the keyword "else" is regarded as having the same
nesting level as the "if" it corresponds to.) For example, the
following indentation practices are not permitted:
if (condition)
statement-group;
if (condition)
statement-group; else
statement-group;
if (condition)
for (init; test; step)
statement-group;
if (condition) statement-group;
else statement group;
(S) Nesting the trinary conditional operator (?:) is not permitted.
(P) For internal formatting and indenting style, the following is recommended:
. 4-space indentations at each level;
. braces delineating blocks used in the style of
if (exp)
{
code
}
or
if (exp)
{
code
}
. a separate declaration statement for each pointer,
due to the confusion that can arise when reading
and modifying a declaration like
char *a, b, *c;
. comments lined up systematically;
. spaces between reserved words and their opening parentheses,
e.g., if (condition) rather than if(condition);
. no deep nesting (greater than 4 levels deep)
. statement blocks less than 1 page long
. one statement per line
. parentheses around the objects of sizeof and return.
(P) Concerning internal comments:
. Full English sentences are recommended.
. It is often clearer and more readable to make
small blocks of comments as "paragraph headers" to a block of
code than to comment every line or so, especially if the code
is straightforward and untricky (which most of it should be,
especially if the programmer is conscientious about variable
naming and datatype compatibility).
. Anything non-obvious should be well-commented.
(P) Concerning white space and other aids to readability and debugging:
. blank lines should be used between blocks of code that are
functionally distinct
. in expressions, operators should be surrounded by blanks
(but not operators which compose primaries, specifically
".", "->")
. in a function definition, the function name and its datatype
should appear on one line. Examples:
int pread(...)
SOMESTRUCT * function(param1, param2)
This latter practice aids readability and the comparison of
the definition of a routine with its uses.
(P) Other suggestions for improving readability:
. Side effects within expressions should be used sparingly.
It is recommended that no more than one operator with a side
effect (=, op=, ++, --) appear within an expression. Function
calls with side effects count as operators for this purpose.
. In an "if-else" chain, the form
if (condition)
statement;
else if (condition)
statement;
else if (condition)
statement;
should only be used when the conditions are all of the same basic
form: e.g., testing the same variable against different values.
If the conditions are qualitatively different, the additional
"if" statements should start on new lines, indented, as in
if (cond)
statement;
else
if (cond2)
statement;
else
statement;
. In the condition portion of an if, for, while, etc., side effects
whose effect extends beyond the extent of the guarded statement
block should be minimized. That is, in a block like
if ((c = getc(file)) != EOF)
{
guarded-stmts
}
other-stmts
it is natural to think of "c" being "bound" to a value only within
the guarded-stmts; use of a variable set or modified in a condition,
outside the range of the statements guarded by the condition, is
quite distracting.
. The use of || and && with right hand operands having side effects
is discouraged. Also, whenever || and && are mixed in the same
expression, parentheses should be used for clarity.
3. MODULARITY
3.1. Routine Length
(P) Routines should be kept reasonably short. In general, a routine
(or command) processes one or more inputs and generates one or
more outputs, where each of the inputs and outputs can be concisely
described. Usually a routine should only perform one function. Signs
that a routine is too long, and ought to be split up, are: length
greater than two pages; heavy use of "internal" variables (variables
whose scope is less than the entire routine).
3.2. Shared Data and Include Files
(S) Declarations of variables that are to be shared among several routines
in a package should be placed at the beginning of the file containing
the routines. If they are entirely internal to the package, they should
be declared "static" to hide them from other files.
(S) Declarations of structures and global variables used for communications
between a package and its callers should be placed in an appropriately
named .h file. Shared global variables should be declared extern in the
.h file so that if the package which sets/uses them is accidentally not
loaded, a diagnostic will be issued by the loader.
(S) Definition and optional initialization of such globals should reside in
one and only one file for each program. If a global is clearly associated
with a specific package, it may be defined in the file for that package;
otherwise, it should be placed in a file called data.c which is
compiled and linked with the other routines when a program is
being built.
(P) Use of globals should be minimized by judicious use of parameters.
Note that while static and extern designators in C both yield "common"
storage allocation, static allows the named variable to be known only
within the context in which it is declared; thus, an identifier declared
static at the top of a file will only be known within the file.
In addition, local symbolic constants (#defines) may occur anywhere within
a routine, and may be placed below the #include directives if the writer
feels that this aids readability.
(S) Include files should contain all and only all of the following items
necessary for a given program and shared among two or more of its files:
. #defines
. typedefs
. extern declarations
(S) Include files may also contain nested #include directives. However, this
practice should be kept to a minimum. It is recommended that
include files which may be embedded in this way contain a check
to see whether they are being included twice, to avoid unnecessary
preprocessor and compiler complaints when the user includes them
both implicitly and explicitly. The simplest way to do this is to
check for a special hidden #define, as in
#ifdef _INCLUDEFILENAME
#define _INCLUDEFILENAME
.
. Contents of include file
.
#endif _INCLUDEFILENAME
3.3 Routine interfaces
(P) In general, a routine should be designed with a "natural",
easily-remembered calling sequence. Routines with more than
five arguments are not recommended. Routines with "op-code"
arguments, where one argument determines the interpretation
and functions of the others, are also not recommended (though
they may prove useful as internal routines to a package,
they should NOT be part of a package's documented interface).
4. PORTABILITY
(P) Adherence to datatype compatibility should be practiced where
reasonable. This can be facilitated by liberal use of C's typedef
facility and explicit casting of types, as well as by the
use of the union datatype.
(P) The following violation of strict adherence is permitted: a package
which returns a pointer to a structure whose format need not be known
outside that package may return a "generic" pointer, of type (char *).
It is recommended that the typedef PTR be used for this purpose; this
typedef will be provided in some standard system file. Note that char*
is specifically chosen because the language guarantees that any pointer
may be converted to a char* and back again without harm.
(S) Liberal use of #defines should eliminate "magic numbers", whether
machine dependent or implementation dependent or arbitrary/random.
(S) To the extent that the conditional compilation facility of C allows, non-
portable constructions can use this facility. Failing this, machine or
implementation dependent constructs should be visibly commented in the
code.
When using conditional compilation for portability purposes, be sure
to use appropriate parameters, rather than machine type, wherever
possible. For example, code which handles the C machine's 20 bit wordsize
or 10 bit bytesize should use the parameter BYTESIZE in cpu.h rather
than being ifdeffed on "mbb".
(P) Up to six register variables can be declared (with some effect)
on the C70 machine, but only three on the 11/70 (where additional ones
are assigned regular automatic storage). Therefore, the first three
register variables declared (in lexicographic order) should be ones
for which the most gain can be gotten.
Note that register variables, judiciously chosen, can be very good space/time
savers, but the compiler is not overly smart about them, and can give you
irritating "expression overflow" messages. In general, as with any
"optimization", it is wise to design, code and debug first, and then add in
register storage to one's declarations.
5. NAMING
(P) Names should be chosen for their mnemonic nature. Recall that although
there is a limit on the number of initial characters of a name that must
be distinct in C (and for a given machine), this does not prevent any
name from being longer if such length will aid readability.
(S) It is a useful C convention to use upper-case for #defines and typedef
names.
(S) One exception to the above is for parameterized #defines.
These may be in lower-case.
**************************************************************************
The following was provided via FTP by Keith A. Lantz at Stanford
<CSL.LANTZ at SU-SCORE> via FTP following the enquiry distributed via
Arpanet BBOARDS.
1
NETWORK GRAPHICS C STYLE SHEET
Andrew Shore, et al.
Computer Systems Laboratory
Stanford University
Stanford, CA 94305
18 June 1982
1. Names
Don't use capital letters in file names (except for V !?).
Avoid the underscore.
Global variables, procedures, structs, unions, typedefs, defined constants,
and macros all begin with a capital letter, and are logically capitalized
thereafter (e.g. MainHashTable). A global variable is one defined outside a
procedure, even though it may not be exported from the file, or an external
variable. The motivation for treating macros and constants this way is that
they may then be freely changed to procedure calls or (global or external)
variables.
Local variables begin with a lower-case letter, but are logically capitalized
thereafter (e.g. bltWidth, power, maxSumOfSquares). Fields within structures
or unions are treated in this manner also.
2. Comments
There are generally two types of comments: block-style comments, and on-the-
line comments. Multi-line, block-style comments will follow the UNIX style of
/* and */ appearing on lines by themselves, and the body of the comment will
start with a properly aligned *. The comment should usually be surrounded by
blank lines as well. The motivation for this is that it is easy to add/delete
first and last lines, and it is easier to detect the common error of omitting
the */ and thus including all code up to and including the next */ in a comment
(Yapp helps with that too).
/*
* this is the first line of a multi-line comment,
* this is another line
* the last line of text
*/
On-line comments are used to detail declarations, and to explain single lines
of code. And, I suppose, for brief (i.e. one line) block-style descriptive
comments.
1
This work was supported by the Defense Advanced Research Projects Agency
under contract number MDA903-80-C-0102.
2
Procedures are preceded by block-style comments, explaining their (abstract)
function in terms of their parameters, results, and side effects. Note that
the parameter declarations are indented, not flushed left.
/*
* Unblock:
* unblock the process pd
*/
Unblock( pd )
register Process pd; /* the process to unblock */
{
register Process *currPd,
*tmpPd;
register unsigned prio;
prio = pd->priority;
Disable;
pd->state = Ready;
/* Add pd to the ready queue */
currPd = (Process *) &ReadyqHead;
while ((tmpPd = currPd->link) != Null)
{
if (tmpPd->priority > prio)
break;
currPd = tmpPd;
}
pd->link = tempPd;
currPd->link = pd;
Enable;
}
3. Indenting
The above example shows many of the indenting rules. Braces ( "{" and "}" )
appear alone on a line, and are indented two spaces from the statement they are
to contain the body of, the body is indented two more spaces from the braces
(for a total of four spaces). else's and else if's line up with their
dominating if statement (to avoid marching off to the right, and to reflect the
semantics of the statement).
3
if ((x = y) == 0)
{
flag = 1;
printf (" the value was zero ");
}
else if (y == 1)
{
switch (today)
{
case Thursday:
flag = 2;
ThursdayAction();
break;
case Friday:
flag = 3;
FridayAction();
break;
default:
OtherDayAction();
}
}
else
printf(" y had the wrong value ");
4. File Contents
I think we agreed on the following order for file contents.
1. initial descriptive comment (see example below) which contains:
a. file name, with indication of the relative path to it when
relevant
b. brief descriptive abstract of contents
c. a list of all defined procedures in their defined order
d. list of authors
e. list of current maintainers
f. list of recent and major modifications in reverse
chronological order with indication (initials) of who made the
change.
2. included files (use relative path names whenever possible)
3. external definitions (imports and exports)
4. function declarations (externals and forward references)
4
5. constant declarations
6. macro definitions
7. type definitions
8. global variable declarations
9. procedure and function definitions
Here is an example of the header comment:
/*
* FILE: libc/vkstuff/malloc.c
*
* CONTENTS:
* C storage allocator stolen and hacked up from UNIX for the SUN
* (NOTE: these were stolen and have the wrong naming conventions)
* malloc
* free
* realloc
* allock DEBUG ONLY!
* SetBrk ! our routine to fake up sbrk()
*
* AUTHORS: stolen and hacked by Andrew I. Shore (shore)
*
* MAINTAINER: shore
*
* HISTORY:
* 03/05/82 AIS replaced calls to UNIX sbrk() with calls to own version
* SetBrk() for the sun/Vkernel
*/
5. Parenthesis ()
We seem to have decided on the following conventions for parentheses. When
parentheses enclose the expression for a statement (if, for, etc.), the
parentheses `belong to' the expression, so there is a space between the keyword
and the parenthesized expression. For function calls the parentheses `belong
to' the call, so there is no space between function name and open paren (there
may some inside the parentheses to make the expression list (argument list)
look nice).
if (Mumble())
{
Grumble( (a = b) == 0 );
return (Nil);
}
else
{
Fumble( a, b, c );
return (ToSender);
}
5
It is unclear what to do with return. Note, then, that it is operators that
cause spaces on the outside of parentheses -- (a + b) * c.
6. General
1. One statement/declaration per line.
2. Make judicious use of blank lines.
a. At least 3 blank lines between individual procedures.
b. Blank lines surround "large" comments.
3. Make sure comments and code agree!
4. Don't just echo the code with comments -- make every comment count!
i.e. nix on:
/* add foo to bar */
bar += foo;
i
Table of Contents
1. Names 1
2. Comments 1
3. Indenting 2
4. File Contents 3
5. Parenthesis () 4
6. General 5
**************************************************************************
-------
Date: 27 Jun 1982 11:48:50-PDT
From: mo at LBL-UNIX (Mike O'Dell [system])
To: JSol at USC-ECLC
cc: Header-People at MIT-MC
Subject: Re: Unexplored Topic -- Length of Mail Message
In-reply-to: Your message of 25 Jun 1982 1715-PDT (Friday).
Yes indeed mail can be BIG!! If you don't have FTP to some
random system (again, not ARPAnet, most likely), but DO have
mail, you do a LOT with it, like abuse it into make-do FTP.
It is crass, but it beats not getting the bits there!
This can often be the case with site 2 networks away in
the internet (note small "i").
While this shouldn't impact ARPAnet sites too much, if 733 is
indeed something the larger world might look to for guidance,
I would advocate JSol's position: Mail is another form of
machine-machine communications, complete unto itself.
As an example, the "net.sources" news topic on USENET
routinely posts fixes and entire source listings of quite
complex programs; and this is on a network with 300 or 1200 baud
hop-by-hop links!! I am not saying this is the ulitimate solution,
or that we should advocate such things, but it does indicate
the tremendous utility of Mail in reducing the isolation of
sites.
-Mike
Date: 27 Jun 1982 0929-PDT
From: JBROOKSHIRE at USC-ECLB
Subject: Re: C programming standards
To: mp at MIT-MC
In response to your message sent Saturday, 26 June 1982, 23:56-EDT
Thanks for the note - if you have any pointers it might help. I have received
three pretty good sets of stuff that I am enclosing here if you are interested.
They are separated by lines of ******** which you can search on if you just
want to read the sources of each.
Regards,
Jerry Brookshire
INGRES CODING CONVENTIONS FOR C/UNIX PROGRAMMING
University of California, Berkeley
"The Ingres data base system encompasses about 75,000 lines of code
in the programming language `C' and runs on top of the Unix operating system.
Over the past six years, Ingres has evolved into a functionally complete and
usable prototype. Development required 25 to 30 programmer-years by a total
of 19 people, and the systems is now in use at over 125 sites around the world."
Allman, Eric.; and Stonebreaker, Michael "Observations on the
Evolution of a Software System." COMPUTER 15, 6 (June 1982),
27-32.
The following represents the current C coding conventions that have
evolved from and during the development of the Ingres system. This document
has been provided by Joe Kalash of Berkeley <INGVAX.kalash at Berkeley> in
response to a general enquiry distributed via Arpanet BBOARDS.
/*
** CODE_CNVNTNS.C -- A Program to Display the INGRES Coding Style
**
** This hunk of code does virtually nothing of use. Its main
** purpose is to demonstrate the "official" ingres coding style.
**
** This demonstrates comments. There should be a block comment
** at the beginning of every file and/or procedure to explain
** the function of the code. Important information to put here
** includes the parameters of the routines, any options that the
** user may specify, etc.
**
** The first line of the comment should be a one-line description
** of what's going on. The remainder should be more detailed.
** Blank lines should seperate major points in the comments. In
** general, ask yourself the question, "If I didn't know what this
** code was, what it was for, how it fit in, etc., and if I didn't
** even have the documentation for it, would these comments be
** enough for me?"
**
** Some general guidelines for the code:
**
** ***** GENERAL SYNTAX *****
**
** - Commas and semicolons should always be followed by a space.
** Binary operators should be surrounded on both sides by
** spaces. Unary operators should be in direct contact
** with the object that they act on, except for "sizeof",
** which should be seperated by one space.
**
** - Two statements should never go on the same line. This includes
** such things as an if and the associated conditionally
** executed statement.
** In cases such as this, the second half of the if
** should be indented one tab stop more than the if. For
** example, use:
** if (cond)
** statement;
** never:
** if (cond) statement;
** or:
** if (cond)
** statement;
**
** - Braces ({}) should (almost) always be on a line by them-
** selves. Exceptions are closing a do, and terminating
** a struct definition or variable initialization. Braces
** should start at the same indent as the statement with
** which they bind, and code inside the braces should be
** indented one stop further. For example, use:
** while (cond)
** {
** code
** }
** and never:
** while (cond)
** {
** code
** }
** or:
** while (cond) {
** code
** }
** or:
** while (cond)
** {
** code
** }
** or anything else in that line. Braces which match
** should always be at the same tab stop.
**
** - Do statements must always be of the form:
** do
** {
** code;
** } while (cond);
** even if "code" is only one line. This is done so that
** it is clear that the "while" is with a do, rather than
** a standalone "while" which is used for the side effects of
** evaluation of the condition.
**
** - There should always be a space following a keyword (i.e.,
** for, if, do, while, switch, and return), but never
** between a function and the paren preceeding its
** arguments. For example, use:
** if (i == 0)
** exit();
** never:
** if(i == 0)
** exit ();
**
** - Every case in a switch statement (including default) should
** be preceeded by a blank line. The actual word "case" or
** "default" should have the indent of the switch statement plus
** two spaces. It should be followed by a space (not a
** tab) and the case constant. Multiple case labels on
** a single block of code should be on seperate lines, but
** they should not be seperated by blank lines. The
** switch statement should in general be used in place of
** such constructs as:
if (i == 1)
** code1;
** else if (i == 34)
** code2;
** else if (i == -1643)
** code3;
** which can be more succinctly stated as:
** switch (i)
** {
** case 1:
** code1;
** break;
**
** case 34:
** code2;
** break;
**
** case -1643:
** code3;
** break;
** }
** In point of fact the equivalent switch will compile
** extremely efficiently. (Note that if you had some
** instance where you could not use a case, e.g., checking
** for i < 5, else check for j > 3, else whatever, then
** the above ("if") code is in the correct style. However,
** if (i < 5)
** code1;
** else
** if (j > 3)
** code2;
** else
** code3;
** is acceptable.
**
** - A blank line should seperate the declarations and the code
** in a procedure. Blank lines should also be used freely
** between major subsections of your code. The major
** subsections should also have a block comment giving
** some idea of what is about to occur.
**
** ***** PREPROCESSOR USAGE *****
**
** - Fields of #defines and #includes should line up. Use:
** # define ARPA 25
** # define MAXFIELDS 18
** and not:
** #define ARPA 25
** #define MAXFIELDS 18
** Conditional compilation (#ifdef/#endif) should be used
** around all trace information, timing code, and code
** which may vary from version to version of UNIX. See
** the code below for an example of conditional compila-
** tion use.
**
** ***** VARIABLES AND DECLARATIONS *****
**
** - Defined constants (defined with the # define feature) must
** be entirely upper case. The exceptions to this are
** compilation flags, which begin with a lower case "x",
** and some sub-types for parser symbols. In any case,
** the majority of the symbol is upper case.
**
** - Global variables should begin with an upper case letter and
** be otherwise all lower case. Local symbols should be
** entirely lower case. Procedure names are all lower
** case. The only exception to this is the trace routine
** "tTf". You should avoid user non-local symbols (globals
** or # define'd symbols) which are one character only;
** it is impossible to distinguish them. Capitalization
** may be used freely inside global names so long as they
** are primarily lower case; for example, "ProcName" is
** an acceptable name (and preferred over either Proc_name
** or Procname).
**
** - Use descriptive variable names, particularly for global var-
** iables. "IEH3462" tells me nothing; nor does "R". On
** the other hand, "Resultid" tells me quite a lot,
** including what it might be, where I might go to see
** how it is initialized, etc. Try not to use variables
** for multiple purposes. Variable names like "i" are
** acceptable for loop indices & temporary storage
** provided that the value does not have long-term
** semantic value.
**
** - When the storage structure or type of a variable is
** important, always state it explicitly. In particular,
** include "auto" if you are going to take the address
** of something using the ampersand operator (so that
** some wayward programmer doesn't change it to register),
** and declare int parameters as int instead of letting
** them default.
**
** ***** GENERAL COMMENTS *****
**
** - It is quite possible to name a file "printr.c" and then
** put the code for "destroydb" in it. Try to arrange
** the names of your files so that given the name of a
** routine, it is fairly easy to figure out which file
** it is in.
**
** - Sometimes it is really pretty much impossible to avoid doing
** something tricky. In these cases, put in a comment
** telling what you are doing and why you are doing it.
** - Try to write things that are clear and safe, rather than
** things which you think are easier to compile. For
** example, always declare temporary buffers as local,
** rather than as global. This way you can another
** routine accidently when it still had useful info
** in it.
**
** ***** COMMENTS *****
**
** - The importance of comments cannot be overemphasised.
** INGRES is primarily a research vehicle rather than
** a program product. This means that there will be
** many people pouring over your code, trying to
** understand what you have done & modify it to do
** other things. Try to make life easy for them &
** maybe they will be nice to you someday.
**
** - Try to keep an idea of the flow of your program. Put
** block comments at the beginning of major segments,
** and use one-line comments at less major junctures.
** A person viewing your code at ten paces should be
** able to tell where the major segments lay.
**
** - The preferred format for block comments is to begin with
** a line containing slash-star alone, followed by a
** number of lines all beginning star-star containing
** the comment, and terminating with a line containing
** star-slash alone. Comments without the double-star
** at the beginning of each line should be avoided,
** since it makes the comments seemingly disappear into
** the body of the code.
**
** - The beginning of each routine should have a comment block
** in parametric form as demonstrated below. The fields
** "Parameters", "Returns", and "Side Effects" should
** be considered mandatory. Mark parameters as being
** (IN), (IN/OUT), or (OUT) parameters, depending on
** whether the parameter is used only to transmit infor-
** mation into the routine, in and out of the routine,
** or only to return information; the default is (IN).
**
** Remember, it is easy to write totally incomprehensible code in
** C, but we don't go in for that sort of thing. It isn't too
** much harder to write brilliantly clear code, and the code is
** worth a lot more later.
**
** For efficiency reasons, you should always use register variables
** when possible. A simple and extremely effective tip is to define
** a register variable, and assign an oft-used parameter to it,
** since it is particularly inefficient to reference a parameter.
** Another particularly inefficient operation is referencing arrays
** of structures. When possible, define a register pointer to the
** structure, and then say:
** struct xyz structure[MAX];
** register struct xyz *p;
** ...
** for (i = 0; i < MAX; i++)
** {
** p = &structure[i];
** p->x = p->y + p->z;
** (diddle with p->???)
** }
** and not:
** struct xyz structure[MAX];
** ...
** for (i = 0; i < MAX; i++)
** {
** Structure[i].x = Structure[i].y + Structure[i].z;
** (diddle with Structure[i].???)
** }
** Remember, the nice things about register variables is that they
** make your code smaller and they run faster. It is hard to
** lose with registers. There are three restrictions which you
** should be aware of on register variables, however. First,
** The only types which may be registers are int's, char's,
** and pointers. Second, there may only be three register
** variables per subroutine. Third, you may not take the address
** of a register variable (i.e., you may not say "&i" if i is
** typed as a register variable).
**
** Usage:
** example [flags] argument
**
** Positional Parameters:
** argument -- this gets echoed to the standard
** output.
**
** Flags:
** -n -- don't put a newline at the end.
** -x -- don't do anything.
** -b -- echo it with a bell character.
**
** Return Codes:
** 0 -- successful
** else -- failure
**
** Defined Constants:
** XEQ1 -- maximum number of simultaneous equijoins.
**
** Compilation Flags:
** xTRACE -- enable trace information
**
** Trace Flags:
** 5 -- general debug
** 6 -- reserved for future use
** Compilation Instructions:
** cc -n example.c
** mv a.out example
** chmod 755 example
**
** Notes:
** These comments don't apply to the code at all,
** since this is just an example program.
** Also, it is wise to avoid this many comments
** except at the head of main programs and
** at the head of major modules. For example,
** this sort of commenting is appropriate at
** the top of ingres.c (system startup) and
** view.c (virtual view subsystem), but not
** in small utility routines, e.g., length.c.
** This sort of routine should be limited to
** "Parameters:", "Returns:", "Side Effects:",
** and anything else that seems relevant in
** that context.
** A fairly large comment block should exist at the
** top of modules [files] which contain many
** procedures; this block should clarify why
** the procedures are grouped together, that
** is, their common purpose in life. A small
** block should occur at the top of each
** procedure explaining details of that proce-
** dure.
** Procedures should be on seperate pages (use the
** form feed character, control-L).
** A program will help you generate this comment block.
** In ex, go to the line where you want to insert
** a block and say "so /mnt/ingres/comment". It
** will ask you for a block type, e.g., "main"
** for main program, "modfn" for a file which
** contains only one function, "function" or
** "procedure" for a procedure within a module,
** "module" for a module header (e.g., as a
** seperate comment block for a major module
** [check .../qrymod/view.c for an example] or
** in header files.
** SCCS should be considered an essential tool, if only
** to maintain history fields.
**
** Deficiencies:
** It should handle pseudo tty's.
*/
/* the following macro is defined by <sccs.h> */
SCCSID(%W%); /* %W% is replaced by a version number by SCCS */
# define XEQ1 5
struct magic
{
char *name; /* name of symbol */
int type; /* type of symbol, defined in symbol.h */
int value; /* optional value. This is actually
* the value if it is type "integer",
* a pointer to the value if it is a
* string. */
};
struct magic Stuff;
main(argc, argv)
int argc;
char *argv[];
{
register struct magic *r;
register int i;
register int j;
int timebuf[2];
auto int status;
/*
** Note that in the declarations of argc and argv above, all
** parameters to any function should be declared, even if they
** are of type int (which is the default).
*/
r = &Stuff;
/* initialize random # generator */
time(timebuf);
srand(timebuf[1]);
/* scan Stuff structure */
for (i = 0; i < XEQ1; i++)
{
# ifdef xTRACE
if (tTf(5, 13))
printf("switch on type %d\n", r->reltype);
# endif
switch (r->type)
{
case 0:
case 1:
case 3:
/* initialize */
printf("hi\n");
break;
case 2:
/* end of query */
printf("bye\n");
break;
default:
/*
** be sure to print plenty of info on an error;
** "syserr("bad reltype");" would not have been
** sufficient. However, don't make syserr's
** overly verbose; they take much space in the
** object module, and it will probably be
** necessary to look at the code anyway.
*/
syserr("main: bad type %d", r->type);
}
}
/* resist the temptation to say "} else {" */
if (i == 5)
{
i++;
j = 4;
}
else
i--;
/* plot the results */
do
{
i = rand() & 017;
plot(i);
} while (j--);
/* wait for child processes to complete */
wait(&status);
/* end of run, print termination message and exit */
for (i = 0; i < 2; i++)
printf("bye ");
printf("\n");
}
** PLOT -- Plot a Bar-Graph
**
** Does a simple plot on a terminal -- one line's worth.
**
** Parameters:
** n (IN) -- number of asterisks to plot
**
** Returns:
** none
**
** Side Effects:
** none
**
** Deficiencies:
** Should allow scaling.
*/
plot(n)
int n;
{
register int i;
for (i = n; i-- > 0; )
{
printf("*");
}
printf("\n");
}
**************************************************************************
BBN PROGRAMMING STANDARDS FOR C
The following document was provided by Dan Franklin <DAN at BBN=UNIX>
in response to a general enquiry distributed to Arpanet BBOARDS:
Here's a short set of guidelines that represents a combination
of the thoughts of two groups within BBN. I was its last editor.
Hope you find it useful. If you come across something more
comprehensive (which this certainly isn't), I'd appreciate it
if you let me know.
PROGRAMMING STANDARDS AND PRACTICES
FOR THE UNIX COST CENTER
This memo proposes a set of practices that might be followed in
the cost center, in order to have a consistently organized and
written, readable, understandable, and ultimately maintainable
software package. Qualifying each of the items below is an (S)
or (P): the former indicates that, once agreed-upon, the rule
must be adhered to rigorously and consistently--a Standard; the
latter items are more of the flavour of "good programming
Practice"--once agreed-upon, programmers should follow the
practice to the extent that common sense dictates.
1. DOCUMENTATION OF ROUTINE INTERFACES
(S) Every routine should be prefaced by a standard header
which describes the routine and its interface precisely, so that
the routine could be used by someone without reading the code.
The rationale for such a header is that it concentrates the critical document-
ation in one place, making it easy for someone (including the original
designer/coder) to use the routine correctly, and allows for the possibility
of automatically stripping off all headers to form an Internal Documentation
document.
In some cases a routine may do a small amount of processing and then
call another routine. (As an example, a routine may provide a
"special case" interface to another more general routine with
a more cumbersome calling sequence.) In this case, a routine's header
may refer the reader to the header of another routine for further information.
The format suggested is illustrated below: comments are surrounded by
< > symbols. Any item that is irrelevant, e.g., no parameters,
no return value, no error conditions, may be omitted.
/*------------------------ E P R I N T -----------------------------------*/
/* <a brief description of the routine...also, put the routine name in
* caps in the line above. The description should give, in general
* terms, the routine's function, including an overall description of its
* parameters, return values, and effect on global databases. It should also
* describe any error conditions that may occur and be reflected to the
* caller. The return value must be described precisely.>
*/
int eprint(estrucp, istart, ilength)
struct estruct *estructp; /* Pointer to eprint's structure */
int istart; /* Place in structure to start from */
int ilength; /* # things in struct to print */
{
}
Note that each parameter gets its own declaration line, and has a
comment to convey its exact meaning.
Each file in a program or subsystem consisting of multiple files
should start with some additional information, giving (essentially)
the justification for putting all these routines in one file.
That is, it should include a description of the common function
they all perform, the related functions they all perform, the database
they have in common and which is contained only in this file, etc.
In the last case, especially, a detailed description of the database
should be included; otherwise, since the database is not part of any
one routine, it will not get described in any other comment field.
The detailed description may require reading comments associated
with the actual declarations in order to be complete.
This header should include a history list describing all modifications
to functions in this file. Each entry in the list should give the
person, the date, the names of the functions (or database elements)
changed, and the reasons.
For the file containing the main routine of a program, the following
standards should be observed:
1. The main routine should be the first routine in the file.
2. Before the main routine should appear an overall comment field
describing the calling sequence in some detail. Generally, the
program will also be described in a manual page as well; this
comment field need not duplicate the entire contents of the
manual page, but it should include information about the overall
structure of the program which would be useful to a maintainer.
3. The main routine should exit by calling exit(0) explicitly.
All programs, however, must return an exit status of zero on success,
and nonzero on error.
2. FORMATTING
(S) All programs must be indented, at least 4 spaces per
indentation level. Statements at the same nesting level should
be at the same indentation level; statements at deeper nesting
levels should be indented more. (For the purposes of this
standard, the keyword "else" is regarded as having the same
nesting level as the "if" it corresponds to.) For example, the
following indentation practices are not permitted:
if (condition)
statement-group;
if (condition)
statement-group; else
statement-group;
if (condition)
for (init; test; step)
statement-group;
if (condition) statement-group;
else statement group;
(S) Nesting the trinary conditional operator (?:) is not permitted.
(P) For internal formatting and indenting style, the following is recommended:
. 4-space indentations at each level;
. braces delineating blocks used in the style of
if (exp)
{
code
}
or
if (exp)
{
code
}
. a separate declaration statement for each pointer,
due to the confusion that can arise when reading
and modifying a declaration like
char *a, b, *c;
. comments lined up systematically;
. spaces between reserved words and their opening parentheses,
e.g., if (condition) rather than if(condition);
. no deep nesting (greater than 4 levels deep)
. statement blocks less than 1 page long
. one statement per line
. parentheses around the objects of sizeof and return.
(P) Concerning internal comments:
. Full English sentences are recommended.
. It is often clearer and more readable to make
small blocks of comments as "paragraph headers" to a block of
code than to comment every line or so, especially if the code
is straightforward and untricky (which most of it should be,
especially if the programmer is conscientious about variable
naming and datatype compatibility).
. Anything non-obvious should be well-commented.
(P) Concerning white space and other aids to readability and debugging:
. blank lines should be used between blocks of code that are
functionally distinct
. in expressions, operators should be surrounded by blanks
(but not operators which compose primaries, specifically
".", "->")
. in a function definition, the function name and its datatype
should appear on one line. Examples:
int pread(...)
SOMESTRUCT * function(param1, param2)
This latter practice aids readability and the comparison of
the definition of a routine with its uses.
(P) Other suggestions for improving readability:
. Side effects within expressions should be used sparingly.
It is recommended that no more than one operator with a side
effect (=, op=, ++, --) appear within an expression. Function
calls with side effects count as operators for this purpose.
. In an "if-else" chain, the form
if (condition)
statement;
else if (condition)
statement;
else if (condition)
statement;
should only be used when the conditions are all of the same basic
form: e.g., testing the same variable against different values.
If the conditions are qualitatively different, the additional
"if" statements should start on new lines, indented, as in
if (cond)
statement;
else
if (cond2)
statement;
else
statement;
. In the condition portion of an if, for, while, etc., side effects
whose effect extends beyond the extent of the guarded statement
block should be minimized. That is, in a block like
if ((c = getc(file)) != EOF)
{
guarded-stmts
}
other-stmts
it is natural to think of "c" being "bound" to a value only within
the guarded-stmts; use of a variable set or modified in a condition,
outside the range of the statements guarded by the condition, is
quite distracting.
. The use of || and && with right hand operands having side effects
is discouraged. Also, whenever || and && are mixed in the same
expression, parentheses should be used for clarity.
3. MODULARITY
3.1. Routine Length
(P) Routines should be kept reasonably short. In general, a routine
(or command) processes one or more inputs and generates one or
more outputs, where each of the inputs and outputs can be concisely
described. Usually a routine should only perform one function. Signs
that a routine is too long, and ought to be split up, are: length
greater than two pages; heavy use of "internal" variables (variables
whose scope is less than the entire routine).
3.2. Shared Data and Include Files
(S) Declarations of variables that are to be shared among several routines
in a package should be placed at the beginning of the file containing
the routines. If they are entirely internal to the package, they should
be declared "static" to hide them from other files.
(S) Declarations of structures and global variables used for communications
between a package and its callers should be placed in an appropriately
named .h file. Shared global variables should be declared extern in the
.h file so that if the package which sets/uses them is accidentally not
loaded, a diagnostic will be issued by the loader.
(S) Definition and optional initialization of such globals should reside in
one and only one file for each program. If a global is clearly associated
with a specific package, it may be defined in the file for that package;
otherwise, it should be placed in a file called data.c which is
compiled and linked with the other routines when a program is
being built.
(P) Use of globals should be minimized by judicious use of parameters.
Note that while static and extern designators in C both yield "common"
storage allocation, static allows the named variable to be known only
within the context in which it is declared; thus, an identifier declared
static at the top of a file will only be known within the file.
In addition, local symbolic constants (#defines) may occur anywhere within
a routine, and may be placed below the #include directives if the writer
feels that this aids readability.
(S) Include files should contain all and only all of the following items
necessary for a given program and shared among two or more of its files:
. #defines
. typedefs
. extern declarations
(S) Include files may also contain nested #include directives. However, this
practice should be kept to a minimum. It is recommended that
include files which may be embedded in this way contain a check
to see whether they are being included twice, to avoid unnecessary
preprocessor and compiler complaints when the user includes them
both implicitly and explicitly. The simplest way to do this is to
check for a special hidden #define, as in
#ifdef _INCLUDEFILENAME
#define _INCLUDEFILENAME
.
. Contents of include file
.
#endif _INCLUDEFILENAME
3.3 Routine interfaces
(P) In general, a routine should be designed with a "natural",
easily-remembered calling sequence. Routines with more than
five arguments are not recommended. Routines with "op-code"
arguments, where one argument determines the interpretation
and functions of the others, are also not recommended (though
they may prove useful as internal routines to a package,
they should NOT be part of a package's documented interface).
4. PORTABILITY
(P) Adherence to datatype compatibility should be practiced where
reasonable. This can be facilitated by liberal use of C's typedef
facility and explicit casting of types, as well as by the
use of the union datatype.
(P) The following violation of strict adherence is permitted: a package
which returns a pointer to a structure whose format need not be known
outside that package may return a "generic" pointer, of type (char *).
It is recommended that the typedef PTR be used for this purpose; this
typedef will be provided in some standard system file. Note that char*
is specifically chosen because the language guarantees that any pointer
may be converted to a char* and back again without harm.
(S) Liberal use of #defines should eliminate "magic numbers", whether
machine dependent or implementation dependent or arbitrary/random.
(S) To the extent that the conditional compilation facility of C allows, non-
portable constructions can use this facility. Failing this, machine or
implementation dependent constructs should be visibly commented in the
code.
When using conditional compilation for portability purposes, be sure
to use appropriate parameters, rather than machine type, wherever
possible. For example, code which handles the C machine's 20 bit wordsize
or 10 bit bytesize should use the parameter BYTESIZE in cpu.h rather
than being ifdeffed on "mbb".
(P) Up to six register variables can be declared (with some effect)
on the C70 machine, but only three on the 11/70 (where additional ones
are assigned regular automatic storage). Therefore, the first three
register variables declared (in lexicographic order) should be ones
for which the most gain can be gotten.
Note that register variables, judiciously chosen, can be very good space/time
savers, but the compiler is not overly smart about them, and can give you
irritating "expression overflow" messages. In general, as with any
"optimization", it is wise to design, code and debug first, and then add in
register storage to one's declarations.
5. NAMING
(P) Names should be chosen for their mnemonic nature. Recall that although
there is a limit on the number of initial characters of a name that must
be distinct in C (and for a given machine), this does not prevent any
name from being longer if such length will aid readability.
(S) It is a useful C convention to use upper-case for #defines and typedef
names.
(S) One exception to the above is for parameterized #defines.
These may be in lower-case.
**************************************************************************
The following was provided via FTP by Keith A. Lantz at Stanford
<CSL.LANTZ at SU-SCORE> via FTP following the enquiry distributed via
Arpanet BBOARDS.
1
NETWORK GRAPHICS C STYLE SHEET
Andrew Shore, et al.
Computer Systems Laboratory
Stanford University
Stanford, CA 94305
18 June 1982
1. Names
Don't use capital letters in file names (except for V !?).
Avoid the underscore.
Global variables, procedures, structs, unions, typedefs, defined constants,
and macros all begin with a capital letter, and are logically capitalized
thereafter (e.g. MainHashTable). A global variable is one defined outside a
procedure, even though it may not be exported from the file, or an external
variable. The motivation for treating macros and constants this way is that
they may then be freely changed to procedure calls or (global or external)
variables.
Local variables begin with a lower-case letter, but are logically capitalized
thereafter (e.g. bltWidth, power, maxSumOfSquares). Fields within structures
or unions are treated in this manner also.
2. Comments
There are generally two types of comments: block-style comments, and on-the-
line comments. Multi-line, block-style comments will follow the UNIX style of
/* and */ appearing on lines by themselves, and the body of the comment will
start with a properly aligned *. The comment should usually be surrounded by
blank lines as well. The motivation for this is that it is easy to add/delete
first and last lines, and it is easier to detect the common error of omitting
the */ and thus including all code up to and including the next */ in a comment
(Yapp helps with that too).
/*
* this is the first line of a multi-line comment,
* this is another line
* the last line of text
*/
On-line comments are used to detail declarations, and to explain single lines
of code. And, I suppose, for brief (i.e. one line) block-style descriptive
comments.
1
This work was supported by the Defense Advanced Research Projects Agency
under contract number MDA903-80-C-0102.
2
Procedures are preceded by block-style comments, explaining their (abstract)
function in terms of their parameters, results, and side effects. Note that
the parameter declarations are indented, not flushed left.
/*
* Unblock:
* unblock the process pd
*/
Unblock( pd )
register Process pd; /* the process to unblock */
{
register Process *currPd,
*tmpPd;
register unsigned prio;
prio = pd->priority;
Disable;
pd->state = Ready;
/* Add pd to the ready queue */
currPd = (Process *) &ReadyqHead;
while ((tmpPd = currPd->link) != Null)
{
if (tmpPd->priority > prio)
break;
currPd = tmpPd;
}
pd->link = tempPd;
currPd->link = pd;
Enable;
}
3. Indenting
The above example shows many of the indenting rules. Braces ( "{" and "}" )
appear alone on a line, and are indented two spaces from the statement they are
to contain the body of, the body is indented two more spaces from the braces
(for a total of four spaces). else's and else if's line up with their
dominating if statement (to avoid marching off to the right, and to reflect the
semantics of the statement).
3
if ((x = y) == 0)
{
flag = 1;
printf (" the value was zero ");
}
else if (y == 1)
{
switch (today)
{
case Thursday:
flag = 2;
ThursdayAction();
break;
case Friday:
flag = 3;
FridayAction();
break;
default:
OtherDayAction();
}
}
else
printf(" y had the wrong value ");
4. File Contents
I think we agreed on the following order for file contents.
1. initial descriptive comment (see example below) which contains:
a. file name, with indication of the relative path to it when
relevant
b. brief descriptive abstract of contents
c. a list of all defined procedures in their defined order
d. list of authors
e. list of current maintainers
f. list of recent and major modifications in reverse
chronological order with indication (initials) of who made the
change.
2. included files (use relative path names whenever possible)
3. external definitions (imports and exports)
4. function declarations (externals and forward references)
4
5. constant declarations
6. macro definitions
7. type definitions
8. global variable declarations
9. procedure and function definitions
Here is an example of the header comment:
/*
* FILE: libc/vkstuff/malloc.c
*
* CONTENTS:
* C storage allocator stolen and hacked up from UNIX for the SUN
* (NOTE: these were stolen and have the wrong naming conventions)
* malloc
* free
* realloc
* allock DEBUG ONLY!
* SetBrk ! our routine to fake up sbrk()
*
* AUTHORS: stolen and hacked by Andrew I. Shore (shore)
*
* MAINTAINER: shore
*
* HISTORY:
* 03/05/82 AIS replaced calls to UNIX sbrk() with calls to own version
* SetBrk() for the sun/Vkernel
*/
5. Parenthesis ()
We seem to have decided on the following conventions for parentheses. When
parentheses enclose the expression for a statement (if, for, etc.), the
parentheses `belong to' the expression, so there is a space between the keyword
and the parenthesized expression. For function calls the parentheses `belong
to' the call, so there is no space between function name and open paren (there
may some inside the parentheses to make the expression list (argument list)
look nice).
if (Mumble())
{
Grumble( (a = b) == 0 );
return (Nil);
}
else
{
Fumble( a, b, c );
return (ToSender);
}
5
It is unclear what to do with return. Note, then, that it is operators that
cause spaces on the outside of parentheses -- (a + b) * c.
6. General
1. One statement/declaration per line.
2. Make judicious use of blank lines.
a. At least 3 blank lines between individual procedures.
b. Blank lines surround "large" comments.
3. Make sure comments and code agree!
4. Don't just echo the code with comments -- make every comment count!
i.e. nix on:
/* add foo to bar */
bar += foo;
i
Table of Contents
1. Names 1
2. Comments 1
3. Indenting 2
4. File Contents 3
5. Parenthesis () 4
6. General 5
**************************************************************************
> Can someone advise me regarding when the GUIs became a standard feature on
> UNIX? Or operating systems whose ancestry was indeed UNIX?
MIT/LCS/TR-368, _The X Window System_, by Scheifler and Gettys, is dated
October 1986. Here are a couple paragraphs from the introduction:
X is the result of the simultaneous need for a window system from two
separate groups at MIT. In the summer of 1984, the Argus system [15]
at the Laboratory for Computer Science needed a debugging environment
for multi-process distributed applications, and a window system seemed
the only viable solution. Project Athena [4] was faced with dozens,
and eventually thousands of workstations with bitmap displays, and
needed a window system to make the display useful. Both groups were
starting with the Digital VS100 display [13] and VAX hardware, but it
was clear at the outset that other architectures and displays had to
be supported. In particular, IBM workstations with bitmap displays of
unknown type were expected eventually within Project Athena.
Portability was therefore a goal from the start. Although all of the
initial implementation work was for Berkeley Unix, it was clear that
the network protocol should not depend on aspects of the operating
system.
The name X derives from the lineage of the system. At Stanford
University, Paul Asente and Brian Reid had begun work on the W window
system [3], as an alternative to VGTS [12, 21] for the V system [5].
Both VGTS and W allow network-transparent access to the display, using
the synchronous V communication mechanism. Both systems provide "text"
windows for ASCII terminal emulation. VGTS provides graphics windows
driven by fairly high-level object definitions from a structured display
file; W provides graphics windows based on a simple display-list
mechanism, with limited functionality. We acquired a Unix-based version
of W for the VS100 (with synchronous communication over TCP [23]) done
by Asente and Chris Kent at Digital's Western Research Laboratory. From
just a few days of experimentation, it was clear that a network-
transparent hierarchical window system was desirable, but that restricting
the system to any fixed set of application-specific modes was completely
inadequate. It was also clear that, although synchronous communication
was perhaps acceptable in the V system (due to very fast networking
primitives), it was completely inadequate in most other operating
environments. X is our "reaction" to W. The X window hierarchy comes
directly from W, although numerous systems have been built with hierarchy
in at least some form [10, 14, 17, 27, 30, 31, 32, 33, 34, 35]. The
asynchronous communication protocol used in X is a significant improvement
over the synchronous protocol used in W, but is very similar to that used
in Andrew [9, 19]. X differs from all of these systems in the degree to
which both graphics functions and "system" functions are pushed back
(across the network) as application functions, and in the ability to
transparently tailor desktop management.
3. Asente. P. W Reference Manual. Stanford University, 1984. internal document.
4. Balkovich, E., Lerman, S., and Parmelee, R. "Computing in Higher
Education: The Athena Experience". _Communications of the ACM 28_,
11 (Nov. 1985).
5. Cheriton, D. "The V Kernel: A Software Base for Distributed Systems".
_IEEE Software 1_, 2 (April 1984).
9. Gosling, J. and Rosenthal, D. A Window-Manager for Bitmapped Displays and
Unix. In _Methodology of Window-Managers_, F.R.A. Hopgood et al, Eds.,
Springer-Verlag, 1986.
10. Hawley, M. J., and Leffler, S. J. Windows for Unix at Lucasfilm.
Summer Conference Proceedings, Portland, USENIX Association, 1985.
12. Lantz, K.A. and Nowicki, W.I. "Structured Graphics for Distributed
Systems". _ACM Transactions on Graphics 3_, 1 (Jan. 1984).
13. Levy, H. "VAXstation: A General-Purpose Raster Graphics Architecture".
_ACM Transactions on Graphics 3_, 1 (Jan. 1984).
14. Lipkie, D.E., Evans, S.R., Newlin, J.K., and Weissman, R.L. "Star Graphics:
An Object-Oriented Implementation." _Computer Graphics 16_, 3 (July 1982).
15. Liskov, B. and Scheifler, R. "Guardians and Actions: Linquistic
Support for Robust, Distributed Programs". _ACM Transactions on
Programming Languages and Systems 5_, 3 (July 1983).
17. _Microsoft Windows: Programmer's Guide_. Microsoft Corporation, 1985.
19. Morris, J., et atl. "Andrew: A Distributed Personal Computing Environment".
_Communications of the ACM 29_, 3 (March 1986).
21. Nowicki, W. _Partitioning of Function in a Distributed Graphics System_.
Ph.D. Th., Stanford University, Stanford, CA, 1985.
23. Postel, J. Transmission Control Protocol. RFC 793, USC/Information
Sciences Institute, Sept. 1981.
27. Stallman, R., Moon, D., and Weinreb, D. Lisp Machine Window System
Manual. MIT Artificial Intelligence Laboratory, Aug., 1983.
30. _Programmer's Reference Manual for SunWindows_. Sun Microsystems, Inc.,
1985.
31. Sweet, R. "Mesa Programming Environment". _ACM SIGPLAN Notices 20_, 7
(July 1985).
32. Sweetman, D. A Modular Window System for Unix. In _Methodology of
Window-Managers_, F.R.A. Hopgood et al, Eds., Springer-Verlag, 1986.
33. _Programming the User Interface_. Symbolics, Inc., 1986.
34. Teitelman, W. The Cedar Programming Environment: A Midterm Report and
Examination. CSL-83-11, Xerox PARC, June, 1984.
35. Trammel, R.D. A Capability Based Hierarchic Architecture for Unix Window
Management. Summer Conference Proceedings, Portland, USENIX Association, 1985.
two other references, not mentioned in the above text, that are worth noting:
11. _Information Processing: Graphical Kernel System (GKS) - Functional
Description_. DIS 7942, International Standards Organization, 1982.
22. Pike, R. "The Blit: A Multiplexed Graphics Terminal". _AT&T Bell
Laboratories Technical Journal 63_, 8 (Oct. 1984).
Hello from Gregg C Levine
Cross posted to both TUH, and PUPS lists, apologies to all.
Can someone advise me regarding when the GUIs became a standard feature on
UNIX? Or operating systems whose ancestry was indeed UNIX? I know that with
Linux, for example started carrying one, about the same time the kernel
became capable of supporting it. Or at least that's my opinion. With regard
to the materials we discuss here, well, that's what I am attempting to
ascertain.
Gregg C Levine drwho8(a)worldnet.att.net
"Oh my!" The Second Doctor's nearly favorite phrase.
Hello from Gregg C Levine
Has anyone tried out the boot images, in that directory on E11 ver 3.1? It
happens that I can get it to work, under Bochs, that is, I can run E11,
there. I haven't as yet, tried any of the boot images, myself. Right now I'm
downloading the ones that I am interested in.
Gregg C Levine drwho8(a)worldnet.att.net
"Oh my!" The Second Doctor's nearly favorite phrase.