summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/booktabs/booktabs.dtx
blob: 969e3b329062a2564f5dbf121bb4f2b05a2333bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
% \iffalse (meta-comment)
% -----------------------------------------------------------------
% booktabs.dtx
% Copyright (C) 1995--2020 Simon Fear
% Maintained by Danie Els <dnjels@gmail.com>
%
% This file is part of the booktabs package for publication
% quality tables for LaTeX
% -----------------------------------------------------------------
%
% This work may be distributed and/or modified under the conditions
% of the LaTeX Project Public License, either version 1.3c of this
% license or (at your option) any later version. The latest version
% of this license is in
% http://www.latex-project.org/lppl.txt
% and version 1.3c or later is part of all distributions of LaTeX
% version 2008/05/04 or later.
%
% -----------------------------------------------------------------
% \fi
%
% \iffalse
%<*driver>
\ProvidesFile{booktabs.dtx}
%</driver>
%<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01]
%<package>\ProvidesPackage{booktabs}
%<*package>
    [2020/01/12 v1.61803398 Publication quality tables]
%</package>
%
%<*driver>
\documentclass{ltxdoc}
  \usepackage{booktabs}[2020/01/12]
  \EnableCrossrefs
  \CodelineIndex
  \RecordChanges
  \setlength\hfuzz{15pt}
  \hbadness=7000
  \MakeShortVerb{\=}
  \MakeShortVerb{\"}
\begin{document}
  \DocInput{booktabs.dtx}
  \PrintChanges
  \PrintIndex
\end{document}
%</driver>
% \fi
%
% \CheckSum{489}
% \CharacterTable
%    {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
%     Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
%     Digits        \0\1\2\3\4\5\6\7\8\9
%     Exclamation   \!     Double quote  \"     Hash (number) \#
%     Dollar        \$     Percent       \%     Ampersand     \&
%     Acute accent  \'     Left paren    \(     Right paren   \)
%     Asterisk      \*     Plus          \+     Comma         \,
%     Minus         \-     Point         \.     Solidus       \/
%     Colon         \:     Semicolon     \;     Less than     \<
%     Equals        \=     Greater than  \>     Question mark \?
%     Commercial at \@     Left bracket  \[     Backslash     \\
%     Right bracket \]     Circumflex    \^     Underscore    \_
%     Grave accent  \`     Left brace    \{     Vertical bar  \|
%     Right brace   \}     Tilde         \~}
%
%
%
% \DeleteShortVerb{\|}
% \GetFileInfo{booktabs.dtx}
%
%  \title{Publication quality tables in \LaTeX%
%        \thanks{This file has version number \fileversion,
%                (converging to phi, the golden ratio),
%                last revised \filedate.}}
% \author{Simon Fear\\300A route de Meyrin\\Meyrin\\Switzerland}
% \date{Printed \today}
%
% \maketitle
%
%
% \begin{abstract}
% This article describes some additional commands to enhance
% the quality of tables in \LaTeX. Guidelines are given as
% to what constitutes a good table in this context. The 2000
% release (Version 1.61) of the =booktabs= package, described
% herein, adds some enhancements to the 1995 release (Version 1.00),
% most notably =longtable= compatibility.
%
% Releases (Versions 1.618, 1.6180, 1.61803 and 1.618033) are
% only bug patches, support for the =colortbl= package and better
% compatability with =longtable=.\footnote{By Danie Els
%  (\texttt{dnjels@sun.ac.za}) in the absence of the author.}
% \end{abstract}
%
% \bigskip
%
% \section{Introduction}
%
% The routines described below are to enable the easy production
% of tables such as should appear in published scientific books and
% journals. What distinguishes these from plain
% \LaTeX{} tables is the default use of additional space above and below rules,
% and rules of varying `thickness'. What further distinguishes them from
% the tables many people {\em do} produce using \LaTeX{} is the
% absence of vertical rules and double rules.
%
% I must draw a clear
% distinction between what I call here a {\em formal table},
% which is a set of values in labelled columns, as distinct from
% what I will call a {\em tableau}. The latter is the kind of thing
% illustrated in the \LaTeX{} manual, and increasingly
% common as the output of
% many database management systems; it will probably have
% icons in abundance, and no doubt use colour too.
% The layout of such a {\em tableau} is determined
% (hopefully) as a one-off, given a jumble of material the
% designer is trying to combine into a meaningful configuration.
% But the layout of a {\em table} has been established over
% centuries of experience and should only be altered in
% extraordinary circumstances.
%
% By way of illustration, consider this tableau from the \LaTeX{}
% manual (p. 64 old edition):
%
% \begin{center}
% \begin{tabular}{||l|lr||} \hline
% gnats     & gram      & \$13.65 \\ \cline{2-3}
%           & each      & .01 \\ \hline
% gnu       & stuffed   & 92.50 \\ \cline{1-1} \cline{3-3}
% emu       &           & 33.33 \\ \hline
% armadillo & frozen    & 8.99 \\ \hline
% \end{tabular}
% \end{center}
%
% This is a hotch-potch of information that is probably
% reasonably clearly presented as is (but is the emu stuffed or
% not?). However, as a published table, this should
% much rather appear along the lines suggested
% further down the page in the manual:
%
% \begin{center}
% \begin{tabular}{@{}llr@{}} \toprule
% \multicolumn{2}{c}{Item} \\ \cmidrule(r){1-2}
% Animal & Description & Price (\$)\\ \midrule
% Gnat  & per gram  & 13.65 \\
%       & each      & 0.01 \\
% Gnu   & stuffed   & 92.50 \\
% Emu   & stuffed   & 33.33 \\
% Armadillo & frozen & 8.99 \\ \bottomrule
% \end{tabular}
% \end{center}
%
% It takes much less work to lay
% this out, as a formal table; we don't have to work out a new
% layout for everything we do. Moreover, we can be almost certain
% that the data cannot be misread, because the reader does not
% have to learn how to read some novel presentation.
%
% The above table cannot be produced in pure \LaTeX,
% unfortunately. It can be laid out as it should be, but despite
% your best efforts, using plain =\hline= commands produces
%
% \begin{center}
% \begin{tabular}{@{}llr@{}} \hline
% \multicolumn{2}{c}{Item} \\ \cline{1-2}
% Animal & Description & Price (\$)\\ \hline
% Gnat  & per gram  & 13.65 \\
%       & each      & 0.01 \\
% Gnu   & stuffed   & 92.50 \\
% Emu   & stuffed   & 33.33 \\
% Armadillo & frozen & 8.99 \\ \hline
% \end{tabular}
% \end{center}
%
% Note (if it is not already obvious) that there is not enough
% space between the top line and the capital I of `Item', and so
% on for all the lines: contrast with the previous version. Also, in
% the first version
% the top and bottom rules (ie lines) are
% heavier than the middle rule, which is turn heavier than the
% subrule underneath `Item'. Of course you \emph{could} redefine
% =\doublerulesep= and then use =\hline\hline= to get something
% near the same effect, and you could use struts to improve
% the spacing. But you should not have to
% think of such things. The =booktabs= style defines its commands so
% that such things are taken care of automatically.
%
% In general, I would say that
% this package is of no interest to those looking for
% an alternative to Pic\TeX{} to conjure up fancy tableaux.
% Rather, it is a style guide for authors of scientific papers
% and books as regards table layout. It is not going too far to
% say that if you cannot
% create a table using the commands in this package, you should
% redesign it.
%
% \subsection{A note on terminology\label{notation}}
%
% In British typesetting, a `line' is always called a `rule'. Perhaps
% confusingly (for historic reasons in fact), the `thickness' of
% rule is often referred to as is its `width' (whereas just about
% everyone else would call this `depth' or `height', if they were thinking
% of a horizontal rule). A `thick black line' is called a `heavy
% rule'. I have used this terminology in most of the new commands
% below. If nothing else it avoids confusion with =\hline=.
%
% \section{The layout of formal tables}
%
% You will not go far wrong if you remember two simple
% guidelines at all times:
% \begin{enumerate}
%   \item Never, ever use vertical rules.
%   \item Never use double rules.
% \end{enumerate}
% These guidelines may seem extreme but I have
% never found a good argument in favour of breaking them. For
% example, if you feel that the information in the left half of
% a table is so different from that on the right that it needs
% to be separated by a vertical line, then you should use two
% tables instead. Not everyone follows the second guideline:
% I have worked for a publisher who insisted on a
% double light rule above a row of totals. But this would not
% have been my choice.
%
% There are three further guidelines worth mentioning here as they
% are generally not known outside the circle of professional
% typesetters and subeditors:
% \begin{enumerate}\setcounter{enumi}{2}
%   \item Put the units in the column heading (not in the body of
%           the table).
%   \item Always precede a decimal point by a digit; thus 0.1
%       {\em not} just .1.
%   \item Do not use `ditto' signs or any other such convention to
%       repeat a previous value. In many circumstances a blank
%       will serve just as well. If it won't, then repeat the value.
% \end{enumerate}
%
% Whether or not you wish to follow the minor niceties,
% if you use only the following commands in your formal tables
% your reader will be grateful. I stress that
% the guidelines are not just to
% keep the pedantic happy. The principal is that enforced structure of
% presentation
% enforces structured thought in the first instance.
%
% \section{Use of the new commands}
%
% \DescribeMacro\toprule
% \DescribeMacro\midrule
% \DescribeMacro\bottomrule
% In the simplest of cases a table begins with a =\toprule=, has
% a single row of column headings, then a dividing rule called
% here a =\midrule=; after the columns of data we finish off with
% a =\bottomrule=. Most book publishers set the =\toprule= and
% =\bottomrule= heavier (ie thicker, or darker; see section \ref{notation})
% than the intermediate =\midrule=. However, when tables appear
% in very small typesizes it is sometimes impossible to make this
% distinction, and moreover quite a few journals routinely use all rules of
% the same heaviness.
%
% The rule commands here all take a default
% which may be reset within the document (preferably, but not
% necessarily, in the preamble). For the top and bottom rules this
% default
% is =\heavyrulewidth= and for midrules it is =\lightrulewidth=
% (fully described below). In very rare cases where you need to do
% something special, you may use the optional arguments to the rule
% commands which have formal syntax as follows:
% \begin{quote}
%   "\toprule["\meta{wd}"]" \\
%   "\midrule["\meta{wd}"]" \\
%   "\bottomrule["\meta{wd}"]"
% \end{quote}
% where \meta{wd} is a \TeX dimension (for example 1pt, .5em,
% etc.).
%
% All the rule commands described here go after the closing
% =\\= of the preceding row (except =\toprule=, which
% comes right after the =\tabular{}= command); in other words,
% exactly where plain \LaTeX{} allows =\hline= or =\cline=.
%
% \DescribeMacro\cmidrule
% Frequently we need a sub-rule to extend over only some of the columns,
% for which we need a =\cmidrule= (the analogue of \LaTeX's =\cline=
% command). Generally, this rule should not come to the full width of
% the columns, and this is especially the case when we need to begin
% a =\cmidrule= straight after the end of another one (\LaTeX's
% =\cline=s crash into each other here if you are not extra careful with
% =\extracolsep=).  Thus, you will generally want to use the optional
% `trimming' commands.
%
% The trimming commands, if used at all, go in
% parentheses (like this), with no spaces separating them. The possible
% specifications are =r=, =r{=\meta{wd}=}=, =l= and
% =l{=\meta{wd}=}=, or any combination of these, where \meta{wd} is a
% dimension, and =r= and =l= indicate whether the right and/or left ends
% of the rule should be trimmed. The form without explicit argument is
% equivalent to =r{\cmidrulekern}=, where =\cmidrulekern= defaults to
% $0.5$ em, but can be set by the user in the preamble.\footnote{User
%   feedback suggested the Version 1.00 default, 0.25 em, was too
%   small. Sorry for any loss of backward compatibility. Remember that
% you
%   can easily set \texttt{\textbackslash cmidrulekern} in the preamble, or just use
%   \texttt{(r\{.25em\})} to recover the original behaviour.}
%
% Here's an illustrative example: =(lr{.75em})= gives you a default
% left trim and exactly $0.75$ em right trim. Equally valid here is
% =(r{.75em}l)=.\footnote{As a matter of fact, \texttt{(lrrlr\{.75em\})}
% does the same thing: only the
% last encountered left and the last encountered right specification
% are applied.}
%
% The full syntax of the command is
% \begin{quote}
%   "\cmidrule["\meta{wd}"]("\meta{trim}"){"$a$--$b$"}"
% \end{quote}
% where \meta{wd} is an optional rule width command, in square
% brackets [like this] (the
% default here is =\cmidrulewidth=), and the last argument, \emph{which
% is not optional}, gives the column numbers to be spanned.
%
% An example of the commands in use is given by the code used to
% produce the example table above:
% \begin{verbatim}
% \begin{tabular}{@{}llr@{}} \toprule
% \multicolumn{2}{c}{Item} \\ \cmidrule(r){1-2}
% Animal & Description & Price (\$)\\ \midrule
% Gnat  & per gram  & 13.65 \\
%       & each      & 0.01 \\
% Gnu   & stuffed   & 92.50 \\
% Emu   & stuffed   & 33.33 \\
% Armadillo & frozen & 8.99 \\ \bottomrule
% \end{tabular}
% \end{verbatim}
%
% \DescribeMacro\addlinespace
% Occasionally we want to put an extra space between certain rows
% of a table; for example, before the last row, if this is a
% total. This is simply a matter of inserting
% \begin{quote}
%   "\addlinespace["\meta{wd}"]"
% \end{quote}
%  after the =\\= alignment marker. Between ordinary rows of text, the
%  effect is identical to the ordinary \LaTeX\ usage
%  =\\[\defaultaddspace]=, which I find rather clumsy, and it is better
%  than =\\ \\=, which inserts too much space. Also,
%  =\addlinespace= can be used before, after, or between rules if you
%  want to control the exact amount of space to be inserted. The default
%  space before or after an adjacent rule is replaced by exactly
%  =\defaultaddspace= or the amount of
%  space specified in the optional argument.\footnote{This is a change
% from version 1.00, where the space was sometimes \emph{in addition
% to} default rule space.}
%
% \section{Abuse of the new commands}
%
% Let's face it, nobody can leave well alone, so here are some
% guidelines and extra commands.
%
% The new rule commands are not guaranteed to work with =\hline=
% or =\cline=, although these remain available and unchanged. I
% cannot foresee any reason to want to mix them.
%
% More importantly the rules generated by the new commands are in
% no way guaranteed to connect with verticals generated by ={|}=
% characters in the preamble. This is a feature (see above). You
% should not use vertical rules in tables, end of story.
%
% \DescribeMacro\morecmidrules
% If you just cannot stop yourself from using a double rule,
% even a construction as bizarre as =\toprule\bottomrule\midrule=
% will work without generating an error message (just as you can
% double =\hline=). These rules will be separated by the ordinary
% \LaTeX\ separator =\doublerulesep=. However if your perversion
% is to want double =\cmidrule=s you will need the extra command
% =\morecmidrules= to do so properly, because normally two
% =\cmidrule=s  in a row is a sane construction
% calling for two rules on the same `rule row'. Thus in
% \begin{quote}
%   "\cmidrule{1-2}\cmidrule{1-2}"
% \end{quote}
% the second command writes a rule that just overwrites the first
% one; I suppose you wanted
% \begin{quote}
%   "\cmidrule{1-2}\morecmidrules\cmidrule{1-2}"
% \end{quote}
% which gives you a double rule between columns one and two,
% separated by =\cmidrulesep= (note: since a =\cmidrule= is
% generally very light, the ordinary =\doublerulesep= is probably
% too much space). Finish off a whole row of rules before giving the
% =\morecmidrules= command. Note that =\morecmidrules= has no
% effect whatsoever if it does not immediately follow a
% =\cmidrule= (ie it is not a general space-generating command).
%
% \DescribeMacro\specialrule
% If you find some extraordinary need to specify exactly $0.5$ em, say, between two
% rules, you could use a construction such as =\midrule =
% =\addlinespace[.5em] \midrule=. In a rare fit of tolerance, though,
% I have also
% provided the command
% \begin{quote}
%   "\specialrule{"\meta{wd}"}{"\meta{abovespace}"}{"\meta{belowspace}"}"
% \end{quote}
% where all three arguments are mandatory (I couldn't be bothered to
% program in defaults). If you use this frequently, you have
% misunderstood the purpose and content of the guidelines given above. A
% preceeding rule does not add its default space below, and a following
% rule adds no space above itself, so you get \emph{exactly} the space
% specified in the arguments.\footnote{This is a change from Version 1.00,
% which rather liked to add an extra \texttt{\textbackslash doublerulesep} space whenever it
% could.}
%
%
% \section{Booktabs and longtables}
%
% If you have both =booktabs= and =longtable= packages loaded, the
% =booktabs= rule commands can now all be used exactly as described
% above, within a longtable.
%
% There is an addition worth noting: within a =longtable=, you can use
% the optional left and right trimming commands, which normally only
% work for =\cmidrule=s, with =\toprule=, =\midrule= and =\bottomrule=
% (and if you must, also with =\specialrule=). Users who hacked the
% previous release for longtable compatability\footnote{Jim Service was
% the first} seemed to like all the rules to be right trimmed 0.5 em. I
% think you can do the same by making =@{}= be the last column
% specifier. Still, after working out the rest of the code, it was easy
% to add parsing for the optional arguments, so I did. (I didn't go the
% whole way and allow the optional trimming \emph{outside} a
% =longtable=; this would be a huge amount of work. If you must have
% trimmed rules, make all your tables be =longtable=s!)
%
% A somewhat technical note: within a =longtable=, =\hline= and
% =\hline\hline= both produce a \emph{double} rule (to allow for page
% breaks occurring at that point). But the =booktabs= rules do
% \emph{not}. Longtable's automatic doubling of =\hline= is
% questionable, even according to the documentation within that
% package. But doubled =booktabs= rules make almost no sense at all. In
% the unfortunate event that a =booktabs= rule should occur at a page
% break, then you will have to make the necessary adjustments by
% hand.\footnote{Fixed in version  1.618033 (Morten H{\o}gholm)}
% (In general, this will mean deleting the offending rule.)
%
%
% \section{Booktabs and and the colortbl package}
%
%  =Booktabs= is now compatible with the =colortbl= package.\footnote{Since v1.6180}
%  The \cmd{\arrayrulecolor} command will result in coloured
%  rules if the =colortbl= package is loaded.
%
%
% \section{Technical summary of commands}
%
% The new rule commands are valid inside the standard =tabular= (and
% =array=) environment, in the modified =tabular= and =array= of
% =\usepackage{array}=, and within both standard tables and longtables
% after =\usepackage{longtable}=.
%
% The commands follow the standard placement syntax of =\hline=.
% There can be space (including carriage-return,
% but not two carriage-returns) between successive
% rule commands.\footnote{A welcome change from Version 1.00, where space between
% rule commands generated a very baffling error message.}
%
% In what amounts to quite a big change from former releases, within
% the macro code I now define three classes of rules. (But we don't need these
% definitions within ordinary use, so I haven't even mentioned them above.)
% A class 1 rule (otherwise called a `normal' rule) is any of
% =\toprule=, =\midrule=, =\bottomrule=, or =\cmidrule=. The class 2
% rules are =\specialrule= and =\addlinespace=. Finally, a class 0 rule
% is none of the preceeding --- or in other words, not a rule at
% all.\footnote{Except that \texttt{\textbackslash hline} and
% \texttt{\textbackslash cline} are class 0. Still, there
%   is no reason to lose sleep over this, since one would not want to mix
%   the two rule-drawing systems.} Note that =\addlinespace= counts as a
% class 2 rule, not as class 0 text.
%
% In the following, we first describe each command in `normal use', meaning
% that the rule is being used between two lines of text (or more
% technically, is preceded and followed by a class 0 rule). After that,
% we will look at the exceptions.
% \begin{quote}
%   "\toprule["\meta{wd}"]"
% \end{quote}
% A rule of width \meta{wd} (default =\heavyrulewidth=) with
% =\abovetopsep= space above and
% =\belowrulesep= extra vertical space inserted below it. By default,
% =\abovetopsep= is zero, which seems sensible for a rule designed to
% go at the top. However, if your
% tables have captions, it can make sense to use =\abovetopsep= to
% insert a reasonable amount of space between caption and table,
% rather than remember to use a =\vspace{}= command in the float.
% \begin{quote}
%   "\midrule["\meta{wd}"]"
% \end{quote}
% A \meta{wd} (default =\lightrulewidth=) rule with
% =\aboverulesep= space above it and
% with =\belowrulesep= space below it.
% \begin{quote}
%   "\bottomrule["\meta{wd}"]"
% \end{quote}
% A \meta{wd} (default =\heavyrulewidth=) rule with =\aboverulesep=
% space above it and with =\belowbottomsep= space below it. By default
% =\belowbottomsep= is zero\footnote{This is a change from Version 1.00,
% where there was always a \texttt{\textbackslash belowrulesep}}.
% There is a frequent and legitimate reason
% you might want space below a bottom rule: namely, when there's a table
% footnote.\footnote{But don't use footnotes, Donald.}
% If you don't override the default you could use
% =\bottomrule \addlinespace[\belowrulesep]=
% or you could put a suitably sized strut
% into the footnote text.\footnote{I don't like either of these. Sort it out in
% Version 1.618?} But the default has to be zero, so that it behaves
% sensibly in a =longtable= footer.
% \begin{quote}
%   "\cmidrule["\meta{wd}"]("\meta{trim}"){"$a$--$b$"}"
% \end{quote}
% A \meta{wd} (default =\cmidrulewidth=) rule with
% =\aboverulesep= space above it (unless following another
% =\cmidrule=, in which case it is on the same vertical alignment; or
% if following =\morecmidrules=, separated from a previous =\cmidrule=
% by =\cmidrulesep=). A =\cmidrule= has
% =\belowrulesep= below it (unless followed by another
% =\cmidrule=, in which case the following rule is on the same
% vertical alignment; or if followed by =\morecmdirules=, when there
% will be
% =\cmidrulesep= below it).
%
% The =\cmidrule= spans columns $a$ to $b$ as specified in the mandatory
% argument. The optional argument \meta{trim}, which goes in parentheses
% if at all, can contain any sequence of the tokens =r=, =l= and
% ={=\meta{wd}=}=, with the latter setting the kerning to be applied to
% right or left sides as specified by the immediately preceding token.
% (There's currently no error checking done here, so be careful to get
% the syntax right.)
% \begin{quote}
%   "\morecmidrules"
% \end{quote}
% Instructs \LaTeX\ to begin a new row of =\cmidrules=,
% separated from the last by =\cmidrulesep=. Has no meaning
% in any other context.
% \begin{quote}
%   "\specialrule{"\meta{wd}"}{"\meta{abovespace}"}{"\meta{belowspace}"}"
% \end{quote}
% A \meta{wd} rule (note: here this is a mandatory argument) with
% \meta{abovespace} above it and \meta{belowspace} below it.
% \begin{quote}
%   "\addlinespace["\meta{wd}"]"
% \end{quote}
% Technically this has the same effect as
% =\specialrule{0pt}{0pt}{=\meta{wd}=}=, i.e. a zero-width rule with no
% space above and with \meta{wd} (default =\defaultaddspace=) space
% below. This command was primarily designed to add space between rows
% in the body of the table, but it may also be used to specify an exact
% amount of space above or below a class 1 rule.
%
% \vspace{1em}
% Now we come to the exceptions to the above. We have already seen in
% the definitions that the type 2 rules are preceded and followed by
% exactly the amount of space specified by the arguments. That is, a
% type 2 rule suppresses the space that would normally be generated by a
% previous type 1 rule (e.g. =\belowrulesep= after a =\toprule=) and
% replaces it by the argument of the type 2 rule. Similarly, in the
% combination \{type 2 rule\}\{type 1 rule\}, the ordinary space above
% the type 1 rule (e.g. =\aboverulesep=) is suppressed. But in the
% combination \{type 2 rule\}\{type 2 rule\}, no space is suppressed:
% the rules will be separated by both the first rule's
% ={=\meta{belowspace}=}= and the second rule's ={=\meta{abovespace}=}=
% arguments. Last but not least, the combination \{type 1 rule\}\{type 1
% rule\} will always give rules separated by =\doublerulesep=,
% suppressing all normal space generated between the rules (but
% retaining normal space above the first and below the second).
%
% As an exception to this last exception, `type 1 rule' excludes
% =\cmidrule=. Such rules combine with other =\cmidrule=s and
% =\morecmidrules= in normal use as described above. I don't know and
% I don't care
% care what the combination =\toprule\cmidrule{1-2}\midrule= would
% produce. I can see no excuse for such usage.
%
%\vspace{1em}
% The default dimensions are defined at the beginning of the macro
% description section (Section \ref{code}). The user can change
% these defaults in the preamble, or outside a
% tabular environment, by simply
% inserting a command in exactly the same format as in Section \ref{code}; the
% redefinition will stay in effect for the rest of the document
% or until redefined again. \emph{Inside a table} you would have to make the
% assignment globally in a =noalign= group:
% e.g. \verb|\noalign\{\global\abovetopsep=1em\toprule}|. I hope
% you never have to do that.
%
% \section{Acknowledgments}
% Hugely indebted of course to DEK and Lamport; the optional
% argument and =\cmidrule=
% stuff especially was stolen from =latex.sty=.
% The documentation driver stuff is stolen from the
% tools package description =dcolumn.dtx= by David Carlisle.
%
% For beta testing and encouragement ...
%
% \StopEventually
%
% \section{The code\label{code}}
%
%    The current version is defined at the top of the file looking
%    something like this
%    \begin{macrocode}
%<*package>
%\NeedsTeXFormat{LaTeX2e}
%\ProvidesPackage{booktabs}
%        [\filedate\space version\fileversion]
%    \end{macrocode}
%
% First we set up the new dimensions described above:
%    \begin{macrocode}
\newdimen\heavyrulewidth
\newdimen\lightrulewidth
\newdimen\cmidrulewidth
\newdimen\belowrulesep
\newdimen\belowbottomsep
\newdimen\aboverulesep
\newdimen\abovetopsep
\newdimen\cmidrulesep
\newdimen\cmidrulekern
\newdimen\defaultaddspace
\heavyrulewidth=.08em
\lightrulewidth=.05em
\cmidrulewidth=.03em
\belowrulesep=.65ex
\belowbottomsep=0pt
\aboverulesep=.4ex
\abovetopsep=0pt
\cmidrulesep=\doublerulesep
\cmidrulekern=.5em
\defaultaddspace=.5em
%    \end{macrocode}
% And some internal counters of no interest to the end user:
% \changes{v1.618}{2003/03/28}{Remove \cs{@cmidrulewidth} }
%    \begin{macrocode}
\newcount\@cmidla
\newcount\@cmidlb
\newdimen\@aboverulesep
\newdimen\@belowrulesep
\newcount\@thisruleclass
\newcount\@lastruleclass
\@lastruleclass=0
\newdimen\@thisrulewidth
%    \end{macrocode}
% which will be described as needed below.
%
% \begin{macro}{\futurenonspacelet}
% Next we define a very useful macro (more-or-less straight from the
% \TeX book's Dirty Tricks chapter; documented there). Use
% =\futurenonspacelet= instead of =\futurelet= when looking for the next
% (non-space) token after a macro that has an argument. (After a macro
% without an argument, space is ignored anyway, so =\futurenonspacelet=
% wouldn't be needed.) This hack allows users to type white
% space between successive rule commands (which did not work in Version
% 1.00).
%    \begin{macrocode}
\def\futurenonspacelet#1{\def\@BTcs{#1}%
   \afterassignment\@BTfnslone\let\nexttoken= }
\def\@BTfnslone{\expandafter\futurelet\@BTcs\@BTfnsltwo}
\def\@BTfnsltwo{\expandafter\ifx\@BTcs\@sptoken\let\next=\@BTfnslthree
   \else\let\next=\nexttoken\fi \next}
\def\@BTfnslthree{\afterassignment\@BTfnslone\let\next= }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Full width  rules}
%
% When we are not in a =longtable= environment, we can simply
% implement the full width rules as a =\hrule= in  a =\noalign{}=
% group. But within a =longtable=, the rule has to be drawn like a
% =\cmidrule{1-\LT@cols}= (the rationale for this is explained in the
% =longtable= documentation).
%
% In order to allow for both, all the rule macros have to
% open a =\noalign= group immediately, while they work out whether
% they have been called within a =longtable=; if you don't do this,
% \TeX's underlying =\halign= process gets hiccups.
% I use \LaTeX's
% dirty trick (\verb?\ifnum=0`}?) to fool the parser that the bracket
% count is OK. The bracket really gets closed after all the skipping
% at the end of the =\@BTendrule= macro.
%
% The class 1 rules, and =\specialrule=, really only differ in the
% defaults for space above and
% below, and the width, passed to a common routine, =\@BTrule=,
% described below. The spaces, =\@aboverulesep= and =\@belowrulesep=,
% are set within the =\noalign= group, so are inherited by
% =\@BTrule=. Similarly, =\@BTrule= knows as much as it needs to
% about the routine that called it by examining the inherited
% =\@thisruleclass=. The optional width argument is parsed by
% =\@BTrule= after being set to default if absent.
%
%
% \begin{macro}{\toprule}
% \changes{v1.61803}{2005/04/14}{Change \cmd{\@belowrulesep} to \cmd{\belowrulesep}}
% \begin{macro}{\midrule}
% \begin{macro}{\bottomrule}
% \begin{macro}{\specialrule}
%    \begin{macrocode}
\def\toprule{\noalign{\ifnum0=`}\fi
  \@aboverulesep=\abovetopsep
  \global\@belowrulesep=\belowrulesep %global cos for use in the next noalign
  \global\@thisruleclass=\@ne
  \@ifnextchar[{\@BTrule}{\@BTrule[\heavyrulewidth]}}
\def\midrule{\noalign{\ifnum0=`}\fi
  \@aboverulesep=\aboverulesep
  \global\@belowrulesep=\belowrulesep
  \global\@thisruleclass=\@ne
  \@ifnextchar[{\@BTrule}{\@BTrule[\lightrulewidth]}}
\def\bottomrule{\noalign{\ifnum0=`}\fi
  \@aboverulesep=\aboverulesep
  \global\@belowrulesep=\belowbottomsep
  \global\@thisruleclass=\@ne
  \@ifnextchar[{\@BTrule}{\@BTrule[\heavyrulewidth]}}
\def\specialrule#1#2#3{\noalign{\ifnum0=`}\fi
  \@aboverulesep=#2\global\@belowrulesep=#3\global\@thisruleclass=\tw@
  \@BTrule[#1]}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \begin{macro}{\addlinespace}
% An =\addlinespace= is essentially a zero-width rule with
% zero space above and argument (or default) space below. But because
%  the rule is not actually drawn, but is just a =\vskip=, there is no
%  need to check if we're in a longtable, so we don't need to call
%  =\@BTrule= as for `real' rules. But we do share the =\@BTendrule=
%  lookahead and flagsetting code (described below), and the =\vskip= is done there.
%    \begin{macrocode}
\def\addlinespace{\noalign{\ifnum0=`}\fi
  \@ifnextchar[{\@addspace}{\@addspace[\defaultaddspace]}}
\def\@addspace[#1]{\global\@belowrulesep=#1\global\@thisruleclass=\tw@
  \futurelet\@tempa\@BTendrule}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@BTrule}
% All the rules (except =\addlinespace=) share this code.
% \changes{v1.618033}{2016/04/27}{Rearranged and added \cmd{\nobreak} within longtable (Morten H{\o}gholm)}
% \changes{v1.6180339}{2019/10/08}{Add test for xltabular (Herbert Voss)}
% \changes{v1.61803398}{2020/01/12}{Restore \cmd{\@BTrule} to v1.618033 (Danie Els) }
%    \begin{macrocode}
\def\@BTrule[#1]{%
%    \end{macrocode}
%  Now we work out, by a very nasty hack, if we're within a
%  =longtable=. It's easy if =\longtable= isn't even defined: then we
%  can't be. But it is not enough just to check if =longtable= is
%  loaded --- we might be within an ordinary table rather than a
%  longtable. So we look to see if =\hline= has been re-defined
%  from its \LaTeX\ definition to be the same as
%  =\LT@hline=. (Longtable currently does this redefinition when it opens a
%  =longtable= environment, but not globally, so it is
%  cleared it when the environment closes.) Another
%  package could potentially do this! And =longtable= might change the
%  way it implements this! So, it is not entirely safe, but I have
%  found no better way so far.
%
%  We set up =\@BTswitch= to call =\@BTnormal= or =\@BLTrule=, as
%  appropriate, then call it.
%    \begin{macrocode}
  \ifx\longtable\undefined
    \let\@BTswitch\@BTnormal
  \else\ifx\hline\LT@hline
    \nobreak
    \let\@BTswitch\@BLTrule
  \else
    \let\@BTswitch\@BTnormal
  \fi\fi
%    \end{macrocode}
% Call =\@BTswitch= at end of macro
%    \begin{macrocode}
  \global\@thisrulewidth=#1\relax
%    \end{macrocode}
% Save the width argument (if the user didn't give one, then the
% calling routine will have called =\@BTrule= with the default) in a global
% variable for later use when drawing the rule.
%    \begin{macrocode}
  \ifnum\@thisruleclass=\tw@\vskip\@aboverulesep\else
%    \end{macrocode}
% Specialrules always insert specified space above. (Note: addlinespaces
% don't come here).
%    \begin{macrocode}
  \ifnum\@lastruleclass=\z@\vskip\@aboverulesep\else
  \ifnum\@lastruleclass=\@ne\vskip\doublerulesep\fi\fi\fi
%    \end{macrocode}
% After text (last rule class 0), precede the rule by =\aboverulesep=;
% but if immediately after a
% previous rule, insert a =\doublerulesep=.
%
%    \begin{macrocode}
  \@BTswitch}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\CT@arc@}
%   \changes{v1.6180}{2005/03/16}{add colortbl command for color support}
%   This is support for the colortbl package for colored
%   rules.  \cmd{\CT@arc@} hold the \cmd{\arrayrulecolor} setting.
%    \begin{macrocode}
\AtBeginDocument{%
   \providecommand*\CT@arc@{}}%% colortbl support
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@BTnormal}
%   \changes{v1.6180}{2005/03/16}{add colortbl \cmd{\CT@arc@} command for color support}
% This is when we're \emph{not} within a longtable. We are already in a
%  =\noalign= group, all we need do is draw an =\hrule= and gobble any
%  trailing spaces, then call the closing routine with =\@tempa= set
%  equal to the next token in the document.
%
%    \begin{macrocode}
\def\@BTnormal{%
    {\CT@arc@\hrule\@height\@thisrulewidth}%
    \futurenonspacelet\@tempa\@BTendrule}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@BLTrule}
