//$Id: CODING.TXT 1.2 1998/01/29 07:10:18 ska Exp $
Hello all,

before starting to actually code the FreeDos library, I think a few
words should be told about the style a source file should look like.

>>
Conclusions    : Consistent appearance of program source code is
                 extremely important.  Learn one way and stick with
                 it.  Encourage your peers to use the same style and
                 pay attention to the same issues of readability.
                 You might have to maintain their code.
<<

The library will not remain forever in the form as it is written today.
We should consider to support future maintenance of the code by sticking
to a coding style, which is known to all, who want to look into the
sources.

This style was formed by influence of the coding styles made known to me
or to the public by:
Chris Peachment <peachmnt@freenet.toronto.on.ca>
Simon Waite <oplec@westminster.ac.uk> (JOSEPH CARNAGE's style)
FreeDos "coding" by Hannibal
and, of course, by myself

Preamble:
+ I'll use the personal pronoun "he" for the programmer, even if he is
actually female.
+ "Definition" means the place or the act to allocate bytes for a
function or a variable. Macro definition does not fall into this
context.
+ "Declaration" means the place or the act to make an identifier
available and associate a type with it.

Contents:
1) The Source Files
2) The C Language
3) Compiling


1) The Source Files

- Names of the source files
	The source files can be named as the programmer wishes; he should
	try to find names, which are direclty associated to the functions
	implemented in the file.
	
	Overlapping names will be handled when the files are put together
	to form the complete library.
	
	[If a source file defines one function, it is a good way to name
	 the file after the function.]
	 
- The complexity
	Keep the complexity of functions within one file low. Don't put
	unrelated functions into the same source file.
	
- File format
	Each source file consists of three sections:
		1) The source file comment section;
		2) The declaration section;
		3) The implementation section.
		
	The comment section consists of a "/* ... */" comment and describes
	the contents of this source file; if the source file defines
	exactly one function, this comment contains the complete function
	description; otherwise, this comment contains common remarks and
	a list of all defined functions and a short description for each.
	The comment closes with the change log; the most current change
	on top.
	
	The declaration section consists of four subsections:
	a) #include's
	b) #define's
	c) typedef's
	d) prototypes of forward local references, if necessary

	a) If an #includ'ed header is required for only very few
	declarations, this should be commented; possibly it not necessary
	anymore, when the source file was revised.
	
	b), c) Comments shall describe their purpose; not where they are
	used.
	
	The implementation section consists of two subsections:
	a) definition of variables
	b) definition of functions
	
	An example of a source file's header:
==================
/* string.c

	Implementation of string handling functions.
	Regardless of the memory model the strings and memory
	areas must not exceed 64KB or warp the segment limit.
	
	strlen(): returns the length of a string
	...
	
	Change Log:
	31 Aug 1996 Steffen Kaiser (ska)
	Bugfix: strlen() returned size including the '\0' terminator.
	
	30 Aug 1996 Steffen Kaiser (ska)
	Initially revision
	
*/

#include <string.h>
#include "_defs.h" /* typedef string */

#define NUL '\0'	/* string terminator */

typedef void *mem;	/* generic pointer into memory */

size_t strlen(string str)
{	return strchr(str, NUL) - str; }

=======================================

2) The C Language
- Indention
	One indent shall be one tab, the suggested expandion of one tab
	is four spaces.
	
	Condition statements and compound statements cause one indent.
	
	For compound statements the K&R style is recommended, e.g.:
		while(condition) {
			statements;
		}
	-or-
		{
			statements;
		}
		
	Non-compound statements, e.g.:
		if(error)
			fprintf(stderr, "Error: %s\n", errStr);
	If both lines are very short, they can be joined, e.g.:
		if(done) return;
	
- Comments
	Use the "/* ... */" comments only. Put a space after '/*' and before
	'*/', unless stated otherwise.
	
	Comments, that describe the functionality of a part of function,
	start one indent left to the current indent level.
	Otherwise the comments trails the commented line; if there is
	not enough room on this line, the comment precedes the commented
	line.
	
	In multi-line comments all but the first line starts one indent level
	right; the closing "*/" trails the last line.

	Don't nest comments, neither the "/* .. */" nor the "// ..." style.
	To comment out portions of the code use:
		#if 0
			commented out text
		#endif
		
