Merged revisions 570-572,574-575,578-579,581-595,598-611 via svnmerge from
[senf.git] / Socket / SocketPolicy.hh
1 // $Id:SocketPolicy.hh 218 2007-03-20 14:39:32Z tho $
2 //
3 // Copyright (C) 2006
4 // Fraunhofer Institute for Open Communication Systems (FOKUS) 
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY 
6 //     Stefan Bund <g0dil@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief Policy Framework public header
25
26     \todo Do we want to support separate read and write policies. This allows to treat pipes within
27         this framework however, is this worth the effort?
28
29     \idea Creating a new Socket will create 4 (!) new instances (The handle, the body, the policy
30         and the protocol) of which 3 (argh) (body, policy and protocol) live on the heap. This is
31         expensive. We should convert all the policy classes to singletons and assign the same
32         instance to all socket bodies with the same policy. This would reduce the number of heap
33         allocations per socket handle to two.
34  */
35
36 /** \defgroup policy_group The Policy Framework
37
38     \htmlonly
39         <map name="socketPolicy">
40           <area shape="rect" alt="SocketPolicy" href="structsenf_1_1SocketPolicy.html" title="SocketPolicy" coords="276,90,558,213" />
41           <area shape="rect" alt="WritePolicyBase" href="structsenf_1_1WritePolicyBase.html" title="WritePolicyBase" coords="39,243,174,268" />
42           <area shape="rect" alt="ReadPolicyBase" href="structsenf_1_1ReadPolicyBase.html" title="ReadPolicyBase" coords="42,204,174,231" />
43           <area shape="rect" alt="CommunicationPolicyBase" href="structsenf_1_1CommunicationPolicyBase.html" title="CommunicationPolicyBase" coords="0,166,215,193" />
44           <area shape="rect" alt="FramingPolicyBase" href="structsenf_1_1FramingPolicyBase.html" title="FramingPolicyBase" coords="30,129,185,155" />
45           <area shape="rect" alt="AddressingPolicyBase" href="structsenf_1_1AddressingPolicyBase.html" title="AddressingPolicyBase" coords="17,90,200,116" />
46         </map>
47         <img src="SocketPolicy.png" border="0" alt="Socket Policy" usemap="#socketPolicy">
48     \endhtmlonly
49         
50     \section policy_group_introduction Introduction to the Policy Framework
51
52     The policy framework conceptually implements a list of parallel inheritance hierarchies each
53     covering a specific interface aspect of the socket handle. The socket handle itself only
54     provides minimal functionality. All further functionality is relayed to a policy class, or more
55     precisely, to a group of policy classes, one for each policy axis. The policy axis are
56
57     <dl><dt><em>addressingPolicy</em></dt><dd>configures, whether a socket is addressable and if
58     so, configures the address type</dd>
59
60     <dt><em>framingPolicy</em></dt> <dd>configures the type of framing the socket provides: either
61     no framing providing a simple i/o stream or packet framing</dd>
62
63     <dt><em>communicationPolicy</em></dt><dd>configures,if and how the communication partner is
64     selected</dd>
65
66     <dt><em>readPolicy</em></dt><dd>configures the readability of the socket</dd>
67
68     <dt><em>writePolicy</em></dt><dd>configures the writability of the socket</dd>
69
70     The template senf::SocketPolicy combines these policy axis to form a concrete socket policy. In
71     a concrete policy, each of these policy axis is assigned a value, the policy value. This value
72     is identified by a class type, a policy class. E.g. possible values for <em>framingPolicy</em>
73     are <tt>DatagramFramingPolicy</tt> or <tt>StreamFramingPolicy</tt> which are classes derived
74     from the axis base class <tt>FramingPolicyBase</tt>. This base class also doubles as
75     <tt>UnspecifiedFramingPolicy</tt> (which is just a typedef alias).  If a policy axis is assigned
76     this Unspecified type, the axis is left unspecified, the concrete policy will be incomplete.
77     
78     The senf::SocketPolicy template defines the behavior of a socket handle. The socket handle
79     instances do not implement any socket functionality themselves instead deferring the
80     implementation to the policy classes. The SocketHandle interface is therefore \e not implemented
81     using virtual members, all important socket functions can be inlined by the compiler to create
82     highly efficient code.
83
84     A senf::SocketPolicy instance can be incomplete. In this case it does \e not completely specify
85     the socket interface, it leaves some aspects open by assigning the Unspecified value to one or
86     more of the policy axis. A senf::SocketHandle based on such a policy will have a reduced
87     interface: It will only support those members for which the corresponding policies are defined.
88
89     To build a senf::SocketPolicy instance the senf::MakeSocketPolicy helper is provided. This
90     helper template takes any number (it is really limited to 6 Arguments but more arguments don't
91     make sense) of policy classes as it's argument. The MakeSocketPolicy helper will take the
92     arguments in the order they are specified and for each argument will check to which axis the
93     policy class belongs (by checking the base classes of that class) and assign it to the correct
94     policy axis in the senf::SocketPolicy template. If any policy axis are not specified, they are
95     defaulted to their corresponding Unspecified value. This helper frees you to specify the policy
96     classes in any order. An additional feature is, that you may specify a complete policy as a
97     first argument. This policy will then be used to provide default values for unspecified axis.
98
99     Two senf::SocketHandle's with different policies can be \e compatible. If they are, the more
100     specific SocketHandle can be converted (assigned to) the more basic SocketHandle. A SocketHandle
101     is more specific then another SocketHandle if the policy of the former is more specific then
102     that of the latter which means, that for each policy axis separately, the value of that axis of
103     the more specific policy is derived from or the same as the value of that axis in the more basic
104     policy. This is like converting a derived class pointer to a base class pointer, only it happens
105     separately but at the same time for each policy axis:
106
107     \code
108     // This defines an incomplete policy where addressingPolicy and writePolicy
109     // are unspecified
110     typedef senf::MakeSocketPolicy<
111         senf::StreamFramingPolicy,
112         senf::ConnectedCommunicationPolicy,
113         senf::ReadablePolicy
114         >::policy MyReadableSocketPolicy
115
116     typedef senf::ClientSocketHandle<MyReadableSocketPolicy> MyReadableHandle;
117
118     // TCPv4ClientSocketHandle is a socket handle with the policy equivalent to
119     // senf::MakeSocketPolicy<
120     //     INet4AddressingPolicy,
121     //     StreamFramingPolicy,
122     //     ConnectedCommunicationPolicy,
123     //     ReadablePolicy,
124     //     WritablePolicy>::policy
125     senf::TCPv4ClientSocketHandle tcpHandle (...);
126
127     MyReadableHandle myHandle (tcpHandle); // Conversion to more basic socket handle
128     \endcode
129
130     \section policy_group_details The Policy Framework Classes
131
132     In the following discussion, deeper insight into C++ and especially the concepts of template
133     meta-programming are needed. However, this information is only needed if you want to write new
134     policy classes or want to use the policy framework explicitly for your own involved
135     optimizations ... or if you are just plain curious :-)
136     
137     In the following discussion we will use the following conventions:
138     \li \e Axis is one or \c AddressingPolicy, \c FramingPolicy, \c CommunicationPolicy, \c
139         ReadPolicy or \c WritePolicy
140     \li \e socketPolicy is any socket policy (that is, an instantiation of the SocketPolicy
141         template)
142     \li \e trait is an any policy class (that is, any class derived from one of the axis base
143         classes)
144
145     Each axis is comprised of a number of classes and templates (all in namespace senf of course):
146
147     <dl><dt>\e Axis \c Base (ex: AddressingPolicyBase)</dt><dd>Baseclass of all policies in this
148     axis</dd>
149
150     <dt>\c Unspecified \e Axis (ex: \ref UnspecifiedAddressingPolicy)</dt> <dd>An alias (typedef)
151     for \e Axis \c Base</dd>
152
153     <dt>\e Axis \c Is < \e socketPolicy, \e trait > (ex: AddressingPolicyIs)</dt> <dd>A template
154     metafunction returning \c boost::true_type, if \e trait (any class derived from \e Axis \c
155     Base) is a compatible policy value of the given \e socketPolicy</dd>
156
157     <dt>\c If \e Axis \c Is < \e socketPolicy, \e trait > (ex: IfAddressingPolicyIs)</dt> <dd>This
158     is a combination of \e Axis \c Is and \c boost::enable_if</dd>
159
160     <dt>\c If \e Axis \c IsNot < \e socketPolicy, \e trait > (ex: IfAddressingPolicyIsNot)</dt>
161     <dd>The inverse of above</dd> </dl>
162
163     These classes form the basis of the policy framework. To bind the policy axis together, there
164     are some more classes and templates.
165
166     <dl><dt>\c class \c SocketPolicyBase</dt> <dd>This class is the base class of the SocketPolicy
167     template. It is used to validate, that a class is really a SocketPolicy (by checking, that it
168     derives from SocketPolicyBase. This is simpler than checking the template directly).</dd>
169
170     <dt>\c template \c SocketPolicy < \e addressingPolicy, \e framingPolicy, \e communicationPolicy,
171     \e readPolicy, \e writePolicy ></dt> <dd>This is the central SocketPolicy
172     template. It combines a complete set of policy classes, one for each axis.</dd>
173
174     <dt>\c template \c MakeSocketPolicy < \e args ></dt> <dd>\c MakeSocketPolicy is a template
175     metafunction which simplifies building SocketPolicy instantiations. It takes any number (ok, up
176     to a maximum of 6) of policy classes as an argument (in any order). It will sort these arguments
177     into the SocketPolicy template arguments. If for some axis no class is specified, it's slot will
178     be filled with \c Unspecified \e Axis. Additionally, the first Argument may optionally be ab
179     arbitrary SocketPolicy. It will provide default values for unspecified axis</dd>
180
181     <dt>\c template \c SocketPolicyIsBaseOf < \e base, \e derived ></dt> <dd>This template
182     metafunction will check, whether the socket policy \e derived is convertible to \e base. This
183     means, that for each axis, the corresponding policy class in \e derived must be derived or be
184     the same as the one on \e base.</dd> </dl>
185
186     \implementation All these classes are created automatically. The \c SENF_SOCKET_POLICIES macro
187     is a Boost.Preprocessor style sequence listing all policy axis. The Boost.Preprocessor library
188     is then used to generate the respective classes.
189
190     \section policy_implement Implementing Policy Classes
191
192     To define a new policy class, derive from the corresponding base class for your policy axes. The
193     only policy axis which might possibly need to be extended is the addressing policy
194     (AddressingPolicyBase). See the Documentation of these classes for more information on which
195     members can be implemented.
196
197     All members you define must be static. For any of the policy classes, you must only define those
198     members which are supported by your implementation. If you leave out a member you automatically
199     disable the corresponding functionality in the ClientSocketHandle/ServerSocketHandle interface.
200
201     The member prototypes given in the base class documentation only specify the call signature not
202     the way, the member must be defined (FileHandle really is not a FileHandle but an arbitrary
203     SocketHandle).
204
205     If the existence of a member depends on other policies, you should use the
206     <code>If</code><i>SomePolicy</i><code>Is</code> and
207     <code>If</code><i>SomePolicy</i><code>IsNot</code> templates to dynamically enable/disable the
208     member depending on some other policy:
209
210     \code
211       struct ExampleAddressingPolicy
212       {
213           template <class Policy>
214           void connect(senf::SocketHandle<Policy> handle, Address & addr,
215                        typename senf::IfCommmunicationPolicyIs<
216                            Policy, senf::ConnectedCommunicationPolicy>::type * = 0);
217       };
218     \endcode
219
220     The \c connect member in this example will only be enabled, it the communication policy of the
221     socket handle is ConnectedCommunicationPolicy (or a derived type). See <a
222     href="http://www.boost.org/libs/utility/enable_if.html">Boost.Enable_If</a> for a discussion of
223     the third argument (\c senf::ConnectedCommunicationPolicyIs is based on the \c boost::enable_if
224     template).
225
226     \see \ref extend_policy \n
227          <a href="http://www.boost.org/libs/utility/enable_if.html">The Boost enable_if utility</a> \n
228          <a href="http://www.boost.org/libs/mpl/doc/index.html">The Boost.MPL library</a> \n
229          <a href="http://www.boost.org/libs/preprocessor/doc/index.html">The Boost.Preprocessor library</a>
230
231     \idea We could combine all the \e Axis \c Is templates into a single template. Since the \e
232     trait argument will automatically specify the axis to be used, it is not necessary to specify
233     that axis in the template functor's name. We could even combine this with \c
234     SocketPolicyIsBaseOf.
235  */
236
237 /** \defgroup policy_impl_group Policy Implementation classes
238     \ingroup policy_group
239
240     Here you will find all policy classes. Also included are some supporting classes which are used
241     as base classes to build other policy classes.
242  */
243
244 #ifndef HH_SocketPolicy_
245 #define HH_SocketPolicy_ 1
246
247 // Custom includes
248
249 //#include "SocketPolicy.mpp"
250 ///////////////////////////////hh.p////////////////////////////////////////
251
252 namespace senf {
253
254     /// \addtogroup policy_group
255     /// @{
256
257     // This may be adapted to change the supported policies (however, ClientSocketHandle and
258     // ServerSocketHandle will probably have to be adjusted accordingly)
259
260     /** \brief List all policy axis
261
262         \internal
263
264         This define symbol is used to configure the policy axis. The base class for each of these
265         axis must be defined explicitly (e.g. AddressingPolicyBase). The implementation files will
266         then automatically generate all the other classes from this list.
267
268         \see policy_group
269      */
270 #   define SENF_SOCKET_POLICIES                 \
271         (AddressingPolicy)                      \
272         (FramingPolicy)                         \
273         (CommunicationPolicy)                   \
274         (ReadPolicy)                            \
275         (WritePolicy)
276
277     // Wer define these classes explicitly (and not with some macro
278     // magic) because
279     // a) AddressingPolicyBase is different from all the others
280     // b) We want to document each one explicitly
281
282     /** \brief Policy defining socket addressing
283
284         AddressingPolicyBase is the baseclass of all addressing policy classes. When defining a new
285         addressing policy, the following members can be defined. All methods must be static.
286
287         <table class="senf">
288         <tr><td>typedef</td> <td><tt>Address</tt></td>                                   <td>Address type</td></tr>
289         <tr><td>method</td>  <td><tt>void local(FileHandle, Address &)</tt></td>         <td>Get local socket address</td></tr>
290         <tr><td>method</td>  <td><tt>void peer(FileHandle, Address &)</tt></td>          <td>Get remote socket address</td></tr>
291         <tr><td>method</td>  <td><tt>void bind(FileHandle, Address const &)</tt></td>    <td>Bind socket to local address</td></tr>
292         <tr><td>method</tr>  <td><tt>void connect(FileHandle, Address const &)</tt></td> <td>Connect to remote address</td></tr>
293         </table>
294
295         \see policy_group
296      */
297     struct AddressingPolicyBase
298     {
299         virtual ~AddressingPolicyBase() {}
300
301         class Address { Address(); };
302     };
303
304     /** \brief Policy defining the framing format
305
306         This policy does not define any operations since it does have no influence on any method
307         signature. It does however affect the semantics of the \c read() and \c write() operations.
308
309         \note This policy axis probably only has two sensible states: StreamFramingPolicy and
310         DatagramFramingPolicy.
311
312         \see policy_group
313      */
314     struct FramingPolicyBase
315     {
316         virtual ~FramingPolicyBase() {}
317     };
318
319     /** \brief Policy defining, how peers are selected
320
321         The CommunicationPolicy may define two members:
322
323         <table class="senf">
324         <tr><td>method</td> <td><tt>void listen(FileHandle, unsigned backlog)</tt></td> <td>Switch socket into listening state</td></tr>
325         <tr><td>method</td> <td><tt>int accept(FileHandle, Address &)</tt></td>         <td>Accept a new connection</td></tr>
326         <tr><td>method</td> <td><tt>int accept(FileHandle)</tt></td>                    <td>Accept a new connection</td></tr>
327         </table>
328
329         The \c listen member is straight forward. The \c accept() member must return a new file
330         descriptor (which will be used to create a new SocketHandle of the correct
331         type). 
332
333         \note This Policy only has two meaningful states: ConnectedCommunicationPolicy and
334         UnconnectedCommunicationPolicy. It is probably not sensible to define a new
335         CommunicationPolicy type.
336
337         \see policy_group
338      */
339     struct CommunicationPolicyBase
340     {
341         virtual ~CommunicationPolicyBase() {}
342     };
343
344     /** \brief Policy defining the readability
345
346         The ReadPolicy defines, whether the socket is readable. It may define two members:
347
348         <table class="senf">
349         <tr><td>method</td> <td><tt>unsigned read(FileHandle, char * buffer, unsigned size)</tt></td>                <td>read data from socket</td></tr>
350         <tr><td>method</td> <td><tt>unsigned readfrom(FileHandle, char * buffer, unsigned size, Address &)</tt></td> <td>read data from unconnected socket</td></tr>
351         </table>
352
353         The second member should only be enabled if the communication policy is
354         UnconnectedCommunicationPolicy (otherwise it does not make sense since the communication partner
355         is fixed) (see AddressingPolicyBase on how to do this).
356
357         \note This Policy only has two meaningful states: ReadablePolicy and NotReadablePolicy. It
358         probably does not make sense to define new read policy types.
359
360         \see policy_group
361      */
362     struct ReadPolicyBase
363     {
364         virtual ~ReadPolicyBase() {}
365     };
366
367     /** \brief Policy defining the writability
368
369         The WritePolicy defines, whether the socket is writable. It may define two members:
370
371         <table class="senf">
372         <tr><td>method</td> <td><tt>unsigned write(FileHandle, char * buffer, unsigned size)</tt></td>              <td>read data from socket</td></tr>
373         <tr><td>method</td> <td><tt>unsigned writeto(FileHandle, char * buffer, unsigned size, Address &)</tt></td> <td>read data from unconnected socket</td></tr>
374         </table>
375
376         The second member should only be enabled if the communication policy is
377         UnconnectedCommunicationPolicy (otherwise it does not make sense since the communication partner
378         is fixed) (see AddressingPolicyBase on how to do this).
379
380         \note This Policy only has two meaningful states: WritablePolicy and NotWritablePolicy. It
381         probably does not make sense to define new write policy types.
382
383         \see policy_group
384      */
385     struct WritePolicyBase
386     {
387         virtual ~WritePolicyBase() {}
388     };
389
390     // The implementation file will for each Policy declared above
391     // define the following (SomePolicy is one of the above):
392     //
393     // struct SomePolicyBase;
394     // typedef UndefinedSomePolicy;
395     // template SomePolicyIs< SocketPolicy, Axis >
396     // template IfSomePolicyIs< SocketPolicy, Axis >
397     // template IfSomePolicyIsNot< SocketPolicy, Axis >
398     //
399     // Additionally the following are defined:
400     //
401     // class SocketPolicyBase
402     // template SocketPolicy< ..policies.. >
403     // template MakeSocketPolicy< ..args.. >
404     // template SocketPolicyIsBaseOf< Base, Derived >
405
406 #   ifdef DOXYGEN
407
408     // The following stub definitions are only visible to doxygen
409
410     /** \brief Alias of AddressingPolicyBase for better readability
411         \see \ref policy_group
412      */
413     typedef AddressingPolicyBase UnspecifiedAddressingPolicy;
414
415     /** \brief Check single policy axis
416
417         This template is an example of the \e Axis \c Is family of template metafunctions. It will
418         check, whether \c Trait is a valid compatible Policy class of \c SocketPolicy. \c Trait must
419         be derived from AddressingPolicyBase (respectively \c Policy \c Base).
420
421         \see \ref policy_group
422      */
423     template <class SocketPolicy, class Trait>
424     struct AddressingPolicyIs
425     {};
426
427     /** \brief Enable template overload depending on policy value
428
429         This template is an example of the \c If \e Axis \c Is family of templates. It is used like
430         <a href="http://www.boost.org/libs/utility/enable_if.html">Boost.enable_if</a> to enable a
431         templated overload only, if the AddressingPolicy of \e Axis is compatible with \c Trait
432         (that is the AddressingPolicy of \c Policy is derived from \c Trait).
433
434         \see policy_group
435      */
436     template <class SocketPolicy, class Trait>
437     struct IfAddressingPolicyIs
438     {};
439
440     /** \brief Inversion of \c IfAddressingPolicyIs
441         \see policy_group
442      */
443     template <class SocketPolicy, class Trait>
444     struct IfAddressingPolicyIsNot
445     {};
446
447     /** \brief Baseclass of all SocketPolicies
448
449         \internal
450
451         This class provides the baseclass of all socket policies (bundles). It serves two purposes:
452         \li It allows us to easily identify a socket policy bundle by checking a classes baseclass.
453         \li It provides an abstract (virtual) interface to access the policy axes
454
455         \see policy_group
456      */
457     struct SocketPolicyBase
458     {
459         /** \brief Polymorphic access to policy axes
460
461             This is an example of a policy axes accessor. It returns a reference to the policy axes
462             used by the concrete protocol bundle. This reference can then be checked using RTTI
463             information.
464          */
465         AddressingPolicyBase const & theAddressingPolicy() const = 0;
466     };
467
468     /** \brief Collection of policy classes
469
470         The SocketPolicy template defines the complete Policy used by the socket library. It
471         contains one policy class for each policy axis. This template takes one policy from each
472         axis as it's template arguments (this example implementation only has AddressingPolicy as an
473         argument).
474
475         A SocketPolicy can be complete or incomplete. An incomplete SocketPolicy will have at least
476         one axis set to \c Undefined \e Axis (or a generic derived class which is used to group some
477         other policies but does not (completely) define the policy behavior). A complete
478         SocketPolicy will have a concrete definition of the desired behavior for each policy axis.
479
480         \see policy_group
481      */
482     template < class AddressingPolicy >
483     struct SocketPolicy
484     {
485         /** \brief Check dynamic policy compatibility
486
487             This check will validate, that a socket with \a other as it's policy is convertible to a
488             socket with the current SocketPolicy as it's policy. This is true, if for each policy
489             axis, the policy class of that axis as defined in the \a other policy is convertible to
490             the policy class of that same axis in the current SocketPolicy instance (as is defined
491             by the template arguments). This again is true, if the \a other policy class is derived
492             from (or is the same as) the policy class taken from the current SocketPolicy instance.
493
494             In other words, this call checks, that the current SocketPolicy (as defined via the
495             template arguments) is more generic than the \a other socket policy.
496
497             \param[in] other SocketPolicy to check
498             \throws std::bad_cast if \a other is not a compatible policy
499          */
500         static void checkBaseOf(SocketPolicyBase const & other);
501     };
502
503     /** \brief Metafunction to create SocketPolicy
504
505         This template metafunction simplifies the creation of a SocketPolicy instantiation. It takes
506         any number (that is up to 6) of Policy classes as arguments in any Order. It will create a
507         SocketPolicy from these policy classes. Any axis not specified will be left as \c
508         Unspecified \e Axis.
509
510         \see policy_group
511      */
512     template <class Arg1, class Arg2, class ArgN>
513     struct MakeSocketPolicy
514     {};
515
516     /** \brief Check policy compatibility
517
518         This template metafunction checks, whether the SocketPolicy \c Derived is more specialized
519         than \c Base (and therefore a SocketHandle with policy \c Derived is convertible to a
520         SocketHandle with policy \c Base).
521
522         The metafunction will return true (that is inherits from \c boost::true_type, see the <a
523         href="http://www.boost.org/libs/mpl/doc/index.html">Boost.MPL</a> library documentation for
524         more information) if each policy class in \c Base is a baseclass of (or the same as) the
525         corresponding policy class in \c Derived.
526
527         \see policy_group
528      */
529     template <class Base, class Derived>
530     struct SocketPolicyIsBaseOf
531     {};
532
533 #   endif
534
535     /// @}
536 }
537
538 //////////////////////////////hh.e////////////////////////////////////////
539 #include "SocketPolicy.ih"
540 //#include "SocketPolicy.cci"
541 #include "SocketPolicy.ct"
542 //#include "SocketPolicy.cti"
543 #endif
544
545 \f
546 // Local Variables:
547 // mode: c++
548 // fill-column: 100
549 // c-file-style: "senf"
550 // indent-tabs-mode: nil
551 // ispell-local-dictionary: "american"
552 // compile-command: "scons -u test"
553 // comment-column: 40
554 // End: