growl / HACKING.txt

Growl coding standards
This is an extreme work in progress, but it's an effort to document coding 
standards that should be used when coding for Growl, or any other Objective-C 
code in the Growl Subversion repository. Developers, feel free to codify 
anything you notice we do in the code as a hard standard here.

Name your variables, classes, methods, functions and all other things in 
American English. Comments should likewise be in English, but your own local 
English is fine (as long as it's readable to anyone fluent in any dialect of 

Font selection
Always code in a monospaced font. If you manage to do otherwise, we will beat 
you harshly, one lash for every line in a non monospaced font.

Variable names
Instance and local variables should generally be named in camelCase, with a 
lowercase initial letter, and no underscores. No form of Hungarian notation is 
to be used, ever.

Type and class names
Use struct or enum when allowed:

struct sockaddr saddr;
struct FSForkIOParam pb;

But not when this is discouraged (as with some Cocoa structures):

NSRect rect; //NOT struct _NSRect

Classes should be named in CamelCase, with an uppercase initial letter, and no 
underscores. Name your classes so that it's obvious what they belong to and 
what they're for. ex: NSCamelCaseObject

Methods should be arranged as follows:
	+ (Foo *) classMethods;
	+ (id) classMethodsThatCreateObjects; //e.g. new or newWithZone
	- (id) init;
	- (id) initWithExtraArgument: andOtherExtraArgument:;
	- (void) dealloc;
	// Other instance methods

Selector names
Always include return type, even if it's id.

All parameter names are assumed to be inputs, unless noted otherwise. You might 
consider using the 'in' or 'out' keyword if it needs to be explicitly 

- (id) tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)column row:(int)row;
- (BOOL) scanUpToString:(NSString *)inString intoString:(NSString **)outString;

Variable Declarations
Always initialise variables at declaration time or immediately afterwards. 
Never use a variable's value without initialising it first.

Fail to adhere to this rule and we shall slowly lower you into a vat of gently 
boiling acid.

Multiple return statements
Allowed sometimes, but try to avoid having too many. Defining 'too many' is an 
exercise left to the reader.

