Ignoring a very common warning.
[privoxy.git] / doc / source / developer-manual.sgml
1 <!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V3.1//EN">
2 <!--
3  File        :  $Source: /cvsroot/ijbswa/current/doc/source/developer-manual.sgml,v $
4
5  Purpose     :  developer manual
6                 This file belongs into
7                 ijbswa.sourceforge.net:/home/groups/i/ij/ijbswa/htdocs/
8                 
9  $Id: developer-manual.sgml,v 1.6 2002/02/24 14:25:06 jongfoster Exp $
10
11  Written by and Copyright (C) 2001 the SourceForge
12  IJBSWA team.  http://ijbswa.sourceforge.net
13
14  Based on the Internet Junkbuster originally written
15  by and Copyright (C) 1997 Anonymous Coders and 
16  Junkbusters Corporation.  http://www.junkbusters.com
17 -->
18
19 <article id="index">
20   <artheader>
21     <title>Junkbuster Developer Manual</title>
22
23     <pubdate>$Id: developer-manual.sgml,v 1.6 2002/02/24 14:25:06 jongfoster Exp $</pubdate>
24
25     <authorgroup>
26       <author>
27         <affiliation>
28           <orgname>By: Junkbuster Developers</orgname>
29         </affiliation>
30       </author>
31     </authorgroup>
32
33     <abstract>
34       <para>
35 The developer manual gives the users information on how to help the developer
36 team. It provides guidance on coding, testing, documentation and other
37 issues. <application>Internet Junkbuster</application> is a web proxy with
38 advanced filtering capabilities for protecting privacy, filtering web page
39 content, managing cookies, controlling access, and removing ads, banners,
40 pop-ups and other obnoxious Internet Junk. Junkbuster has a very flexible
41 configuration and can be customized to suit individual needs and
42 tastes. <application>Internet Junkbuster</application> has application for
43 both stand-alone systems and multi-user networks.
44  </para>
45       <para>
46 You can find the latest version of the user manual at <ulink
47 url="http://ijbswa.sourceforge.net/developer-manual/">http://ijbswa.sourceforge.net/developer-manual/</ulink>.
48 Please see the Contact section in the user-manual if you want to contact the developers.
49  </para>
50
51 <!--        <para> -->
52 <!--    Feel free to send a note to the developers at <email>ijbswa-developers@lists.sourceforge.net</email>. -->
53 <!--   </para> -->
54
55     </abstract>
56   </artheader>
57
58   <!--   ~~~~~       New section      ~~~~~     -->
59   <sect1 id="introduction"><title>Introduction</title>
60     <para>To be filled.
61 </para>
62   </sect1>
63
64   <!--   ~~~~~       New section      ~~~~~     -->
65   <sect1 id="quickstart"><title>Quickstart to Junkbuster Development</title>
66     <para>To be filled.
67 </para>
68   </sect1>
69
70   <!--   ~~~~~       New section      ~~~~~     -->
71   <sect1 id="documentation"><title>Documentation Guidelines</title>
72     <para>
73         All docs are in SGML format and located in the <computeroutput>doc/source</computeroutput> directory.
74         </para>
75         <para>
76         How do you update the webserver (i.e. the pages on sourceforge)?
77         <orderedlist numeration="arabic">
78                 <listitem><para>
79         Run <computeroutput>make dok</computeroutput> (which uses the documents in <computeroutput>doc/source</computeroutput> to update all
80         text files in <computeroutput>doc/text</computeroutput> and to update
81 all web documents in <computeroutput>doc/webserver</computeroutput>.
82                 </para></listitem>
83                 <listitem><para>
84         Run <computeroutput>make webserver</computeroutput> which copies all files from
85 <computeroutput>doc/webserver</computeroutput> to the sourceforge webserver
86 via scp.
87                 </para></listitem>
88         </orderedlist>
89   </para>
90  </sect1>
91
92 <!--     <listitem><para>be consistent with the redirect script (i.e. the junkbuster program -->
93 <!--       points via the redirect URL at sf to valid end-points in the document)</para></listitem> -->
94
95   <!--   ~~~~~       New section      ~~~~~     -->
96   <sect1 id="coding"><title>Coding Guidelines</title>
97
98     <sect2 id="s1"><title>Introduction</title>
99
100     <para>This set of standards is designed to make our lives easier.
101     It is developed with the simple goal of helping us keep the
102     "new and improved Junkbusters" consistent and reliable. Thus
103     making maintenance easier and increasing chances of success of
104     the project.</para>
105
106     <para>And that of course comes back to us as individuals. If we
107     can increase our development and product efficiencies then we
108     can solve more of the request for changes/improvements and in
109     general feel good about ourselves. ;-></para>
110
111   </sect2>
112
113     <sect2 id="s2"><title>Using Comments</title>
114  
115
116     <sect3 id="s3"><title>Comment, Comment, Comment</title>
117
118     <para><emphasis>Explanation:</emphasis></para>
119
120     <para>Comment as much as possible without commenting the obvious.
121     For example do not comment "aVariable is equal to bVariable".
122     Instead explain why aVariable should be equal to the bVariable.
123     Just because a person can read code does not mean they will
124     understand why or what is being done. A reader may spend a lot
125     more time figuring out what is going on when a simple comment
126     or explanation would have prevented the extra research. Please
127     help your brother IJB'ers out!</para>
128
129     <para>The comments will also help justify the intent of the code.
130     If the comment describes something different than what the code
131     is doing then maybe a programming error is occurring.</para>
132
133     <para><emphasis>Example:</emphasis></para>
134 <programlisting>
135 /* if page size greater than 1k ... */
136 if ( PageLength() > 1024 )
137 {
138     ... "block" the page up ...
139 }
140
141 /* if page size is small, send it in blocks */
142 if ( PageLength() > 1024 )
143 {
144     ... "block" the page up ...
145 }
146
147 This demonstrates 2 cases of "what not to do".  The first is a
148 "syntax comment".  The second is a comment that does not fit what
149 is actually being done.
150 </programlisting>
151   </sect3>
152
153     
154
155     <sect3 id="s4"><title>Use blocks for comments</title>
156
157     <para><emphasis>Explanation:</emphasis></para>
158
159     <para>Comments can help or they can clutter. They help when they
160     are differentiated from the code they describe. One line
161     comments do not offer effective separation between the comment
162     and the code. Block identifiers do, by surrounding the code
163     with a clear, definable pattern.</para>
164
165     <para><emphasis>Example:</emphasis></para>
166 <programlisting>
167 /*********************************************************************
168  * This will stand out clearly in your code!
169  *********************************************************************/
170 if ( thisVariable == thatVariable )
171 {
172    DoSomethingVeryImportant();
173 }
174
175
176 /* unfortunately, this may not */
177 if ( thisVariable == thatVariable )
178 {
179    DoSomethingVeryImportant();
180 }
181
182
183 if ( thisVariable == thatVariable ) /* this may not either */
184 {
185    DoSomethingVeryImportant();
186 }</programlisting>
187
188     <para><emphasis>Exception:</emphasis></para>
189
190     <para>If you are trying to add a small logic comment and do not
191     wish to "disrubt" the flow of the code, feel free to use a 1
192     line comment which is NOT on the same line as the code.</para>
193
194     
195   </sect3>
196     
197
198     <sect3 id="s5"><title>Keep Comments on their own line</title>
199
200     <para><emphasis>Explanation:</emphasis></para>
201
202     <para>It goes back to the question of readability. If the comment
203     is on the same line as the code it will be harder to read than
204     the comment that is on its own line.</para>
205
206     <para>There are three exceptions to this rule, which should be
207     violated freely and often: during the definition of variables,
208     at the end of closing braces, when used to comment
209     parameters.</para>
210
211     <para><emphasis>Example:</emphasis></para>
212 <programlisting>
213 /*********************************************************************
214  * This will stand out clearly in your code,
215  * But the second example won't.
216  *********************************************************************/
217 if ( thisVariable == thatVariable )
218 {
219    DoSomethingVeryImportant();
220 }
221
222 if ( thisVariable == thatVariable ) /*can you see me?*/
223 {
224    DoSomethingVeryImportant(); /*not easily*/
225 }
226
227
228 /*********************************************************************
229  * But, the encouraged exceptions:
230  *********************************************************************/
231 int urls_read     = 0;     /* # of urls read + rejected */
232 int urls_rejected = 0;     /* # of urls rejected */
233
234 if ( 1 == X )
235 {
236    DoSomethingVeryImportant();
237 }
238
239
240 short DoSomethingVeryImportant(
241    short firstparam,   /* represents something */
242    short nextparam     /* represents something else */ )
243 {
244    ...code here...
245
246 }   /* -END- DoSomethingVeryImportant */
247 </programlisting>
248   </sect3>
249     
250
251     <sect3 id="s6"><title>Comment each logical step</title>
252
253     <para><emphasis>Explanation:</emphasis></para>
254
255     <para>Logical steps should be commented to help others follow the
256     intent of the written code and comments will make the code more
257     readable.</para>
258
259     <para>If you have 25 lines of code without a comment, you should
260     probably go back into it to see where you forgot to put
261     one.</para>
262
263     <para>Most "for", "while", "do", etc... loops _probably_ need a
264     comment. After all, these are usually major logic
265     containers.</para>
266
267     
268   </sect3>
269     
270
271     <sect3 id="s7"><title>Comment All Functions Thoroughly</title>
272
273     <para><emphasis>Explanation:</emphasis></para>
274
275     <para>A reader of the code should be able to look at the comments
276     just prior to the beginning of a function and discern the
277     reason for its existence and the consequences of using it. The
278     reader should not have to read through the code to determine if
279     a given function is safe for a desired use. The proper
280     information thoroughly presented at the introduction of a
281     function not only saves time for subsequent maintenance or
282     debugging, it more importantly aids in code reuse by allowing a
283     user to determine the safety and applicability of any function
284     for the problem at hand. As a result of such benefits, all
285     functions should contain the information presented in the
286     addendum section of this document.</para>
287
288     
289   </sect3>
290     
291
292     <sect3 id="s8"><title>Comment at the end of braces if the
293     content is more than one screen length</title>
294
295     <para><emphasis>Explanation:</emphasis></para>
296
297     <para>Each closing brace should be followed on the same line by a
298     comment that describes the origination of the brace if the
299     original brace is off of the screen, or otherwise far away from
300     the closing brace. This will simplify the debugging,
301     maintenance, and readability of the code.</para>
302
303     <para>As a suggestion , use the following flags to make the
304     comment and its brace more readable:</para>
305
306     <para>use following a closing brace: } /* -END- if() or while ()
307     or etc... */</para>
308
309     <para><emphasis>Example:</emphasis></para>
310 <programlisting>
311 if ( 1 == X )
312 {
313    DoSomethingVeryImportant();
314    ...some long list of commands...
315 } /* -END- if x is 1 */
316
317 or:
318
319 if ( 1 == X )
320 {
321    DoSomethingVeryImportant();
322    ...some long list of commands...
323 } /* -END- if ( 1 == X ) */
324 </programlisting>
325   </sect3>
326     
327   </sect2>
328
329     <sect2 id="s9"><title>Naming Conventions</title>
330
331     
332
333     <sect3 id="s10"><title>Variable Names</title>
334
335     <para><emphasis>Explanation:</emphasis></para>
336
337     <para>Use all lowercase, and seperate words via an underscore
338     ('_'). Do not start an identifier with an underscore. (ANSI C
339     reserves these for use by the compiler and system headers.) Do
340     not use identifiers which are reserved in ANSI C++. (E.g.
341     template, class, true, false, ...). This is in case we ever
342     decide to port JunkBuster to C++.</para>
343
344     <para><emphasis>Example:</emphasis></para>
345 <programlisting>
346 int ms_iis5_hack = 0;</programlisting>
347
348     <para><emphasis>Instead of:</emphasis></para>
349
350     <para>
351 <programlisting>
352 int msiis5hack = 0; int msIis5Hack = 0;
353 </programlisting>
354 </para>
355
356     
357
358   </sect3>    
359
360     <sect3 id="s11"><title>Function Names</title>
361
362     <para><emphasis>Explanation:</emphasis></para>
363
364     <para>Use all lowercase, and seperate words via an underscore
365     ('_'). Do not start an identifier with an underscore. (ANSI C
366     reserves these for use by the compiler and system headers.) Do
367     not use identifiers which are reserved in ANSI C++. (E.g.
368     template, class, true, false, ...). This is in case we ever
369     decide to port JunkBuster to C++.</para>
370
371     <para><emphasis>Example:</emphasis></para>
372 <programlisting>
373 int load_some_file( struct client_state *csp )</programlisting>
374
375     <para><emphasis>Instead of:</emphasis></para>
376
377     <para>
378 <programlisting>
379 int loadsomefile( struct client_state *csp )
380 int loadSomeFile( struct client_state *csp )
381 </programlisting>
382 </para>
383
384     
385   </sect3>
386     
387
388     <sect3 id="s12"><title>Header file prototypes</title>
389
390     <para><emphasis>Explanation:</emphasis></para>
391
392     <para>Use a descriptive parameter name in the function prototype
393     in header files. Use the same parameter name in the header file
394     that you use in the c file.</para>
395
396     <para><emphasis>Example:</emphasis></para>
397 <programlisting>
398 (.h) extern int load_aclfile( struct client_state *csp );
399 (.c) int load_aclfile( struct client_state *csp )</programlisting>
400
401     <para><emphasis>Instead of:</emphasis>
402 <programlisting>
403 (.h) extern int load_aclfile( struct client_state * ); or 
404 (.h) extern int load_aclfile(); 
405 (.c) int load_aclfile( struct client_state *csp )
406 </programlisting>
407 </para>
408
409     
410   </sect3>
411     
412
413     <sect3 id="s13"><title>Enumerations, and #defines</title>
414
415     <para><emphasis>Explanation:</emphasis></para>
416
417     <para>Use all capital letters, with underscores between words. Do
418     not start an identifier with an underscore. (ANSI C reserves
419     these for use by the compiler and system headers.)</para>
420
421     <para><emphasis>Example:</emphasis></para>
422 <programlisting>
423 (enumeration) : enum Boolean { FALSE, TRUE };
424 (#define) : #define DEFAULT_SIZE 100;</programlisting>
425
426     <para><emphasis>Note:</emphasis> We have a standard naming scheme for #defines
427     that toggle a feature in the preprocessor: FEATURE_>, where
428     > is a short (preferably 1 or 2 word) description.</para>
429
430     <para><emphasis>Example:</emphasis></para>
431 <programlisting>
432 #define FEATURE_FORCE 1
433
434 #ifdef FEATURE_FORCE
435 #define FORCE_PREFIX blah
436 #endif /* def FEATURE_FORCE */
437 </programlisting>
438   </sect3>
439     
440
441     <sect3 id="s14"><title>Constants</title>
442
443     <para><emphasis>Explanation:</emphasis></para>
444
445     <para>Spell common words out entirely (do not remove vowels).</para>
446
447     <para>Use only widely-known domain acronyms and abbreviations.
448     Capitalize all letters of an acronym.</para>
449
450     <para>Use underscore (_) to separate adjacent acronyms and
451     abbreviations. Never terminate a name with an underscore.</para>
452
453     <para><emphasis>Example:</emphasis></para>
454 <programlisting>
455 #define USE_IMAGE_LIST 1</programlisting>
456
457     <para><emphasis>Instead of:</emphasis></para>
458
459     <para>
460 <programlisting>
461 #define USE_IMG_LST 1 or 
462 #define _USE_IMAGE_LIST 1 or
463 #define USE_IMAGE_LIST_ 1 or 
464 #define use_image_list 1 or
465 #define UseImageList 1
466 </programlisting>
467 </para>
468
469     
470   </sect3>
471
472   </sect2>
473     
474
475     <sect2 id="s15"><title>Using Space</title>
476
477     
478
479     <sect3 id="s16"><title>Put braces on a line by themselves.</title>
480
481     <para><emphasis>Explanation:</emphasis></para>
482
483     <para>The brace needs to be on a line all by itself, not at the
484     end of the statement. Curly braces should line up with the
485     construct that they're associated with. This practice makes it
486     easier to identify the opening and closing braces for a
487     block.</para>
488
489     <para><emphasis>Example:</emphasis></para>
490 <programlisting>
491 if ( this == that )
492 {
493    ...
494 }</programlisting>
495
496     <para><emphasis>Instead of:</emphasis></para>
497
498     <para>if ( this == that ) { ... }</para>
499
500     <para>or</para>
501
502     <para>if ( this == that ) { ... }</para>
503
504     <para><emphasis>Note:</emphasis> In the special case that the if-statement is
505     inside a loop, and it is trivial, i.e. it tests for a
506     condidtion that is obvious from the purpose of the block,
507     one-liners as above may optically preserve the loop structure
508     and make it easier to read.</para>
509
510     <para><emphasis>Status:</emphasis> developer-discrection.</para>
511
512     <para><emphasis>Example exception:</emphasis></para>
513 <programlisting>
514 while ( more lines are read )
515 {
516    /* Please document what is/is not a comment line here */
517    if ( it's a comment ) continue;
518
519    do_something( line );
520 }
521 </programlisting>
522   </sect3>
523     
524
525     <sect3 id="s17"><title>ALL control statements should have a
526     block</title>
527
528     <para><emphasis>Explanation:</emphasis></para>
529
530     <para>Using braces to make a block will make your code more
531     readable and less prone to error. All control statements should
532     have a block defined.</para>
533
534     <para><emphasis>Example:</emphasis></para>
535 <programlisting>
536 if ( this == that )
537 {
538    DoSomething();
539    DoSomethingElse();
540 }</programlisting>
541
542     <para><emphasis>Instead of:</emphasis></para>
543
544     <para>if ( this == that ) DoSomething(); DoSomethingElse();</para>
545
546     <para>or</para>
547
548     <para>if ( this == that ) DoSomething();</para>
549
550     <para><emphasis>Note:</emphasis> The first example in "Instead of" will execute
551     in a manner other than that which the developer desired (per
552     indentation). Using code braces would have prevented this
553     "feature". The "explanation" and "exception" from the point
554     above also applies.</para>
555
556     
557   </sect3>
558     
559
560     <sect3 id="s18"><title>Do not belabor/blow-up boolean
561     expressions</title>
562
563     <para><emphasis>Example:</emphasis></para>
564 <programlisting>
565 structure->flag = ( condition );</programlisting>
566
567     <para><emphasis>Instead of:</emphasis></para>
568
569     <para>if ( condition ) { structure->flag = 1; } else {
570     structure->flag = 0; }</para>
571
572     <para><emphasis>Note:</emphasis> The former is readable and consice. The later
573     is wordy and inefficient. Please assume that any developer new
574     to the project has at least a "good" knowledge of C/C++. (Hope
575     I do not offend by that last comment ... 8-)</para>
576
577     
578   </sect3>
579     
580
581     <sect3 id="s19"><title>Use white space freely because it is
582     free</title>
583
584     <para><emphasis>Explanation:</emphasis></para>
585
586     <para>Make it readable. The notable exception to using white space
587     freely is listed in the next guideline.</para>
588
589     <para><emphasis>Example:</emphasis></para>
590 <programlisting>
591 int firstValue   = 0;
592 int someValue    = 0;
593 int anotherValue = 0;
594 int thisVariable = 0;
595
596 if ( thisVariable == thatVariable )
597
598 firstValue = oldValue + ( ( someValue - anotherValue ) - whatever )
599 </programlisting>
600   </sect3>
601     
602
603     <sect3 id="s20"><title>Don't use white space around structure
604     operators</title>
605
606     <para><emphasis>Explanation:</emphasis></para>
607
608     <para>- structure pointer operator ( "->" ) - member operator (
609     "." ) - functions and parentheses</para>
610
611     <para>It is a general coding practice to put pointers, references,
612     and function parentheses next to names. With spaces, the
613     connection between the object and variable/function name is not
614     as clear.</para>
615
616     <para><emphasis>Example:</emphasis></para>
617 <programlisting>
618 aStruct->aMember;
619 aStruct.aMember;
620 FunctionName();</programlisting>
621
622     <para><emphasis>Instead of:</emphasis> aStruct -> aMember; aStruct . aMember;
623     FunctionName ();</para>
624
625     
626   </sect3>
627     
628
629     <sect3 id="s21"><title>Make the last brace of a function stand
630     out</title>
631
632     <para><emphasis>Example:</emphasis></para>
633 <programlisting>
634 int function1( ... )
635 {
636    ...code...
637    return( retCode );
638
639 }   /* -END- function1 */
640
641
642 int function2( ... )
643 {
644 }   /* -END- function2 */
645 </programlisting>
646
647     <para><emphasis>Instead of:</emphasis></para>
648
649     <para>int function1( ... ) { ...code... return( retCode ); } int
650     function2( ... ) { }</para>
651
652     <para><emphasis>Note:</emphasis> Use 1 blank line before the closing brace and 2
653     lines afterwards. This makes the end of function standout to
654     the most casual viewer. Although function comments help
655     seperate functions, this is still a good coding practice. In
656     fact, I follow these rules when using blocks in "for", "while",
657     "do" loops, and long if {} statements too. After all whitespace
658     is free!</para>
659
660     <para><emphasis>Status:</emphasis> developer-discrection on the number of blank
661     lines. Enforced is the end of function comments.</para>
662
663     
664   </sect3>
665     
666
667     <sect3 id="s22"><title>Use 3 character indentions</title>
668
669     <para><emphasis>Explanation:</emphasis></para>
670
671     <para>If some use 8 character TABs and some use 3 character TABs,
672     the code can look *very* ragged. So use 3 character indentions
673     only. If you like to use TABs, pass your code through a filter
674     such as "expand -t3" before checking in your code.</para>
675
676     <para><emphasis>Example:</emphasis></para>
677 <programlisting>
678 static const char * const url_code_map[256] =
679 {
680    NULL, ...
681 };
682
683
684 int function1( ... )
685 {
686    if ( 1 )
687    {
688       return( ALWAYS_TRUE );
689    }
690    else
691    {
692       return( HOW_DID_YOU_GET_HERE );
693    }
694
695    return( NEVER_GETS_HERE );
696
697 }
698 </programlisting>
699   </sect3>
700
701   </sect2>
702     
703
704     <sect2 id="s23"><title>Initializing</title>
705
706     
707
708     <sect3 id="s24"><title>Initialize all variables</title>
709
710     <para><emphasis>Explanation:</emphasis></para>
711
712     <para>Do not assume that the variables declared will not be used
713     until after they have been assigned a value somewhere else in
714     the code. Remove the chance of accidentally using an unassigned
715     variable.</para>
716
717     <para><emphasis>Example:</emphasis></para>
718 <programlisting>
719 short anShort = 0;
720 float aFloat  = 0;
721 struct *ptr = NULL;</programlisting>
722
723     <para><emphasis>Note:</emphasis> It is much easier to debug a SIGSEGV if the
724     message says you are trying to access memory address 00000000
725     and not 129FA012; or arrayPtr[20] causes a SIGSEV vs.
726     arrayPtr[0].</para>
727
728     <para><emphasis>Status:</emphasis> developer-discrection if and only if the
729     variable is assigned a value "shortly after" declaration.</para>
730
731   </sect3>
732   </sect2>
733     
734
735     <sect2 id="s25"><title>Functions</title>
736
737     
738
739     <sect3 id="s26"><title>Name functions that return a boolean as a
740     question.</title>
741
742     <para><emphasis>Explanation:</emphasis></para>
743
744     <para>Value should be phrased as a question that would logically
745     be answered as a true or false statement</para>
746
747     <para><emphasis>Example:</emphasis></para>
748 <programlisting>
749 ShouldWeBlockThis();
750 ContainsAnImage();
751 IsWebPageBlank();
752 </programlisting>
753   </sect3>
754     
755
756     <sect3 id="s27"><title>Always specify a return type for a
757     function.</title>
758
759     <para><emphasis>Explanation:</emphasis></para>
760
761     <para>The default return for a function is an int. To avoid
762     ambiguity, create a return for a function when the return has a
763     purpose, and create a void return type if the function does not
764     need to return anything.</para>
765
766     
767   </sect3>
768     
769
770     <sect3 id="s28"><title>Minimize function calls when iterating by
771     using variables</title>
772
773     <para><emphasis>Explanation:</emphasis></para>
774
775     <para>It is easy to write the following code, and a clear argument
776     can be made that the code is easy to understand:</para>
777
778     <para><emphasis>Example:</emphasis></para>
779 <programlisting>
780 for ( size_t cnt = 0; cnt &lt; blockListLength(); cnt ++ )
781 {
782    ....
783 }</programlisting>
784
785     <para><emphasis>Note:</emphasis> Unfortunately, this makes a function call for
786     each and every iteration. This increases the overhead in the
787     program, because the compiler has to look up the function each
788     time, call it, and return a value. Depending on what occurs in
789     the blockListLength() call, it might even be creating and
790     destroying structures with each iteration, even though in each
791     case it is comparing "cnt" to the same value, over and over.
792     Remember too - even a call to blockListLength() is a function
793     call, with the same overhead.</para>
794
795     <para>Instead of using a function call during the iterations,
796     assign the value to a variable, and evaluate using the
797     variable.</para>
798
799     <para><emphasis>Example:</emphasis></para>
800 <programlisting>
801 size_t len = blockListLength();
802
803 for ( size_t cnt = 0; cnt &lt; len; cnt ++ )
804 {
805    ....
806 }</programlisting>
807
808     <para><emphasis>Exceptions:</emphasis> if the value of blockListLength() *may*
809     change or could *potentially* change, then you must code the
810     function call in the for/while loop.</para>
811
812     
813   </sect3>
814     
815
816     <sect3 id="s29"><title>Pass and Return by Const Reference</title>
817
818     <para><emphasis>Explanation:</emphasis></para>
819
820     <para>This allows a developer to define a const pointer and call
821     your function. If your function does not have the const
822     keyword, we may not be able to use your function. Consider
823     strcmp, if it were defined as: extern int strcmp( char *s1,
824     char *s2 );</para>
825
826     <para>I could then not use it to compare argv's in main: int main(
827     int argc, const char *argv[] ) { strcmp( argv[0], "junkbusters"
828     ); }</para>
829
830     <para>Both these pointers are *const*! If the c runtime library
831     maintainers do it, we should too.</para>
832
833     
834   </sect3>
835     
836
837     <sect3 id="s30"><title>Pass and Return by Value</title>
838
839     <para><emphasis>Explanation:</emphasis></para>
840
841     <para>Most structures cannot fit onto a normal stack entry (i.e.
842     they are not 4 bytes or less). Aka, a function declaration
843     like: int load_aclfile( struct client_state csp )</para>
844
845     <para>would not work. So, to be consistent, we should declare all
846     prototypes with "pass by value": int load_aclfile( struct
847     client_state *csp )</para>
848
849     
850   </sect3>
851     
852
853     <sect3 id="s31"><title>Names of include files</title>
854
855     <para><emphasis>Explanation:</emphasis></para>
856
857     <para>Your include statements should contain the file name without
858     a path. The path should be listed in the Makefile, using -I as
859     processor directive to search the indicated paths. An exception
860     to this would be for some proprietary software that utilizes a
861     partial path to distinguish their header files from system or
862     other header files.</para>
863
864     <para><emphasis>Example:</emphasis></para>
865 <programlisting>
866 #include &lt;iostream.h&gt;     /* This is not a local include */
867 #include "config.h"       /* This IS a local include */
868 </programlisting>
869
870     <para><emphasis>Exception:</emphasis></para>
871
872     <para>
873 <programlisting>
874 /* This is not a local include, but requires a path element. */ 
875 #include &lt;sys/fileName.h&gt;
876 </programlisting>
877 </para>
878
879     <para><emphasis>Note:</emphasis> Please! do not add "-I." to the Makefile
880     without a _very_ good reason. This duplicates the #include
881     "file.h" behaviour.</para>
882
883     
884   </sect3>
885     
886
887     <sect3 id="s32"><title>Provide multiple inclusion
888     protection</title>
889
890     <para><emphasis>Explanation:</emphasis></para>
891
892     <para>Prevents compiler and linker errors resulting from
893     redefinition of items.</para>
894
895     <para>Wrap each header file with the following syntax to prevent
896     multiple inclusions of the file. Of course, replace PROJECT_H
897     with your file name, with "." Changed to "_", and make it
898     uppercase.</para>
899
900     <para><emphasis>Example:</emphasis></para>
901 <programlisting>
902 #ifndef PROJECT_H_INCLUDED
903 #define PROJECT_H_INCLUDED
904  ...
905 #endif /* ndef PROJECT_H_INCLUDED */
906 </programlisting>
907   </sect3>
908     
909
910     <sect3 id="s33"><title>Use `extern "C"` when appropriate</title>
911
912     <para><emphasis>Explanation:</emphasis></para>
913
914     <para>If our headers are included from C++, they must declare our
915     functions as `extern "C"`. This has no cost in C, but increases
916     the potential re-usability of our code.</para>
917
918     <para><emphasis>Example:</emphasis></para>
919 <programlisting>
920 #ifdef __cplusplus
921 extern "C"
922 {
923 #endif /* def __cplusplus */
924
925 ... function definitions here ...
926
927 #ifdef __cplusplus
928 }
929 #endif /* def __cplusplus */
930 </programlisting>
931   </sect3>
932     
933
934     <sect3 id="s34"><title>Where Possible, Use Forward Struct
935     Declaration Instead of Includes</title>
936
937     <para><emphasis>Explanation:</emphasis></para>
938
939     <para>Useful in headers that include pointers to other struct's.
940     Modifications to excess header files may cause needless
941     compiles.</para>
942
943     <para><emphasis>Example:</emphasis></para>
944 <programlisting>
945 /*********************************************************************
946  * We're avoiding an include statement here!
947  *********************************************************************/
948 struct file_list;
949 extern file_list *xyz;</programlisting>
950
951     <para><emphasis>Note:</emphasis> If you declare "file_list xyz;" (without the
952     pointer), then including the proper header file is necessary.
953     If you only want to prototype a pointer, however, the header
954     file is unneccessary.</para>
955
956     <para><emphasis>Status:</emphasis> Use with discrection.</para>
957
958     
959   </sect3>
960   </sect2>
961
962     <sect2 id="s35"><title>General Coding Practices</title>
963
964     
965
966     <sect3 id="s36"><title>Turn on warnings</title>
967
968     <para><emphasis>Explanation</emphasis></para>
969
970     <para>Compiler warnings are meant to help you find bugs. You
971     should turn on as many as possible. With GCC, the switch is
972     "-Wall". Try and fix as many warnings as possible.</para>
973
974     
975   </sect3>
976     
977
978     <sect3 id="s37"><title>Provide a default case for all switch
979     statements</title>
980
981     <para><emphasis>Explanation:</emphasis></para>
982
983     <para>What you think is guaranteed is never really guaranteed. The
984     value that you don't think you need to check is the one that
985     someday will be passed. So, to protect yourself from the
986     unknown, always have a default step in a switch statement.</para>
987
988     <para><emphasis>Example:</emphasis></para>
989 <programlisting>
990 switch( hash_string( cmd ) )
991 {
992    case hash_actions_file :
993       ... code ...
994       break;
995
996    case hash_confdir :
997       ... code ...
998       break;
999
1000    default :
1001       log_error( ... );
1002       ... anomly code goes here ...
1003       continue; / break; / exit( 1 ); / etc ...
1004
1005 } /* end switch( hash_string( cmd ) ) */</programlisting>
1006
1007     <para><emphasis>Note:</emphasis> If you already have a default condition, you
1008     are obviously exempt from this point. Of note, most of the
1009     WIN32 code calls `DefWindowProc' after the switch statement.
1010     This API call *should* be included in a default statement.</para>
1011
1012     <para><emphasis>Another Note:</emphasis> This is not so much a readability issue
1013     as a robust programming issue. The "anomly code goes here" may
1014     be no more than a print to the STDERR stream (as in
1015     load_config). Or it may really be an ABEND condition.</para>
1016
1017     <para><emphasis>Status:</emphasis> Programmer discretion is advised.</para>
1018
1019     
1020   </sect3>
1021     
1022
1023     <sect3 id="s38"><title>Try to avoid falling through cases in a
1024     switch statement.</title>
1025
1026     <para><emphasis>Explanation:</emphasis></para>
1027
1028     <para>In general, you will want to have a 'break' statement within
1029     each 'case' of a switch statement. This allows for the code to
1030     be more readable and understandable, and furthermore can
1031     prevent unwanted surprises if someone else later gets creative
1032     and moves the code around.</para>
1033
1034     <para>The language allows you to plan the fall through from one
1035     case statement to another simply by omitting the break
1036     statement within the case statement. This feature does have
1037     benefits, but should only be used in rare cases. In general,
1038     use a break statement for each case statement.</para>
1039
1040     <para>If you choose to allow fall through, you should comment both
1041     the fact of the fall through and reason why you felt it was
1042     necessary.</para>
1043
1044     
1045   </sect3>
1046     
1047
1048     <sect3 id="s39"><title>Use 'long' or 'short' Instead of
1049     'int'</title>
1050
1051     <para><emphasis>Explanation:</emphasis></para>
1052
1053     <para>On 32-bit platforms, int usually has the range of long. On
1054     16-bit platforms, int has the range of short.</para>
1055
1056     <para><emphasis>Status:</emphasis> open-to-debate. In the case of most FSF
1057     projects (including X/GNU-Emacs), there are typedefs to int4,
1058     int8, int16, (or equivalence ... I forget the exact typedefs
1059     now). Should we add these to IJB now that we have a "configure"
1060     script?</para>
1061
1062     
1063   </sect3>
1064     
1065
1066     <sect3 id="s40"><title>Don't mix size_t and other types</title>
1067
1068     <para><emphasis>Explanation:</emphasis></para>
1069
1070     <para>The type of size_t varies across platforms. Do not make
1071     assumptions about whether it is signed or unsigned, or about
1072     how long it is. Do not compare a size_t against another
1073     variable of a different type (or even against a constant)
1074     without casting one of the values. Try to avoid using size_t if
1075     you can.</para>
1076
1077     
1078   </sect3>
1079     
1080
1081     <sect3 id="s41"><title>Declare each variable and struct on its
1082     own line.</title>
1083
1084     <para><emphasis>Explanation:</emphasis></para>
1085
1086     <para>It can be tempting to declare a series of variables all on
1087     one line. Don't.</para>
1088
1089     <para><emphasis>Example:</emphasis></para>
1090 <programlisting>
1091 long a = 0;
1092 long b = 0;
1093 long c = 0;</programlisting>
1094
1095     <para><emphasis>Instead of:</emphasis></para>
1096
1097     <para>long a, b, c;</para>
1098
1099     <para><emphasis>Explanation:</emphasis> - there is more room for comments on the
1100     individual variables - easier to add new variables without
1101     messing up the original ones - when searching on a variable to
1102     find its type, there is less clutter to "visually"
1103     eliminate</para>
1104
1105     <para><emphasis>Exceptions:</emphasis> when you want to declare a bunch of loop
1106     variables or other trivial variables; feel free to declare them
1107     on 1 line. You should, although, provide a good comment on
1108     their functions.</para>
1109
1110     <para><emphasis>Status:</emphasis> developer-discrection.</para>
1111
1112     
1113   </sect3>
1114     
1115
1116     <sect3 id="s42"><title>Use malloc/zalloc sparingly</title>
1117
1118     <para><emphasis>Explanation:</emphasis></para>
1119
1120     <para>Create a local stuct (on the stack) if the variable will
1121     live and die within the context of one function call.</para>
1122
1123     <para>Only "malloc" a struct (on the heap) if the variable's life
1124     will extend beyond the context of one function call.</para>
1125
1126     <para><emphasis>Example:</emphasis></para>
1127 <programlisting>
1128 If a function creates a struct and stores a pointer to it in a
1129 list, then it should definately be allocated via `malloc'.
1130 </programlisting>
1131   </sect3>
1132     
1133
1134     <sect3 id="s43"><title>The Programmer Who Uses 'malloc' is
1135     Responsible for Ensuring 'free'</title>
1136
1137     <para><emphasis>Explanation:</emphasis></para>
1138
1139     <para>If you have to "malloc" an instance, you are responsible for
1140     insuring that the instance is `free'd, even if the deallocation
1141     event falls within some other programmer's code. You are also
1142     responsible for ensuring that deletion is timely (i.e. not too
1143     soon, not too late). This is known as "low-coupling" and is a
1144     "good thing (tm)". You may need to offer a
1145     free/unload/destuctor type function to accomodate this.</para>
1146
1147     <para><emphasis>Example:</emphasis></para>
1148 <programlisting>
1149 int load_re_filterfile( struct client_state *csp ) { ... }
1150 static void unload_re_filterfile( void *f ) { ... }</programlisting>
1151
1152     <para><emphasis>Exceptions:</emphasis></para>
1153
1154     <para>The developer cannot be expected to provide `free'ing
1155     functions for C run-time library functions ... such as
1156     `strdup'.</para>
1157
1158     <para><emphasis>Status:</emphasis> developer-discrection. The "main" use of this
1159     standard is for allocating and freeing data structures (complex
1160     or nested).</para>
1161
1162     
1163   </sect3>
1164     
1165
1166     <sect3 id="s44"><title>Add loaders to the `file_list' structure
1167     and in order</title>
1168
1169     <para><emphasis>Explanation:</emphasis></para>
1170
1171     <para>I have ordered all of the "blocker" file code to be in alpha
1172     order. It is easier to add/read new blockers when you expect a
1173     certain order.</para>
1174
1175     <para><emphasis>Note:</emphasis> It may appear that the alpha order is broken in
1176     places by POPUP tests coming before PCRS tests. But since
1177     POPUPs can also be referred to as KILLPOPUPs, it is clear that
1178     it should come first.</para>
1179
1180     
1181   </sect3>
1182     
1183
1184     <sect3 id="s45"><title>"Uncertain" new code and/or changes to
1185     exitinst code, use FIXME</title>
1186
1187     <para><emphasis>Explanation:</emphasis></para>
1188
1189     <para>If you have enough confidence in new code or confidence in
1190     your changes, but are not *quite* sure of the reprocussions,
1191     add this:</para>
1192
1193     <para>/* FIXME: this code has a logic error on platform XYZ, *
1194     attempthing to fix */ #ifdef PLATFORM ...changed code here...
1195     #endif</para>
1196
1197     <para>or:</para>
1198
1199     <para>/* FIXME: I think the original author really meant this...
1200     */ ...changed code here...</para>
1201
1202     <para>or:</para>
1203
1204     <para>/* FIXME: new code that *may* break something else... */
1205     ...new code here...</para>
1206
1207     <para><emphasis>Note:</emphasis> If you make it clear that this may or may not
1208     be a "good thing (tm)", it will be easier to identify and
1209     include in the project (or conversly exclude from the
1210     project).</para>
1211
1212     
1213   </sect3>
1214
1215   </sect2>
1216
1217     <sect2 id="s46"><title>Addendum: Template for files and function
1218     comment blocks:</title>
1219
1220     <para><emphasis>Example for file comments:</emphasis></para>
1221 <programlisting>
1222 const char FILENAME_rcs[] = "$Id: developer-manual.sgml,v 1.6 2002/02/24 14:25:06 jongfoster Exp $";
1223 /*********************************************************************
1224  *
1225  * File        :  $S<!-- Break CVS Substitution -->ource$
1226  *
1227  * Purpose     :  (Fill me in with a good description!)
1228  *
1229  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
1230  *                IJBSWA team.  http://ijbswa.sourceforge.net
1231  *
1232  *                Based on the Internet Junkbuster originally written
1233  *                by and Copyright (C) 1997 Anonymous Coders and
1234  *                Junkbusters Corporation.  http://www.junkbusters.com
1235  *
1236  *                This program is free software; you can redistribute it
1237  *                and/or modify it under the terms of the GNU General
1238  *                Public License as published by the Free Software
1239  *                Foundation; either version 2 of the License, or (at
1240  *                your option) any later version.
1241  *
1242  *                This program is distributed in the hope that it will
1243  *                be useful, but WITHOUT ANY WARRANTY; without even the
1244  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
1245  *                PARTICULAR PURPOSE.  See the GNU General Public
1246  *                License for more details.
1247  *
1248  *                The GNU General Public License should be included with
1249  *                this file.  If not, you can view it at
1250  *                http://www.gnu.org/copyleft/gpl.html
1251  *                or write to the Free Software Foundation, Inc., 59
1252  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
1253  *
1254  * Revisions   :
1255  *    $L<!-- Break CVS Substitution -->og$
1256  *
1257  *********************************************************************/
1258
1259
1260 #include "config.h"
1261
1262    ...necessary include files for us to do our work...
1263
1264 const char FILENAME_h_rcs[] = FILENAME_H_VERSION;
1265 </programlisting>
1266
1267     <para><emphasis>Note:</emphasis> This declares the rcs variables that should be
1268     added to the "show-proxy-args" page. If this is a brand new
1269     creation by you, you are free to change the "Copyright" section
1270     to represent the rights you wish to maintain.</para>
1271
1272     <para><emphasis>Note:</emphasis> The formfeed character that is present right
1273     after the comment flower box is handy for (X|GNU)Emacs users to
1274     skip the verbige and get to the heart of the code (via
1275     `forward-page' and `backward-page'). Please include it if you
1276     can.</para>
1277
1278     <para><emphasis>Example for file header comments:</emphasis></para>
1279 <programlisting>
1280 #ifndef _FILENAME_H
1281 #define _FILENAME_H
1282 #define FILENAME_H_VERSION "$Id: developer-manual.sgml,v 1.6 2002/02/24 14:25:06 jongfoster Exp $"
1283 /*********************************************************************
1284  *
1285  * File        :  $S<!-- Break CVS Substitution -->ource$
1286  *
1287  * Purpose     :  (Fill me in with a good description!)
1288  *
1289  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
1290  *                IJBSWA team.  http://ijbswa.sourceforge.net
1291  *
1292  *                Based on the Internet Junkbuster originally written
1293  *                by and Copyright (C) 1997 Anonymous Coders and
1294  *                Junkbusters Corporation.  http://www.junkbusters.com
1295  *
1296  *                This program is free software; you can redistribute it
1297  *                and/or modify it under the terms of the GNU General
1298  *                Public License as published by the Free Software
1299  *                Foundation; either version 2 of the License, or (at
1300  *                your option) any later version.
1301  *
1302  *                This program is distributed in the hope that it will
1303  *                be useful, but WITHOUT ANY WARRANTY; without even the
1304  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
1305  *                PARTICULAR PURPOSE.  See the GNU General Public
1306  *                License for more details.
1307  *
1308  *                The GNU General Public License should be included with
1309  *                this file.  If not, you can view it at
1310  *                http://www.gnu.org/copyleft/gpl.html
1311  *                or write to the Free Software Foundation, Inc., 59
1312  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
1313  *
1314  * Revisions   :
1315  *    $L<!-- Break CVS Substitution -->og$
1316  *
1317  *********************************************************************/
1318
1319
1320 #include "project.h"
1321
1322 #ifdef __cplusplus
1323 extern "C" {
1324 #endif
1325
1326    ... function headers here ...
1327
1328
1329 /* Revision control strings from this header and associated .c file */
1330 extern const char FILENAME_rcs[];
1331 extern const char FILENAME_h_rcs[];
1332
1333
1334 #ifdef __cplusplus
1335 } /* extern "C" */
1336 #endif
1337
1338 #endif /* ndef _FILENAME_H */
1339
1340 /*
1341   Local Variables:
1342   tab-width: 3
1343   end:
1344 */
1345 </programlisting>
1346
1347     <para><emphasis>Example for function comments:</emphasis></para>
1348 <programlisting>
1349 /*********************************************************************
1350  *
1351  * Function    :  FUNCTION_NAME
1352  *
1353  * Description :  (Fill me in with a good description!)
1354  *
1355  * parameters  :
1356  *          1  :  param1 = pointer to an important thing
1357  *          2  :  x      = pointer to something else
1358  *
1359  * Returns     :  0 => Ok, everything else is an error.
1360  *
1361  *********************************************************************/
1362 int FUNCTION_NAME( void *param1, const char *x )
1363 {
1364    ...
1365    return( 0 );
1366
1367 }
1368 </programlisting>
1369
1370     <para><emphasis>Note:</emphasis> If we all follow this practice, we should be
1371     able to parse our code to create a "self-documenting" web
1372     page.</para>
1373
1374   </sect2>
1375
1376   </sect1>
1377
1378   <!--   ~~~~~       New section      ~~~~~     -->
1379   <sect1 id="cvs"><title>Version Control Guidelines</title>
1380     <para>To be filled. note on cvs comments. don't comment what you did, comment
1381 why you did it.
1382 </para>
1383   </sect1>
1384
1385   <!--   ~~~~~       New section      ~~~~~     -->
1386   <sect1 id="testing"><title>Testing Guidelines</title>
1387     <para>To be filled.
1388 </para>
1389
1390     <!--   ~~~~~       New section      ~~~~~     -->
1391     <sect2 id="testing-plan"><title>Testplan for releases</title>
1392       <para>
1393 Explain release numbers. major, minor. developer releases. etc.
1394
1395 <orderedlist numeration="arabic">
1396           <listitem><para>
1397 Remove any existing rpm with rpm -e
1398 </para></listitem>
1399           <listitem><para>
1400 Remove any file that was left over. This includes (but is not limited to)
1401       <itemizedlist>
1402                 <listitem><para>/var/log/junkbuster</para></listitem>
1403                 <listitem><para>/etc/junkbuster</para></listitem>
1404                 <listitem><para>/usr/sbin/junkbuster</para></listitem>
1405                 <listitem><para>/etc/init.d/junkbuster</para></listitem>
1406                 <listitem><para>/usr/doc/junkbuster*</para></listitem>
1407               </itemizedlist>
1408 </para></listitem>
1409           <listitem><para>
1410 Install the rpm. Any error messages?
1411 </para></listitem>
1412           <listitem><para>start,stop,status junkbuster with the specific script
1413       (e.g. /etc/rc.d/init/junkbuster stop). Reboot your machine. Does
1414       autostart work?</para></listitem>
1415           <listitem><para>Start browsing. Does the junkbuster work? Logfile written?</para></listitem>
1416           <listitem><para>Remove the rpm. Any error messages? All files removed?</para></listitem>
1417         </orderedlist>
1418 </para>
1419     </sect2>
1420
1421     <!--   ~~~~~       New section      ~~~~~     -->
1422     <sect2 id="testing-report"><title>Test reports</title>
1423       <para>
1424 Please submit test reports only with the <ulink url="http://sourceforge.net/tracker/?func=add&amp;group_id=11118&amp;atid=395005">test form</ulink>
1425 at sourceforge. Three simple steps:
1426         <itemizedlist>
1427           
1428           <listitem><para>Select category: the distribution you test on.</para></listitem>
1429           <listitem><para>Select group: the version of Junkbuster that we are about to release.</para></listitem>
1430           <listitem><para>Fill the Summary and Detailed Description with something
1431               intelligent (keep it short and precise).</para>
1432           </listitem>
1433         </itemizedlist>
1434         Do not mail to the mailinglist (we cannot keep track on issues there).
1435       </para>
1436     </sect2>
1437     
1438   </sect1>
1439   
1440   <!--   ~~~~~       New section      ~~~~~     -->
1441   <sect1 id="contact"><title>Contact the developers</title>
1442     <para>Please see the user manual for information on how to contact the developers.
1443     </para>
1444   </sect1>
1445   
1446   <!--   ~~~~~       New section      ~~~~~     -->
1447   <sect1 id="copyright"><title>Copyright and History</title>
1448     <para>Please see the user manual for information on Copyright and History.
1449     </para>
1450   </sect1>
1451   
1452   <!--   ~~~~~       New section      ~~~~~     -->
1453   <sect1 id="seealso"><title>See also</title>
1454     <para>Please see the user manual for information on references.
1455     </para>
1456   </sect1>
1457
1458   <!--
1459
1460   This program is free software; you can redistribute it 
1461   and/or modify it under the terms of the GNU General
1462   Public License as published by the Free Software
1463   Foundation; either version 2 of the License, or (at
1464   your option) any later version.
1465
1466   This program is distributed in the hope that it will
1467   be useful, but WITHOUT ANY WARRANTY; without even the
1468   implied warranty of MERCHANTABILITY or FITNESS FOR A
1469   PARTICULAR PURPOSE.  See the GNU General Public
1470   License for more details.
1471
1472   The GNU General Public License should be included with
1473   this file.  If not, you can view it at
1474   http://www.gnu.org/copyleft/gpl.html
1475   or write to the Free Software Foundation, Inc., 59
1476   Temple Place - Suite 330, Boston, MA  02111-1307, USA.
1477
1478   $Log: developer-manual.sgml,v $
1479   Revision 1.6  2002/02/24 14:25:06  jongfoster
1480   Formatting changes.  Now changing the doctype to DocBook XML 4.1
1481   will work - no other changes are needed.
1482
1483   Revision 1.5  2001/10/31 18:16:51  swa
1484   documentation added: howto generate docs in text and html
1485   format, howto move stuff to the webserver.
1486
1487   Revision 1.4  2001/09/23 10:13:48  swa
1488   upload process established. run make webserver and
1489   the documentation is moved to the webserver. documents
1490   are now linked correctly.
1491
1492   Revision 1.3  2001/09/13 15:27:40  swa
1493   cosmetics
1494
1495   Revision 1.2  2001/09/13 15:20:17  swa
1496   merged standards into developer manual
1497
1498   Revision 1.1  2001/09/12 15:36:41  swa
1499   source files for junkbuster documentation
1500
1501   Revision 1.3  2001/09/10 17:43:59  swa
1502   first proposal of a structure.
1503
1504   Revision 1.2  2001/06/13 14:28:31  swa
1505   docs should have an author.
1506
1507   Revision 1.1  2001/06/13 14:20:37  swa
1508   first import of project's documentation for the webserver.
1509
1510   -->
1511
1512 </article>