- Programmer created identifiers
	The names shall be as readable as possible but short, think of the
	maintainer, who gets the source in 6 month.
	
	Never use an underscore (except see below).
	
	The first letter of each natural word portion of the identifier
	shall be capitalized, the other letters be lower case. Single letter
	identifiers are allowed for local variables only.
	
	Variables, functions, and typedef'ed names: The first letter shall
	be lower case.
	#define's constants: Fully upper-cased. Try to avoid these constants
	in favorit of "const" variables.
	#define'd function macros: If the macro body is free of side
	effects, tread the name as normal functions, otherwise capitalize
	the first letter.
	Tagnames of struct and union: The first letter shall be capitalized.
	
	If a function macro wraps a normal function without sideeffects,
	name the function macro after the function and append one underscore
	to the function's name, e.g.:
		#define appList(head,item) (&(head), (item))
		int appList_(void **head, void *item);
		
	Keep in mind that names starting with: '_', 'str', and 'mem' are
	implementor defined.
	
	Take care to name different kind of identifiers equally, e.g.
	variables and functions.
	
	Local single letter variables are defined as such:
		x, y, z: mathematical purpose
		i, j, k: counter, index
		l: length
		s: string
		h, p, q: temporary pointer
		f: FILE *
		a, b: counter of interlaced loops
		c: character [usually (int)]
		r: REGPACK, REGS
		
- Hungarian Notation
	It is commonly used to keep track of the type of identifiers in C.
	However, it enlarges the size of the code (and the more code is
	written, the more errors can be made), makes the source more
	unreadeble, and increases the work, if the type must be changed.
	
	So don't use Hungarian Notation for local variables. If you feel
	that you cannot keep track of the variable's type, the function has
	grown to large and should be separated into smaller pieces.
	
	Global variables, as they are defined in the standards, don't follow
	the Hungarian Notation. It makes no sense to introduce HN for
	non-standard names.
	
- Whitespaces
	Always use a single space as whitespaces, except to delimit a
	comment from the start of the line. In this case, use one or more
	tabs.
	
	Whitepaces are written after punctation characters, such as: ',',
	':', '?'; before and after in-fix operators, such as: '+', '-', '&',
	'&&', '=', '<<='; before '{'.
	
	Don't separate paranthizes except where they coincide with in-fix
	operators.
	
	Don't separate unary operators from their destination.
	
	Don't separate two or more statements by ';' on the same line,
	except in the for() statement.

	Don't separate C-statements (if, while, ...) from the left
	parenthize by a whitespaces.
	
- Breaking up Long Lines
	Keep all lines smaller than 80 characters. Break long lines at
	"arbitary" places, where the semantic is not effected. Indent all
	but the first line by a single space.
	
	Indicate that a line is syntactically a part of the preceeding line
	by placing an operator in front of the line, that is usually invalid
	at the first poisition of a statement, e.g.:
		if((a || b) && (c || d))
	->
		if((a || b)
		 && (c || d))
		 
	Don't use the "\" style concatenation of string literals, use the
	ANSI style and indent the string properly, e.g.:
	
		puts("Line is \
broken.");
	->
		puts("Line is "
			 "broken.");
			 
- Breaking up Lists
	If a list grows larger than one line, break up each item of the list
	and align all commas at the same column. The first item is indented
	by one space, because it has no comma. If the list is a function
	parameter list, place the closing parenthize on the same line of the
	last item; otherwise align the closing characters with the commas,
	e.g.:
		extern int	 flag1	/* cool flag */
					,flag2	/* another cool flag */
					;
	This simplifies maintaining of the list.
	
- Function Definition
	Each definition is preceeded by the comment describing the function,
	its parameters, and the special behaviours, such as: "free(NULL)
	does nothing"; "malloc(0) returns a unique pointer to a memory area
	with no data byte". The comment starts with "/*" at column 1 and
	leaves the rest of the line blank. All the other lines are indented
	by a single space, an asterisk '*' and a tab. The closing "*/" starts
	at column 2 and appears on its own line.
	
	If the comment grows larger than 20 lines, the prototype of the
	function is repeated in the "/*" line of the comment. The last
	portion of the comment describes the return value, if any.
	
	The following lines consist of:
	First, write the function type. If this type is (int), write it.
	Second, the function name, the opening '(', and the first argument
	(or 'void' if the function has no argument).
	Third, aligned by the column of the '(' start the next argument
	declaration with the ','.
	On the line of the last argument delcaration appears the ')'.
	
	Comment each argument with a single line comment, if their meaning
	is not clear or the function is not a standardized one.
	
	The immediately following line contains the '{' parenthize in the
	first column and, possibly, the first variable definition with the
	indention of one tab.
	
	The last line of the function contains the '}' in the first column
	and the finished function name as a comment. All delimiters consists
	of a single space, no tab.
	
	One example:
