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