Example of how to avoid this:
- (NSString *) whosYourDaddy:(NSString *)inChild {
	NSString *returnString = nil;
	if (inChild != nil) {
		returnString = [NSString stringWithString:@"Alan Kay"];
	return returnString;

Message breaking
Encouraged for long messages:
	newApp = [[GrowlApplicationTicket alloc] initWithApplication:appName

(Note how the colons line up vertically in a monospaced font.)

Line breaking is generally encouraged for all sorts of long expressions, 
provided it does not reduce readability. Consider:

	if (some_long_condition && some_other_long_condition || some_completely_different_long_condition) 

as opposed to:

	if (some_long_condition
		&& some_other_long_condition
		|| some_completely_different_long_condition)

Braces and Whitespace
- (void) foo:(id)a :(NSObject *)b :(NSProxy *)c {
	if (a) {
	} else if (b) {
	} else {

	GrowlQ q = [GrowlQ sharedQ];
	if (q)

	/*comments should be at the same level as the code, and should explain
	 *	the line following them.

	/*It is also recommended to have comments in a paragraph by themselves to
	 *	explain the state of the object/algorithm at a particular point in the
	 *	method or function. This will help other programmers to understand your
	 *	code if they need to modify it.

	more_work_by_the_algorithm(); //above comment is in paragraph by itself

Always use tabs to indent. Never spaces. Ever.

Indent your instance variables, too.

Always use spaces around operators:
 	2 + 2, not 2+2
 	x && y, not x&&y
 	x << 256 not x<<256

Put a space between a keyword and the opening parenthesis:
	if (a)
	// not: if(a)
But not between a function name and the opening parenthesis:
	printf("%s", "Hello world!\n");
	// not: printf ("%s", "Hello world!\n");

Don't pad the inside of the parentheses with spaces:
	if (a && b)
	// not: if ( a && b )

Don't use parentheses around the argument to return (making it look like a 
function call):
	return 0;
	// not: return(0);
But it's OK for parenthesized expressions:
	return ((x * y) ? 42 : [array objectAtIndex:fallback]);

Leave all blank lines (those with no visible characters) empty (not containing *any* characters). This means that a blank line should not contain any tabs or spaces.

Labels should always be on a line by themselves, and should be 1 indent to the 
left of the statement they apply to:

	switch (answer) {
		case 42:
			printf("Found the answer! (%i)\n", answer);

Note that in a switch, all statements are indented ~two~ levels to allow for 
the case labels.

Use of +new
Allowed, but where alloc/init is being used, stay uniform. Also switch to 
alloc/init when you need to use alloc/initWithFoo:.

Ternary operator (foo ? bar : baz)

Comma operator (x, y)
Use only in loop controls.

for (unsigned x = 0, y = 0; x < maxX && y < maxY; ++x, ++y) {

Remember that the comma operator only appears in expressions; it is not part of 
a function call:

	foo(x, y, z) //no comma operator here

nor a message:

	[NSString stringWithFormat:@"%u/%u", soFar, total] //no comma operator here

Index variables
Always unsigned unless necessary. Never use index variables for NSArrays; use 
NSEnumerator to iterate on those. (Only keep an index variable if you need to 
replace elements of an NSMutableArray.)

// C99 single-line comments are allowed.
// Put a space after the //.

/* Multi-line ('winged') comments should be used whenever a comment spans
 * multiple lines, like this one.
 * Be sure the stars line up in a nice column, and that the end wing is on its
 * own line.
 * Also make sure you use a space after the column of stars.

A single-line comment can appear on the same line as the statement to which it 

	area = r * r * 3.14159; //pi * r-squared

But should be moved to the line before it if the total line would be too long:

	// No newline on this string because NSLog will provide one (sort of)
	message = [NSString stringWithFormat:@"Area: %g; radius: %g", area, r];

Multi-line comments should always come before the statement.

It is also recommended in some situations to use small winged comments 
containing the argument names when using constants in a C function call. 
For example:

	unsigned len = [str length];
	// Count UTF-8 code units (may be more than the number of Unicode 
	// code-points)
	CFIndex UTF8len;
		CFRangeMake(0, len),
		/*lossByte*/ 0U,
		/*isExternalRepresentation*/ false,
		/*buffer*/ NULL,

Numeric constants
Always supply a fraction and an integer in any floating-point constant: 0.0, 
not 0. or .0.

Specify f for float constants: 0.0f not 0.0 (0.0 is a double constant).

Use U for unsigned integers, and L and LL for long and long long integers:

	0U;   //unsigned
	0L;   //long
	0UL;  //unsigned long
	0LL;  //long long
	0ULL; //unsigned long long

Use nil for Cocoa types, and NULL elsewhere:

- (char *) UTF8String {
	if (UTF8String == NULL)
		UTF8String = malloc([self length]);
	if (UTF8String != NULL)
		strcpy(UTF8String, "I am the Walrus");
	return UTF8String;

The above is for example purposes; whenever testing against NULL/nil, use 
simple truth-testing (and the ! operator when appropriate):

	void *buf = NULL;
	size_t size = 0U, increment = getpagesize();
	do {
		buf = realloc(buf, size);
		if (!buf)
			NSLog(@"Could not allocate %zu bytes", size);
			size += increment;
	} while (buf);

Otherwise, always use constants whenever possible; for example:

	- Use NSComparisonResult constants instead of -1, 0, +1 when working with -compare:.
	- Use NSNotFound when testing whether a range- or index-search method found a match.
	- When creating Core Foundation objects, use the CFAllocator constants (e.g. kCFAllocatorDefault) at all times, even when requesting the default allocator. Don't use NULL to get the default allocator.

Type names
Don't use 'int' unless there are no qualifiers on it. All three of these declarations are correct:

	int x; //no qualifiers
	unsigned y; //qualifier 'unsigned'
	short z; //qualifier 'short'

Exception: signed int is OK.

Use prefix version whenever possible.

	while (--argc)
		printf("%s\n", *++argv);

UTF-8. Always and forever. (Exception: strings files must be UTF-16.)

C standard
Use C99 with all warnings turned on (except for 'Unknown automatic variables',
'Unused parameters', and 'Four-character constants'). Ignore the #import
warning; fix everything else.

Feel free to use #warning, but fix it as soon as possible.

Naturally, anything allowed in C99 is allowed here, like single-line comments 
and variable declarations in for loops (see example under Comma_operator_ above).