/*
 *	strcmp() compares both strings s1 and s2.
 *	
 *	If s1 and/or s2 do not point to an ASCIIZ string, the return value is undefined.
 *	
 *	Return:	== 0: both strings are equal
 *			<0: s1 is less than s2
 *			>0: s1 is greater than s2
 */
int
strcmp(const char *s1
	  ,const char *s2)
{	int cmp;

	while((cmp = *(unsigned char*)s1 - *(unsigned char*)s2) != 0 && *s1)
		++s1, ++s2;
	return cmp;
} /* strcmp */

- Compound Statements
	Use compound statement anywhere you wish. There is no need to avoid
	local variables.

- The if() Statement	
	Always use a compound statement in the "true" branch of an if()
	statement, if the branch contains an if() statement itself.

	Align the 'if' and 'else' keywords and the closing '}', if any, in
	the same column.
	
- The switch() Statement
	Never use local variables within a switch() block outside compound
	statements.
	
	Never use switch() without a compound statement around all the
	case's.
	
	Align the 'switch', 'case', 'default' keywords and the closing '}'
	in the same column.
	
	Explicitly mark "fall through" cases. Otherwise, finish all case's,
	including the last one, with the 'break' statement. Delimit all
	case's by an empty line.
	
	Comment, if necessary, each 'case' line; otherwise leave the rest of
	this line blank.
	
	If more than one 'case' label applies to the same case; write all of
	them into single lines, but don't delimit them. If the case constant
	is identically (e.g. a numerical character constant) write as many
	of them as possible on the same line sorted literally.
	
- The Loop Statements
	If the argument list of for() grows to large, try to break on the
	';' firstly and align them with the '('.
	
	The 'do {} while();' loop is quite confusing, because while() is a
	legal statement for its own. Therefore, if there is no compound
	statement, align the 'do' and 'while' keywords in the same column of
	immediately following lines; if this is impossible, parenthize the
	statement. With a compund statement write the loop as such:
		do {
			statements;
		} while(condition);
		
- Return value
	The 'return' statement is no function call. Don't make the
	maintainer believe, it is one, by surrounding the value by
	parenthizes. If it seems to be necessary, delimit the 'return'
	keyword from the parenthize by a whitespace.
	
	There is no need to place a 'return;' statement at the last line of
	a 'void' function.

- Module internally identifiers
	Any function or variable, that is used by a single module only and
	is not part of the proposed library standard, must be declared as
	local to the module by the 'static' modifier.
	
	If the function or variable is necessary in more than one module,
	the particular identifier becomes an "internal" identifier by
	prefixing it with an underscore and putting it into the library
	standard under the rubric "compiler specific identifier".
	
- Preprocessor Statements
	Don't indent preprocessor statements, neither before nor after the
	'#'.
	
	If indention seems to be necessary, indent the argument of the
	preprocessore statement and comment the '#else' and '#endif'
	statements.
	
- Size of Identifiers
	Use the sizeof() function. Don't rely on any sizeof(int) == 2 or
	something like that. The only ever-true condition is:
		sizeof(char) == 1
	
	To get the size of an array, use sizeof(arrayname).
	
	To get the number of elements of an array, decide if it is more
	likely to change the array's type or its number of elements. In the
	first case, typedef a new type with an upper case first letter and
	use:
		sizeof(arrayname) / sizeof(arraytype)
	In the second case, #define a macro named after the array with all
	letters uppercased.
	
- Offsets of Members
	To get the offset of a particular member into a structure, use
	offsetof(struct_type, struct_member).
	
	Use offsets seldom and only, if there is no other acceptable way.
	
	Try to avoid relying on the fact that structure members are ordered
	as they are defined.

	To access DOS internal structures prefer overlaying a structure
	instead of directly working with the offsets. Because all of them
	are aligned to one byte (or pack at one byte) surround the
	declaration of the structure by:
		#include <algnbyte.h>
	and
		#include <algndflt.h>
	These include files alter the currently used alignment into one byte
	(no pad bytes at all) or back into the default one.
	Avoid explicit alignments in other circumstances.

	Beware of structures that are not defined with the same Tagname or
	typedef'ed type. The pad bytes are possibly different.
	
	Never assign structures or unions at a whole, use the memcpy()
	function instead.
	
	Unaligned structures must be compared individually.
	