% This is for full width rule within a =longtable=. First we check if
%  a kerning argument has been used; if so let =\@@BLTrule= read it,
%  else call =\@@BLTrule= with an empty string:
%    \begin{macrocode}
\def\@BLTrule{\@ifnextchar({\@@BLTrule}{\@@BLTrule()}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\@@BLTrule}
%    \begin{macrocode}
\def\@@BLTrule(#1){\@setrulekerning{#1}%
\global\@cmidlb\LT@cols
%    \end{macrocode}
% The =\@setrulekerning= routine parses the kerning argument tokens
% and sets global kerning widths accordingly (or to defaults, if user
% hasn't set them explicitly). The global assignment to =\@cmidlb=
% sets up the column count for the =\@cmidruleb= macro, which is
% shared with =cmidrules=.
%    \begin{macrocode}
\ifnum0=`{\fi}%
%    \end{macrocode}
% Close the currently open =\noalign= group. Within a =longtable=,
% rules are all to be drawn as leaders within a text box that is
% =\LT@cols= columns wide.
%    \begin{macrocode}
\@cmidruleb
%    \end{macrocode}
% Draw the rule. We share the =\@cmidruleb= code with ordinary =\cmidrule=s.
%    \begin{macrocode}
\noalign{\ifnum0=`}\fi
%    \end{macrocode}
% We have to open a new noalign immediately else \TeX will start a new
%    text box where we don't want one. Then, after gobbling any
%    unwanted white space, we call the closing routine.
%    \begin{macrocode}
\futurenonspacelet\@tempa\@BTendrule}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\@BTendrule}
% We look one step ahead (token is in =\@tempa=) to see if another
% rule follows (shame on user!). If so, we set =\@lastruleclass= equal
% to =\@thisruleclass= (thus setting it up for the following rule). If
% there isn't a following rule, we clear =\@lastruleclass= (ie set it
% to zero), which isn't technically true since we have just drawn a
% rule, but sets it up correctly for the next rule encountered, which
% must be following some intervening text.
%    \begin{macrocode}
\def\@BTendrule{\ifx\@tempa\toprule\global\@lastruleclass=\@thisruleclass
  \else\ifx\@tempa\midrule\global\@lastruleclass=\@thisruleclass
  \else\ifx\@tempa\bottomrule\global\@lastruleclass=\@thisruleclass
  \else\ifx\@tempa\cmidrule\global\@lastruleclass=\@thisruleclass
  \else\ifx\@tempa\specialrule\global\@lastruleclass=\@thisruleclass
  \else\ifx\@tempa\addlinespace\global\@lastruleclass=\@thisruleclass
  \else\global\@lastruleclass=\z@\fi\fi\fi\fi\fi\fi
  \ifnum\@lastruleclass=\@ne\relax\else\vskip\@belowrulesep\fi
  \ifnum0=`{\fi}}
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{Special subrules}
%
% \begin{macro}{\@setrulekerning}
% The following code parses the trimming arguments (if there are any)
%    for =\cmidrule= or a =\BLTrule=. The rule
%     will be trimmed left and right by =\cmrkern@l= and =\cmrkern@l=,
%     which are zero by default, set to =\cmidrulekern= by the plain
%     =(lr)= arguments, or user set as in =(r{.5em})=. We parse token by
%     token through the arguments. The
%     tokens =r= and =l= cause =\cmrkern@r= or =\cmrkern@l= to be set to
%     =\cmidrulekern=. There is no lookahead to see if a width is the
%     next token; this strategy is efficient for the plain commands,
%     while inefficient for the qualified commands, but more importantly
%     it is much easier to program. Tokens =r= and =l= also set
%     =\cmrswitch= so that if the next token turns out to be
%     ={=\meta{wd}=}= then the kerning will be done on the side
%     currently specified. I have been too lazy to program an error
%     message should one encounter tokens other than =r=, =l= or
%     ={=\meta{wd}=}=.
% \changes{v1.6180}{2005/03/16}{Refine option testing in \cmd{\@setrulekerning}}
%    \begin{macrocode}
\def\@setrulekerning#1{%
   \global\let\cmrkern@l\z@
   \global\let\cmrkern@r\z@
   \@tfor\@tempa :=#1\do
  {\def\@tempb{r}%
   \ifx\@tempa\@tempb
      \global\let\cmrkern@r\cmidrulekern
      \def\cmrsideswitch{\cmrkern@r}%
   \else
      \def\@tempb{l}%
      \ifx\@tempa\@tempb
         \global\let\cmrkern@l\cmidrulekern
         \def\cmrsideswitch{\cmrkern@l}%
      \else
         \global\expandafter\let\cmrsideswitch\@tempa
      \fi
   \fi}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\cmidrule}
% \begin{macro}{\@cmidrule}
% \begin{macro}{\@@cmidrule}
% \begin{macro}{\@@@cmidrule}
% The =\cmidrule= re-uses =\@lastruleclass= in an entirely different
%  way from the full width rules. (Maybe I should have used a
%  different flag; it seemed efficient at the time \ldots). This
% is (left) set to one if you are in the middle of a row of
% =\cmidrules=, or starting a new one (with =\morecmidrules=).
% Otherwise, when =\@lastruleclass= is zero, we precede the
% rule with =\aboverulesep=.
%    \begin{macrocode}
\def\cmidrule{\noalign{\ifnum0=`}\fi
    \@ifnextchar[{\@cmidrule}{\@cmidrule[\cmidrulewidth]}}
