e58d9909dafe58ea13a5bcee0280d746648e9b7d
[free-sw/xcb/libxcb] / src / c-client.xsl
1 <?xml version="1.0" encoding="utf-8"?>
2 <!--
3 Copyright (C) 2004 Josh Triplett.  All Rights Reserved.
4
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in all
13 copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the names of the authors or their
23 institutions shall not be used in advertising or otherwise to promote the
24 sale, use or other dealings in this Software without prior written
25 authorization from the authors.
26 -->
27 <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
28                version="1.0"
29                xmlns:e="http://exslt.org/common">
30   
31   <xsl:output method="text" />
32
33   <xsl:strip-space elements="*" />
34
35   <!-- "header" or "source" -->
36   <xsl:param name="mode" />
37
38   <!-- Path to the core protocol descriptions. -->
39   <xsl:param name="base-path" />
40
41   <!-- Path to the extension protocol descriptions. -->
42   <xsl:param name="extension-path" select="$base-path" />
43
44   <xsl:variable name="h" select="$mode = 'header'" />
45   <xsl:variable name="c" select="$mode = 'source'" />
46   
47   <!-- String used to indent lines of code. -->
48   <xsl:variable name="indent-string" select="'    '" />
49
50   <xsl:variable name="ucase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
51   <xsl:variable name="lcase" select="'abcdefghijklmnopqrstuvwxyz'" />
52
53   <xsl:variable name="header" select="/xcb/@header" />
54   <xsl:variable name="ucase-header"
55                 select="translate($header,$lcase,$ucase)" />
56
57   <xsl:variable name="ext" select="/xcb/@extension-name" />
58
59   <!-- Other protocol descriptions to search for types in, after checking the
60        current protocol description. -->
61   <xsl:variable name="search-path-rtf">
62     <xsl:for-each select="/xcb/import">
63       <path><xsl:value-of select="concat($extension-path, ., '.xml')" /></path>
64     </xsl:for-each>
65     <xsl:if test="not($header='xproto')">
66       <path><xsl:value-of select="concat($base-path, 'xproto.xml')" /></path>
67     </xsl:if>
68   </xsl:variable>
69   <xsl:variable name="search-path" select="e:node-set($search-path-rtf)/path"/>
70
71   <xsl:variable name="root" select="/" />
72   
73   <!-- First pass: Store everything in a variable. -->
74   <xsl:variable name="pass1-rtf">
75     <xsl:apply-templates select="/" mode="pass1" />
76   </xsl:variable>
77   <xsl:variable name="pass1" select="e:node-set($pass1-rtf)" />
78   
79   <xsl:template match="xcb" mode="pass1">
80     <xcb>
81       <xsl:copy-of select="@*" />
82       <xsl:if test="$ext">
83         <constant type="XCBExtension" name="XCB{$ext}Id">
84           <xsl:attribute name="value">{ "<xsl:value-of select="@extension-xname" />" }</xsl:attribute>
85         </constant>
86         <function type="const XCBQueryExtensionRep *" name="XCB{$ext}Init">
87           <field type="XCBConnection *" name="c" />
88           <l>return XCBGetExtensionData(c, &amp;XCB<!--
89           --><xsl:value-of select="$ext" />Id);</l>
90         </function>
91       </xsl:if>
92       <xsl:apply-templates mode="pass1" />
93     </xcb>
94   </xsl:template>
95
96   <!-- Modify names that conflict with C++ keywords by prefixing them with an
97        underscore.  If the name parameter is not specified, it defaults to the
98        value of the name attribute on the context node. -->
99   <xsl:template name="canonical-var-name">
100     <xsl:param name="name" select="@name" />
101     <xsl:if test="$name='new' or $name='delete'
102                   or $name='class' or $name='operator'">
103       <xsl:text>_</xsl:text>
104     </xsl:if>
105     <xsl:value-of select="$name" />
106   </xsl:template>
107
108   <!-- List of core types, for use in canonical-type-name. -->
109   <xsl:variable name="core-types-rtf">
110     <type name="BOOL" />
111     <type name="BYTE" />
112     <type name="CARD8" />
113     <type name="CARD16" />
114     <type name="CARD32" />
115     <type name="INT8" />
116     <type name="INT16" />
117     <type name="INT32" />
118
119     <type name="char" />
120     <type name="void" />
121     <type name="float" />
122     <type name="double" />
123     <type name="XID" />
124   </xsl:variable>
125   <xsl:variable name="core-types" select="e:node-set($core-types-rtf)" />
126
127   <!--
128     Output the canonical name for a type.  This will be
129     XCB{extension-containing-Type-if-any}Type, wherever the type is found in
130     the search path, or just Type if not found.  If the type parameter is not
131     specified, it defaults to the value of the type attribute on the context
132     node.
133   -->
134   <xsl:template name="canonical-type-name">
135     <xsl:param name="type" select="string(@type)" />
136
137     <xsl:variable name="is-unqualified" select="not(contains($type, ':'))"/>
138     <xsl:variable name="namespace" select="substring-before($type, ':')" />
139     <xsl:variable name="unqualified-type">
140       <xsl:choose>
141         <xsl:when test="$is-unqualified">
142           <xsl:value-of select="$type" />
143         </xsl:when>
144         <xsl:otherwise>
145           <xsl:value-of select="substring-after($type, ':')" />
146         </xsl:otherwise>
147       </xsl:choose>
148     </xsl:variable>
149
150     <xsl:choose>
151       <xsl:when test="$is-unqualified and $core-types/type[@name=$type]">
152         <xsl:value-of select="$type" />
153       </xsl:when>
154       <xsl:otherwise>
155         <xsl:variable name="type-definitions"
156                       select="(/xcb|document($search-path)/xcb
157                               )[$is-unqualified or @header=$namespace]
158                                /*[((self::struct or self::union
159                                     or self::xidtype or self::enum
160                                     or self::event or self::eventcopy
161                                     or self::error or self::errorcopy)
162                                    and @name=$unqualified-type)
163                                   or (self::typedef
164                                       and @newname=$unqualified-type)]" />
165         <xsl:choose>
166           <xsl:when test="count($type-definitions) = 1">
167             <xsl:for-each select="$type-definitions">
168               <xsl:text>XCB</xsl:text>
169               <xsl:value-of select="concat(/xcb/@extension-name,
170                                            $unqualified-type)" />
171             </xsl:for-each>
172           </xsl:when>
173           <xsl:when test="count($type-definitions) > 1">
174             <xsl:message terminate="yes">
175               <xsl:text>Multiple definitions of type "</xsl:text>
176               <xsl:value-of select="$type" />
177               <xsl:text>" found.</xsl:text>
178               <xsl:if test="$is-unqualified">
179                 <xsl:for-each select="$type-definitions">
180                   <xsl:text>
181     </xsl:text>
182                   <xsl:value-of select="concat(/xcb/@header, ':', $type)" />
183                 </xsl:for-each>
184               </xsl:if>
185             </xsl:message>
186           </xsl:when>
187           <xsl:otherwise>
188             <xsl:message terminate="yes">
189               <xsl:text>No definitions of type "</xsl:text>
190               <xsl:value-of select="$type" />
191               <xsl:text>" found</xsl:text>
192               <xsl:if test="$is-unqualified">
193                 <xsl:text>, and it is not a known core type</xsl:text>
194               </xsl:if>
195               <xsl:text>.</xsl:text>
196             </xsl:message>
197           </xsl:otherwise>
198         </xsl:choose>   
199       </xsl:otherwise>
200     </xsl:choose>
201   </xsl:template>
202   
203   <!-- Helper template for requests, that outputs the cookie type.  The
204        parameter "request" must be the request node, which defaults to the
205        context node. -->
206   <xsl:template name="cookie-type">
207     <xsl:param name="request" select="." />
208     <xsl:text>XCB</xsl:text>
209     <xsl:choose>
210       <xsl:when test="$request/reply">
211         <xsl:value-of select="concat($ext, $request/@name)" />
212       </xsl:when>
213       <xsl:otherwise>
214         <xsl:text>Void</xsl:text>
215       </xsl:otherwise>
216     </xsl:choose>
217     <xsl:text>Cookie</xsl:text>
218   </xsl:template>
219
220   <xsl:template match="request" mode="pass1">
221     <xsl:variable name="req" select="." />
222     <xsl:if test="reply">
223       <struct name="XCB{$ext}{@name}Cookie">
224         <field type="unsigned int" name="sequence" />
225       </struct>
226     </xsl:if>
227     <struct name="XCB{$ext}{@name}Req">
228       <field type="CARD8" name="major_opcode" no-assign="true" />
229       <xsl:if test="$ext">
230         <field type="CARD8" name="minor_opcode" no-assign="true" />
231       </xsl:if>
232       <xsl:apply-templates select="*[not(self::reply)]" mode="field" />
233       <middle>
234         <field type="CARD16" name="length" no-assign="true" />
235       </middle>
236     </struct>
237     <function name="XCB{$ext}{$req/@name}">
238       <xsl:attribute name="type">
239         <xsl:call-template name="cookie-type">
240           <xsl:with-param name="request" select="$req" />
241         </xsl:call-template>
242       </xsl:attribute>
243       <field type="XCBConnection *" name="c" />
244       <xsl:apply-templates select="$req/*[not(self::reply)]" mode="param" />
245       <do-request ref="XCB{$ext}{$req/@name}Req" opcode="{$req/@opcode}">
246         <xsl:if test="$req/reply">
247           <xsl:attribute name="has-reply">true</xsl:attribute>
248         </xsl:if>
249       </do-request>
250     </function>
251     <xsl:if test="reply">
252       <struct name="XCB{$ext}{@name}Rep">
253         <field type="BYTE" name="response_type" />
254         <xsl:apply-templates select="reply/*" mode="field" />
255         <middle>
256           <field type="CARD16" name="sequence" />
257           <field type="CARD32" name="length" />
258         </middle>
259       </struct>
260       <iterator-functions ref="XCB{$ext}{@name}" kind="Rep" />
261       <function type="XCB{$ext}{@name}Rep *" name="XCB{$ext}{@name}Reply">
262         <field type="XCBConnection *" name="c" />
263         <field name="cookie">
264           <xsl:attribute name="type">
265             <xsl:call-template name="cookie-type" />
266           </xsl:attribute>
267         </field>
268         <field type="XCBGenericError **" name="e" />
269         <l>return (XCB<xsl:value-of select="concat($ext, @name)" />Rep *)<!--
270         --> XCBWaitForReply(c, cookie.sequence, e);</l>
271       </function>
272     </xsl:if>
273   </xsl:template>
274
275   <xsl:template match="xidtype" mode="pass1">
276     <struct name="XCB{$ext}{@name}">
277       <field type="CARD32" name="xid" />
278     </struct>
279     <iterator ref="XCB{$ext}{@name}" />
280     <iterator-functions ref="XCB{$ext}{@name}" />
281     <function type="XCB{$ext}{@name}" name="XCB{$ext}{@name}New">
282       <field type="XCBConnection *" name="c" />
283       <l>XCB<xsl:value-of select="concat($ext, @name)" /> ret;</l>
284       <l>ret.xid = XCBGenerateID(c);</l>
285       <l>return ret;</l>
286     </function>
287   </xsl:template>
288
289   <xsl:template match="struct|union" mode="pass1">
290     <struct name="XCB{$ext}{@name}">
291       <xsl:if test="self::union">
292         <xsl:attribute name="kind">union</xsl:attribute>
293       </xsl:if>
294       <xsl:apply-templates select="*" mode="field" />
295     </struct>
296     <iterator ref="XCB{$ext}{@name}" />
297     <iterator-functions ref="XCB{$ext}{@name}" />
298   </xsl:template>
299
300   <xsl:template match="event|eventcopy|error|errorcopy" mode="pass1">
301     <xsl:variable name="suffix">
302       <xsl:choose>
303         <xsl:when test="self::event|self::eventcopy">
304           <xsl:text>Event</xsl:text>
305         </xsl:when>
306         <xsl:when test="self::error|self::errorcopy">
307           <xsl:text>Error</xsl:text>
308         </xsl:when>
309       </xsl:choose>
310     </xsl:variable>
311     <constant type="number" name="XCB{$ext}{@name}" value="{@number}" />
312     <xsl:choose>
313       <xsl:when test="self::event|self::error">
314         <struct name="XCB{$ext}{@name}{$suffix}">
315           <field type="BYTE" name="response_type" />
316           <xsl:if test="self::error">
317             <field type="BYTE" name="error_code" />
318           </xsl:if>
319           <xsl:apply-templates select="*" mode="field" />
320           <xsl:if test="not(self::event and boolean(@no-sequence-number))">
321             <middle>
322               <field type="CARD16" name="sequence" />
323             </middle>
324           </xsl:if>
325         </struct>
326       </xsl:when>
327       <xsl:when test="self::eventcopy|self::errorcopy">
328         <typedef newname="XCB{$ext}{@name}{$suffix}">
329           <xsl:attribute name="oldname">
330             <xsl:call-template name="canonical-type-name">
331               <xsl:with-param name="type" select="@ref" />
332             </xsl:call-template>
333             <xsl:value-of select="$suffix" />
334           </xsl:attribute>
335         </typedef>
336       </xsl:when>
337     </xsl:choose>
338   </xsl:template>
339
340   <xsl:template match="typedef" mode="pass1">
341     <typedef>
342       <xsl:attribute name="oldname">
343         <xsl:call-template name="canonical-type-name">
344           <xsl:with-param name="type" select="@oldname" />
345         </xsl:call-template>
346       </xsl:attribute>
347       <xsl:attribute name="newname">
348         <xsl:call-template name="canonical-type-name">
349           <xsl:with-param name="type" select="@newname" />
350         </xsl:call-template>
351       </xsl:attribute>
352     </typedef>
353     <iterator ref="XCB{$ext}{@newname}" />
354     <iterator-functions ref="XCB{$ext}{@newname}" />
355   </xsl:template>
356
357   <xsl:template match="enum" mode="pass1">
358     <enum name="XCB{$ext}{@name}">
359       <xsl:for-each select="item">
360         <item name="XCB{$ext}{../@name}{@name}">
361           <xsl:copy-of select="*" />
362         </item>
363       </xsl:for-each>
364     </enum>
365   </xsl:template>
366
367   <!--
368     Templates for processing fields.
369   -->
370
371   <xsl:template match="pad" mode="field">
372     <xsl:copy-of select="." />
373   </xsl:template>
374   
375   <xsl:template match="field|exprfield" mode="field">
376     <xsl:copy>
377       <xsl:attribute name="type">
378         <xsl:call-template name="canonical-type-name" />
379       </xsl:attribute>
380       <xsl:attribute name="name">
381         <xsl:call-template name="canonical-var-name" />
382       </xsl:attribute>
383       <xsl:copy-of select="*" />
384     </xsl:copy>
385   </xsl:template>
386
387   <xsl:template match="list" mode="field">
388     <xsl:variable name="type"><!--
389       --><xsl:call-template name="canonical-type-name" /><!--
390     --></xsl:variable>
391     <list type="{$type}">
392       <xsl:attribute name="name">
393         <xsl:call-template name="canonical-var-name" />
394       </xsl:attribute>
395       <xsl:if test="not(parent::request) and node()
396                     and not(.//*[not(self::value or self::op)])">
397         <xsl:attribute name="fixed">true</xsl:attribute>
398       </xsl:if>
399       <!-- Handle lists with no length expressions. -->
400       <xsl:if test="not(node())">
401         <xsl:choose>
402           <!-- In a request, refer to an implicit localparam for length. -->
403           <xsl:when test="parent::request">
404             <fieldref>
405               <xsl:value-of select="concat(@name, '_len')" />
406             </fieldref>
407           </xsl:when>
408           <!-- In a reply, use the length of the reply to determine the length
409                of the list. -->
410           <xsl:when test="parent::reply">
411             <op op="/">
412               <op op="&lt;&lt;">
413                 <fieldref>length</fieldref>
414                 <value>2</value>
415               </op>
416               <function-call name="sizeof">
417                 <param><xsl:value-of select="$type" /></param>
418               </function-call>
419             </op>
420           </xsl:when>
421           <!-- Other cases generate an error. -->
422           <xsl:otherwise>
423             <xsl:message terminate="yes"><!--
424               -->Encountered a list with no length expresssion outside a<!--
425               --> request or reply.<!--
426             --></xsl:message>
427           </xsl:otherwise>
428         </xsl:choose>
429       </xsl:if>
430       <xsl:copy-of select="*" />
431     </list>
432   </xsl:template>
433
434   <xsl:template match="valueparam" mode="field">
435     <field>
436       <xsl:attribute name="type">
437         <xsl:call-template name="canonical-type-name">
438           <xsl:with-param name="type" select="@value-mask-type" />
439         </xsl:call-template>
440       </xsl:attribute>
441       <xsl:attribute name="name">
442         <xsl:call-template name="canonical-var-name">
443           <xsl:with-param name="name" select="@value-mask-name" />
444         </xsl:call-template>
445       </xsl:attribute>
446     </field>
447     <list type="CARD32">
448       <xsl:attribute name="name">
449         <xsl:call-template name="canonical-var-name">
450           <xsl:with-param name="name" select="@value-list-name" />
451         </xsl:call-template>
452       </xsl:attribute>
453       <function-call name="XCBPopcount">
454         <param>
455           <fieldref>
456             <xsl:call-template name="canonical-var-name">
457               <xsl:with-param name="name" select="@value-mask-name" />
458             </xsl:call-template>
459           </fieldref>
460         </param>
461       </function-call>
462     </list>
463   </xsl:template>
464
465   <xsl:template match="field|localfield" mode="param">
466     <field>
467       <xsl:attribute name="type">
468         <xsl:call-template name="canonical-type-name" />
469       </xsl:attribute>
470       <xsl:attribute name="name">
471         <xsl:call-template name="canonical-var-name" />
472       </xsl:attribute>
473     </field>
474   </xsl:template>
475
476   <xsl:template match="list" mode="param">
477     <!-- If no length expression is provided, use a CARD32 localfield. -->
478     <xsl:if test="not(node())">
479       <field type="CARD32" name="{@name}_len" />
480     </xsl:if>
481     <field>
482       <xsl:attribute name="type">
483         <xsl:text>const </xsl:text>
484         <xsl:call-template name="canonical-type-name" />
485         <xsl:text> *</xsl:text>
486       </xsl:attribute>
487       <xsl:attribute name="name">
488         <xsl:call-template name="canonical-var-name" />
489       </xsl:attribute>
490     </field>
491   </xsl:template>
492
493   <xsl:template match="valueparam" mode="param">
494     <field>
495       <xsl:attribute name="type">
496         <xsl:call-template name="canonical-type-name">
497           <xsl:with-param name="type" select="@value-mask-type" />
498         </xsl:call-template>
499       </xsl:attribute>
500       <xsl:attribute name="name">
501         <xsl:call-template name="canonical-var-name">
502           <xsl:with-param name="name" select="@value-mask-name" />
503         </xsl:call-template>
504       </xsl:attribute>
505     </field>
506     <field type="const CARD32 *">
507       <xsl:attribute name="name">
508         <xsl:call-template name="canonical-var-name">
509           <xsl:with-param name="name" select="@value-list-name" />
510         </xsl:call-template>
511       </xsl:attribute>
512     </field>
513   </xsl:template>
514
515   <!-- Second pass: Process the variable. -->
516   <xsl:variable name="result-rtf">
517     <xsl:apply-templates select="$pass1/*" mode="pass2" />
518   </xsl:variable>
519   <xsl:variable name="result" select="e:node-set($result-rtf)" />
520
521   <xsl:template match="xcb" mode="pass2">
522     <xcb>
523       <xsl:copy-of select="@*" />
524       <xsl:apply-templates mode="pass2"
525                            select="constant|enum|struct|typedef|iterator" />
526       <xsl:apply-templates mode="pass2"
527                            select="function|iterator-functions" />
528     </xcb>
529   </xsl:template>
530
531   <!-- Generic rules for nodes that don't need further processing: copy node
532        with attributes, and recursively process the child nodes. -->
533   <xsl:template match="*" mode="pass2">
534     <xsl:copy>
535       <xsl:copy-of select="@*" />
536       <xsl:apply-templates mode="pass2" />
537     </xsl:copy>
538   </xsl:template>
539
540   <xsl:template match="struct" mode="pass2">
541     <xsl:if test="@kind='union' and list[not(@fixed)]">
542       <xsl:message terminate="yes">Unions must be fixed length.</xsl:message>
543     </xsl:if>
544     <struct name="{@name}">
545       <xsl:if test="@kind">
546         <xsl:attribute name="kind">
547           <xsl:value-of select="@kind" />
548         </xsl:attribute>
549       </xsl:if>
550       <!-- FIXME: This should go by size, not number of fields. -->
551       <xsl:copy-of select="node()[not(self::middle)
552                    and position() &lt; 3]" />
553       <xsl:if test="middle and (count(*[not(self::middle)]) &lt; 2)">
554         <pad bytes="{2 - count(*[not(self::middle)])}" />
555       </xsl:if>
556       <xsl:copy-of select="middle/*" />
557       <xsl:copy-of select="node()[not(self::middle) and (position() > 2)]" />
558     </struct>
559   </xsl:template>
560
561   <xsl:template match="do-request" mode="pass2">
562     <xsl:variable name="struct"
563                   select="$pass1/xcb/struct[@name=current()/@ref]" />
564
565     <xsl:variable name="num-parts" select="(1+count($struct/list))*2" />
566
567     <l>static const XCBProtocolRequest xcb_req = {</l>
568     <indent>
569       <l>/* count */ <xsl:value-of select="$num-parts" />,</l>
570       <l>/* ext */ <xsl:choose>
571                      <xsl:when test="$ext">
572                        <xsl:text>&amp;XCB</xsl:text>
573                        <xsl:value-of select="$ext" />
574                        <xsl:text>Id</xsl:text>
575                      </xsl:when>
576                      <xsl:otherwise>0</xsl:otherwise>
577                    </xsl:choose>,</l>
578       <l>/* opcode */ <xsl:value-of select="@opcode" />,</l>
579       <l>/* isvoid */ <xsl:value-of select="1-boolean(@has-reply)" /></l>
580     </indent>
581     <l>};</l>
582
583     <l />
584     <l>struct iovec xcb_parts[<xsl:value-of select="$num-parts+2" />];</l>
585     <l><xsl:value-of select="../@type" /> xcb_ret;</l>
586     <l><xsl:value-of select="@ref" /> xcb_out;</l>
587
588     <l />
589     <xsl:apply-templates select="$struct//*[(self::field or self::exprfield)
590                                             and not(boolean(@no-assign))]"
591                          mode="assign" />
592
593     <l />
594     <l>xcb_parts[2].iov_base = (char *) &amp;xcb_out;</l>
595     <l>xcb_parts[2].iov_len = sizeof(xcb_out);</l>
596     <l>xcb_parts[3].iov_base = 0;</l>
597     <l>xcb_parts[3].iov_len = -xcb_parts[2].iov_len &amp; 3;</l>
598
599     <xsl:for-each select="$struct/list">
600       <l>xcb_parts[<xsl:value-of select="2 + position() * 2"/>].iov_base = (char *) <!--
601       --><xsl:value-of select="@name" />;</l>
602       <l>xcb_parts[<xsl:value-of select="2 + position() * 2"/>].iov_len = <!--
603       --><xsl:apply-templates mode="output-expression" /><!--
604       --><xsl:if test="not(@type = 'void')">
605         <xsl:text> * sizeof(</xsl:text>
606         <xsl:value-of select="@type" />
607         <xsl:text>)</xsl:text>
608       </xsl:if>;</l>
609       <l>xcb_parts[<xsl:value-of select="3 + position() * 2"/>].iov_base = 0;</l>
610       <l>xcb_parts[<xsl:value-of select="3 + position() * 2"/>].iov_len = -xcb_parts[<xsl:value-of select="2 + position() * 2"/>].iov_len &amp; 3;</l>
611     </xsl:for-each>
612
613     <l>xcb_ret.sequence = XCBSendRequest(c, <!--
614     --><xsl:choose>
615          <xsl:when test="@has-reply">XCB_REQUEST_CHECKED</xsl:when>
616          <xsl:otherwise>0</xsl:otherwise>
617        </xsl:choose>, xcb_parts + 2, &amp;xcb_req);</l>
618     <l>return xcb_ret;</l>
619   </xsl:template>
620
621   <xsl:template match="field" mode="assign">
622     <l>
623       <xsl:text>xcb_out.</xsl:text>
624       <xsl:value-of select="@name" />
625       <xsl:text> = </xsl:text>
626       <xsl:value-of select="@name" />
627       <xsl:text>;</xsl:text>
628     </l>
629   </xsl:template>
630
631   <xsl:template match="exprfield" mode="assign">
632     <l>
633       <xsl:text>xcb_out.</xsl:text>
634       <xsl:value-of select="@name" />
635       <xsl:text> = </xsl:text>
636       <xsl:apply-templates mode="output-expression" />
637       <xsl:text>;</xsl:text>
638     </l>
639   </xsl:template>
640
641   <xsl:template match="iterator" mode="pass2">
642     <struct name="{@ref}Iter">
643       <field type="{@ref} *" name="data" />
644       <field type="int" name="rem" />
645       <field type="int" name="index" />
646     </struct>
647   </xsl:template>
648
649   <!-- Change a_name_like_this to ANameLikeThis.  If the parameter name is not
650        given, it defaults to the name attribute of the context node. -->
651   <xsl:template name="capitalize">
652     <xsl:param name="name" select="string(@name)" />
653     <xsl:if test="$name">
654       <xsl:value-of select="translate(substring($name,1,1), $lcase, $ucase)" />
655       <xsl:choose>
656         <xsl:when test="contains($name, '_')">
657           <xsl:value-of select="substring(substring-before($name, '_'), 2)" />
658           <xsl:call-template name="capitalize">
659             <xsl:with-param name="name" select="substring-after($name, '_')" />
660           </xsl:call-template>
661         </xsl:when>
662         <xsl:otherwise>
663           <xsl:value-of select="substring($name, 2)" />
664         </xsl:otherwise>
665       </xsl:choose>
666     </xsl:if>
667   </xsl:template>
668
669   <xsl:template match="iterator-functions" mode="pass2">
670     <xsl:variable name="ref" select="@ref" />
671     <xsl:variable name="kind" select="@kind" />
672     <xsl:variable name="struct"
673                   select="$pass1/xcb/struct[@name=concat($ref,$kind)]" />
674     <xsl:variable name="nextfields-rtf">
675       <nextfield>R + 1</nextfield>
676       <xsl:for-each select="$struct/list[not(@fixed)]">
677         <xsl:choose>
678           <xsl:when test="substring(@type, 1, 3) = 'XCB'">
679             <nextfield><xsl:value-of select="@type" />End(<!--
680             --><xsl:value-of select="$ref" /><!--
681             --><xsl:call-template name="capitalize" />Iter(R))</nextfield>
682           </xsl:when>
683           <xsl:otherwise>
684             <nextfield><xsl:value-of select="$ref" /><!--
685             --><xsl:call-template name="capitalize" />End(R)</nextfield>
686           </xsl:otherwise>
687         </xsl:choose>
688       </xsl:for-each>
689     </xsl:variable>
690     <xsl:variable name="nextfields" select="e:node-set($nextfields-rtf)" />
691     <xsl:for-each select="$struct/list[not(@fixed)]">
692       <xsl:variable name="number"
693                     select="1+count(preceding-sibling::list[not(@fixed)])" />
694       <xsl:variable name="nextfield" select="$nextfields/nextfield[$number]" />
695       <xsl:variable name="is-first"
696                     select="not(preceding-sibling::list[not(@fixed)])" />
697       <xsl:variable name="field-name"><!--
698         --><xsl:call-template name="capitalize" /><!--
699       --></xsl:variable>
700       <xsl:variable name="is-variable"
701                     select="$pass1/xcb/struct[@name=current()/@type]/list
702                             or document($search-path)/xcb
703                                /struct[concat('XCB',
704                                               ancestor::xcb/@extension-name,
705                                               @name) = current()/@type]
706                                /*[self::valueparam or self::list]" />
707       <xsl:if test="not($is-variable)">
708         <function type="{@type} *" name="{$ref}{$field-name}">
709           <field type="const {$ref}{$kind} *" name="R" />
710           <xsl:choose>
711             <xsl:when test="$is-first">
712               <l>return (<xsl:value-of select="@type" /> *) <!--
713               -->(<xsl:value-of select="$nextfield" />);</l>
714             </xsl:when>
715             <xsl:otherwise>
716               <l>XCBGenericIter prev = <!--
717               --><xsl:value-of select="$nextfield" />;</l>
718               <l>return (<xsl:value-of select="@type" /> *) <!--
719               -->((char *) prev.data + XCB_TYPE_PAD(<!--
720               --><xsl:value-of select="@type" />, prev.index));</l>
721             </xsl:otherwise>
722           </xsl:choose>
723         </function>
724       </xsl:if>
725       <function type="int" name="{$ref}{$field-name}Length">
726         <field type="const {$ref}{$kind} *" name="R" />
727         <l>return <xsl:apply-templates mode="output-expression">
728                     <xsl:with-param name="field-prefix" select="'R->'" />
729                   </xsl:apply-templates>;</l>
730       </function>
731       <xsl:choose>
732         <xsl:when test="substring(@type, 1, 3) = 'XCB'">
733           <function type="{@type}Iter" name="{$ref}{$field-name}Iter">
734             <field type="const {$ref}{$kind} *" name="R" />
735             <l><xsl:value-of select="@type" />Iter i;</l>
736             <xsl:choose>
737               <xsl:when test="$is-first">
738                 <l>i.data = (<xsl:value-of select="@type" /> *) <!--
739                 -->(<xsl:value-of select="$nextfield" />);</l>
740               </xsl:when>
741               <xsl:otherwise>
742                 <l>XCBGenericIter prev = <!--
743                 --><xsl:value-of select="$nextfield" />;</l>
744                 <l>i.data = (<xsl:value-of select="@type" /> *) <!--
745                 -->((char *) prev.data + XCB_TYPE_PAD(<!--
746                 --><xsl:value-of select="@type" />, prev.index));</l>
747               </xsl:otherwise>
748             </xsl:choose>
749             <l>i.rem = <xsl:apply-templates mode="output-expression">
750                          <xsl:with-param name="field-prefix" select="'R->'" />
751                        </xsl:apply-templates>;</l>
752             <l>i.index = (char *) i.data - (char *) R;</l>
753             <l>return i;</l>
754           </function>
755         </xsl:when>
756         <xsl:otherwise>
757           <xsl:variable name="cast">
758             <xsl:choose>
759               <xsl:when test="@type='void'">char</xsl:when>
760               <xsl:otherwise><xsl:value-of select="@type" /></xsl:otherwise>
761             </xsl:choose>
762           </xsl:variable>
763           <function type="XCBGenericIter" name="{$ref}{$field-name}End">
764             <field type="const {$ref}{$kind} *" name="R" />
765             <l>XCBGenericIter i;</l>
766             <xsl:choose>
767               <xsl:when test="$is-first">
768                 <l>i.data = ((<xsl:value-of select="$cast" /> *) <!--
769                 -->(<xsl:value-of select="$nextfield" />)) + (<!--
770                 --><xsl:apply-templates mode="output-expression">
771                      <xsl:with-param name="field-prefix" select="'R->'" />
772                    </xsl:apply-templates>);</l>
773               </xsl:when>
774               <xsl:otherwise>
775                 <l>XCBGenericIter child = <!--
776                 --><xsl:value-of select="$nextfield" />;</l>
777                 <l>i.data = ((<xsl:value-of select="$cast" /> *) <!--
778                 -->child.data) + (<!--
779                 --><xsl:apply-templates mode="output-expression">
780                      <xsl:with-param name="field-prefix" select="'R->'" />
781                    </xsl:apply-templates>);</l>
782               </xsl:otherwise>
783             </xsl:choose>
784             <l>i.rem = 0;</l>
785             <l>i.index = (char *) i.data - (char *) R;</l>
786             <l>return i;</l>
787           </function>
788         </xsl:otherwise>
789       </xsl:choose>
790     </xsl:for-each>
791     <xsl:if test="not($kind)">
792       <function type="void" name="{$ref}Next">
793         <field type="{$ref}Iter *" name="i" />
794         <xsl:choose>
795           <xsl:when test="$struct/list[not(@fixed)]">
796             <l><xsl:value-of select="$ref" /> *R = i->data;</l>
797             <l>XCBGenericIter child = <!--
798             --><xsl:value-of select="$nextfields/nextfield[last()]" />;</l>
799             <l>--i->rem;</l>
800             <l>i->data = (<xsl:value-of select="$ref" /> *) child.data;</l>
801             <l>i->index = child.index;</l>
802           </xsl:when>
803           <xsl:otherwise>
804             <l>--i->rem;</l>
805             <l>++i->data;</l>
806             <l>i->index += sizeof(<xsl:value-of select="$ref" />);</l>
807           </xsl:otherwise>
808         </xsl:choose>
809       </function>
810       <function type="XCBGenericIter" name="{$ref}End">
811         <field type="{$ref}Iter" name="i" />
812         <l>XCBGenericIter ret;</l>
813         <xsl:choose>
814           <xsl:when test="$struct/list[not(@fixed)]">
815             <l>while(i.rem > 0)</l>
816             <indent>
817               <l><xsl:value-of select="$ref" />Next(&amp;i);</l>
818             </indent>
819             <l>ret.data = i.data;</l>
820             <l>ret.rem = i.rem;</l>
821             <l>ret.index = i.index;</l>
822           </xsl:when>
823           <xsl:otherwise>
824             <l>ret.data = i.data + i.rem;</l>
825             <l>ret.index = i.index + ((char *) ret.data - (char *) i.data);</l>
826             <l>ret.rem = 0;</l>
827           </xsl:otherwise>
828         </xsl:choose>
829         <l>return ret;</l>
830       </function>
831     </xsl:if>
832   </xsl:template>
833
834   <!-- Output the results. -->
835   <xsl:template match="/">
836     <xsl:if test="not(function-available('e:node-set'))">
837       <xsl:message terminate="yes"><!--
838         -->Error: This stylesheet requires the EXSL node-set extension.<!--
839       --></xsl:message>
840     </xsl:if>
841
842     <xsl:if test="not($h) and not($c)">
843       <xsl:message terminate="yes"><!--
844         -->Error: Parameter "mode" must be "header" or "source".<!--
845       --></xsl:message>
846     </xsl:if>
847
848     <xsl:apply-templates select="$result/*" mode="output" />
849   </xsl:template>
850
851   <xsl:template match="xcb" mode="output">
852     <xsl:variable name="guard"><!--
853       -->__<xsl:value-of select="$ucase-header" />_H<!--
854     --></xsl:variable>
855
856 <xsl:text>/*
857  * This file generated automatically from </xsl:text>
858 <xsl:value-of select="$header" /><xsl:text>.xml by c-client.xsl using XSLT.
859  * Edit at your peril.
860  */
861 </xsl:text>
862
863 <xsl:if test="$h"><xsl:text>
864 #ifndef </xsl:text><xsl:value-of select="$guard" /><xsl:text>
865 #define </xsl:text><xsl:value-of select="$guard" /><xsl:text>
866 </xsl:text>
867 #include "xcb.h"
868 <xsl:for-each select="$root/xcb/import">
869 <xsl:text>#include "</xsl:text><xsl:value-of select="." /><xsl:text>.h"
870 </xsl:text>
871 </xsl:for-each>
872 <xsl:text>
873 </xsl:text>
874 </xsl:if>
875
876 <xsl:if test="$c"><xsl:text>
877 #include &lt;assert.h&gt;
878 #include "xcbext.h"
879 #include "</xsl:text><xsl:value-of select="$header" /><xsl:text>.h"
880
881 </xsl:text></xsl:if>
882
883     <xsl:apply-templates mode="output" />
884
885 <xsl:if test="$h">
886 <xsl:text>
887 #endif
888 </xsl:text>
889 </xsl:if>
890   </xsl:template>
891
892   <xsl:template match="constant" mode="output">
893     <xsl:choose>
894       <xsl:when test="@type = 'number'">
895         <xsl:if test="$h">
896           <xsl:text>#define </xsl:text>
897           <xsl:value-of select="@name" />
898           <xsl:text> </xsl:text>
899           <xsl:value-of select="@value" />
900           <xsl:text>
901
902 </xsl:text>
903         </xsl:if>
904       </xsl:when>
905       <xsl:when test="@type = 'string'">
906         <xsl:if test="$h">
907           <xsl:text>extern </xsl:text>
908         </xsl:if>
909         <xsl:text>const char </xsl:text>
910         <xsl:value-of select="@name" />
911         <xsl:text>[]</xsl:text>
912         <xsl:if test="$c">
913           <xsl:text> = "</xsl:text>
914           <xsl:value-of select="@value" />
915           <xsl:text>"</xsl:text>
916         </xsl:if>
917         <xsl:text>;
918
919 </xsl:text>
920       </xsl:when>
921       <xsl:otherwise>
922         <xsl:if test="$h">
923           <xsl:text>extern </xsl:text>
924         </xsl:if>
925         <xsl:call-template name="type-and-name" />
926         <xsl:if test="$c">
927           <xsl:text> = </xsl:text>
928           <xsl:value-of select="@value" />
929         </xsl:if>
930         <xsl:text>;
931
932 </xsl:text>
933       </xsl:otherwise>
934     </xsl:choose>
935   </xsl:template>
936
937   <xsl:template match="typedef" mode="output">
938     <xsl:if test="$h">
939       <xsl:text>typedef </xsl:text>
940       <xsl:value-of select="@oldname" />
941       <xsl:text> </xsl:text>
942       <xsl:value-of select="@newname" />
943       <xsl:text>;
944
945 </xsl:text>
946     </xsl:if>
947   </xsl:template>
948
949   <xsl:template match="struct" mode="output">
950     <xsl:if test="$h">
951       <xsl:variable name="type-lengths">
952         <xsl:call-template name="type-lengths">
953           <xsl:with-param name="items" select="field/@type" />
954         </xsl:call-template>
955       </xsl:variable>
956       <xsl:text>typedef </xsl:text>
957       <xsl:if test="not(@kind)">struct</xsl:if><xsl:value-of select="@kind" />
958       <xsl:text> {
959 </xsl:text>
960       <xsl:for-each select="exprfield|field|list[@fixed]|pad">
961         <xsl:text>    </xsl:text>
962         <xsl:apply-templates select=".">
963           <xsl:with-param name="type-lengths" select="$type-lengths" />
964         </xsl:apply-templates>
965         <xsl:text>;
966 </xsl:text>
967       </xsl:for-each>
968       <xsl:text>} </xsl:text>
969       <xsl:value-of select="@name" />
970       <xsl:text>;
971
972 </xsl:text>
973     </xsl:if>
974   </xsl:template>
975
976   <xsl:template match="enum" mode="output">
977     <xsl:if test="$h">
978       <xsl:text>typedef enum {
979     </xsl:text>
980       <xsl:call-template name="list">
981         <xsl:with-param name="separator"><xsl:text>,
982     </xsl:text></xsl:with-param>
983         <xsl:with-param name="items">
984           <xsl:for-each select="item">
985             <item>
986               <xsl:value-of select="@name" />
987               <xsl:if test="node()"> <!-- If there is an expression -->
988                 <xsl:text> = </xsl:text>
989                 <xsl:apply-templates mode="output-expression" />
990               </xsl:if>
991             </item>
992           </xsl:for-each>
993         </xsl:with-param>
994       </xsl:call-template>
995       <xsl:text>
996 } </xsl:text><xsl:value-of select="@name" /><xsl:text>;
997
998 </xsl:text>
999     </xsl:if>
1000   </xsl:template>
1001
1002   <xsl:template match="function" mode="output">
1003     <xsl:variable name="decl-open" select="concat(@name, ' (')" />
1004     <xsl:variable name="type-lengths">
1005       <xsl:call-template name="type-lengths">
1006         <xsl:with-param name="items" select="field/@type" />
1007       </xsl:call-template>
1008     </xsl:variable>
1009     <xsl:value-of select="@type" />
1010     <xsl:text>
1011 </xsl:text>
1012     <xsl:value-of select="$decl-open" />
1013     <xsl:call-template name="list">
1014       <xsl:with-param name="separator">
1015         <xsl:text>,
1016 </xsl:text>
1017         <xsl:call-template name="repeat">
1018           <xsl:with-param name="count" select="string-length($decl-open)" />
1019         </xsl:call-template>
1020       </xsl:with-param>
1021       <xsl:with-param name="items">
1022         <xsl:for-each select="field">
1023           <item>
1024             <xsl:apply-templates select=".">
1025               <xsl:with-param name="type-lengths" select="$type-lengths" />
1026             </xsl:apply-templates>
1027           </item>
1028         </xsl:for-each>
1029       </xsl:with-param>
1030     </xsl:call-template>
1031     <xsl:text>)</xsl:text>
1032
1033     <xsl:if test="$h"><xsl:text>;
1034
1035 </xsl:text></xsl:if>
1036
1037     <xsl:if test="$c">
1038       <xsl:text>
1039 {
1040 </xsl:text>
1041       <xsl:apply-templates select="l|indent" mode="function-body">
1042         <xsl:with-param name="indent" select="$indent-string" />
1043       </xsl:apply-templates>
1044       <xsl:text>}
1045
1046 </xsl:text>
1047     </xsl:if>
1048   </xsl:template>
1049
1050   <xsl:template match="l" mode="function-body">
1051     <xsl:param name="indent" />
1052     <xsl:value-of select="concat($indent, .)" /><xsl:text>
1053 </xsl:text>
1054   </xsl:template>
1055
1056   <xsl:template match="indent" mode="function-body">
1057     <xsl:param name="indent" />
1058     <xsl:apply-templates select="l|indent" mode="function-body">
1059       <xsl:with-param name="indent" select="concat($indent, $indent-string)" />
1060     </xsl:apply-templates>
1061   </xsl:template>
1062
1063   <xsl:template match="value" mode="output-expression">
1064     <xsl:value-of select="." />
1065   </xsl:template>
1066
1067   <xsl:template match="fieldref" mode="output-expression">
1068     <xsl:param name="field-prefix" />
1069     <xsl:value-of select="concat($field-prefix, .)" />
1070   </xsl:template>
1071
1072   <xsl:template match="op" mode="output-expression">
1073     <xsl:param name="field-prefix" />
1074     <xsl:text>(</xsl:text>
1075     <xsl:apply-templates select="node()[1]" mode="output-expression">
1076       <xsl:with-param name="field-prefix" select="$field-prefix" />
1077     </xsl:apply-templates>
1078     <xsl:text> </xsl:text>
1079     <xsl:value-of select="@op" />
1080     <xsl:text> </xsl:text>
1081     <xsl:apply-templates select="node()[2]" mode="output-expression">
1082       <xsl:with-param name="field-prefix" select="$field-prefix" />
1083     </xsl:apply-templates>
1084     <xsl:text>)</xsl:text>
1085   </xsl:template>
1086
1087   <xsl:template match="bit" mode="output-expression">
1088     <xsl:text>(1 &lt;&lt; </xsl:text>
1089     <xsl:value-of select="." />
1090     <xsl:text>)</xsl:text>
1091   </xsl:template>
1092
1093   <xsl:template match="function-call" mode="output-expression">
1094     <xsl:param name="field-prefix" />
1095     <xsl:value-of select="@name" />
1096     <xsl:text>(</xsl:text>
1097     <xsl:call-template name="list">
1098       <xsl:with-param name="separator" select="', '" />
1099       <xsl:with-param name="items">
1100         <xsl:for-each select="param">
1101           <item><xsl:apply-templates mode="output-expression">
1102             <xsl:with-param name="field-prefix" select="$field-prefix" />
1103           </xsl:apply-templates></item>
1104         </xsl:for-each>
1105       </xsl:with-param>
1106     </xsl:call-template>
1107     <xsl:text>)</xsl:text>
1108   </xsl:template>
1109
1110   <!-- Catch invalid elements in expressions. -->
1111   <xsl:template match="*" mode="output-expression">
1112     <xsl:message terminate="yes">
1113       <xsl:text>Invalid element in expression: </xsl:text>
1114       <xsl:value-of select="name()" />
1115     </xsl:message>
1116   </xsl:template>
1117
1118   <xsl:template match="field|exprfield">
1119     <xsl:param name="type-lengths" select="0" />
1120     <xsl:call-template name="type-and-name">
1121       <xsl:with-param name="type-lengths" select="$type-lengths" />
1122     </xsl:call-template>
1123   </xsl:template>
1124
1125   <xsl:template match="list[@fixed]">
1126     <xsl:param name="type-lengths" select="0" />
1127     <xsl:call-template name="type-and-name">
1128       <xsl:with-param name="type-lengths" select="$type-lengths" />
1129     </xsl:call-template>
1130     <xsl:text>[</xsl:text>
1131     <xsl:apply-templates mode="output-expression" />
1132     <xsl:text>]</xsl:text>
1133   </xsl:template>
1134
1135   <xsl:template match="pad">
1136     <xsl:param name="type-lengths" select="0" />
1137
1138     <xsl:variable name="padnum"><xsl:number /></xsl:variable>
1139
1140     <xsl:call-template name="type-and-name">
1141       <xsl:with-param name="type" select="'CARD8'" />
1142       <xsl:with-param name="name">
1143         <xsl:text>pad</xsl:text>
1144         <xsl:value-of select="$padnum - 1" />
1145       </xsl:with-param>
1146       <xsl:with-param name="type-lengths" select="$type-lengths" />
1147     </xsl:call-template>
1148     <xsl:if test="@bytes > 1">
1149       <xsl:text>[</xsl:text>
1150       <xsl:value-of select="@bytes" />
1151       <xsl:text>]</xsl:text>
1152     </xsl:if>
1153   </xsl:template>
1154
1155   <!-- Output the given type and name (defaulting to the corresponding
1156        attributes of the context node), with the appropriate spacing.  The
1157        type must consist of a base type (which may contain spaces), then
1158        optionally a single space and a suffix of one or more '*' characters.
1159        If the type-lengths parameter is provided, use it to line up the base
1160        types and suffixs of the type declarations. -->
1161   <xsl:template name="type-and-name">
1162     <xsl:param name="type" select="@type" />
1163     <xsl:param name="name" select="@name" />
1164     <xsl:param name="type-lengths">
1165       <max-type-length>0</max-type-length>
1166       <max-suffix-length>0</max-suffix-length>
1167     </xsl:param>
1168     
1169     <xsl:variable name="type-lengths-ns" select="e:node-set($type-lengths)" />
1170     <xsl:variable name="min-type-length"
1171                   select="$type-lengths-ns/max-type-length" />
1172     <xsl:variable name="min-suffix-length"
1173                   select="$type-lengths-ns/max-suffix-length" />
1174
1175     <xsl:variable name="base-type">
1176       <xsl:choose>
1177         <xsl:when test="contains($type, ' *')">
1178           <xsl:value-of select="substring-before($type, ' *')" />
1179         </xsl:when>
1180         <xsl:otherwise>
1181           <xsl:value-of select="$type" />
1182         </xsl:otherwise>
1183       </xsl:choose>
1184     </xsl:variable>
1185     <xsl:variable name="suffix">
1186       <xsl:if test="contains($type, ' *')">
1187         <xsl:text>*</xsl:text>
1188         <xsl:value-of select="substring-after($type, ' *')" />
1189       </xsl:if>
1190     </xsl:variable>
1191
1192     <xsl:value-of select="$base-type" />
1193     <xsl:if test="string-length($base-type) &lt; $min-type-length">
1194       <xsl:call-template name="repeat">
1195         <xsl:with-param name="count" select="$min-type-length
1196                                              - string-length($base-type)" />
1197       </xsl:call-template>
1198     </xsl:if>
1199     <xsl:text> </xsl:text>
1200     <xsl:if test="string-length($suffix) &lt; $min-suffix-length">
1201       <xsl:call-template name="repeat">
1202         <xsl:with-param name="count" select="$min-suffix-length
1203                                              - string-length($suffix)" />
1204       </xsl:call-template>
1205     </xsl:if>
1206     <xsl:value-of select="$suffix" />
1207     <xsl:value-of select="$name" />
1208   </xsl:template>
1209
1210   <!-- Output a list with a given separator.  Empty items are skipped. -->
1211   <xsl:template name="list">
1212     <xsl:param name="separator" />
1213     <xsl:param name="items" />
1214
1215     <xsl:for-each select="e:node-set($items)/*">
1216       <xsl:value-of select="." />
1217       <xsl:if test="not(position() = last())">
1218         <xsl:value-of select="$separator" />
1219       </xsl:if>
1220     </xsl:for-each>
1221   </xsl:template>
1222
1223   <!-- Repeat a string (space by default) a given number of times. -->
1224   <xsl:template name="repeat">
1225     <xsl:param name="str" select="' '" />
1226     <xsl:param name="count" />
1227
1228     <xsl:if test="$count &gt; 0">
1229       <xsl:value-of select="$str" />
1230       <xsl:call-template name="repeat">
1231         <xsl:with-param name="str"   select="$str" />
1232         <xsl:with-param name="count" select="$count - 1" />
1233       </xsl:call-template>
1234     </xsl:if>
1235   </xsl:template>
1236
1237   <!-- Record the maximum type lengths of a set of types for use as the
1238        max-type-lengths parameter of type-and-name. -->
1239   <xsl:template name="type-lengths">
1240     <xsl:param name="items" />
1241     <xsl:variable name="type-lengths-rtf">
1242       <xsl:for-each select="$items">
1243         <item>
1244           <xsl:choose>
1245             <xsl:when test="contains(., ' *')">
1246               <xsl:value-of select="string-length(
1247                                     substring-before(., ' *'))" />
1248             </xsl:when>
1249             <xsl:otherwise>
1250               <xsl:value-of select="string-length(.)" />
1251             </xsl:otherwise>
1252           </xsl:choose>
1253         </item>
1254       </xsl:for-each>
1255     </xsl:variable>
1256     <xsl:variable name="suffix-lengths-rtf">
1257       <xsl:for-each select="$items">
1258         <item>
1259           <xsl:choose>
1260             <xsl:when test="contains(., ' *')">
1261               <xsl:value-of select="string-length(substring-after(., ' *'))
1262                                     + 1" />
1263             </xsl:when>
1264             <xsl:otherwise>
1265               <xsl:text>0</xsl:text>
1266             </xsl:otherwise>
1267           </xsl:choose>
1268         </item>
1269       </xsl:for-each>
1270     </xsl:variable>
1271     <max-type-length>
1272       <xsl:call-template name="max">
1273         <xsl:with-param name="items"
1274                         select="e:node-set($type-lengths-rtf)/*" />
1275       </xsl:call-template>
1276     </max-type-length>
1277     <max-suffix-length>
1278       <xsl:call-template name="max">
1279         <xsl:with-param name="items"
1280                         select="e:node-set($suffix-lengths-rtf)/*" />
1281       </xsl:call-template>
1282     </max-suffix-length>
1283   </xsl:template>
1284
1285   <!-- Return the maximum number in a set of numbers. -->
1286   <xsl:template name="max">
1287     <xsl:param name="items" />
1288     <xsl:choose>
1289       <xsl:when test="count($items) = 0">
1290         <xsl:text>0</xsl:text>
1291       </xsl:when>
1292       <xsl:otherwise>
1293         <xsl:variable name="head" select="number($items[1])" />
1294         <xsl:variable name="tail-max">
1295           <xsl:call-template name="max">
1296             <xsl:with-param name="items" select="$items[position() > 1]" />
1297           </xsl:call-template>
1298         </xsl:variable>
1299         <xsl:choose>
1300           <xsl:when test="$head > number($tail-max)">
1301             <xsl:value-of select="$head" />
1302           </xsl:when>
1303           <xsl:otherwise>
1304             <xsl:value-of select="$tail-max" />
1305           </xsl:otherwise>
1306         </xsl:choose>
1307       </xsl:otherwise>
1308     </xsl:choose>
1309   </xsl:template>
1310 </xsl:transform>