- Character Arethemtics
	Be careful passing (char) to functions. They are promoted into
	(int), what can cause strange errors.
	
	Be aware that C has neither a (char) nor (short) arethemtic. Both
	types are possibly casted to (int). But don't rely on the cast. Cast
	them explicitly.
	
	Avoid (char) arethmetics, because for the one byte, which is spared
	in the data/stack space, the code space grows by one byte each time
	the (char) variable is read, because, mostly, promoting (char) to
	(int) requires one assembly instruction.
	
- Prototypes
	Each non-static function must has a prototype in one of the header
	files. Include all header files where prototypes of used functions
	and variables are included.
	
	Name each argument, however, the name need not match the name of the
	function definition.
	
- In-statement Assignment
	Pay a little care to in-statement assignments and their
	associativity. In conditions, never rely on the fact that "!= 0" is
	appended, make sure you really wanted to write an assignment rather
	than a compare, e.g.:
		if(a = b)
	->
		if((a = b) != 0)

- NULL, 0, (void*)0, '\0', 0.0
	Rely on the fact that:
		#define NULL ((void*)0)
	
	That means that you can use NULL in a variable argument line and in
	all type-related contexts, too.
	
	Stick to NULL in every pointer context; stick to 0 (zero) in every
	(int) arethmetic context; stick to 0.0 in every (float) arethmetic
	context; stick to '\0' in every (char) context. Latter can be
	replaced by NUL.
	
- Boolean Arethmetic
	C has no boolean type. C never will.
	
	Think of only one true definition in this context: 0 (zero) is
	false. Everything else leads to wrong assumptions.
	
	If you need a boolean type, either typedef a new type to (int) or
	use (int) and compare this value with 0 (zero) only, either implied
	in a condition [if(), while()] or explizitly with the two binary
	operators: '==' and '!='.

	Perhaps it's a good idea to introduce a library-wide type FLAG or
	BOOL, and the FALSE #define for this context.
	
- Character Literals
	Don't rely on the fact that hexadecimal or octal character literals
	are abbreviated after two or three numbers, use the ANSI
	concatenation feature instead, e.g.:
		"\0007"
	->
		"\0" "007"
	-or-
		"\0" "7"

- Order of evaluation
	ANSI defined several rules for "reference points". Points, where the
	programmer can assume that all pending evaluation, including
	assignments, invoking functions and incrementing/decrementing, gets
	done.
	
	For instance: end of statement ';', list ',', boolean arethmetic
	'&&', '||', '?:'.
	
	There is none: function's parameter list, binary operators, e.g.:
		a = i++ + i++;
		a(i++, i++);
		a = fct(i) + ++i;
	All these examples causes an undefined behaviour.
	
3) Compiling

- Destination Method of the complete sources
	The destination method to compile all the sources is by MAKE and/or
	by a batch file. This does not effect the developing process.
	
- Header Files
	There is a standardized amount of header files. They will be
	available, of course. While developing the sources internally used
	functions and variables will be necessary. They are grouped together
	by their functionality and found one header file.
	
	Normally one header file is necessary for one C file. If the C file
	was broken up to support non-smart linking, this is not required.
	
	Multiple includation of header files often causes strange effects.
	To avoid this surroud all the text of the file but the introducing
	comment by:
		#ifndef uppercaseFilename_H_
		#define uppercaseFilename_H_
			:
			:
		#endif
	
	Standard header files or library internal header files are also prefixed with one underscore.
	
- Distribution and Maintaining
	The library will be distributed as a whole. The source files might
	be broken up into smaller ones to support non-smart linking. There
	will be no precompiled .LIB files.
	
	Each emitted file is prefixed by the GNU GPL notice, so don't
	include the notice yourself.
	
	The copyright notice holds the author and followed by notices about
	"revised by" and "modified by". Each "modifier" receives a sign,
	with what he must "sign" each modification.
	
	Revision remarks and notices will be removed by the author.