\def\@cmidrule[#1]{\@ifnextchar({\@@cmidrule[#1]}{\@@cmidrule[#1]()}}
\def\@@cmidrule[#1](#2)#3{\@@@cmidrule[#3]{#1}{#2}}
%    \end{macrocode}
% The above is fiddling around to set defaults for missing optional
% arguments. We also pass to =\@@@cmidrule= in a different order,
% namely =[a-b]=={width required}= ={kerning commands}= (this being
% the order in which the arguments are actually processed):
%    \begin{macrocode}
\def\@@@cmidrule[#1-#2]#3#4{\global\@cmidla#1\relax
    \global\advance\@cmidla\m@ne
    \ifnum\@cmidla>0\global\let\@gtempa\@cmidrulea\else
    \global\let\@gtempa\@cmidruleb\fi
    \global\@cmidlb#2\relax
    \global\advance\@cmidlb-\@cmidla
%    \end{macrocode}
% This has set up a switch (=\@gtempa=) to call the relevant routine,
% =\@cmidrulea= or =\@cmidruleb=, depending on whether we start
% from column one or not.
%    \begin{macrocode}
    \global\@thisrulewidth=#3
%    \end{macrocode}
% That is, set per default or given argument. Then parse any trimming
% arguments to set, globally, =\cmrkern@r= and =\cmrkern@l= accordingly:
%    \begin{macrocode}
    \@setrulekerning{#4}
%    \end{macrocode}
% Now insert space above if needed, close the =\noalign=,
% then switch to appropriate rule drawing routine as determined
% above (=\let= to =\@gtempa=):
%    \begin{macrocode}
    \ifnum\@lastruleclass=\z@\vskip \aboverulesep\fi
    \ifnum0=`{\fi}\@gtempa
%    \end{macrocode}
% Having now drawn the rule,
% open another =\noalign=, and call the closing routine:
%    \begin{macrocode}
    \noalign{\ifnum0=`}\fi\futurenonspacelet\@tempa\@xcmidrule}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@xcmidrule}
% In this closing routine, see if another =\cmidrule= follows;
% if so, backspace
% vertical so it will line up with the one you just drew,
% and setting =\@lastruleclass= to 1 will suppress
% adding space above the next. If a =\morecimdrules= follows,
% we add (positive) =\cmidrulesep= (and again set =\@lastruleclass=
% to one). Otherwise this is the last rule of the current group
% and we can just add =\belowrulesep=. Finally, we close the =\noalign=.
% \changes{v1.618}{2003/03/28}{Change to \cmd{\@xcmidrule}:
%         replace \cmd{\@cmidrulewidth} with \cmd{\@thisrulewidth }}
%    \begin{macrocode}
\def\@xcmidrule{%
   \ifx\@tempa\cmidrule
       \vskip-\@thisrulewidth
       \global\@lastruleclass=\@ne
   \else \ifx\@tempa\morecmidrules
       \vskip \cmidrulesep
       \global\@lastruleclass=\@ne\else
       \vskip \belowrulesep
       \global\@lastruleclass=\z@
   \fi\fi
   \ifnum0=`{\fi}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\@cmidrulea}
% This code (called below) actually draws the rules. They are drawn
% as boxes in text, rather than in a =\noalign= group, which permits
% the left and right kerning.
%   \changes{v1.6180}{2005/03/16}{add colortbl \cmd{\CT@arc@} command for color support}
%   \changes{v1.618033}{2016/04/27}{add  \cmd{\kern}\cmd{\z@}  after \cmd{\hfill} to protects against unskips}
%    \begin{macrocode}
\def\@cmidrulea{%
   \multispan\@cmidla&\multispan\@cmidlb
   \unskip\hskip\cmrkern@l%
  {\CT@arc@\leaders\hrule \@height\@thisrulewidth\hfill\kern\z@}%
   \hskip\cmrkern@r\cr}%
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\@cmidruleb}
%   \changes{v1.6180}{2005/03/16}{add colortbl \cmd{\CT@arc@} command for color support}
%   \changes{v1.618033}{2016/04/27}{add  \cmd{\kern}\cmd{\z@}  after \cmd{\hfill} to protects against unskips}
%    \begin{macrocode}
\def\@cmidruleb{%
    \multispan\@cmidlb
    \unskip\hskip \cmrkern@l%
   {\CT@arc@\leaders\hrule \@height\@thisrulewidth\hfill\kern\z@}%
    \hskip\cmrkern@r\cr}%
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\morecmidrules}
% This is really a dummy command; all the work is done above
% within the =\cmidrule= routine. We look one step ahead there
% to see if a =\morecmidrules= follows the current =\cmidrule=,
% and if so set the flag. Otherwise,  =\morecmidrules= itself
% does nothing.
%    \begin{macrocode}
\def\morecmidrules{\noalign{\relax}}
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \Finale
%