struct estat). They are referenced with the parent pointers upwards to the root, and the estat::by_inode and estat::by_name downwards.waa__input_tree() two memory ranges are allocated - one for the struct estats read, and one for the filenames.
Because of this free()ing of part of the entries is not possible; a freelist for the struct estats is used, but the string space is more or less permanent.
O(n); but it's possible that I forgot something.O(log2(n)), as I use bsearch().waa__output_tree()) is optimized by having all lists pre-sorted; about half the time (tested) a single compare is enough to determine the next written entry.
by_inode and by_name members are pointers to arrays of pointers to entries (:-); they must reference the same entries, only the order may differ.
by_inode must (nearly) always be valid ; by_name is optional.
The flag estat::to_be_sorted tells waa__output_tree() that the order of the by_inode array might be wrong, and has to be re-sorted before use.
While scanning for changes we use a global by_inode ordering, as this is much faster than naive traversal; the by_name array is used for comparing directories, to determine whether there are any new entries.
Both arrays must include a NULL -pointer at the end of the array.
We calculate the MD5 of each buffer, and store them along with their start offset in the file. So on commit we can find identical blocks and send only those, and while comparing we can return "changed" as soon as we find a difference.
The return value of functions in this program is normally (int); 0 means success, something else an error.
Either this error is expected (like ENOENT for some operations) and handled, or it must be returned to the caller. Most of this is already defined in macros.
Typical function layout is like this (taken from waa.c): 
int waa__make_info_link(char *directory, char *name, char *dest) { int status; char *path, *eos; STOPIF( waa___get_waa_directory(directory, &path, &eos), NULL); strcpy(eos, name); ... if (access(path, F_OK) != 0) STOPIF_CODE_ERR( symlink(dest, path) == -1, errno, "cannot create informational symlink '%s' -> '%s'", path, dest); ex: return status; }
When a function gets called by subversion libraries, we have to use their return type. Here an example from commit.c: 
svn_error_t *ci___set_props(void *baton, struct estat *sts, change_any_prop_t function, apr_pool_t *pool) { const char *ccp; svn_string_t *str; int status; svn_error_t *status_svn; status=0; ... if (sts->entry_type != FT_SYMLINK) { ... str=svn_string_createf (pool, "%u %s", sts->st.uid, hlp__get_uname(sts->st.uid, "") ); STOPIF_SVNERR( function, (baton, propname_owner, str, pool) ); ... } ex: RETURN_SVNERR(status); }
The various STOPIF() -macros automatically print an error message and, depending on the debug- and verbosity-flags given on the command line, a back trace too.
Another special case is output to STDOUT; if we get an error EPIPE here, we pass it up to main() as -EPIPE (to avoid confusion with writing some other data), where it gets ignored. To avoid printing an error message this is hardcoded in the STOPIF() macros.
Assertions should be checked by BUG_ON(condition, format_string, ...). This will cause a segmentation violation, which (for debug builds) will automatically attach a debugger (gdb, only if present on the system).
"/** ... */".
For non-trivial things it's practical to document the thoughts, too; such internal documentation uses the normal C-style comments ("/* ... */").
/ and a star * have to be used in the documentation, there's a hack by putting a paragraph symbol (\c2\xa7 in UTF-8) between them, so that it doesn't break the comment block.There's a perl hack for documentation generation, where these get removed.
# if 0 block around that comment block. Doxygen doesn't allow this; even if using a shell script (with comments indicated by #) doxygen doesn't allow "/* or */."sleep 1" commands in the tests, to get directories' mtime to change for new entries.
Now they are mostly changed to a simple "-o delay=yes" on the commit just above, which should give us about half a second on average.
& and wait doesn't really work.
 1.5.9