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
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
|
\documentclass[a4paper,10pt,final,language=UKenglish,fancysec,fancyfnote]{amltxdoc}
\makeatletter
\let\sectionbreak\medbreak
\begin{document}
\begin{frontmatter}
\suptitle{}
\title{The \texttt{\color{blue}skeyval} Package\titleref{t1,t2}}
\titlenote[t1]{The \pkgm{skeyval} was formerly called the \pkgm{keyreader} until
version~0.5. The \asty{keyreader} is now obsolete and no longer supported.}
\iftogon{pdf}{%
\titlenote[t2]{The package is available at \url{\@titleurl}.}%
}{%
\titlenote[t2]{The package is available at \url{\@shorttitleurl}.}%
}
\subtitle{Version 0.72}
\titleurl{http://www.ctan.org/tex-archive/macros/latex/contrib/skeyval/}
\shorttitleurl{http://www.ctan.org/}
\author{Ahmed Musa\Email{a.musa@rocketmail.com}\\Preston, Lancashire, UK}
\NewLet\abstname\abstractname
\redef*\abstractname{\vspace{-\baselineskip}}
\begin{abstract}
\frameshade[width=\hsize,fillcolor=yellow!20,framesep=2pt,framerule=2pt,
framecolor=brown]{%
\frameshade[fillcolor=white,width=2.5cm,framecolor=red,framerule=2pt]%
{\centering\abstname}\small
This package provides several extensions to the \pkgm{xkeyval}. It introduces toggle keys and complementary (bipolar and unipolar) native-boolean and toggle-boolean keys. It also provides mechanisms for reserving, unreserving, suspending, restoring, and removing keys. Furthermore, it introduces a set of commands for key definition which bar the developer or user from inadvertently redefining existing keys of the same family and prefix. Commands are provided for checking the statuses of keys across multiple key prefixes and families. Also, the package provides a scheme for defining multiple keys of different genres using only one command, thereby making it possible to considerably economize on tokens when defining keys. The package introduces the notion of ``user-value keys'' and provides facilities for managing those keys. The pointer mechanisms of the \asty{xkeyval}, which were only available at key setting time, are now invocable at key definition. Some other general-purpose developer macros and hooks are provided by the package.
}
\end{abstract}
\NewLet\licname\licensename
\redef*\licensename{\vspace{-\baselineskip}}
\begin{license}
\frameshade[width=\hsize,fillcolor=white,framesep=2pt,framerule=2pt,
framecolor=brown]{\small
\vspace{1ex}\centerline{\licname}\endgraf
This work (\ie, all the files in the \asty{skeyval} bundle) may be distributed and/or modified under the conditions of the \lppl (LPPL), either version~1.3 of this license or any later version.
\endgraf
The \lppl maintenance status of this software is ``author-maintained''. This software is provided ``as it is,'' without warranty of any kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose.
\endgraf
The package is now at open beta stage and package distributors are advised to wait for at least a stable version~1.0 before embarking on distribution. Bug reports and suggestions to improve the package are particularly welcome. Correspondents should use the file \asty{skeyval-bugreport.tex}, provided as part of the bundle, to report bugs.
\endgraf\centerline{\makered{\CopyrightYear}}%
}
\end{license}
\end{frontmatter}
\newpage
\frameshade[fillcolor=yellow!20,framecolor=brown,framerule=2pt,framesep=2pt,
width=1.1\hsize]{\tableofcontents}
\section{Motivation}
\label{sec:motivation}
\lletter{T}oggle booleans were introduced by the \pkgm{etoolbox} and have proved attractive mainly for two reasons: unlike the legacy/native \tex switches which require three commands per switch, toggles require only one command per switch, and toggles occupy their own separate namespace, thereby avoiding clashes with other macros. So we can effectively have both the following sets in the same file:
\begin{example}
|comm(Knuth/native switch:)
\newif\ifmyboolean |tto 3 separate commands:
\ifmyboolean \mybooleantrue
\mybooleanfalse
|comm(Toggle switch:)
\newtog{myboolean} |tto only 1 command and no clash with
commands in other namespaces
\end{example}
\Note A toggle is also a boolean or switch. We refer to it here as \emph{toggle} or \emph{toggle switch} or \emph{toggle boolean}. The term \emph{Knuth/native switch} is reserved here for \tex's legacy boolean or switch.
The \pkg{xkeyval} can't be used to define and set toggle keys. The present package provides facilities for defining and setting toggle keys.
Secondly, the \pkg{xkeyval} can't be used to define and set complementary (bipolar and unipolar) keys, which can be handy in the case of native boolean and toggle keys. Complementary bipolar keys are mutually exclusive keys, \ie, they never assume the same state of a two-valued logic, and they switch states automatically, depending on the state of any one of them. So whenever one of them assumes one of the two states of a two-valued logic, the other one automatically switches its state from whatever state it was previously, such that the two are never in the same state. Simple examples of complementary bipolar keys would be the options \acmd{draft} and \acmd{final} in a document; they are mutually exclusive. Complementary bipolar keys carry equal charge, \ie, each one can equally toggle the other with identical propensity, but the one that represents the default state of a two-valued logic is usually considered the primary, while the other is secondary. In many document classes, for instance, \acmd{final} is considered a default document option and \acmd{draft} would have to be explicitly selected by the user to toggle \acmd{final} to false.
Complementary unipolar keys, on the other hand, are mutually inclusive, \ie, both are always in the same state of a two-valued logic: when one is switched to a particular state, the complement too is automatically toggled to the same state. An example of complementary unipolar keys would be the options \fx{hyperref} and \fx{microtype} in a package or class file. When \pkgm{hyperref} is loaded, we may want \pkgm{microtype} loaded as well, and vice versa. Complementary unipolar keys, like bipolar keys, also carry equal charge, \ie, one can toggle the other with equal propensity, but to the same state for the two keys. For a pair of unipolar keys, the primary key is the one that is associated with the default state.
The present package introduces these concepts of bipolar and unipolar keys and additionally permits the submission of individual and different custom key macros to complementary (bipolar and unipolar) native boolean and toggle keys. Biunipolar keys, which combines the two concepts of bipolar and unipolar keys, are introduced as well.
The third motivation for this package relates to economy of tokens in style files. The \pkg{xkeyval} provides \acmd{\define@cmdkeys} and \acmd{\define@boolkeys} for defining and setting multiple command keys and boolean keys, but in each category the keys must have the same default value and no key macro/function. This package seeks to lift these restrictions, so that multiple keys of all categories (ordinary keys, command keys, boolean keys, tog keys, and choice/menu keys) can be defined in one go (using only one command) and those keys can have different default values and functions. This greatly minimizes tokens, as hundreds of keys can, in principle, be issued simultaneously by one command.
Fourthly, macros are introduced for defining all key types without the fear of inadvertently redefining existing keys in the same family and with the same key prefix. This has a philosophy akin to the \acmd{\newcommand} concept in \LaTeX.
The package also provides facilities for disabling, suspending, restoring and removing keys across multiple families of keys. The pointer system of the \pkg{xkeyval} is also extended by the \pkg{skeyval}, and the notion of ``user-value'' keys is introduced and operationalized.
Normally when setting keys, the \pkg{xkeyval} terminates with an error message if any key in the list of keys to be set is currently undefined or unknown. This means that if you have a set of keys to set simultaneously and you misspell a few of them, you would have to make several passes to get all the keys right. The \pkg{skeyval} takes a different approach. For each call to \acmd{\setkeys}, it saves the names of undefined keys (and their associated families and prefixes) in a macro and issues an error message (together with the contents of that macro) if at the end of the call that macro is non-empty. Such undefined keys are not set in the pass. In this way, you can correct all wrongly entered keys in one go, rather than repeat the pass for each of them.
The new macros can be used together with the machinery from the \pkg{xkeyval} for efficient and versatile key management.
\section{Brace stripping by the \texttt{xkeyval} package}
The \pkg{xkeyval} strips off up to three levels of braces in the value part of the \acmd{key-value} pair: one by using the \pkgm{keyval}'s leading and trailing space removal command and two in internal parsings (at some known commands). The \asty{keyval} strips off only two levels of braces: one in using its space removal routine and one in internal parsings. The \pkgm{kvsetkeys} strips off only one level of braces. The matter of these differences has not yet been shown to have serious implications for existing or new packages, although it is apparently of concern to the \pkgm{keycommand}.
The \pkg{skeyval} internally uses a space removal scheme that doesn't strip off braces from its arguments, but since the present package relies, to a good extent, on the engine of the \pkg{xkeyval}, the brace stripping effect has remained. We have had to redefine a significant number of the internal macros of the \pkg{xkeyval}, but getting rid of the brace-stripping issue would require even more substantial revision of the internal macros of the \pkg{xkeyval}. It can easily be solved but there is currently no sufficient reason to do so. If, odd enough, you want at least one level of braces to persist in the value part of the \acmd{key-value} pair throughout parsing, you simply surround the value with four levels of braces in the \acmd{\setkeys} command. If the users of this, or the \pkg{xkeyval}, feel that this issue is of significant concern, then it can be addressed in the future.
\section{The \texttt{skeyval} package options}
\label{sec:loading-package}
The package can be loaded in style and class files by
\begin{example}
\RequirePackage[options]{skeyval}
\end{example}
and in document files via
\begin{example}
\usepackage[options]{skeyval}
\end{example}
where the user options and their default values are
\begin{macro}
keyparser=;, macroprefix=mp@, keyprefix=KV, keyfamily=fam,
verbose=false
\end{macro}
\acmdm*{keyparser,macroprefix,keyprefix,keyfamily,verbose}
The \ang{keyparser} is the separator between the keys in the key list to be defined in one go (see \cref{sec:multkeys-examples}). The \ang{macroprefix}, \ang{keyprefix}, and \ang{keyfamily} are, respectively, the macro prefix, key prefix and key family for all the keys to be defined upon the declaration of these options. All these options can be set or changed dynamically by using the \acmdm{\skvoptions} macro:
\begin{macro}
\skvoptions{keyparser=;, macroprefix=mp@, keyprefix=KV,
keyfamily=fam}
\end{macro}
These options are explained in more detail in subsequent sections.
If, as unlikely as it may seem, a clash arises between package and/or user macros as a result of the use of the defaults for \ang{macroprefix}, \ang{keyprefix} and \ang{keyfamily}, then the user will have to make his own choices for these defaults so as to avoid clashes.
The \pkg{skeyval} issues a fatal error if it is loaded before (or run without) \acmd{\documentclass}.
\section[Complementary native boolean keys]{Complementary native-boolean keys}
\label{sec:comp-boolkeys}
\subsection{Bipolar native-boolean keys}
\label{sec:biboolkeys}
As mentioned in \cref{sec:motivation}, complementary bipolar keys are keys that depend inversely on each other: when one of them is in a particular state of a two-valued logic, the other one automatically assumes the opposite or complementary state. For each pair of bipolar keys, one is normally assumed to be the primary key and the other the secondary. The primary boolean key will usually represent the default state of a two-valued logic. Whenever one bipolar key (primary or secondary) is true, its complement is automatically set false; and vice versa: when one bipolar key (primary or secondary) is false, its complement is automatically set true. Generally, the transition of the state of a key from negative (false) to positive (true) is associated with the execution of the key's macro.
The syntax for creating bipolar native-boolean keys is
\begin{macro}
\define@biboolkeys[|vang(keyprefix)]{|vang(family)}[|vang(macroprefix)]
{|vang(primary boolean)}[|vang(default value for primary boolean)]
{|vang(secondary boolean)}{|vang(func for primary boolean)}
{|vang(func for secondary boolean)}
\end{macro}
\acmdm*{\define@biboolkeys}
This command is robust and can be used in expansion contexts, but expandable commands may need to be protected. When the user doesn't supply the \ang{keyprefix} and/or \ang{macroprefix}, the package will use \ang{KV} and \ang{mp@}, respectively. When the default value for the primary boolean is not supplied, the package will use \acmd{true}. Infinite loops, which are possible in back-linked key settings, are avoided in the \pkg{skeyval}. The machinery of the \pkg{xkeyval}, such as \acmd{\setkeys}, \acmd{\presetkeys}, \acmd{\savekeys}, \acmd{\savevalue}, \acmd{\usevalue}, \etc, are all applicable to all complementary keys.
As an example, we define below two bipolar native-boolean keys \ang{draft} and \ang{final} with different key macros:
\begin{example}
\define@biboolkeys[KV]{fam}[mp@]{draft}[true]{final}%
{%
\ifmp@draft
\def\noneofone##1{}%
\else
\def\oneofone##1{##1}%
\fi
}{%
\ifmp@final
\def\noneoftwo##1##2{}%
\else
\def\oneoftwo##1##2{##1}%
\fi
}
\end{example}
The key prefix (default \fx{KV}), macro prefix (default \fx{mp@}), key macros (no default), and the default value of the primary boolean (\fx{true}) can all be empty:
\begin{example}
\define@biboolkeys{fam}{draft}{final}{}{}.
\end{example}
The defined complementary bipolar keys \ang{draft} and \ang{final} can now be set separately as follows:
\begin{example}
\setkeys[KV]{fam}{draft=true |makered(or) on}
\setkeys[KV]{fam}{final=true |makered(or) on}
\end{example}
The second statement above reverses the boolean \ang{draft} to \ang{false}, which had been set in the first statement to \ang{true}. There is no apparent meaning to the following:
\begin{example}
\setkeys[KV]{fam}{draft=true,final=true}.
\end{example}
\Note
In the \pkg{skeyval}, the acceptable values for native-boolean and toggle-boolean keys are \fx{true}, \fx{on}, \fx{false}, and \fx{off}. Toggle-booleans (\cref{sec:toggle-booleans}) and switches (\cref{sec:switches}) also accept these values. The value \fx{on} is synonymous with \fx{true}, whilst \fx{off} is an alias for \fx{false}. Being merely aliases, both \fx{on} and \fx{off} don't increase the number of commands per switch: the number remains three.
The \pkg{skeyval} has the \acmdm{\NewIfs} and \acmdm{\DefIfs} macros, both of which define five commands per switch:
\begin{macro}
\NewIfs[|vang(optional prefix)]{|vang(boolean list)}[|vang(optional state)]
\DefIfs[|vang(optional prefix)]{|vang(boolean list)}[|vang(optional state)]
\end{macro}
The command \fx{\NewIfs} provides, for each member of the comma-separated list \ang{boolean list}, a new native-boolean register if the register didn't already exist. If the boolean register already existed, an error is flagged. Each member of \ang{boolean list} is prefixed with \ang{prefix} upon definition. The command \fx{\DefIfs}, on the other hand, provides, for each member of the comma-separated list \ang{boolean list}, a new native-boolean register whether or not the register already existed. If the boolean register already existed, and the package option \fx{verbose} is enabled, a message is entered in the transcript log file that the boolean has been redefined.
The optional \ang{state} can be either \fx{true}, \fx{false}, \fx{on} or \fx{off}; the default is \fx{false}. The state \fx{on} is synonymous with \fx{true}, whilst \fx{off} is equivalent to \fx{false}. After declaring
\begin{example}
\NewIfs[bool]{a,b}[true]
\end{example}
you can say \fx{\ifboola}, \fx{\boolaon} and \fx{\boolaoff}, just like you would normally do \fx{\boolatrue} and \fx{\boolafalse}. The disadvantage of \fx{\NewIfs} and \fx{\DefIfs} is that they define five commands per switch; they should therefore be employed only in special circumstances.
\subsection{Unipolar native-boolean keys}
Unipolar boolean keys are two keys that are always in the same state: when one is true (or false), the other one is also true (or false). In this regard, the key macro is always executed when a key transits to the ``true'' state. The syntax for creating unipolar native-boolean keys is exactly as that for defining bipolar native-boolean keys:
\begin{macro}
\define@uniboolkeys[|vang(keyprefix)]{|vang(family)}[|vang(macroprefix)]
{|vang(primary boolean)}[|vang(default value for primary boolean)]
{|vang(secondary boolean)}{|vang(func for primary boolean)}
{|vang(func for secondary boolean)}
\end{macro}
\acmdm*{\define@uniboolkeys}
This command is robust and can be used in expansion contexts, but expandable commands may need to be protected. Again, if the user doesn't supply the \ang{keyprefix} and/or \ang{macroprefix}, the package will use \ang{KV} and \ang{mp@}, respectively. When the default value for the primary boolean is not supplied, the package will assume it to be \fx{true}.
The following example constructs two unipolar native-boolean keys:
\begin{example}
\NewToks[temptoks]{a,b}
\define@uniboolkeys[KV]{fam}[mp@]{pdfmode}[true]{microtype}%
{%
\ifmp@pdfmode
\temptoksa{Yes, in `pdfmode'}%
\else
\temptoksa{No, not in `pdfmode'}%
\fi
}{%
\ifmp@microtype
\temptoksb{Yes, `microtype' loaded}%
\else
\temptoksb{No, `microtype' not loaded}%
\fi
}
\end{example}
\subsection{Biunipolar native-boolean keys}
\label{sec:biuni-boolean}
Biunipolar keys are the generalized forms of bipolar and unipolar boolean keys, with one important restriction: unlike bipolar and unipolar keys, biunipolar keys have no symmetrical relationships. That is to say that the relationship between a pair of biunipolar keys is entirely determined by the primary key. A pair of biunipolar boolean keys possess only one of the following four types of relationship:
\begin{enum}
\item Unipolar property: When the primary key is \fx{false}, it sets the secondary key to \fx{false} (\RedStar\RedPlus-form of biunipolar keys). The secondary key macro isn't executed.
\item Bipolar property: When the primary key is \fx{false}, it sets the secondary key to \fx{true} (\RedStar-form). The secondary key macro is executed.
\item Bipolar property: When the primary key is \fx{true}, it sets the secondary key to \fx{false} (\RedPlus-form). The secondary key macro isn't executed.
\item Unipolar property: When the primary key is \fx{true}, it sets the secondary key to \fx{true} (unsigned form). The secondary key macro is executed.
\end{enum}
Of course, the primary key can be true only after it has been set.
The syntax for establishing biuni boolean keys is exactly like that for creating other complementary boolean keys, except for the optional \RedStar and \RedPlus signs:
\begin{macro}
\define@biuniboolkeys|redstar|redplus[|vang(keyprefix)]{|vang(family)}[|vang(macroprefix)]
{|vang(primary boolean)}[|vang(default value for primary boolean)]
{|vang(secondary boolean)}{|vang(macro for primary boolean)}
{|vang(macro for secondary boolean)}
\end{macro}
\acmdm*{\define@biuniboolkeys,\define@biuniboolkeys*,\define@biuniboolkeys*+}
As an example, consider the arbitrary package or class options \fx{review} and \fx{preprint}. The option \fx{preprint} can automatically toggle \fx{review} to true, but possibly not vice versa: not every \fx{preprint} is a manuscript for \fx{review}. This is depicted below:
\begin{example}
\define@biuniboolkeys[KV]{fam}[mp@]{preprint}[true]{review}{%
|comm(No key macro for preprint; otherwise, it would)
|comm(have come in here.)
}{%
\ifmp@review
\SKV@BeforeDocumentStart{%
\linespread{1.5}\selectfont
\def\banner{\fbox{\textit{This is a review document}}}%
}%
\else
\SKV@BeforeDocumentStart{\let\banner\@empty}%
\fi
}
\end{example}
\acmd*{\SKV@BeforeDocumentStart}
As another example, consider the following biuni keys, each with its own macro:
\begin{example}
\define@biuniboolkeys|redstar|redplus[KV]{fam}[mp@]{brother}[true]{sister}{%
\ifmp@brother
\def\mybrother{Hamilton}%
\fi
}{%
\ifmp@sister
\SKV@AfterDocumentStart{\def\mysister{Kate}}%
\else
\SKV@AfterDocumentStart{\let\mysister\@gobble}%
\fi
}
\setkeys[KV]{fam}{brother=true}
\end{example}
\acmd*{\SKV@AfterDocumentStart}
\section{Toggle booleans and toggle keys}
\label{sec:toggles}
In the following \crefrange{sec:toggle-booleans}{sec:toggle-keys} we define toggle booleans/switches and use them to introduce toggle-boolean keys.
\subsection{Toggle booleans}
\label{sec:toggle-booleans}
The following toggle switches are defined in the \pkg{skeyval}. They largely mimic those in the \pkg{etoolbox}, except for the commands \acmdm{\deftog} and \acmd{\requiretog}. The internal control sequences and user interfaces of the two packages are, however, different, thus avoiding clashes.
All the commands in this section are robust and can be used in expansion or moving contexts without fear of premature expansion, but fragile arguments would need to be protected in those settings.
\begin{macro}
\deftog[|vang(optional prefix)]{|vang(toggle)}[|vang(optional state)]
\end{macro}
This defines a new \ang{toggle}, prefixed with \ang{prefix} upon definition, whether or not \ang{toggle} (with its prefix) is already defined. If \ang{toggle} is already defined, a warning message is logged in the transcript file (if the package option \acmd{verbose} is selected) and the new definition is effected. The optional \ang{state} can be either \fx{true}, \fx{false}, \fx{on} or \fx{off}.
\begin{macro}
\newtog[|vang(optional prefix)]{|vang(toggle)}[|vang(optional state)]
\end{macro}
\acmdm*{\newtog}
This defines a new \ang{toggle}, prefixed with \ang{prefix} upon definition, if \ang{toggle} (with its prefix) is not already defined; otherwise the package issues a fatal error. The optional \ang{state} can be either \fx{true}, \fx{false}, \fx{on} or \fx{off}.
You can define a set of toggles by the following commands:
\begin{macro}
\NewTogs[|vang(optional prefix)]{|vang(toggles)}[|vang(optional state)]
\DefTogs[|vang(optional prefix)]{|vang(toggles)}[|vang(optional state)]
\end{macro}
\acmdm*{\NewTogs,\DefTogs}
where \ang{toggles} is a comma-separated list. Each member of \ang{toggles} is prefixed with \ang{prefix} upon definition. The optional \ang{state} can be either \fx{true}, \fx{false}, \fx{on} or \fx{off}. For example, we may define new toggles \fx{togx}, \fx{togy}, \fx{togz} by the following:
\begin{example}
\NewTogs[tog]{x,y,z}[true]
\end{example}
\begin{macro}
\providetog{|vang(toggle)}
\end{macro}
\acmdm*{\providetog}
This defines a new \ang{toggle} if \ang{toggle} is not already defined. If \ang{toggle} is already defined, the command does nothing. Please note that there are no tog prefix here, and that the default state is \fx{false}.
\begin{macro}
\requiretog{|vang(toggle)}
\end{macro}
\acmdm{\requiretog} takes arguments like \fx{\newtog} and behaves like \fx{\providetog} with the difference: if the toggle is already defined, the command \fx{\requiretog} calls \LaTeX's \acmdm{\CheckCommand} to make sure that the new and existing definitions are identical, whereas \fx{\providetog} assumes that if the toggle is already defined, the existing definition should persist. \fx{\requiretog} assures that a toggle will have the given definition, but (if the package option \fx{verbose} is selected) \fx{\requiretog} also warns the user if there was a previous and different existing definition. For example, if the toggle \ang{toga} is currently \ang{true}, then since all new toggles start out as \ang{false}, a call \fx{\requiretog{toga}} will, if the package option \fx{verbose} is selected, issue a warning in the log file that the new and old definitions of \ang{toga} don't agree and the new definition, therefore, can't go ahead. Note that there are no tog prefix here, and that the default state is \fx{false}.
The \pkg{skeyval} also provides the command \acmd{\requirecmd}, which has the same logic as \fx{\requiretog} but can be used for general \latex commands, including those with optional arguments (see \cref{sec:misce-commands}).
\begin{macro}
\settog{|vang(toggle)}{|vang(true |amdvert false |amdvert on |amdvert off)}
\end{macro}
\acmdm*{\settog}
This command sets \ang{toggle} to \ang{value}, where \ang{value} may be either \fx{true}, \fx{false}, \fx{on} or \fx{off}. This statement will issue an error if \ang{toggle} wasn't previously defined.
\begin{macro}
\togon{|vang(toggle)}
\togtrue{|vang(toggle)}
\end{macro}
\acmdm*{\togon, \togtrue}
These set \ang{toggle} to \ang{true} or \fx{on}. They will issue an error if \ang{toggle} wasn't previously defined.
\begin{macro}
\togoff{|vang(toggle)}
\togfalse{|vang(toggle)}
\end{macro}
\acmdm*{\togoff, \togfalse}
These set \ang{toggle} to \ang{false} or \fx{off}. They will issue an error if \ang{toggle} wasn't previously defined.
\begin{macro}
\iftogon{|vang(toggle)}{|vang(true)}{|vang(false)}
\iftogtrue{|vang(toggle)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\iftogon, \iftogtrue}
These yield the \ang{true} statement if the boolean \ang{toggle} is currently \ang{true}, and \ang{false} otherwise. They will issue an error if \ang{toggle} wasn't previously defined.
\begin{macro}
\iftogoff{|vang(toggle)}{|vang(not true)}{|vang(not false)}
\iftogfalse{|vang(toggle)}{|vang(not true)}{|vang(not false)}
\end{macro}
\acmdm*{\iftogoff, \iftogfalse}
These behave like \fx{\iftogon} and \fx{\iftogtrue} but reverse the logic of the test. They will issue an error if \ang{toggle} wasn't previously defined.
\subsection{Toggle-boolean keys}
\label{sec:toggle-keys}
The user interfaces for defining toggle-boolean keys is exactly like those for native-boolean keys in the \pkg{xkeyval}. This allows all the machinery of the \pkg{xkeyval} (including \acmd{\setkeys}, \acmd{\presetkeys}, \acmd{\savekeys}, \acmd{\savevalue}, \acmd{\usevalue}, etc) to be applicable to toggle-boolean keys.
As mentioned earlier, toggles have their own separate namespace. However, the \acmd{\setkeys} command (and friends) of the \pkg{xkeyval} is unaware of this. This can cause problems when the user uses the same name for native-boolean and toggle keys (or indeed any key type) in the same family and with the same key prefix, believing rightly that toggle keys have their own separate namespace. If this is a source of significant concern to any user, he will be well advised to instead use the commands \acmd{\newboolkey}, \acmd{\newboolkeys}, \acmd{\newtogkey}, \acmd{\newtogkeys}, \etc, of \cref{sec:redef-keys}. In those commands a mechanism is included to bar keys from having the same name as other keys in the same family and with the same prefix. Toggle keys can still share the same names with keys across families and key prefixes. Since it is not always certain which of the keys the user may want to first define (before its definition is possibly repeated), the fear of interference has necessitated new syntaxes for defining all key types, which completely avoid interference (see \cref{sec:redef-keys}).
The user interfaces for defining toggle keys are
\begin{macro}
\define@togkey[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(key)}[|vang(default)]%
{|vang(function)}
\define@togkey|redplus[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(key)}[|vang(default)]%
{|vang(function1)}{|vang(function2)}
\end{macro}
\acmdm*{\define@togkey,\define@togkey+}
If the macro prefix \ang{mp} is not specified, these create a toggle of the form \fnn{prefix}{family}{key}{} using \acmd{\deftog} (which initializes the toggle switch to \fx{false}) and a key macro of the form \bs\fnn{prefix}{family}{key}{} which first checks the validity of the user input. If the value is valid, it uses it to set the toggle and then executes \ang{function}. If the user input wasn't valid (\ie, neither \fx{true} nor \fx{false}), then the toggle will not be set and the package will generate a fatal error to this effect.
If \ang{mp} is specified, then the key definition process will create a toggle of the form \fnm{mp}{key}{}{} and a key macro of the form \bs\fnm{mp}{key}{}{}. The value \ang{default} will be used by the key macro when the user sets the key without a value.
If the plus (\RedPlus) version of the macro is used, the user can specify two key macros \ang{function1} and \ang{function2}. If user input is valid, the macro will set the toggle and executes \ang{function1}; otherwise, it will not set the boolean but will execute \ang{function2}.
As an example, consider the following:
\begin{example}
\define@togkey{fam}[my@]{frame}{%
\iftogon{my@frame}{%
\PackageInfo{mypack}{Turning frames on}%
}{%
\PackageInfo{mypack}{Turning frames off}%
}%
}
\define@togkey|redplus{fam}{shadow}{%
\iftogon{KV@fam@shadow}{%
\PackageInfo{mypack}{Turning shadows on}%
}{%
\PackageInfo{mypack}{Turning shadows off}%
}%
}{%
\PackageWarning{mypack}{Erroneous input `#1' ignored}%
}
\end{example}
The first example creates the toggle \ang{my@frame} and defines the key macro
\fx{\KV@fam@frame} to set the boolean (if the input is valid). The second key intimates
the user of changed settings, or produces a warning when input was incorrect.
It is also possible to define multiple toggle keys with a single command:
\begin{macro}
\define@togkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(keys)}[|vang(default)]
\end{macro}
\acmdm*{\define@togkeys}
This creates a toggle key for every entry in the comma-separated list \ang{keys}. As is the case with the commands \acmd{\define@cmdkeys} and \acmd{\define@boolkeys} from the \pkg{xkeyval}, the individual keys in this case can't have a custom function. See \cref{sec:def-multiple-keys} for how to define multiple keys with custom functions.
As an example of defining multiple toggle keys, consider
\begin{example}
\define@togkeys{fam}[my@]{toga,togb,togc}
\end{example}
This is an abbreviation for
\begin{example}
\define@togkey{fam}[my@]{toga}{}
\define@togkey{fam}[my@]{togb}{}
\define@togkey{fam}[my@]{togc}{}
\end{example}
Now we can do
\begin{example}
\define@togkey{fam}[my@]{book}{%
\iftogon{my@book}{\setkeys[KV]{fam}{togc=true}}{}%
}
\setkeys[KV]{fam}{book=true}
\end{example}
\acmd*{\define@togkey,\setkeys}
Toggle keys can be set in the same way that other key types are set.
The status of toggles can be examined by doing
\begin{example}
\show\SKV@toggle@|vang(mp)|vang(key)
\end{example}
when the \ang{mp} is present. When the user has specified no \ang{mp} in defining the key, he has to issue
\begin{example}
\show\SKV@toggle@|vang(prefix)@|vang(family)@|vang(key).
\end{example}
\section{Complementary toggle keys}
\label{sec:comptogkeys}
\subsection{Bipolar toggle-boolean keys}
Similar to complementary native-boolean keys of \cref{sec:comp-boolkeys}, the \pkg{skeyval} introduces facilities for creating complementary (bipolar, unipolar and biunipolar) toggle keys. The syntax for defining bipolar toggle keys is identical to that for defining bipolar native-boolean keys:
\begin{macro}
\define@bitogkeys[|vang(keyprefix)]{|vang(family)}[|vang(macroprefix)]
{|vang(primary toggle)}[|vang(default value for primary toggle)]
{|vang(secondary toggle)}{|vang(func for primary toggle)}
{|vang(func for secondary toggle)}.
\end{macro}
\acmdm*{\define@bitogkeys}
This command is robust and can be used in expansion contexts, but non-robust commands have to be protected. When the user doesn't supply the \ang{keyprefix} and/or \ang{macroprefix}, the package will use \ang{KV} and \ang{mp@}, respectively. When the default value for the primary toggle-boolean is not supplied, the package will use \fx{true}. When one of the bipolar toggle keys (primary or secondary) is true, the other is automatically set false; and vice versa: when one toggle key (primary or secondary) is false, the other is automatically set true.
As an example, we define below two bipolar toggle keys \ang{xdraft} and \ang{xfinal} with different key macros:
\begin{example}
\define@bitogkeys[KV]{fam}[mp@]{xdraft}[true]{xfinal}%
{\def\gobble##1{}}{\def\firstofone##1{##1}}
\end{example}
The key prefix (default \fx{KV}), macro prefix (default \fx{mp@}), key macros (no default), and the default value of the primary boolean (default \fx{true}) can all be empty:
\begin{example}
\define@bitogkeys{fam}{xdraft}{xfinal}{}{}.
\end{example}
The defined bipolar toggle keys \ang{xdraft} and \ang{xfinal} can now be set as follows:
\begin{example}
\setkeys[KV]{fam}{xdraft=true}
\setkeys[KV]{fam}{xfinal=true}
\end{example}
\acmd*{\setkeys}
The second statement above reverses the toggle \ang{xdraft} to \ang{false}, which had been set in the first statement to \ang{true}.
\Note
Toggle keys may easily be confused with the conventional boolean keys, especially at the time of key setting. It is, therefore, always safer to use the syntaxes in \cref{sec:redef-keys} for defining keys; they avoid interference between new and existing keys.
If we were to use the key names \acmd{draft} and \acmd{final} as toggle keys above, instead of \fx{xdraft} and \fx{xfinal}, there would have been a clash with the keys \acmd{draft} and \acmd{final} defined as (complementary) native-boolean keys in \cref{sec:comp-boolkeys}---because they share the same family \ang{fam} and prefix \ang{KV}. The names \acmd{draft} and \acmd{final} could safely be used as toggles only if the family \ang{fam} or prefix \ang{KV} is changed. See \cref{sec:avoiding-redef} for further details.
\subsection{Unipolar toggle-boolean keys}
The syntax for defining unipolar toggle keys is exactly the same as that for defining bipolar toggle keys:
\begin{macro}
\define@unitogkeys[|vang(keyprefix)]{|vang(family)}[|vang(macroprefix)]
{|vang(primary toggle)}[|vang(default value for primary toggle)]
{|vang(secondary toggle)}{|vang(func for primary toggle)}
{|vang(func for secondary toggle)}.
\end{macro}
\acmdm*{\define@unitogkeys}
Here too, if the user doesn't supply the \ang{keyprefix} and/or \ang{macroprefix}, the package will use \ang{KV} and \ang{mp@}, respectively. When the default value for the primary toggle key is not supplied, the package will use \acmd{true}.
\begin{example}
\define@unitogkeys[KV]{fam}[mp@]{draft}[true]{final}%
{\def\x##1{}}{\def\y##1{##1}}
\setkeys[KV]{fam}{draft=true}|comm(``final'' becomes ``true'' here.)
\end{example}
\acmd*{\setkeys}
\subsection{Biunipolar toggle-boolean keys}
The interface for creating biuni toggle keys is exactly like that for creating other complementary boolean keys, except for the optional \RedStar and \RedPlus signs. The interface is as follows (the meaning of the optional \RedStar and \RedPlus is given in \cref{sec:biuni-boolean}):
\begin{macro}
\define@biunitogkeys|redstar|redplus[|vang(keyprefix)]{|vang(family)}[|vang(macroprefix)]
{|vang(primary boolean)}[|vang(default value for primary boolean)]
{|vang(secondary boolean)}{|vang(macro for primary boolean)}
{|vang(macro for secondary boolean)}
\end{macro}
\acmdm*{\define@biunitogkeys,\define@biunitogkeys*,\define@biunitogkeys*+}
\begin{example}
\define@biunitogkeys|redplus[KV]{fam}[mp@]{preprint}[true]{review}{%
\iftogon{mp@preprint}{%
\def\banner{\fbox{\textsf{This is a preprint copy}}}%
}{}%
}{%
\iftogon{mp@review}{%
\SKV@AtDocumentStart{\linespread{1.5}\selectfont}%
\def\banner{\fbox{\textit{This is a review article}}}%
}{%
\let\banner\@empty
}%
}
\setkeys[KV]{fam}{preprint=false |orr true}
\end{example}
\acmd*{\setkeys,\SKV@AtDocumentStart}
\section[Defining multiple keys by one command]
{Defining multiple keys of all genres by one command}
\label{sec:def-multiple-keys}
The user interface for defining multiple keys of all kinds in one go is the command \acmdm{\define@keylist}, whose syntax is
\begin{macro}
\define@keylist{|vang(key type/id), |vang(key), |vang(key default value),
|vang(key macro/function); |vang(another set of key specifiers); etc}
\end{macro}
Here, there are five key types: 1~(ordinary key), 2~(command key), 3~(native-boolean key),
4~(toggle-boolean key), and 5~(choice/menu key). The key types can be indicated either in numeral format (\fx{1}~to~\fx{5}) or in alphabetic format (\fx{ord}, \fx{cmd}, \fx{bool}, \fx{tog}, \fx{choice}, \fx{menu}). ``Choice'' and ``menu'' keys imply the same thing (key type~5): the user can pick the name he prefers. The key and its attributes are separated by commas; they constitute one ``object'' or ``instance''. The objects are separated by the \ang{keyparser}, which is the semicolon in the above example. The \ang{keyparser} is a package option and can be changed dynamically.
If the key list is available in a macro, say,
\begin{example}
\def\keylist{|vang(key type/id), |vang(key), |vang(key default value),
|vang(key macro/function); |vang(another set of key specifiers); etc},
\end{example}
then the keys can be defined by the starred form of \fx{\define@keylist}:
\begin{example}
\define@keylist|redstar\keylist.
\end{example}
\fx{\define@keylist}\redstar\ takes a macro as argument, while \fx{\define@keylist} accepts a key list.
\acmdm*{\define@keylist*}
The \fx{\define@keylist} macro uses the following commands in the background:
\begin{example}
\define@key, \define@cmdkey, \define@boolkey,
\define@choicekey, \define@togkey.
\end{example}
\acmdm*{\define@cmdkey,\define@boolkey,\define@choicekey,\define@togkey}
\acmd*{\define@key}
Therefore, it assumes that it is safe to redefine a previously defined key. If this assumption is unwarranted, then the user should consider using the machinery of \cref{sec:redef-keys}. The machinery of \cref{sec:redef-keys} can be utilized to safely define new keys without the fear of inadvertently redefining an existing key within the same family and with the same key prefix.
Keys defined by the tools in this section are amenable to management by pointers of \cref{sec:pointer-mech}.
\subsection{Choice key values}
\label{sec:choice-key-values}
The \acmdm{\choicekeyvalues} macro is provided for defining choice keys; it lists the alternate
admissible values for a choice key and thus can't be empty when a choice key
is being defined via \fx{\define@keylist}. Its syntax is
\begin{macro}
\choicekeyvalues|redstar[|vang(prefix)][|vang(family)]{|vang(key)}{|vang(list)},
\end{macro}
where \ang{list} is a comma-separated list of admissible key values. Unless the key prefix or family changes, the unstarred variant of \fx{\choicekeyvalues} wouldn't allow you to set two \fx{\choicekeyvalues} for the same choice key. The starred variant \fx{\choicekeyvalues}\unskip\redstar, on the other hand, allows you to overwrite admissible choice values for a key within a specified family and with the given key prefix. The arguments \ang{prefix} and \ang{family} are optional, provided the key prefix and family have been specified before calling \fx{\choicekeyvalues}, using \fx{\skvoptions}. If \ang{prefix} and \ang{family} are not given, the prevailing key prefix and key family are used internally by \fx{\choicekeyvalues} to build distinct alternate values list for the choice key. Therefore, any number of choice keys are allowed to appear in one \acmd{\define@keylist} or \acmd{\define@keylist}\unskip\redstar\ statement, if their lists of alternate/admissible values have been set by \fx{\choicekeyvalues}.
It doesn't matter which choice key first gets a \fx{\choicekeyvalues}.
To further save tokens, the macro \fx{\choicekeyvalues} may be abbreviated by \acmdm{\CKVS}. It has to be provided for each choice key that is being defined.
For example, if we want to define two choice keys \fx{align} and \fx{shootingmodes}, then before the call to \acmd{\define@keylist}, we have to set
\begin{example}
\CKVS{align}{center,right,left,justified}
\CKVS{shootingmodes}{portrait,indoor,foliage,underwater}
\end{example}
As mentioned earlier, the key family and other package options can be changed dynamically via
\begin{example}
\skvoptions{keyparser=value,macroprefix=value,keyprefix=value,
keyfamily=value}.
\end{example}
\acmd*{\skvoptions}
In line with the philosophy of the \pkg{xkeyval}, all the choice keys to be defined using the \pkg{skeyval} require a menu: choice keys, by definition, have pre-ordained or expected values.
\subsection{Some examples}
\label{sec:multkeys-examples}
In this section we provide a glimpse of the potential applications of the tools provided by the \pkg{skeyval} in the context of defining multiple keys by one command.
Suppose that the key family and other attributes have been set as
\begin{example}
\skvoptions{keyparser=;,macroprefix=mp@,keyprefix=KV,
keyfamily=fam}
\end{example}
\acmd*{\skvoptions}
Further, suppose we wish to define a set of keys \fx{{color,angle,scale,align}}. The key \fx{color} will be defined as ordinary key, the keys \fx{angle} and \fx{scale} will de defined as command keys, while the key \fx{align} will be defined as a choice key. Assume that the \fx{align} key can only assume one of the values \leftbrace\fx{center} \amdvert\ \fx{right} \amdvert\ \fx{left} \amdvert\ \fx{justified}\rightbrace, where the first three values would further imply \fx{\centering}, \fx{\flushright}, and \fx{\flushleft}, respectively. Moreover, we assume that the key \fx{scale} will be associated with a macro called \fx{\mydo}, which depends on a previously defined macro \fx{\do}. Together with \fx{align}, we would also like to define another choice key: \fx{weather}. The key \fx{color} isn't associated with any macro. Then we can do:
\begin{example}
|comm(We use space freely in these examples for the sake)
|comm(of illustration:)
\def\someweather{windy}
\CKVS{align}{center,right,left,justified}
\CKVS{weather}{sunny,cloudy,lightrain,heavyrain,snow,
sleet,\someweather}
\def\funcforalign{%
\ifcase\nr\relax
\def\mp@align{\centering}%
\or\def\mp@align{\flushright}%
\or\def\mp@align{\flushleft}%
\or\let\mp@align\relax
\fi
}
|comm(Keys `color' and `mybool' have no macro.)
|comm(Submitted value of key `angle' is ##1 |tto \mp@angle.)
\define@keylist{%
ord,color,gray!25,;
cmd,angle,45,\def\anglevalue{##1};
cmd,scale,1,\def\mydo####1{\do ####1};
choice,align,center,\funcforalign;
|makered(\listbreak);|label(mac:listbreak)
bool,mybool,true,;
choice,weather,sunny,\edef\Weather{\val}%
}
\setkeys[KV]{fam}{angle=45,scale=1cm,weather=cloudy}
\end{example}
\acmd*{\CKVS}
Note the number of parameter characters in the definition of \fx{\mydo}. We will return to this matter in \cref{sec:macros-in-keymacros}. The \acmdm{\nr} and \acmdm{\val} macros are bin parameters for choice keys, as defined by the \pkg{xkeyval}. \fx{\val} contains the user input for the current key and \fx{\nr} contains the numeral corresponding to the numerical order of the user input in the \acmd{\CKVS} list, starting from~0 (zero). For example, in the \fx{\CKVS{align}} list, the \fx{\nr} values are \fx{center}~(0), \fx{right}~(1), \fx{left}~(2), and \fx{justified}~(3). These parameters thus refresh with the choice key and its user-supplied value.
Instead of defining the macro \fx{\funcforalign} before hand, we can submit its replacement text directly to the macro \acmd{\define@keylist}, but, because \fx{\funcforalign} contains a conditional, some care is needed in doing so (see \cref{sec:condit-in-keys}). Once the key \fx{align} has been defined, the macro \fx{\funcforalign} can't be reused before the key \fx{align} is set. This is because it is at key setting time that the function \fx{\funcforalign} would be called. This is uneconomical: it is thus desirable to submit the key macro directly to \acmd{\define@keylist} irrespective of the presence of conditionals.
Please note the \makered{\texttt{\string\listbreak}} token inserted on \macref{mac:listbreak} above. Because of it, the keys \fx{mybool} and \fx{weather} will not be read and defined; all the keys before \acmdm{\listbreak} (\ie, \fx{color}, \fx{angle}, \fx{scale} and \fx{align}) will be read and defined. All the entries for \fx{mybool} and \fx{weather} will instead be saved in the macro \acmdm{\SKV@remainder}, possibly for some other uses.
Hundreds of keys can be defined efficiently in this way, using very few tokens. As another example, we consider the following keys:
\acmd*{\CKVS,\define@keylist,\AtBeginDocument}
\begin{example}
\CKVS|redstar{align}{center,right,left,justified}
\CKVS{election}{state,federal,congress,senate}
\def\funcfortextwidth{\AtBeginDocument{\wlog{`textwidth' %
is `\mp@textwidth'}}}
\def\funcfortextheight{%
\ifx\@empty\mp@textheight
\wlog{`textheight' value empty}%
\else
\wlog{`textheight' value not empty}%
\fi
}
\def\funcforpaperwidth{\wlog{`paperwidth' was defined as %
ordinary key.}}
\def\funcforalign{%
\ifcase\nr\relax
\def\mp@align{\centering}%
\or\def\mp@align{\flushright}%
\or\def\mp@align{\flushleft}%
\or\let\mp@align\relax
\fi
}
|comm(`boolvar', `paperheight' and `evensidemargin' have no)
|comm(key macros:)
\define@keylist{%
bool,boolvar,true,;
ord,paperheight,\paperheight,;
ord,paperwidth,\paperwidth,\funcforpaperwidth;
cmd,textheight,\textheight,\funcfortextheight;
cmd,textwidth,\textwidth,\funcfortextwidth;
ord,evensidemargin,\evensidemargin,;
tog,togvar,true,\iftogon{mp@togvar}{\def\catch####1{####1}}%
{\def\gobble####1{}};
choice,align,center,\funcforalign;
choice,election,congress,\def\electiontype{##1};
cmd,testdim,2cm,\long\def\funcfortestdim####1{%
A test dimension ####1 \endgraf\bigskip}%
}
\setkeys[KV]{fam}{togvar=true,testdim=1cm,election=senate}
\end{example}
The macro \fx{\electiontype} corresponds to \fx{\val} for choice key \fx{election}.
Again, the intermediate/utility key macros can be reused only after their associated keys have been set.
The same set of keys can be defined via the starred form of \acmd{\define@keylist}, as shown below:
\begin{example}
\def\keylistvector{%
bool,boolvar,true,;
ord,paperheight,\paperheight,;
ord,paperwidth,\paperwidth,\funcforpaperwidth;
cmd,textheight,\textheight,\funcfortextheight;
cmd,textwidth,\textwidth,\funcfortextwidth;
ord,evensidemargin,\evensidemargin,;
tog,togvar,true,\iftogon{mp@togvar}{\def\catch####1{####1}}%
{\def\gobble####1{}};
choice,align,center,\funcforalign;
choice,election,congress,\def\electiontype{##1};
cmd,testdim,2cm,\long\def\funcfortestdim####1{%
A test dimension ####1 \endgraf\bigskip}%
}
\define@keylist|redstar\keylistvector
\end{example}
\acmd*{\define@keylist*}
Since the keys have been defined, they can now be set. In the following, we set only two of the keys:
\begin{example}
\setkeys[KV]{fam}{align=right,testdim=3cm}
\end{example}
\acmd*{\setkeys}
The macro \fx{\mp@align} holds the value \fx{\flushright}, while \fx{\KV@fam@testdim} holds the macros:
\begin{example}
\def\mp@testdim{#1}
\long\def\funcfortestdim##1{A test dimension ##1},
\end{example}
where \fx{#1} is the value (3cm) submitted for the key \fx{testdim}. The number of parameter characters normally increases in the macro \fx{\define@keylist} (see \cref{sec:macros-in-keymacros}). After setting the keys, you can do \fx{\show\mp@align} and \fx{\show\KV@fam@testdim} to confirm the above assertions.
The rest of the defined keys can now be set as follows:
\begin{example}
\setkeys[KV]{fam}{boolvar=true,paperheight,paperwidth,
textheight,textwidth=6cm}
\end{example}
\acmd*{\setkeys}
Try \fx{\show\ifmp@boolvar} to confirm that \fx{boolvar} is now \ang{true}; it was originally set as \ang{false}. The macro \fx{\KV@fam@paperwidth} holds the function \fx{\funcforpaperwidth}, while \fx{\mp@textheight} holds the value submitted to key \fx{textheight} at any instance of \acmd{\setkeys}. By the above \acmd{\setkeys}, only the default values of \fx{paperheight}, \fx{paperwidth}, and \fx{textheight} are presently available.
Instead of using macros to pass key macros and functions, it is also possible to use token list registers. Some examples are provided below:
\begin{example}
\NewToks[temptoks]{a,b}
|comm(See page |pageref(page:newtoks) for definition of \NewToks and related commands.)
\temptoksa{\ifmp@boola\def\do#1{%
\def#1##1##2{\expandafter\expandafter\expandafter\in@
\expandafter\expandafter\expandafter{\expandafter##1%
\expandafter}\expandafter{##2}}}\fi}
\temptoksb{\iftogon{mp@toga}{\def\order#1{Use `#1' now!}}%
{\def\altorder#1{Don't use `#1' now!}}}
\define@keylist{3,boola,true,\the\temptoksa;
4,toga,true,\the\temptoksb}
\setkeys[KV]{fam}{boola=true,toga=true}
|comm(You can now test your new function \do:)
\def\y{x} \def\z{xxx}
\do\x\x\y\z
\end{example}
\acmd*{\define@keylist}
The advantage of using token list registers is that the parameter characters need not be doubled in the token list registers, unlike when using macros. The token list register \fx{\temptoksa} can be reused as soon as the key \fx{boola} has been set. See \cref{sec:condit-in-macros} for more information on using macros and token list registers to parse key functions.
\subsubsection{Parameterized macros in key macros}
\label{sec:macros-in-keymacros}
The examples in \cref{sec:multkeys-examples} would have provided some glimpse of the rules guiding the use of parameter characters in key macros. The general rules are as follows:
\begin{enum}
\item When key macros are parsed through token list registers, the parameter characters shouldn't be doubled (\ie, use \cmdtext{\#1} for outermost parameters).
\item When key macros are parsed via intermediate macros, the parameter characters should be doubled but only once (\ie, use \cmdtext{\#\#1} for outermost parameters).
\item In all other cases (\ie, when using \fx{\define@keylist} or \acmd{\newkeylist} and their starred variants) the parameter characters should be doubled twice (\ie, use \cmdtext{\#\#\#\#1} for outermost parameters).
\item Within \fx{\define@keylist} and \fx{\newkeylist}, you can refer to the user-submitted key value by \cmdtext{\#\#1}.
\end{enum}
\tex will flag a fatal error when any of these rules is breached. The need to double the parameter character arises from setting keys, not when defining keys. When absorbing their arguments, both \fx{\define@keylist} and \fx{\newkeylist} actually temporarily sanitize the parameter character.
The following examples illustrate the use of these rules. The commands \fx{\skif}, \fx{\skifx}, \fx{\skelse} and \fx{\skfi} are described in \cref{sec:pseudo-primitives}.
\begin{example}
\define@keylist{%
tog,toga,true,\iftogon{mp@toga}{%
\def\swear####1{Repeat after me: `####1'!}%
}{%
\let\swear\@gobble
}%
}
\setkeys[KV]{fam}{toga=true}
\NewToks[temptoks]{a}
\temptoksa={\long\def\funcforproclaim#1%
{A proclaimed statement: #1}}
\define@keylist{%
bool,boola,true,\skif{mp@boola}\def\yes####1%
{Accept `####1'!}\skelse\def\no####1{Reject `####1'!}\skfi;
cmd,proclaim,Statement,\the\temptoksa
}
\setkeys[KV]{fam}{boola=true,proclaim=nature}
\CKVS{align}{left,right,center}
\define@keylist{choice,align,center,
\skifcase\nr
\def\hold####1{\def####1########1{===########1===}}%
\skor
\def\hold####1{\def####1########1{+++########1+++}}%
\skfi
}
\setkeys[KV]{fam}{align=right}
\CKVS{focus}{left,right,center}
\def\keylistvector{%
choice,focus,center,\def\hold####1%
{\def####1########1{===########1===}}%
}
\define@keylist*\keylistvector
\setkeys[KV]{fam}{focus=right}
\def\keylistvector{cmd,keya,xxx,\def\hold####1%
{\def####1########1{===########1===}}}
\define@keylist*\keylistvector
\setkeys[KV]{fam}{keya=yyy}
\def\funcforkeyb{\def\hold##1{\def##1####1{===####1===}}}
\define@keylist{cmd,keyb,xxx,\funcforkeyb}
\setkeys[KV]{fam}{keyb=yyy}
\define@cmdkey[KV]{fam}[mp@]{keyc}[xxx]{\def\hold##1{##1}}
\setkeys[KV]{fam}{keyc=yyy}
\def\keylistvector{%
ord,keyda,aaa,\def\hold####1%
{\def####1########1{===########1===}};
cmd,keydb,bbb,\def\althold####1%
{\def####1########1{***########1***}}%
}
\define@keylist*\keylistvector
\setkeys[KV]{fam}{keyda=xxx,keydb=yyy}
|comm(The next one fails. Why?)
\define@keylist{%
ord,keye,unknown,\def\hold##1{\def##1####1{####1}}%
}
\setkeys[KV]{fam}{keye=yyy}
\define@keylist{%
ord,keyfa,xxx,
\skifx\x\y
\def\hold####1{\def####1########1{===########1===}}%
\skelse
\def\hold####1{\def####1########1{***########1***}}%
\skfi;
cmd,keyfb,yyy,
\SKV@ifx\x\y{%
\def\nosupergobble####1{\def####1########1{########1}}%
}{%
\def\supergobble####1{\def####1########1{}}%
}%
}
\setkeys[KV]{fam}{keyfa=value,keyfb=value}
\def\funcforboolb{\ifmp@boolba\def\do##1{%
\def##1####1####2{\expandafter\expandafter\expandafter\in@
\expandafter\expandafter\expandafter{\expandafter####1%
\expandafter}\expandafter{####2}}}\fi}
\define@keylist{3,boolba,true,\funcforboolb;3,boolbb,true,;}
\setkeys[KV]{fam}{boolba=true}
\NewToks[temptoks]{a,b}
\temptoksa{\ifmp@boolc\def\do#1{%
\def#1##1##2{\expandafter\expandafter\expandafter\in@
\expandafter\expandafter\expandafter{\expandafter##1%
\expandafter}\expandafter{##2}}}\fi}
\temptoksb{\iftogon{mp@togb}{\def\tempa#1{Use #1}}%
{\def\tempb#1{Don't use #1}}}
\define@keylist{3,boolc,true,\the\temptoksa;
4,togb,true,\the\temptoksb}
\setkeys[KV]{fam}{boolc=true,togb=true}
\do\x \def\y{x} \def\z{xxx} \x\y\z
\def\keylistvector{bool,boold,true,
\ifswitchon{mp@boold}{%
\def\hold####1{\def####1########1{***########1***}}%
}{%
\def\hold####1{\def####1########1{===########1===}}%
}%
}
\define@keylist*\keylistvector
\setkeys[KV]{fam}{boold=true}
\end{example}
\subsection{Input error}
\label{sec:input-error}
Native-boolean, toggle-boolean and choice keys issue error messages if the key value is not valid, \ie, not in the list of admissible values. The admissible values of native-boolean and toggle keys are \fx{true} and \fx{false}. The valid values of choice keys are set by the user via \acmd{\CKVS}. The default input error is defined by the macro \fx{\SKV@inputerr}. It takes two arguments (\ie, value and key) and can be customized by the user.
\subsection{Conditionals in key macros}
\label{sec:condit-in-keys}
\index{TeXBook=The \TeX Book}
The \tex conditional primitives \fx{\if}, \fx{\ifx}, \fx{\else} and \fx{\fi} cannot appear in the key macro when \acmd{\define@keylist} is being invoked. The reason can be traced to the discussion on page~211 of the \TeX Book and the loops used in the \pkg{skeyval} to define keys by means of \acmd{\define@keylist}. There are many possible approaches to resolving this problem, but only four appear to be attractive (see \crefrange{sec:condit-in-macros}{sec:using-toggles}).
\subsubsection[Using macros or token list registers]
{Burying conditionals in intermediate macros or token list registers}
\label{sec:condit-in-macros}
Key macros/functions involving conditional operations such as
\begin{example}
\ifmp@bool \do \else \donot \fi
\end{example}
can be submitted to \acmd{\define@keylist} via intermediate macros, as seen above (in \cref{sec:multkeys-examples}), but the approach isn't economical and thus not advisable. Nevertheless, we give more examples of deploying intermediate macros below. Let the key macro prefix be \fx{mp@}, the key prefix be \fx{KV}, and the key family be \fx{fam}.
Suppose we want to submit the following:
\begin{example}
\define@keylist{3,bool,true,\ifmp@bool \do \else \donot \fi}.
\end{example}
\acmd*{\define@keylist}
The presence of \fx{\if} and \fx{\fi} in the argument will trigger an error when \tex is scanning and skipping tokens, and, secondly, because of the loops and conditionals used by the \pkg{skeyval} in defining keys via \acmd{\define@keylist}. Neither \fx{\protect} nor \fx{\noexpand} is helpful here. One solution is to first define
\begin{example}
\def\funcforbool{\ifmp@bool \do \else \donot \fi}
\end{example}
and then do
\begin{example}
\define@keylist{3,bool,true,\funcforbool},
\end{example}
\acmd*{\define@keylist}
which will execute \fx{\funcforbool} when the key \fx{bool} is set. One significant drawback of this approach is that once the key \fx{bool} has been defined by the above statement, the function \fx{\funcforbool} may not be redefined and reused before the key \fx{bool} is set. This is wasteful and not advisable. This approach is included here only for demonstration purposes. The schemes in \crefrange{sec:pseudo-primitives}{sec:switches} are preferable.
As another example, we may do
\begin{example}
\def\funcforboola{\ifmp@boola\def\do##1{%
\def##1####1####2{\expandafter\expandafter\expandafter\in@
\expandafter\expandafter\expandafter{\expandafter####1%
\expandafter}\expandafter{####2}}}\fi}
\define@keylist{3,boola,true,\funcforboola}
\setkeys[KV]{fam}{boola=true}
\def\y{x} \def\z{xxx} \do\x \x\y\z
\end{example}
Token list registers can be used here economically instead of macros. Below we define one native-boolean key and one toggle-boolean key:
\begin{example}
\NewToks[temptoks]{a,b}
\temptoksa{\ifmp@boola\def\do#1{%
\def#1##1##2{\expandafter\expandafter\expandafter\in@
\expandafter\expandafter\expandafter{\expandafter##1%
\expandafter}\expandafter{##2}}}\fi}
\temptoksb{\iftogon{mp@toga}{\def\order#1{Use `#1' now!}}{}}
\define@keylist{3,boola,true,\the\temptoksa;
4,toga,true,\the\temptoksb}
\setkeys[KV]{fam}{boola=true,toga=true}
\end{example}
\acmd*{\define@keylist,\setkeys,\NewToks}
You can see the significant reduction in the number of parameter characters when using token list registers. The utility token list registers \fx{\temptoksa} and \fx{\temptoksb} can be reused to define many other keys as soon as the keys \fx{boola} and \fx{toga} have been set. However, as noted earlier, the approach of using intermediate macros and token list registers to parse arguments to \fx{\define@keylist} is not attractive because of the overheads in the number of macros and token list registers.
\subsubsection[Using pseudo-primitives]
{Using pseudo-primitives to submit the conditionals}
\label{sec:pseudo-primitives}
There are two downsides to the above approach of hiding conditionals in macros: the macros have to be defined and, although they can be redefined and reused (after the associated key has been set), they tend to defeat the initial aim of the package, which is to economize on tokens.
Suppose we want to define a native-boolean key \fx{mybool} with the following key macro:
\begin{example}
\ifmp@mybool
\def\hold##1{\def##1####1{***####1***}}%
\else
\def\hold##1{\def##1####1{===####1===}}%
\fi
\end{example}
where the key prefix \fx{KV}, key family \fx{fam}, and the macro prefix \fx{mp@} are assumed to have been defined previously. Then, instead of hiding the conditional in an intermediate macro, we may adopt the following:
\begin{example}
\define@keylist{3,mybool,true,
|makered(\skif{|mcolor(mp@mybool)})\def\hold##1{\def##1####1{***####1***}}%
|makered(\skelse)\def\hold##1{\def##1####1{===####1===}}|makered(\skfi)
}
\setkeys[KV]{fam}{mybool=true |makered(or) false}
\hold\x
\end{example}
\acmdm*{\skif,\skifx,\skelse,\skfi}
\acmd*{\skifcase,\skor,\define@keylist}
Here we have used the pseudo-primitives \fx{\skif{mp@mybool}}, \fx{\skifx}, \fx{\skelse} and \fx{\skfi} for the commands \fx{\ifmp@mybool}, \fx{\ifx}, \fx{\else} and \fx{\fi}, respectively, to hide the latter four from \TeX's scanning and skipping mechanism. It should be noted that \fx{\skif{mp@mybool}} requires that the argument \ang{mp@mybool} be enclosed in braces. Something like \fx{\skifmp@mybool} will be interpreted by \tex as an undefined control sequence when the key \fx{mybool} is being set. Defining the command \fx{\skif{mp@mybool}} to be \fx{\ifmp@mybool} before hand would have failed because \tex's scanner would then get the hint of the assignment.
\Note We haven't found any package that has defined \fx{\skif}, \fx{\skifx}, \fx{\skelse}, \fx{\skfi}, \fx{\skifcase} or \fx{\skor}. The \pkgm{xifthen}, for example, uses \fx{\OR}, not \fx{\skor}. If the situation changes in the future (\ie, if a package is observed to have defined any of these commands), they will be appropriately modified in the \pkg{skeyval}. Information and feedback from package users is solicited in this regard.
We have redefined the \fx{\setkeys} command of the \pkg{xkeyval} to recognize that \fx{\skif{boolean}}, \fx{\skifx}, \fx{\skelse}, \fx{\skfi}, \fx{\skifcase} and \fx{\skor} stand for \fx{\ifboolean}, \fx{\ifx}, \fx{\else}, \fx{\fi}, \fx{\ifcase} and \fx{\or}, respectively. The redefined \fx{\setkeys} command has the same syntaxes as as in \pkg{xkeyval}:
\begin{macro}
\setkeys[|vang(prefix)]{|vang(families)}[|vang(na)]{|vang(keys=values)}
\setkeys|redstar[|vang(prefix)]{|vang(families)}[|vang(na)]{|vang(keys=values)}
\setkeys|redplus[|vang(prefix)]{|vang(families)}[|vang(na)]{|vang(keys=values)}
\setkeys|redstar|redplus[|vang(prefix)]{|vang(families)}[|vang(na)]{|vang(keys=values)}.
\end{macro}
\acmdm*{\setkeys,\setkeys*,\setkeys*+}
No errors are produced if any of the sets \ang{prefix}, \ang{families}, \ang{na}, and \ang{keys=values} is empty. In fact, an instruction such as \fx{\setkeys[]{}[]{}} is completely benign, and so is \fx{\setkeys{}{}}.
\paragraph{Conditionals involving \textcolor{xmagenta1}{\@bs ifcase}:}
The case of conditionals involving \fx{\ifcase} can be handled in the same way as those involving \fx{\if}:
\begin{example}
\CKVS{focus}{center,left,right,justified}
\temptoksa{\ifcase\nr\relax
\def\mp@focus{\centering}\or\def\mp@focus{\flushright}
\or\def\mp@focus{\flushleft}\or\let\mp@focus\relax\fi}
\define@keylist{5,focus,center,\the\temptoksa}
\end{example}
\acmd*{\CKVS,\define@keylist}
This can be written more compactly as follows, which obviates the need for intermediate macros and list registers:
\begin{example}
\define@keylist{menu,focus,center,|makered(\skifcase)\nr\relax
\def\mp@focus{\centering}|makered(\skor)\def\mp@focus{\flushright}
|makered(\skor)\def\mp@focus{\flushleft}|makered(\skor)\let\mp@focus\relax|makered(\skfi)}
\end{example}
\acmdm*{\skifcase,\skor}
Here, the \pkg{skeyval} uses \fx{\skifcase}, \fx{\skor}, and \acmd{\skfi} for \fx{\ifcase}, \fx{\or} and \fx{\fi}, respectively; otherwise, \tex would be grumpy.
The key \fx{focus} can now be readily set: \fx{\setkeys[KV]{fam}{focus=left}}.
\subsubsection[Using switches]{Using switches to submit the conditionals}
\label{sec:switches}
The approaches of \cref{sec:pseudo-primitives} provide a familiar \tex-like syntax for submitting conditionals to \fx{\define@keylist}. There is yet another approach that we developed. It is related to the native \tex boolean conditional. By \emph{switches} we mean the usual \tex's \fx{\iftrue} and \fx{\iffalse} booleans, but expressed in different syntax and semantics.
New switches can be introduced by using the following commands:
\begin{macro}
\newswitch[|vang(optional prefix)]{|vang(boolean)}[|vang(optional state)]
\defswitch[|vang(optional prefix)]{|vang(boolean)}[|vang(optional state)]
\end{macro}
\acmdm*{\newswitch,\defswitch}
The command \fx{\newswitch} provides a new native-boolean register of the form \fx{\if}\unskip\ang{prefix}\unskip\ang{boolean} if the register didn't already exist; if the register already existed, an error is flagged. The command \fx{\defswitch}, on the other hand, doesn't flag any error even if the switch register \ang{boolean} already existed. Instead it makes an entry (warning or information) in the transcript log file if the package option \fx{verbose} is selected.
The optional \ang{state} can be either \fx{true} (or \fx{on}) or \fx{false} (or \fx{off}); the switch will be initialized to that state. With this definition, you can issue \fx{\if}\unskip\ang{switch}, \bs\ang{switch}\unskip\fx{true}, and \bs\ang{switch}\unskip\fx{false}. One advantage of \fx{\newswitch} is that a switch can start off as either \fx{true} (or \fx{on}) or \fx{false} (or \fx{off}), unlike the classical \tex's case in which all booleans start off as \fx{false}. Also, switches can be used where primitive \tex conditionals may prove impossible. For example, we know that you can't do \fx{\let\ifabc\iftrue} within the body of a conditional text without hiding the assignment from \tex's scanning mechanism.
\begin{example}
\newswitch{boola} |tto \newif\ifboola
\newswitch[bool]{b}[true] |tto \newif\ifboolb \boolbtrue
\newswitch[bool]{c}[on] |tto \newif\ifboolc \boolctrue
\newswitch[bool]{d}[off] |tto \newif\ifboold \booldfalse
\end{example}
You can define many switches in a row by the following commands:
\begin{macro}
\NewSwitches[|vang(optional prefix)]{|vang(switches)}[|vang(optional state)]
\DefSwitches[|vang(optional prefix)]{|vang(switches)}[|vang(optional state)]
\end{macro}
\acmdm*{\NewSwitches,\DefSwitches}
Each member of \ang{switches} is prefixed with \ang{prefix} upon definition. The optional \ang{state} can be either \fx{true} (or \fx{on}) or \fx{false} (or \fx{off}).
Here are some examples:
\begin{example}
\NewSwitches{x,y,z}[off]
|tto \newswitch{x}[false] \newswitch{y}[false]
\newswitch{z}[false]
\DefSwitches[skv@]{u,w}[true]
|tto \defswitch[skv@]{u}[true] \defswitch[skv@]{w}[true]
|tto \defswitch{skv@u}[true] \defswitch{skv@w}[true]
\end{example}
Switches may be set and tested using the following commands:
\begin{macro}
\setswitch{|vang(switch)}{|vang(value/state)}
\switchon{|vang(switch)} |tto \|vang(switch)true
\switchtrue{|vang(switch)} |tto \|vang(switch)true
\switchoff{|vang(switch)} |tto \|vang(switch)false
\switchfalse{|vang(switch)} |tto \|vang(switch)false
\ifswitchon{|vang(switch)}{|vang(true text)}{|vang(false text)}
\ifswitchtrue{|vang(switch)}{|vang(true text)}{|vang(false text)}
\ifswitchoff{|vang(switch)}{|vang(not true)}{|vang(not false)}
\ifswitchfalse{|vang(switch)}{|vang(not true)}{|vang(not false)}
\end{macro}
\acmdm*{\newswitch,\setswitch,\switchon,\switchoff,\ifswitchon,
\ifswitchoff,\switchtrue,\switchfalse,\ifswitchtrue,
\ifswitchfalse}
\begin{example}
\NewSwitches{w,x,y,z}
\setswitch{w}{true} |tto \setswitch{w}{on}
\setswitch{x}{on} |tto \setswitch{x}{true}
\setswitch{y}{false} |tto \setswitch{y}{off}
\setswitch{z}{off} |tto \setswitch{z}{false}
\ifswitchon{x}{\def\xx{On}}{\def\xx{Off}}
\ifswitchoff{y}{\def\yy{Off}}{\def\yy{On}}
\end{example}
Now how do we use switches in \fx{\define@keylist}? Suppose the key prefix is \fx{KV}, the key family is \fx{fam}, and the key macro is \fx{mp@}. Then the following works:
\begin{example}
\define@keylist{3,swa,true,
|makered(\ifswitchon){mp@swa}{\def\say{Swtich `a' is true}}
{\def\say{Swtich `a' is false}}}
\setkeys[KV]{fam}{swa=true |makered(or) false |makered(or) on |makered(or) off}
\end{example}
\acmd*{\define@keylist}
\Note Please note that ``switch keys'' are actually native-boolean keys (\fx{bool} or type~\fx{3} key). When setting native-boolean and toggle-boolean keys you can supply either \fx{true}, \fx{false}, \fx{on} or \fx{off} as values. We have modified the relevant internal macros of the \pkg{xkeyval} to make this possible for the native-boolean keys as well.
\subsubsection[Using toggles]{Using toggles to submit the conditionals}
\label{sec:using-toggles}
Toggle booleans, described in \cref{sec:toggles}, can also be used to circumvent the problem of matching \fx{\if} and \fx{\fi} in difficult circumstances, since toggles aren't \tex primitives, and, as noted in \cref{sec:toggles}, toggles are very economical. For example, the following works:
\begin{example}
\define@keylist{4,toga,true,
|makered(\iftogon){mp@toga}{\def\say{Toggle `a' is true}}%
{\def\say{Toggle `a' is false}}}
\setkeys[KV]{fam}{toga= true |makered(or) false}
\end{example}
\acmd*{\define@keylist,\iftogon}
where the key prefix, key family, and macro prefix are still assumed to be \fx{KV}, \fx{fam}, \fx{mp@}, respectively. Recall that toggle keys are type~4 keys.
\section{Key command and key environment}
\label{sec:keycommand}
The \fx{\define@keylist} macro of \cref{sec:def-multiple-keys}, together with the \fx{\newkeylist} macro of \cref{sec:avoiding-redef}, provides an attractive toolkit for developing a system for defining commands using keys, in the manner of the \pkgm{keycommand} but with a more compact user interface. See the \pkgm{skeycommand} for details.
\section{Checking and redefining keys}
\label{sec:check-redef-keys}
\subsection{Checking the status of a key}
\label{sec:status-keys}
Three mechanisms have been introduced in the \pkg{skeyval} to ascertain the statuses of keys. These are as follows.
\begin{macro}
\ifkeydefined[|vang(prefixes)]{|vang(families)}{|vang(key)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\ifkeydefined}
This executes \ang{true} if \ang{key} is defined, reserved, or suspended with a prefix in \ang{prefixes} and family in \ang{families}; it returns \ang{false} otherwise. This is similar to
the \pkg{xkeyval}'s \acmdm{\key@ifundefined}, but, apart from reversing the logic of the test, \fx{\ifkeydefined} loops over prefixes (in addition to looping over families) to locate the key, and also considers reserved and suspended keys as defined. The lists \ang{prefixes} and \ang{families} may contain nil, one or more elements.
\begin{macro}
\ifkeyreserved[|vang(prefixes)]{|vang(families)}{|vang(key)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\ifkeyreserved}
This returns \ang{true} if \ang{key} is reserved with a prefix in \ang{prefixes} and family in \ang{families}; it returns \ang{false} otherwise. Reserved keys are introduced in \cref{sec:reserve-keys}.
\begin{macro}
\ifkeysuspended[|vang(prefixes)]{|vang(families)}{|vang(key)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\ifkeysuspended}
This executes \ang{true} if \ang{key} is suspended with a prefix in \ang{prefixes} and family in \ang{families}; it executes \ang{false} otherwise. Suspended keys are introduced in \cref{sec:suspend-keys}.
\subsection{Unintentional redefinition of keys}
\label{sec:redef-keys}
The \pkg{xkeyval}, by default, permits the automatic redefining of keys of the same \ang{prefix} and \ang{family}: at the point of defining a new key, the package doesn't, by default, check whether or not the key had been previously defined with the same \ang{prefix} and \ang{family}. In some circumstances this can be undesirable, and even dangerous, especially if the same key (of the same \ang{prefix} and \ang{family}) is mistakenly redefined with different macros/functions in the same package or across packages. One way to solve this problem is to use \pkg{xkeyval}'s \fx{\key@ifundefined} command (or the \pkg{skeyval}'s \fx{\ifkeydefined}) to confirm the status of a key prior to its definition. However, using these commands before defining every key can be laborious.
Consider the following two scenarios:
\begin{example}
\define@key[KV]{fam}{keya}[$\star$]{\def\tempa##1{##1}}
\define@boolkey[KV]{fam}{keya}[true]{%
\ifKV@fam@keya\def\tempb{#1}\fi}
\setkeys[KV]{fam}{keya=$\textbullet$}
\end{example}
\acmd*{\setkeys}
Obviously the two definitions of \ang{keya} are valid and will be implemented but the \acmd{\setkeys} command here will issue an unintelligible error message, like \LaTeX's ``You are in trouble here \textellipsis''. The key \ang{keya} has been defined twice and \acmd{\setkeys} has sought to use its latest definition to set its value, which is incorrect. As mentioned in \cref{sec:toggle-keys}, the \acmd{\setkeys} command (and friends) of the \pkg{xkeyval} doesn't know if a key has been redefined in the same \ang{family} and with the same \ang{prefix}. At the high level, it doesn't consider the key type: it uses the latest definition of the key to set its value using the key's macro. This is particularly worrisome in the case of toggle keys, since although toggle keys have their own separate namespace, they can easily be confusing (at least to \acmd{\setkeys}) if they have names identical to other keys within the same family and with the same prefix. In fact, the problem can manifest itself in more ways than the scenario just depicted.
If the package option \acmd{verbose} is enabled, the \pkg{skeyval} provides a warning system (by making an entry in the transcript log file) if an existing key is being redefined (within the same family and with the same prefix) by any of the following commands:
\begin{macro}
\define@key, \define@cmdkey, \define@cmdkeys,
\define@choicekey, \define@boolkey, \define@boolkeys,
\define@biboolkeys, \define@uniboolkeys, \define@biuniboolkeys,
\define@togkey, \define@togkeys, \define@bitogkeys,
\define@unitogkeys, \define@biunitogkeys
\end{macro}
The machinery of \cref{sec:avoiding-redef} can be used to avoid inadvertently redefining existing keys.
\subsubsection{Avoiding multiple definitions of same key}
\label{sec:avoiding-redef}
For the above reasons, the \pkg{skeyval} introduces the following commands, which have the same syntaxes as their counterparts from the \asty{xkeyval} and \asty{skeyval} packages but which bar the user from repeated definition of keys with identical names within the same \ang{family} and with the same \ang{prefix}:
\acmd*{\define@boolkey}
\acmdm*{\newordkey,\newcmdkey,\newboolkey,\newboolkeys,\newtogkey,\newtogkeys,
\newchoicekey,\newbiboolkeys,\newuniboolkeys,\newbiuniboolkeys,\newbitogkeys,
\newunitogkeys,\newbiunitogkeys,\define@key,\define@cmdkey,
\define@cmdkeys,\define@biboolkeys,\define@uniboolkeys,
\define@biuniboolkeys,\define@bitogkeys,\define@unitogkeys,\define@biunitogkeys}
\begin{macro}
|comm(The following defines ``ordinary'' keys |:the counterpart)
|comm(of \define@key from the xkeyval package|!:)
\newordkey[|vang(prefix)]{|vang(family)}{|vang(key)}[|vang(default)]{|vang(funtion)}
|comm(Counterpart of \define@cmdkey:)
\newcmdkey[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(key)}[|vang(default)]%
{|vang(funtion)}
|comm(Counterpart of \define@cmdkeys:)
\newcmdkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(keys)}[|vang(default)]
|comm(Counterparts of \define@boolkey:)
\newboolkey[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(key)}[|vang(default)]%
{|vang(funtion)}
\newboolkey|redplus[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(key)}[|vang(default)]%
{|vang(funtion1)}{|vang(funtion2)}
|comm(Counterpart of \define@boolkeys:)
\newboolkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(keys)}[|vang(default)]
|comm(Counterpart of \define@biboolkeys:)
\newbiboolkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]
{|vang(primary boolean)}[|vang(default value for primary boolean)]
{|vang(secondary boolean)}{|vang(func for primary boolean)}
{|vang(func for secondary boolean)}
|comm(Counterpart of \define@uniboolkeys:)
\newuniboolkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]
{|vang(primary boolean)}[|vang(default value for primary boolean)]
{|vang(secondary boolean)}{|vang(func for primary boolean)}
{|vang(func for secondary boolean)}
|comm(Counterpart of \define@biuniboolkeys:)
\newbiuniboolkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]
{|vang(primary boolean)}[|vang(default value for primary boolean)]
{|vang(secondary boolean)}{|vang(func for primary boolean)}
{|vang(func for secondary boolean)}
|comm(Counterparts of \define@togkey:)
\newtogkey[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(key)}[|vang(default)]%
{|vang(funtion)}
\newtogkey|redplus[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(key)}[|vang(default)]%
{|vang(funtion1)}{|vang(funtion2)}
|comm(Counterpart of \define@togkeys:)
\newtogkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(keys)}[|vang(default)]
|comm(Counterpart of \define@bitogkeys:)
\newbitogkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]
{|vang(primary toggle)}[|vang(default value for primary toggle)]
{|vang(secondary toggle)}{|vang(func for primary toggle)}
{|vang(func for secondary toggle)}
|comm(Counterpart of \define@unitogkeys:)
\newunitogkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]
{|vang(primary toggle)}[|vang(default value for primary toggle)]
{|vang(secondary toggle)}{|vang(func for primary toggle)}
{|vang(func for secondary toggle)}
|comm(Counterpart of \define@biunitogkeys:)
\newbiunitogkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]
{|vang(primary toggle)}[|vang(default value for primary toggle)]
{|vang(secondary toggle)}{|vang(func for primary toggle)}
{|vang(func for secondary toggle)}
|comm(Counterparts of \define@choicekey:)
\newchoicekey[|vang(prefix)]{|vang(family)}{|vang(key)}[|vang(bin)]{|vang(alt)}%
[|vang(default)]{|vang(funtion)}
\newchoicekey|redstar[|vang(prefix)]{|vang(family)}{|vang(key)}[|vang(bin)]{|vang(alt)}%
[|vang(default)]{|vang(funtion)}
\newchoicekey|redplus[|vang(prefix)]{|vang(family)}{|vang(key)}[|vang(bin)]{|vang(alt)}%
[|vang(default)]{|vang(funtion1)}{|vang(funtion2)}
\newchoicekey|redstar|redplus[|vang(prefix)]{|vang(family)}{|vang(key)}[|vang(bin)]{|vang(alt)}%
[|vang(default)]{|vang(funtion1)}{|vang(funtion2)}
|comm(Counterpart of \define@keylist:)
\newkeylist{|vang(key type/id), |vang(key), |vang(key default value),
|vang(key macro/function); |vang(another set of key specifiers); etc}.
\end{macro}
\acmdm*{\define@choicekey,\newchoicekey*,\newchoicekey*+,\newkeylist,\newkeylist*}
The following aliases are defined in the \pkg{skeyval}:
\begin{macro}
\define@menukey|redstar|redplus |tto \define@choicekey|redstar|redplus
\newmenukey|redstar|redplus |tto \newchoicekey|redstar|redplus
\end{macro}
\acmdm*{\define@menukey, \define@menukey*, \newmenukey, \newmenukey*}
We could simply have redefined/modified the legacy key definition commands in the \pkg{xkeyval} to make it impossible to define keys of the same name in the same family and with the same prefix, but this approach would be unsafe since there are many packages using the \pkg{xkeyval} and those packages may well have redefined identical keys. Moreover, the legacy key definition commands from the \pkg{xkeyval} may be needed to redefine a disabled key (see \cref{sec:disable-reserv-keys}).
All the commands of the type \textnewkey are robust and may be used in expansion contexts without fear of premature expansion, although expandable tokens in the definition may need to be protected. Commands of the type \textdefinekey are originally, in the \pkg{xkeyval}, non-robust and remain so in the \pkg{skeyval}.
With the above macros, the following will flag an understandable error message, namely that the key \ang{keya} is about being redefined in the same family \ang{fam} and with the same prefix \ang{KV}:
\begin{example}
\newordkey[KV]{fam}{keya}[$\star$]{\def\tempa##1{##1}}
\newboolkey[KV]{fam}{keya}[true]{%
\ifKV@fam@keya\def\tempb{#1}\fi}
\end{example}
\section[Disabling, reserving, suspending keys, etc.]%
{Disabling, localizing, reserving, suspending, restoring, and removing keys}
\label{sec:disable-reserv-keys}
Besides macros for defining keys, the \pkg{skeyval} also introduces mechanisms for disabling, localizing, reserving, suspending, restoring, and completely removing existing keys.
\subsection{Disabling keys}
\label{sec:disable-keys}
The \pkg{skeyval} has modified the definition of \fx{\disable@keys} from the \pkg{xkeyval} to allow for looping over key prefixes and key families and for bespoke warnings and error messages, without engendering any potential conflict with the legacy \fx{\disable@keys}. The new command is still called \fx{\disable@keys} and has the same syntax as the native \fx{\disable@keys} of the \pkg{xkeyval}, except that the new command accepts key prefixes (instead of just one prefix) and key families (instead of just one family):
\begin{macro}
\disable@keys[|vang(prefixes)]{|vang(families)}{|vang(keys)}.
\end{macro}
\acmdm*{\disable@keys}
Here \ang{prefixes}, \ang{families}, \ang{keys} are lists of comma-separated entries referring to the keys to be disabled. Each of the lists \ang{prefixes}, \ang{families}, \ang{keys} may contain nil, one or more elements. If any of the members in \ang{keys} can't be located in \ang{families} and with prefix in \ang{prefixes}, an informational (not error) message is logged in respect of this member, but only if the package option \fx{verbose} is selected.
The legacy version of \fx{\disable@keys} (\ie, that of the \pkg{xkeyval}) is still available via the starred variant:
\begin{macro}
\disable@keys|redstar[|vang(prefix)]{|vang(family)}{|vang(keys)}
\end{macro}
\acmdm*{\disable@keys*}
Note that this doesn't accept key prefixes and families, but only one key prefix and only one key family: the \fx{\disable@keys} command from the \pkg{xkeyval} can only be used to disable keys with the same \ang{prefix} and from the same \ang{family}, but not across prefixes and families.
Any attempt to subsequently set or use a disabled key will prompt the following error message. (The \pkg{xkeyval} issues a warning in this case.) The error message can be modified by the user, but the names of the controls \fx{\SKV@disabledkey@err} and \acmd{\SKV@disabledkey} should be retained.
\begin{macro}
\def\SKV@disabledkey@err{%
\PackageError{skeyval}{%
Key |vang(key) with prefix |vang(prefix) in family |vang(family)
was disabled on input line |vang(lineno)
}{%
You can't set or reset |vang(key) at this
late stage. Perhaps you're required to set it
earlier, within a package or in the document's preamble.
}%
}
\end{macro}
\acmdm*{\SKV@disabledkey@err}
If the user attempts to disable an undefined key, the \pkg{xkeyval} issues a fatal error; the \pkg{skeyval}, on the other hand, issues a warning in the transcript log file (if the package option \acmd{verbose} is selected), since the situation isn't fatal to the outcome of the \latex pass or the document.
Disabled keys can be redefined with commands in the \textdefinekey category but not with commands in the \textnewkey category, since a disabled key remains defined: only its macro has been replaced by an error message signifying the disabling of the key.
\textbf{Note:} Reserved and suspended keys can't be disabled, until they are unreserved or restored (see \crefrange{sec:reserve-keys}{sec:suspend-keys}).
\subsection{Localizing keys}
\label{sec:local-keys}
By localizing a key we mean disabling a key at the end of the current class or package file. This is basically the command \acmd{\disable@keys} executed on the hook \acmd{\SKV@BeforeClassEnd} or \acmd{\SKV@BeforePackageEnd}, depending on \acmd{\@currext}. The hooks \acmd{\SKV@BeforeClassEnd} and \acmd{\SKV@BeforePackageEnd} are described in \cref{sec:misce-commands} (\macrangeref{befpkgend}{befclsend}).
The syntax for localizing keys is exactly like that for disabling keys:
\begin{macro}
\localize@keys[|vang(prefixes)]{|vang(families)}{|vang(keys)}.
\end{macro}
\acmdm*{\localize@keys}
If any of the members of the set \ang{keys} is not found in any of the members of \ang{families} and with a prefix from \ang{prefixes}, an informational message is written into the log file (if the package option \fx{verbose} is selected), but no errors are flagged.
The starred variant of \fx{\localize@keys} disables the keys listed in \ang{keys}, not at the end of the package or class file, but right before the start of document (\ie, at the boundary between the document preamble and \acmd{\AtBeginDocument}):
\begin{macro}
\localize@keys|redstar[|vang(prefixes)]{|vang(families)}{|vang(keys)}.
\end{macro}
\acmdm*{\localize@keys*}
The hook used here is \acmd{\SKV@BeforeDocumentStart}, described in \cref{sec:misce-commands}, \macref{beforedocstart}.
A key can be localized as soon as it is defined. In fact, a key can be localized even before it is defined: the actual disablement of the key will take place at the execution of the contents of \acmd{\SKV@BeforeClassEnd} or \acmd{\SKV@BeforePackageEnd} or \acmd{\SKV@BeforeDocumentStart}.
Localized keys can be redefined with commands in the \textdefinekey category, but not with commands in the \textnewkey category.
\subsection{Reserving and unreserving keys}
\label{sec:reserve-keys}
The \pkg{xkeyval} bars its users from defining new keys with \fx{XKV} as a prefix. The \pkg{skeyval} generalizes this concept via the following three developer macros:
\begin{macro}
\ReserveKeyPrefixNames{|vang(list)}
\ReserveKeyPrefixNames|redstar{|vang(list)}
\end{macro}
\acmdm*{\ReserveKeyPrefixNames,\ReserveKeyPrefixNames*}
This allows the package developer to bar the future use of names appearing in \ang{list} as key prefixes when defining, disabling, reserving and suspending keys; but not when setting keys. The \ang{list}, whose members are comma-separated, can be populated by the package developer as required. The starred variant takes effect at the end of current package; the unstarred one assumes immediate effect. If the developer wants to use any member of \ang{list} in his own package, it may be necessary for him to use the starred version.
\begin{macro}
\ReserveMacroPrefixNames{|vang(list)}
\ReserveMacroPrefixNames|redstar{|vang(list)}
\end{macro}
\acmdm*{\ReserveMacroPrefixNames,\ReserveMacroPrefixNames*}
This has a similar functionality to \fx{\ReserveKeyPrefixNames}, but applies to macro prefixes instead of key prefixes. The starred variant takes effect at the end of current package, while the unstarred one assumes immediate effect.
\begin{macro}
\ReserveFamilyNames{|vang(list)}
\ReserveFamilyNames|redstar{|vang(list)}
\end{macro}
\acmdm*{\ReserveFamilyNames,\ReserveFamilyNames*}
This reserves family names \ang{list} and prevents further use of members of \ang{list}. The starred variant takes effect at the end of current package, while the unstarred one assumes immediate effect.
\textbf{Note:} The lists in these macros are scanned only when defining, disabling, reserving or suspending keys, and not when setting existing keys. If the lists were also to be scanned when keys are being set, then a situation could arise in which existing keys (including those defined by prior packages) couldn't be set.
These macros could be used, for instances, to secure against future use the key prefixes, macro prefixes, and key families that have used in a new style or class file. For example, we have used these facilities to bar users of the \pkg{skeyval} from using the key prefix \fx{SKV}, the family name \fx{skeyval}, and the macro prefix \fx{SKV@} to define new keys in their packages.
In addition to the above reservation commands, the \pkg{skeyval} also introduces the following command:
\begin{macro}
\reserve@keys[|vang(prefixes)]{|vang(families)}{|vang(keys)},
\end{macro}
\acmdm*{\reserve@keys}
where the lists \ang{prefixes}, \ang{families}, \ang{keys} can contain nil, one or more elements. Defined, reserved and suspended keys can't be reserved.
Reserved keys have to be unreserved with the following command before they can be defined and used:
\begin{macro}
\unreserve@keys[|vang(prefixes)]{|vang(families)}{|vang(keys)},
\end{macro}
\acmdm*{\unreserve@keys}
where, again, the lists \ang{prefixes}, \ang{families}, \ang{keys} can contain nil, one or more elements. If a key was not previously reserved, this command will simply issue an informational message in the log file (if the package option \fx{verbose} is selected) and ignore that key. Defined keys and suspended keys can also be unreserved, which is equivalent to removing the keys (see \cref{sec:remove-keys}).
\subsection{Suspending and restoring keys}
\label{sec:suspend-keys}
For some keys, it might be preferable to temporarily suspend them from a family (rather than disable or remove them) and restore them later. In this way, a key's state and macro can be frozen while the key remains defined.
The syntax for suspending keys is
\begin{macro}
\suspend@keys[|vang(prefixes)]{|vang(families)}{|vang(keys)},
\end{macro}
\acmdm*{\suspend@keys}
where the lists \ang{prefixes}, \ang{families}, \ang{keys} can contain nil, one or more elements.
A key of particular prefix not previously defined in a family can't be suspended from that family. Similarly, a key previously suspended from a family can't be suspended again (for the second time) from the same family without being first restored in that family.
Suspended keys can be restored to their frozen states (\name{ex ante} suspension) by the following command:
\begin{macro}
\restore@keys[|vang(prefixes)]{|vang(families)}{|vang(keys)}.
\end{macro}
\acmdm*{\restore@keys}
Only keys (with a given prefix) previously suspended from a family can be restored in that family: ``unsuspended'' keys can't be restored.
\subsection{Removing keys}
\label{sec:remove-keys}
The \pkg{skeyval} provides for removing keys completely, such that any attempt to set or use a removed key will prompt the error message that the key is undefined in the given family and with the given prefix. The command \acmd{\key@ifundefined} from the \pkg{xkeyval} and the macro \acmd{\ifkeydefined} from the \pkg{skeyval} will both identify a removed key as undefined. The syntax for removing keys is:
\begin{macro}
\remove@keys[|vang(prefixes)]{|vang(families)}{|vang(keys)}
\end{macro}
\acmdm*{\remove@keys}
Removed keys can't be restored but can be redefined with the commands in both the \textnewkey and \textdefinekey categories.
\section{User-value keys}
\label{sec:uservaluekeys}
We define these keys as those for which the user must supply values at key setting time whether or not the keys have default values. All the commands for defining new keys have a facility for providing the default value of a key, which would be used by the \acmd{\setkeys} macro if the user didn't supply a value for the key. If no default value has been specified for a key at definition time and no value is provided at key setting time, the \pkg{xkeyval} will issue a fatal error. This scenario is preserved by the \pkg{skeyval}. In addition, the \pkg{skeyval} introduces a facility for requiring a user to supply a value for a key whether or not that key had a default value at definition time. Why is this necessary or useful? You may specify default values for keys in a package or class file to aid future revisions of the package, or for other purposes, but such values may not be suitable for all users---or indeed for any user. Examples of this type of situation abound: the signatory to a letter, the module code or title in a faculty programme, \etc.
The following command can be used to require a user to supply a value for a key at key setting time, whether or not that key has a default value:
\begin{macro}
\uservaluekeys[|vang(prefix)]{|vang(family)}{|vang(keys)}
\end{macro}
\acmdm*{\uservaluekeys}
where \ang{keys} is the list of keys with \ang{prefix} and in \ang{family} for which the user must supply values at key setting time. It is obviously not logical to loop over key prefixes or families in this case. What the command \fx{\uservaluekeys} does is to populate the container \fnl{SKV}{prefix}{family}{uservalue} which is scanned for user-value key names at key setting time.
The \fx{\uservaluekeys} macro works incrementally, \ie, new inputs are added to an existing list for the family in question only if they haven't previously been included.
\begin{example}
\newcmdkey[KV]{fam}[mp@]{keya}[12pt]{\def\x{#1}}
\newboolkey[KV]{fam}[mp@]{boola}[true]%
{\ifmp@boola\def\x{#1}\fi}
\uservaluekeys[KV]{fam}{keya,boola}
\setkeys[KV]{fam}{keya,boola=true}
|tto |makered(Error: no value supplied for `keya')
\end{example}
\acmd*{\newcmdkey,\newboolkey,\setkeys}
%\acmd*{\uservaluekeys}
\subsection{Using pointers to dynamically indicate user-value keys}
\label{sec:uservalue-pointers}
Instead of using the macro \fx{\uservaluekeys} to accumulate user-value keys, there is another way to dynamically specify these keys at key definition time: by using pointers. At key definition time, the pointers \acmdm{\uservalue} and \acmdm{\guservalue} can be associated with a user-value key. In the following statements, the pointer \fx{\uservalue} specifies that the user of the affected key must supply a value at the time of using/setting the key. The pointer \fx{\uservalue} has local effect, \ie, its impact can't escape local groups; on the other hand, \fx{\guservalue} has global effect, \ie, using it within or out of a local group means that the user of the affected key must specify a value for the key at key setting time. \fx{\guservalue} ensures that the internal container \fnl{SKV}{prefix}{family}{uservalue} is defined globally so that the settings can escape local groups.
\begin{example}
\newordkey[KV]{fam}{|makered(\uservalue{|mcolor(keya)})}[12pt]{\def\x{#1}}
\define@togkey|redplus[KV]{fam}[mp@]{|makered(\guservalue{|mcolor(toga)})}[true]%
{%
\iftogon{mp@toga}{\def\x{#1}}{}%
}{%
\@latex@error{Value `#1' not valid}\@ehc
}
\end{example}
\acmd*{\newordkey,\define@togkey,\iftogon}
As these examples show, the newly introduced pointers (namely, \fx{\uservalue} and \fx{\guservalue}) can be used to dynamically build a list of user-value keys. See \cref{sec:pointer-mech} for more comments on pointer systems.
\section{Extensions to the pointer system of the \texttt{xkeyval} package}
\label{sec:pointer-mech}
The \pkg{xkeyval} introduced a key pointer system. This basically involves the pointers
\acmdm{\savevalue}, \acmdm{\gsavevalue}, and \acmdm{\usevalue}. However, by the mechanism of that package, these pointers could be used only within the \acmd{\setkeys} command or context. In the key definition commands, the \fx{\usevalue} pointer could also be used in default values of keys, as in
\begin{example}
\define@key{fam}{keya}{\def\keya{#1}}
\define@key{fam}{keyb}[|makered(\usevalue{|mcolor(keya)})]{\def\keyb{#1}}
\define@key{fam}{keyc}[|makered(\usevalue{|mcolor(keyb)})]{\def\keyc{#1}}
\setkeys{fam}{|makered(\savevalue{|mcolor(keya)})=test}
\setkeys{fam}{|makered(\savevalue{|mcolor(keyb)})}|comm(Yes, this also works.)
\setkeys{fam}{keyc}
\end{example}
\acmd*{\define@key,\setkeys}
The default values of keys are called (invoked) within \acmd{\setkeys}. The pointers can't, however, be used as part of key names outside default values. The following, \eg, fails:
\begin{example}
\define@key{fam}{|makered(\savevalue{|mcolor(keya)})}{\def\keya{#1}}
\end{example}
The \pkg{skeyval} has extended the pointer system to be issuable as part of key names within key definition commands in the two scenarios illustrated above (within and outside default values). Moreover, the pointers \fx{\savevalue} and \fx{\gsavevalue} can be deployed concurrently with \acmd{\uservalue} and \acmd{\guservalue} of \cref{sec:uservalue-pointers} within the same key definition command. In combining the two pointer subclasses (\ie, \fx{\savevalue} subclass and \acmd{\uservalue} subclass) in the same key definition command, it doesn't matter which subclass comes first, as the following examples show.
The pointers \fx{\savevalue} and \fx{\gsavevalue} make entries into the container \fnl{XKV}{prefix}{family}{save} that is used by the \pkg{xkeyval} to hold keys whose values should be saved at key setting time. The difference between \fx{\savevalue} and \fx{\gsavevalue} is that the former has a local effect while the latter can escape local groups (similar to the group properties of \acmd{\uservalue} and \acmd{\guservalue} of \cref{sec:uservalue-pointers}). The pointers \fx{\savevalue} and \fx{\gsavevalue} of the \pkg{skeyval} are entirely compatible with those of the \pkg{xkeyval}. One additional new feature is that the pointer \fx{\gsavevalue} prompts the global revision of the container \fnl{XKV}{prefix}{family}{save} and also makes global pointer entries\footnote{By \emph{global pointer entry} we mean an entry like \fx{\global{keya}} for \fx{keya} into the container \fnl{XKV}{prefix}{family}{save}.} of the affected keys into the container. The effects of the new feature are illustrated by the following examples. Depending on application, this new feature may be more attractive than the traditional one implemented via \acmd{\setkeys}. One obvious advantage of the new system emanates from the fact that some keys do not have default values.
\subsection{Examples}
\subsubsection{Legacy \texttt{xkeyval} pointer features}
The following provide examples of legacy pointer features of the \pkg{xkeyval} (key pointers at key setting time):
\acmdm*{\gsavekeys,\savekeys,\global\{key\}}
\begin{example}
\savekeys[KV]{fam}{keya,|makered(\global{|mcolor(keyb)})}
\gsavekeys[KV]{fam}{keyc,keyd,|makered(\global{|mcolor(keye)})}|label(mac:gsavekeys)
\setkeys[KV]{fam}{|makered(\gsavevalue{|mcolor(keyd)})=yyy,|label(mac:setkeyd)
keye=|makered(\usevalue{|mcolor(keyd)})}
\end{example}
If we had included \fx{\global{keyb}} in \fx{\gsavekeys} of \macref{mac:gsavekeys}, its entry in \fx{\savekeys} would have been overwritten, since keys in the container \acmdm{\XKV@KV@fam@save} normally get overwritten if they have the same name. The macro \fx{\gsavekeys} ensures the global definition of \fx{\XKV@KV@fam@save} when the keys \fx{keyc}, \fx{keyd} and \fx{keye} are being included, while \fx{\global{keyb}} ensures that, when \fx{keyb} is used in a \acmd{\setkeys} command, its value will be saved globally to \fx{\KV@fam@keyb@value}. When the keys \fx{keyc} and \fx{keyd} are set, their values will be saved locally, even though the container \fx{\XKV@KV@fam@save} was defined globally when the keys \fx{keyc} and \fx{keyd} were inserted. However, when keys \fx{keyb} and \fx{keye} are set, their values will be saved globally (even though \fx{keyb} appears in \fx{\savekeys} and not in \fx{\gsavekeys}).
The pointer \fx{\gsavevalue{keyd}} of \macref{mac:setkeyd} will ensure that the value of \fx{keyd} is saved globally to \fx{\KV@fam@keyd@value} at \acmd{\setkeys}.
\subsubsection{Extensions by \texttt{skeyval} package}
The following provide examples of new pointer features enabled by the \pkg{skeyval} (key pointers at key definition time):
\begin{example}
\define@key[KV]{fam}{|makered(\savevalue{|mcolor(keya)})}[xxx]{\def\x{*#1*}}
\newordkey[KV]{fam}{|makered(\gsavevalue{|mcolor(keyb)})}[zzz]{\def\x{=#1=}}|label(mac:pointers:a)
\newtogkey|redplus[KV]{fam}[mp@]{|makered(\savevalue\uservalue{|mcolor(toga)})}[true]%
{
\iftogon{mp@toga}{\def\x{#1}}{}%
}{%
\@latex@error{Value `#1' not valid}\@ehc
}
\define@cmdkey[KV]{fam}[mp@]{|makered(\uservalue\savevalue{|mcolor(keyc)})}%
[www]{\def\x{#1}}
\newboolkey|redplus[KV]{fam}[mp@]{|makered(\gsavevalue\uservalue{|mcolor(boola)})}%
[true]{%
\ifmp@boola\def\x{#1}\fi
}{%
\@latex@error{Value `#1' not valid}\@ehc
}
\define@cmdkey[KV]{fam}[mp@]{|makered(\guservalue\savevalue{|mcolor(keyd)})}%
[www]{\def\x{#1}}
\newchoicekey|redstar|redplus[KV]{fam}{|makered(\guservalue\gsavevalue{|mcolor(align)})}%
[\val\nr]{center,right,left}[center]%
{%
\ifcase\nr\relax
\def\@align{\centering}%
\or
\def\@align{\flushright}%
\or
\def\@align{\flushleft}%
\fi
}{%
\@latex@error{Inadmissible value `#1' for align}\@ehc
}
\setkeys[KV]{fam}{keya=Hello World,keyb=|makered(\usevalue{|mcolor(keya)})}
\end{example}
\acmd*{\define@key,\define@cmdkey,\newchoicekey,\newordkey,
\newtogkey,\setkeys,\iftogon}
With the new mechanism of the \pkg{skeyval}, the \acmd{\gsavevalue} pointer in the command on \macref{mac:pointers:a} will ensure that \fx{\global{keyb}} (not \fx{keyb}) is inserted in the container \fx{\XKV@KV@fam@save} and that this container is updated globally after \fx{\global{keyb}} has been inserted. At \acmd{\setkeys}, in view of the entry \fx{\global{keyb}}, the value of \fx{keyb} will be saved globally. The same applies to keys \fx{boola} and \fx{align}. This thus has a double effect. Keys \fx{keyc} and \fx{keyd} will be saved locally.
\section{Setting keys: list normalization}
\label{sec:list-normal}
We have redefined the \acmd{\setkeys} command of the \pkg{xkeyval} in two respects: firstly to accommodate the use of the \acmd{\skif}, \acmd{\skifx}, \acmd{\skelse}, and \acmd{\skfi} macros of \cref{sec:pseudo-primitives}, and secondly to automatically convert double (or even multiple) commas and equality signs inadvertently submitted by the user into single comma and single equality sign. The following exaggerated example depicts the difficulties that might arise and which we wish to address:
\begin{example}
\define@key[KV]{fam}{width}[1cm]{}
\define@key[KV]{fam}{color}[black]{}
\setkeys[KV]{fam}{width= =2cm, ,,color, == = =,green}
\end{example}
\acmd*{\define@key,\setkeys}
Here, the legacy \acmd{\setkeys} will give the value nil to the key \fx{width}, and the default value of the key \fx{color}, if it was specified at key definition time, will be given to the key \fx{color}. Some of the mistakes (especially spurious values without keys) can disrupt a compilation run, while some (multiple commas and equality signs) will not be fatal to compilation but may lead to bizarre results of subsequent calculations. Mistakes of this kind can, surprisingly, be difficult to trace. The extra spaces and multiple commas aren't as serious as the multiple equality signs and values without keys, but we have taken care of all peculiar situations in the new \acmd{\setkeys}. Multiple commas, equality signs, and spaces are now detected and reduced appropriately: that is what we mean by key-value \emph{list normalization}. We have adopted the premise that ``\fx{,=}'' (comma followed by equal) and ``\fx{=,}'' (equal followed by comma) are both most likely to mean ``\fx{=}'' (equal). In the unlikely event that this premise fails, then the user may get tricky errors if he makes this type of mistake.
If, for any reason, the user needs to pass keys with ``\fx{,=}'' and/or ``\fx{=,}'', then he may separate the comma from the equality sign with \fx{{}}, \eg, as in
\begin{example}
\setkeys[KV]{fam}{width=2cm,head={},tail=not measured},
\end{example}
\acmd*{\setkeys}
which shows that the value of the key \fx{head} is \fx{\empty}, a valid and better assignment.
\section{Miscellaneous macros}
\label{sec:misce-commands}
This package is predominantly about \latex keys and their efficient creation and management, but it also contains many commands for general \tex programming, such that a package author may not need to redefine most of them or load some other packages to access those commands. Some of the available commands are described in this section. The index provides a comprehensive quick resource locator for the commands.
\macrosection{Defining new commands}
The following are provided in the \pkg{skeyval} but you're advised to use the \fx{\TestProvidedCommand} macro (described below) to test that you are really using the \fx{\newdef} of the \pkg{skeyval}:
\begin{macro}
\SKV@newdef|redstar|vang(cs)|vang(parameters){|vang(replacement text)}
\newdef|redstar|vang(cs)|vang(parameters){|vang(replacement text)}
\end{macro}
\acmdm*{\SKV@newdef,\SKV@newdef*,\newdef,\newdef*}
These commands adopt \tex's syntax and accept parameter delimiters. They are both robust. The unstarred variant produces long macros. The command \fx{\newdef} is defined in the \pkg{skeyval} only if it hasn't been defined by a previously loaded package; the command \fx{\SKV@newdef}, on the other hand, is always available. If \ang{cs} was previously defined, both \fx{\SKV@newdef} and \fx{\newdef} will issue an error.
\macrosubsection{Defining robust commands}
\begin{macro}
\SKV@robustdef|redstar|vang(cs)|vang(parameters){|vang(replacement text)}
\robustdef|redstar|vang(cs)|vang(parameters){|vang(replacement text)}
\end{macro}
\acmdm*{\SKV@robustdef,\SKV@robustdef*,\robustdef,\robustdef*}
These use \etex's \acmd{\protected} prefix to provide something resembling \latex's \acmdm{\DeclareRobustCommand} whilst conforming to \tex's \fx{\def} interface. The unstarred variants produce long macros. These commands accept parameter delimiters and are all robust. The command \fx{\robustdef} is defined in the \pkg{skeyval} only if it hasn't been defined by a previously loaded package; the command \fx{\SKV@robustdef}, on the other hand, is always available. If \ang{cs} was previously defined, both \fx{\SKV@robustdef} and \fx{\robustdef} will issue an error. You can use the above \fx{\TestProvidedCommand} to check whether or not you are using the \fx{\robustdef} of the \pkg{skeyval}.
\macrosubsection{\tex-like \@bs providecommand}
\begin{macro}
\SKV@providedef|redstar|vang(cs)|vang(parameters){|vang(replacement text)}
\providedef|redstar|vang(cs)|vang(parameters){|vang(replacement text)}
\SKV@providerobustdef|redstar|vang(cs)|vang(parameters){|vang(replacement text)}
\providerobustdef|redstar|vang(cs)|vang(parameters){|vang(replacement text)}
\end{macro}
\acmdm*{\SKV@providedef,\SKV@providerobustdef,\providerobustdef,
\SKV@providedef*,\SKV@providerobustdef*,\providerobustdef*}
\acmds*\providedef\SKV@providedef
These emulate \latex's \acmdm{\providecommand}, but they conform to \tex's \fx{\def} interface. The unstarred variants produce long macros. These commands accept parameter delimiters and are all robust. The commands \fx{\providedef} and \fx{\providerobustdef} are defined in the \pkg{skeyval} only if they haven't been defined by a previously loaded package; the commands \fx{\SKV@providedef} and \fx{\SKV@providerobustdef}, on the other hand, are always available. Macros defined by \fx{\SKV@providerobustdef} and \fx{\providerobustdef} are robust, while those defined by \fx{\SKV@providedef} and \fx{\providedef} are nonrobust. If \ang{cs} was previously defined, all these commands will simply ignore the new definition and enter a message to this effect in the log file (if the package option \fx{verbose} is selected).
\macrosubsection{\@bs requirecmd}
\begin{macro}
\requirecmd{|vang(cs)}[|vang(number of args)][|vang(default)]%
{|vang(replacement text)}
\end{macro}
This is explained in \cref{sec:toggle-booleans}. If \ang{cs} is already defined, \acmdm{\requirecmd} checks if the new and old definitions are identical. If they aren't, a warning message is logged in the transcript file (if the package option \fx{verbose} is selected) and the new definition is aborted.
\macrosubsection{Testing \emph{provided} commands}
\begin{macro}
\TestProvidedCommand|vang(cs){|vang(true text)}{|vang(false text)}|label(mac:testprovide)
\end{macro}
This can be used to test whether or not one is using the \fx{\newdef} (or any other ``provided'' command) of the \pkg{skeyval}. Here \ang{cs} is either \fx{\newdef} or any ``provided'' command. In fact, if you define any command using the macro \fx{\SKV@providedef} or \fx{\SKV@providerobustdef} (see below), you can verify by \acmdm{\TestProvidedCommand} whether or not the new definition is the one in effect.
\begin{example}
\SKV@providerobustdef*\newcmd{\newcommand}
\TestProvidedCommand\newcmd{%
\@latex@info{`\string\newcmd' is `\string\newcommand'}%
}{%
\@latex@error{`\string\newcmd' isn't %
`\string\newcommand'}\@ehd
}
\end{example}
\begin{example}
\SKV@providedef*\declarecommand{\newcommand}
\TestProvidedCommand\declarecommand{}%
{\let\declarecommand\newcommand}
\end{example}
\macrosection{Declaring new unique variables collectively}
New definable variables can be introduced in sets by the following commands.
\begin{macro}
\NewBooleans[|vang(optional prefix)]{|vang(boolean list)}[|vang(optional state)]
\DefBooleans[|vang(optional prefix)]{|vang(boolean list)}[|vang(optional state)]
\end{macro}
\acmdm*{\NewBooleans,\DefBooleans}
The function \fx{\NewBooleans} provides, for each member of the comma-separated list \ang{boolean list}, a new native-boolean register if the register didn't already exist; if the boolean already existed, an error is flagged. \fx{\DefBooleans}, on the other hand, provides, for each member of the comma-separated list \ang{boolean list}, a new native-boolean register whether or not the register already existed. If the boolean already existed, a warning message is logged in the transcript file if the package option \fx{verbose} is enabled.
Each member of \ang{boolean list} is prefixed with \ang{prefix} upon definition. The optional \ang{state} can be either \fx{true}, \fx{false}, \fx{on} or \fx{off}. The state \fx{on} is synonymous with \fx{true}, whilst \fx{off} is equivalent to \fx{false}.
\begin{example}
\NewBooleans[bool]{a,b,c}[true]
|tto \newif\ifboola \newif\ifboolb \newif\ifboolc
\boolatrue \boolbtrue \boolctrue
\NewBooleans{boold} |tto \newif\ifboold
\DefBooleans[skv@]{e,f,g}[false]
|tto \newif\ifskv@e \newif\ifskv@f \newif\ifskv@g
\skv@efalse \skv@ffalse \skv@gfalse
\end{example}
Notice that members of the list \ang{boolean list} don't have \fx{\if} in their names.
\begin{macro}
\NewTogs[|vang(optional prefix)]{|vang(tog list)}[|vang(optional state)]
\DefTogs[|vang(optional prefix)]{|vang(tog list)}[|vang(optional state)]
\end{macro}
\acmdm*{\NewTogs,\DefTogs}
The command \fx{\NewTogs} provides a new toggle register for each member of the comma-separated list \ang{tog list} if the register didn't already exist, otherwise an error is flagged. The command \fx{\DefTogs}, on the other hand, will not raise any error even if the toggle already existed, but (if the package option \fx{verbose} is selected) will instead make an entry in the transcript log file to the effect that the toggle has been redefined. Each member of \ang{tog list} is prefixed with \ang{prefix} upon definition. The optional \ang{state} can be either \fx{true}, \fx{false}, \fx{on} or \fx{off}. The state \fx{on} is synonymous with \fx{true}, whilst \fx{off} is equivalent to \fx{false}.
\begin{example}
\NewTogs[tog]{a,b,c}[true]
|tto \newtog{toga} \newtog{togb} \newtog{togc}
\togon{toga} \togon{togb} \togon{togc}
\NewTogs{togd} |tto \newtog{togd}
\end{example}
\begin{macro}
\NewToks[|vang(optional prefix)]{|vang(toks list)}
\DefToks[|vang(optional prefix)]{|vang(toks list)}
\end{macro}
\acmdm*{\NewToks,\DefToks}\label{page:newtoks}
This provides a new token list register for each member of the comma-separated list \ang{toks list} if the register didn't already exist, otherwise an error is flagged. Each member of \ang{toks list} is prefixed with \ang{prefix} upon definition. The command \fx{\DefToks}, on the other hand, will not raise any error even if the token list register already existed, but (if the package option \fx{verbose} is selected) will instead make an entry in the transcript log file to the effect that the register has been redefined.
\begin{example}
\NewToks[toks]{a,b,c}
|tto \newtoks\toksa \newtoks\toksb \newtoks\toksc
\NewToks{toksd} |tto \newtoks\toksd
\end{example}
\begin{macro}
\NewCounts[|vang(optional prefix)]{|vang(counter list)}
\DefCounts[|vang(optional prefix)]{|vang(counter list)}
\end{macro}
\acmdm*{\NewCounts,\DefCounts}
This provides a new counter register for each member of the comma-separated list \ang{counter list} if the register didn't already exist, otherwise an error is flagged. Each member of \ang{counter list} is prefixed with \ang{prefix} upon definition. The command \fx{\DefCounts}, on the other hand, will not raise any error even if the counter already existed, but (if the package option \fx{verbose} is selected) will instead make an entry in the transcript log file to the effect that the counter has been redefined.
\begin{macro}
\NewDimens[|vang(optional prefix)]{|vang(dimen list)}
\DefDimens[|vang(optional prefix)]{|vang(dimen list)}
\end{macro}
\acmdm*{\NewDimens,\DefDimens}
This provides a new dimension register for each member of the comma-separated list \ang{dimen list} if the register didn't already exist, otherwise an error is flagged. Each member of \ang{dimen list} is prefixed with \ang{prefix} upon definition. The command \fx{\DefDimens}, on the other hand, will not raise any error even if the dimension register already existed, but (if the package option \fx{verbose} is selected) will instead make an entry in the transcript log file to the effect that the register has been redefined.
\begin{macro}
\NewBoxes[|vang(optional prefix)]{|vang(box list)}
\DefBoxes[|vang(optional prefix)]{|vang(box list)}
\end{macro}
\acmdm*{\NewBoxes,\DefBoxes}
This allocates a new box register for each member of the comma-separated list \ang{box list} if the box register didn't already exist, otherwise an error is flagged. Each member of \ang{box list} is prefixed with \ang{prefix} upon definition. The command \fx{\DefBoxes}, on the other hand, will not raise any error even if the box register already existed, but (if the package option \fx{verbose} is selected) will instead make an entry in the transcript log file to the effect that the register has been redefined.
\begin{example}
\NewBoxes[box]{a,b,c}
|tto \newbox\boxa \newbox\boxb \newbox\boxc
\NewBoxes{boxd} |tto \newbox\boxd
\end{example}
\begin{macro}
\NewWrites[|vang(optional prefix)]{|vang(stream list)}
\DefWrites[|vang(optional prefix)]{|vang(stream list)}
\end{macro}
\acmdm*{\NewWrites,\DefWrites}
This allocates a new output stream for each member of the comma-separated list \ang{stream list} if the stream didn't already exist, otherwise an error is flagged. Each member of \ang{stream list} is prefixed with \ang{prefix} upon definition. The command \fx{\DefWrites}, on the other hand, will not raise any error even if the write stream already existed, but (if the package option \fx{verbose} is selected) will instead make an entry in the transcript log file to the effect that the stream has been redefined.
\begin{example}
\NewWrites[write]{a,b,c}
|tto \newwrite\writea \newwrite\writeb \newwrite\writec
\NewWrites{writed} |tto \newwrite\writed
\end{example}
\begin{macro}
\NewReads[|vang(optional prefix)]{|vang(stream list)}
\DefReads[|vang(optional prefix)]{|vang(stream list)}
\end{macro}
\acmdm*{\NewReads,\DefReads}
This allocates a new input stream for each member of the comma-separated list \ang{stream list} if the stream didn't already exist, otherwise an error is flagged. Each member of \ang{stream list} is prefixed with \ang{prefix} upon definition. The command \fx{\DefReads}, on the other hand, will not raise any error even if the read stream already existed, but (if the package option \fx{verbose} is selected) will instead make an entry in the transcript log file to the effect that the stream has been redefined.
The macros \fx{\NewBooleans}, \fx{\DefBooleans}, \fx{\NewToks}, \fx{\DefToks}, \fx{\NewCounts}, \fx{\DefCounts}, \fx{\NewDimens}, \fx{\DefDimens}, \fx{\NewBoxes}, \fx{\DefBoxes}, \fx{\NewWrites}, \fx{\DefWrites}, \fx{\NewReads}, and \fx{\DefReads} are non-outer, unlike their primitive counterparts.
\macrosection{Defining new names}
\begin{macro}
\SKV@csdef|redstar|redplus{|vang(name)}{|vang(definition)}
\SKV@csgdef|redstar|redplus{|vang(name)}{|vang(definition)}
\SKV@csedef|redstar|redplus{|vang(name)}{|vang(definition)}
\SKV@csxdef|redstar|redplus{|vang(name)}{|vang(definition)}
\end{macro}
\acmdm*{\SKV@csdef,\SKV@csgdef,\SKV@csedef,\SKV@csxdef,
\SKV@csdef*,\SKV@csgdef*,\SKV@csedef*,\SKV@csxdef*,
\SKV@csdef*+,\SKV@csgdef*+,\SKV@csedef*+,\SKV@csxdef*+}
The variants of these commands without the plus (\RedPlus) sign turn \ang{name} into a control sequence in terms of \ang{definition} whether or not the control was already defined. No error or warning messages are issued. The variants with plus (\RedPlus) sign turn \ang{name} into a control sequence if it wasn't already defined; if it is already defined, an error message is flagged. The starred (\RedStar) variants give ``short'' macros, while the unstarred variants yield ``long'' definitions. These derive from a concept based on that of \acmd{\newcommand}, but (i)~\textrelaxed\ commands are considered undefined in this regard, and (ii)~these commands retain the powerful machinery of plain \tex.\footnote{The \pkg{skeyval} contains other undocumented tools for defining new commands.}
\macrosection{Name use}
\begin{macro}
\SKV@csuse{|vang(name)}
\end{macro}
\acmdm*{\SKV@csuse}
This is similar to \LaTeX's legacy \acmdm{\@nameuse} but returns \fx{\@empty} (instead of an error) if \ang{name} is undefined. This is due originally to \pkg{etoolbox}.
\macrosection{\texttt{\@bs let} assignments}
\begin{macro}
\SKV@newlet{|vang(cs1)}{|vang(cs2)}
\NewLet{|vang(cs1)}{|vang(cs2)}
\SKV@newlet|redstar{|vang(cs1)}{|vang(cs2)}
\end{macro}
\acmdm*{\SKV@newlet,\SKV@newlet*,\NewLet}
The first two of these assign \ang{cs2} to \ang{cs1} if \ang{cs2} exists and if \ang{cs1} isn't already defined, otherwise an error is flagged. \fx{\SKV@newlet}\unskip\redstar\ will assign \ang{cs2} to \ang{cs1} whether or not \ang{cs1} is already defined.
The command \fx{\NewLet} is defined in the \pkg{skeyval} only if it hasn't been defined by a previously loaded package; the command \fx{\SKV@newlet}, on the other hand, is always available. You can use \acmd{\TestProvidedCommand} (\macref{mac:testprovide}) to test whether or not you are using the \fx{\NewLet} command of the \pkg{skeyval}.
\begin{macro}
\SKV@cslet{|vang(name)}{|vang(cs)}
\SKV@letcs{|vang(cs)}{|vang(name)}
\SKV@csletcs{|vang(name)}{|vang(name)}
\end{macro}
\acmdm*{\SKV@cslet,\SKV@letcs,\SKV@csletcs}
These perform \fx{\let} assignments if the second argument is defined, otherwise an error message is flagged. The notation \ang{cs} means a control sequence, and \ang{name} means a control sequence name.
\begin{macro}
\SKV@cslet|redstar{|vang(name)}{|vang(cs)}
\SKV@letcs|redstar{|vang(cs)}{|vang(name)}
\SKV@csletcs|redstar{|vang(name)}{|vang(name)}
\end{macro}
\acmdm*{\SKV@cslet*,\SKV@letcs*,\SKV@csletcs*}
These perform \fx{\let} assignments whether or not the second argument is defined. If the second argument is undefined, the first remains undefined and the hash table is not filled.
\macrosection{Number and dimension expressions}
\begin{macro}
\SKV@numdef|redplus|redclam{|vang(num)}{|vang(expression)}
\end{macro}
\acmdm{\SKV@numdef} defines \ang{num} from \ang{expression} using \etex's \acmd{\numexpr}. If \ang{num} was previously undefined, it is first initialized with \acmd{\newcount} before the expression is built. If you do \fx{\SKV@numdef\x{1+2+3}}, you would need to prefix \fx{\x} with \fx{\the} or \acmd{\number} in expressions. Expressions defined by \fx{\SKV@numdef} can be used with \tex's operators such as \fx{\advance} or \fx{\multiply} and \etex's \acmd{\numexpr} operator.
The plus sign (\RedPlus) means that \fx{\SKV@numdef} takes a control sequence name instead of a control sequence, while the exclamation mark (\RedClam) implies that the macro \fx{\SKV@numdef} effects a global assignment which can thus escape local groups.
\begin{macro}
\SKV@dimdef|redplus|redclam{|vang(dim)}{|vang(expression)}
\end{macro}
\acmdm{\SKV@dimdef} defines \ang{dim} from \ang{expression} using \etex's \acmd{\dimexpr}. If \ang{dim} was previously undefined, it is first initialized with \acmd{\newdimen} before the expression is built. If you do \fx{\SKV@dimdef\x{1pt+2pt+3pt}}, you would need to prefix \fx{\x} with \fx{\the} in expressions. Expressions defined by \fx{\SKV@dimdef} can be used with \etex's \acmd{\dimexpr} operator.
The plus sign (\RedPlus) means that \fx{\SKV@dimdef} takes a control sequence name instead of a control sequence, while the exclamation mark (\RedClam) implies that the macro \fx{\SKV@dimdef} effects a global assignment which can thus escape local groups.
\macrosection{Verifying definability}
\begin{macro}
\SKV@ifdefinable|vang(cs){|vang(function)}
\SKV@csifdefinable|vang(cs name){|vang(function)}
\end{macro}
\acmdm*{\SKV@ifdefinable, \SKV@csifdefinable}
\latex kernel's \fx{\@ifdefinable} fills up the hash table and also considers commands that are \fx{\relax}'ed as defined. Moreover, if the command being tested (\ang{cs} in the above example) is definable, the \fx{\@ifdefinable} macro begins executing \ang{function} while still in the \fx{\if} \textellipsis \fx{\fi} conditional. You can't do \fx{\let\ifabc\iftrue} in such conditionals. The command \fx{\SKV@ifdefinable}, which is robust, seeks to avoid these problems. \fx{\SKV@csifdefinable} expects a control sequence name instead of a control sequence.
\begin{macro}
\SKV@ifdefinable@n{|vang(list)}
\end{macro}
The macro \acmdm{\SKV@ifdefinable@n} accepts a comma-separated list of control sequence \emph{names} whose definability are to be tested. It should be noted that the macro \fx{\SKV@ifdefinable@n} doesn't accept \ang{function}, unlike the above \fx{\SKV@ifdefinable}. The aim of \fx{\SKV@ifdefinable@n} is simply to test the definability of instances/members of \ang{list}.
\begin{example}
\SKV@ifdefinable@n{ax,ay,az}
\end{example}
\begin{macro}
\SKV@ifnewcmd|redstar|redplus[|vang(optional parser)]{|vang(list)}
\end{macro}
\acmdm*{\SKV@ifnewcmd,\SKV@ifnewcmd*,\SKV@ifnewcmd*+}
The macro \fx{\SKV@ifnewcmd} is similar to, but more versatile, than the command \fx{\SKV@ifdefinable@n}. The star sign (\RedStar) in \fx{\SKV@ifnewcmd} indicates that \ang{list} is available in a macro, say \fx{\mylist}; and the plus sign (\RedPlus) shows \fx{\SKV@ifnewcmd} that members of \ang{list} (or \fx{\mylist}) are control sequence names, otherwise they are control sequences (see examples below). The default value of the optional \ang{parser} is ``,'' (comma). The macro \fx{\SKV@ifnewcmd}, like \fx{\SKV@ifdefinable@n} but unlike \fx{\SKV@ifdefinable}, doesn't execute any \ang{function}. Both \fx{\SKV@ifdefinable@n} and \fx{\SKV@ifnewcmd} are robust.
\begin{example}
\def\mylist{ax,ay,az}
\SKV@ifnewcmd|redstar|redplus[,]\mylist
\SKV@ifnewcmd|redstar|redplus\mylist
\SKV@ifnewcmd|redplus{ax,ay,az}
\SKV@ifnewcmd{\ax\ay\az}
\def\my@list{\ax\ay\az}
\SKV@ifnewcmd|redstar\my@list
\def\my@@list{ax;ay;az}
\SKV@ifnewcmd|redstar|redplus[;]\my@@list
\SKV@ifnewcmd\ax |tto \SKV@ifnewcmd|redplus{ax} |tto \SKV@ifdefinable@n{ax}
\end{example}
\macrosection{Verifying the status of variables}
\begin{macro}
\SKV@ifdef|vang(cs){|vang(true)}{|vang(false)}
\SKV@ifcsdef{|vang(name)}{|vang(true)}{|vang(false)}
\SKV@ifundef|vang(cs){|vang(true)}{|vang(false)}
\SKV@ifcsundef{|vang(name)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\SKV@ifdef,\SKV@ifcsdef,\SKV@ifundef,\SKV@ifcsundef}
These use \etex's facilities to test the existence of the control sequence \ang{cs} or control sequence name \ang{name}. These commands aren't robust and may be used to determine the current state of the macro replacement text, if such replacement text contains these commands. \textrelaxed\ macros are considered undefined by \emph{all} these commands. To test if a macro is \textrelaxed, use the following commands:
\begin{macro}
\SKV@ifrelax|vang(cs){|vang(true)}{|vang(false)}
\SKV@ifcsrelax{|vang(name)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\SKV@ifrelax,\SKV@ifcsrelax}
\begin{macro}
\SKV@ifdefax|vang(cs){|vang(defined)}{|vang(relaxed)}{|vang(undefined)}
\SKV@ifcsdefax{|vang(name)}{|vang(defined)}{|vang(relaxed)}{|vang(undefined)}
\end{macro}
\acmdm*{\SKV@ifdefax,\SKV@ifcsdefax}
These test if \ang{cs} or \ang{name} is defined, relaxed, or undefined. In using these three-valued logical tests, it is often easy to forget to include the null state (\ie, \ang{undefined}) because \tex is dominated by two-valued logical tests.
\macrosection{Undefining macros}
\begin{macro}
\SKV@Undef|redstar|redplus|redclam[|vang(optional parser)]{|vang(cs)}
\end{macro}
\acmdm*{\SKV@Undef,\SKV@Undef*,\SKV@Undef*+}
This undefines the macros or control sequence names in the list \ang{cs} (of nil, one or more elements) such that \tex will subsequently consider each element undefined. The star sign (\RedStar) indicates that \ang{cs} is given as a macro whose \emph{contents} are to be individually undefined, and the plus sign (\RedPlus) shows that \ang{cs} is made up of \emph{control sequence names} instead of control sequences. The exclamation mark (\RedClam) directs \fx{\SKV@Undef} to \emph{globally} undefine all the control sequences or names in \ang{cs}. Control sequence names are to be separated by the parser; control sequences shouldn't be separated. The default value of the \ang{parser} is ``,'' (comma). The command \fx{\SKV@Undef} is robust (it will thus not expand in expansion contexts), but fragile arguments would need to be protected in expansion contexts.\footnote{Macros such as \acmdm{\@ifnextchar}, \acmdm{\@ifstar}, and those involving optional arguments normally can't be evaluated in expansion contexts. The same applies to the \pkg{skeyval} macros with optional arguments. The \pkgm{etextools} introduced expandable variants of these commands, but in the contexts these commands are employed in the \pkg{skeyval}, the expandable variants aren't particularly advantageous. The main reason is that some of our internal macros (\eg, looping macros) aren't amenable to full expansion anyway. Actually, the \pkg{skeyval} provides the fully expandable variants (\acmdm{\SKV@TestOpt}, \acmdm{\SKV@IfStar}, \acmdm{\SKV@IfPlus}, and \acmdm{\SKV@IfAsk}) of the non-expandable commands \acmdm{\SKV@testopt}, \acmdm{\SKV@ifstar}, \acmdm{\SKV@ifplus}, and \acmdm{\SKV@ifask}. The commands \fx{\SKV@ifask} and \fx{\SKV@IfAsk} look for an optional question mark (\RedClam).}
\begin{example}
\def\unwanted{tempa,tempb,tempc,temp1}
\SKV@Undef|redstar|redplus|redclam[,]\unwanted
\def\unwanted{t1emp,te2mp,tem3p}
\SKV@Undef|redstar|redplus|redclam[,]\unwanted
\SKV@Undef|redplus|redclam[;]{tempd;tempe;tempf}
\SKV@Undef\tempe
\SKV@Undef|redclam{\tempea\tempeb\tempec\temped}
\SKV@Undef|redplus{tempf}
\SKV@Undef|redclam\tempg
\def\notwanted{\temph\tempi\tempj}
\SKV@Undef|redstar\notwanted
\end{example}
The following non-generic variants avoid the above complications of signs, but they don't take lists:
\begin{macro}
\SKV@undef{|vang(cs)} |tto \SKV@Undef{|vang(cs)}
\SKV@gundef{|vang(cs)} |tto \SKV@Undef|redclam{|vang(cs)}
\SKV@csundef{|vang(cs name)} |tto \SKV@Undef|redplus{|vang(cs)}
\SKV@csgundef{|vang(cs name)} |tto \SKV@Undef|redplus|redclam{|vang(cs)}
\end{macro}
\acmdm*{\SKV@undef,\SKV@gundef,\SKV@csundef,\SKV@csgundef}
\macrosection{Expansion control}
\begin{macro}
\SKV@expox{|vang(cs)}
\end{macro}
\acmdm*{\SKV@expox}
This expands its argument \ang{cs} once and forbids further expansion.
\begin{macro}
\SKV@csexpox{|vang(name)}
\end{macro}
\acmdm*{\SKV@csexpox}
This is similar to \fx{\SKV@expox} but accepts control sequence name \ang{name} instead of control sequence.
\begin{macro}
\SKV@exptx{|vang(cs)}
\end{macro}
\acmdm*{\SKV@exptx}
This expands its argument \ang{cs} twice and forbids further expansion.
\begin{macro}
\SKV@csexptx{|vang(name)}
\end{macro}
\acmdm*{\SKV@csexptx}
This is similar to \fx{\SKV@exptx} but accepts control sequence name \ang{name} instead of control sequence.
\begin{macro}
\SKV@expargs|vang(n)|vang(function)|vang(arg1)|vang(arg2)\@nil
\end{macro}
\acmdm*{\SKV@expargs}
\LaTeX's \acmdm{\@expandtwoargs} is often used as a utility macro to expand two arguments \ang{arg1} and \ang{arg2} in order to execute \ang{function}. The command \fx{\SKV@expargs}, on the other hand, accepts up to four expansion types, signified by \ang{n}, which runs \mbox{from 0 to 3}:
\begin{enum}
\item If \ang{n} is 0, then \ang{arg2} is empty and only \ang{arg1} will be expanded before \ang{function} is executed.
\item If \ang{n} is 1, then both \ang{arg1} and \ang{arg2} are nonempty but only \ang{arg2} will be expanded before \ang{function} is executed.
\item When \ang{n} is 2, then both \ang{arg1} and \ang{arg2} are nonempty and both will be expanded before \ang{function} is executed. This is equivalent to \LaTeX's \fx{\@expandtwoargs}.
\item If \ang{n} is 3, then both \ang{arg1} and \ang{arg2} are nonempty but only \ang{arg1} is expanded before \ang{function} is executed.
\item If \ang{n} isn't in the list \fnv{0,1,2,3}, then an error message is flagged.
\end{enum}
Because \ang{arg2} is delimited, it can be empty. The command \fx{\SKV@expargs} can be used to save \fx{\expandafter}'s, but caution should be exercised in deploying it: for example, the \fx{\edef} it uses may expand too deeply in some cases. Also, precaution may be necessary when the expanded arguments (\ang{arg1} and/or \ang{arg2}) involve the \tex primitive \fx{\if}. When invoking \fx{\SKV@expargs}, the macros \fx{\SKV@expox} and \fx{\SKV@exptx} can be used to control the level of expansion.
Some trivial examples follow:
\begin{example}
\SKV@expargs{0}{\def\tempc#1#2}{\def\noexpand##1{##2}}\@nil|label(mac:expargs)
\tempc\tempa{aaa}
\tempc\tempb{abcaaabbccbca}
\SKV@expargs{2}\SKV@in@\tempa\tempb\@nil
\show\ifin@
\end{example}
\acmd*{\SKV@in@}
These expressions show how \fx{\SKV@expargs} can be used to economize on chains of \fx{\expandafter}'s. The expression on \macref{mac:expargs}, for example, isn't directly possible by \fx{\@expandtwoargs}.
\macrosection{Checking values of \texttt{choice} keys}
Choice keys should, by definition, have preordained values. This requirement can be useful even for non-choice keys, as we illustrate below.
\begin{macro}
\SKV@checkchoice{|vang(value)}{|vang(altlist)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\SKV@checkchoice}
This is an enhanced form of \pkg{xkeyval}'s \fx{\XKV@checkchoice}. It checks if the user-submitted \ang{value} of a key (say, \ang{keya}) is in the list \ang{altlist}. It executes \ang{true} if \ang{value} is found in \ang{altlist} and \ang{false} otherwise. Additionally, it returns \acmd{\val} for the expanded value of \ang{value} and \acmd{\nr} for the numerical order of \acmd{\val} in the list \ang{altlist}. If \ang{value} isn't found in \ang{altlist}, then \acmd{\nr} will return $-1$. If \ang{value} and \ang{altlist} are buried in macros, the macros are fully expanded before the search for \ang{value} in the list \ang{altlist} is effected. In that case, \acmd{\val} will hold the expanded form of \ang{value} and can be used in subsequent computations.
Choice keys do accept macros as values, but such values aren't directly suitable for matching against the contents of \ang{altlist}. For example, \ang{altlist} may be the set \fx{{left,right,center}}, but given as a macro \fx{\@altlist}, while \ang{value} is given as \fx{\def\@value{center}}. Obviously, \fx{\@value} contains one of the elements of \ang{altlist}, but choice keys won't know this without the expansion of both \fx{\@altlist} and \fx{\@value}. This is \name{raison d'\^e tre} of the \fx{\SKV@checkchoice} macro.
Moreover, \fx{\SKV@checkchoice} can be used in the definition of non-choice keys. In the following example we check the value of an \emph{ordinary} key by means of \fx{\SKV@checkchoice}:
\begin{example}
\def\@altlist{left,right,center}
\newordkey[KV]{fam}{keya}[true]{%
\SKV@checkchoice{#1}{\@altlist}{%
\ifcase\nr\relax
\edef\tempa##1##2{##1===\val===##2}%
\or
\edef\tempa##1##2{##1***\val***##2}%
\or
\edef\tempa##1##2{##1+++\val+++##2}%
\fi
}{%
\@latex@error{Wrong value for `keya'}\@eha
}%
}
\def\@value{center}
\setkeys[KV]{fam}{keya=\@value}
\end{example}
The reader may wish to do \fx{\show\tempa} to see what \fx{\tempa} gets upon setting the key \fx{keya}.
\macrosection{Testing for substring}
\begin{macro}
\SKV@in@{|vang(substring)}{|vang(string)}
\end{macro}
\acmdm*{\SKV@in@}
This is similar to the \latex kernel's \fny{\in@}{substring}{string} which tests if \ang{substring} is in \ang{string}, but the present test avoids the problem of false result, which is typified by the following test:
\begin{example}
\in@{aa}{ababba}
\end{example}
This incorrectly returns \acmdm{\ifin@} as \fx{\iftrue}. The macro \fx{\SKV@in@}, on the other hand, correctly gives \fx{\ifin@} as \fx{\iffalse} in this case. The command \fx{\SKV@in@} is robust.
\begin{macro}
\SKV@in@n{|vang(substring)}{|vang(string)}{|vang(true text)}{|vang(false text)}
\end{macro}
\acmdm*{\SKV@in@n}
This is similar to \fx{\SKV@in@} but, as shown here, the returned result has a different syntax.
\begin{macro}
\SKV@in@o{|vang(substring)}{|vang(string)}{|vang(true text)}{|vang(false text)}
\end{macro}
\acmdm*{\SKV@in@o}
This expands each of its two arguments once before the test.
\begin{macro}
\SKV@in@x{|vang(substring)}{|vang(string)}{|vang(true text)}{|vang(false text)}
\end{macro}
\acmdm*{\SKV@in@x}
This expands each of its two arguments fully before the test.
\begin{macro}
\in@tog{|vang(substring)}{|vang(string)}
\end{macro}
\acmdm*{\in@tog}
In this case the returned boolean is the toggle switch \ang{in@} instead of the kernel's \ang{in@} switch which is used as \fx{\ifin@}. The toggle \ang{in@} can be used in the following way and in other manners that toggles can be employed:
\begin{example}
\iftogon{in@}{|vang(true text)}{|vang(false text)}.
\end{example}
\acmd*{\iftogon}
The command \fx{\in@tog} is robust.
\begin{macro}
\in@tok{|vang(substring)}{|vang(string)}
\end{macro}
\acmdm*{\in@tok}
Sometimes you want to use the \latex kernel's \fny{\in@}{substring}{string} to test if \ang{substring} is in \ang{string} irrespective of their catcodes. The robust command \fny{\in@tok}{substring}{string} makes this possible, and eliminates the tokens that would have been necessary if the user was required to first detokenize the two arguments. It returns the same switch \fx{\ifin@} as the kernel's \fny{\in@}{substring}{string}. Actually, it calls \fx{\SKV@in@} to avoid false returns.
\macrosection{Testing equality of strings}
\begin{macro}
\SKV@ifstrequal{|vang(string1)}{|vang(string2)}{|vang(true)}{|vang(false)}
\SKV@ifstrnotequal{|vang(string1)}{|vang(string2)}{|vang(not true)}{|vang(not false)}
\SKV@oifstrequal{|vang(string1)}{|vang(string2)}{|vang(true)}{|vang(false)}
\SKV@xifstrequal{|vang(string1)}{|vang(string2)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\SKV@ifstrequal,\SKV@ifstrnotequal,\SKV@oifstrequal,\SKV@xifstrequal}
In order to properly test the equality of strings, it may be necessary to remove leading and trailing spaces before the test. Such spaces may have cropped into the strings from input or from pre-processing and may invalidate the test. The macro \fx{\SKV@ifstrequal} takes care of such situations. It executes \ang{true} if \ang{string1} is equal (character code wise) to \ang{string2}, and \ang{false} otherwise. Both \ang{string1} and \ang{string2} are detokenized before the test. The macro \fx{\SKV@oifstrequal} is similar to \fx{\SKV@ifstrequal} but first expands its arguments (the two strings \ang{string1} and \ang{string2}) once before the test. The macro \fx{\SKV@xifstrequal} first expands its arguments fully before the test.
\macrosection{Testing for empty or blank}
\begin{macro}
\SKV@ifempty{|vang(token)}{|vang(true)}{|vang(false)}
\SKV@ifnotempty{|vang(token)}{|vang(not true)}{|vang(not false)}
\SKV@oifempty{|vang(token)}{|vang(true)}{|vang(false)}
\SKV@xifempty{|vang(token)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\SKV@ifempty,\SKV@ifnotempty,\SKV@oifempty,\SKV@xifempty}
These yield \ang{true} if \ang{token} is empty, and \ang{false} otherwise. In the command \fx{\SKV@ifempty}, \ang{token} isn't expanded before the test; in the command \fx{\SKV@oifempty}, \ang{token} is expanded once before the test; in the command \fx{\SKV@xifempty}, \ang{token} is fully expanded before the test.
\begin{macro}
\SKV@ifblank{|vang(token)}{|vang(true)}{|vang(false)}
\SKV@ifnotblank{|vang(token)}{|vang(not true)}{|vang(not false)}
\SKV@oifblank{|vang(token)}{|vang(true)}{|vang(false)}
\SKV@xifblank{|vang(token)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\SKV@ifblank,\SKV@ifnotblank,\SKV@oifblank,\SKV@xifblank}
These macros test if the argument is blank or not. The first of these is from \pkgm{ifmtarg}. \fx{\SKV@oifblank} expands its argument once before the test, while \fx{\SKV@xifblank} expands its argument fully before the test.
\macrosection{Verifying \texttt{draft} and \texttt{final} options}
\begin{macro}
\SKV@ifdraft{|vang(true)}{|vang(false)}
\SKV@ifnotdraft{|vang(not true)}{|vang(not false)}
\SKV@iffinal{|vang(true)}{|vang(false)}
\SKV@ifnotfinal{|vang(not true)}{|vang(not false)}
\iftogon{draft}{|vang(true)}{|vang(false)}
\iftogoff{draft}{|vang(not true)}{|vang(not false)}
\iftogon{final}{|vang(true)}{|vang(false)}
\iftogoff{final}{|vang(not true)}{|vang(not false)}
\end{macro}
\acmdm*{\SKV@ifdraft,\SKV@ifnotdraft,\SKV@iffinal,\SKV@ifnotfinal,\iftogon\{draft\},
\iftogoff\{draft\},\iftogon\{final\},\iftogoff\{final\}}
These execute \ang{true} or \ang{false} depending on whether \fx{draft} or \fx{final} appears as \fx{true} in the options list of \acmd{\documentclass} or \fnx{\usepackage}{skeyval}.
The default is that \fx{final} is true, which implies that \fx{draft} is false by default. The keys \fx{draft} and \fx{final} are complementary native-boolean keys (see \cref{sec:comp-boolkeys}), which reduces the risk of mixing them. These commands are robust.
\begin{macro}
\ifdraft{|vang(true)}{|vang(false)}
\ifnotdraft{|vang(not true)}{|vang(not false)}
\iffinal{|vang(true)}{|vang(false)}
\ifnotfinal{|vang(not true)}{|vang(not false)}
\end{macro}
\acmdm*{\ifdraft,\ifnotdraft,\iffinal,\ifnotfinal}
These are also defined in the \pkg{skeyval}, but because packages such as \pkgm{ifdraft} already exist, the \pkg{skeyval} defines them only if they haven't already been defined. If they existed before \pkg{skeyval} is loaded, they aren't redefined, and (if the package option \acmd{verbose} is selected) a warning is logged in the transcript file to indicate that the definition being used isn't from the \pkg{skeyval}. The warning is logged only once. I am aware of the existence of only \fx{\ifdraft} outside the \pkg{skeyval}: therefore, the definition of \fx{\ifdraft} is deferred until \acmd{\AtBeginDocument}. You can use \acmd{\TestProvidedCommand} to check the version of the \fx{\ifdraft} that you are using.
\macrosection{Verifying \texttt{dvi} and \texttt{pdf} modes}
\begin{macro}
\SKV@ifpdf{|vang(true)}{|vang(false)}
\SKV@ifnotpdf{|vang(not true)}{|vang(not false)}
\iftogon{pdf}{|vang(true)}{|vang(false)}
\iftogoff{pdf}{|vang(not true)}{|vang(not false)}
\end{macro}
\acmdm*{\SKV@ifpdf,\SKV@ifnotpdf,\iftogon\{pdf\},\iftogoff\{pdf\}}
These execute \ang{true} or \ang{false} depending on whether \fx{dvi} or \fx{pdf} output is being produced. These commands are robust and may be used in expansion contexts.
\begin{macro}
\ifpdf{|vang(true)}{|vang(false)}
\ifnotpdf{|vang(not true)}{|vang(not false)}
\end{macro}
\acmdm*{\ifpdf,\ifnotpdf}
These are available only if they haven't been previously defined by another package. If they existed outside the \pkg{skeyval}, a warning is logged in the transcript log file (if the package option \fx{verbose} is selected), but only once, and the commands are not redefined. In particular, the above \fx{\ifpdf} is available only at \acmd{\AtBeginDocument} and is defined only if it doesn't already exist. The reason is that the popular \pkg{hyperref} loads the \pkg{ifpdf} and the \pkg{ifpdf} will abort if it detects that \fx{\ifpdf} has been defined by a package loaded earlier.
\Note The \fx{\ifpdf} command of the \pkg{ifpdf} is used in the \fx{\if} \ldots \fx{\else} \ldots \fx{\fi} conditional, while the above \fx{\ifpdf} command is used as indicated above. You can use the \acmd{\TestProvidedCommand} macro to check the version of the \fx{\ifpdf} command that you are using.
\macrosection{Tests related to package loading}
\begin{macro}
\@ifpackagecurrent{|vang(package)}{|vang(date)}{|vang(true)}{|vang(false)}
\@ifpackagenotcurrent{|vang(package)}{|vang(date)}{|vang(not true)}{|vang(not false)}
\end{macro}
\acmdm*{\@ifpackagecurrent,\@ifpackagenotcurrent}
These executes \ang{true} if the date of the current/loaded version \ang{package} is greater than or equal to \ang{date}. This is similar to \latex's \acmdm{\@ifpackagelater} but, unlike the latter, both \fx{\@ifpackagecurrent} and \fx{\@ifpackagenotcurrent} are robust. My main reason for these commands is that the nomenclature \fx{\@ifpackagelater} is subject to the wrong interpretation of being space (rather than time) related.
\begin{macro}
\@afterpackageloaded{|vang(package)}{|vang(code)}
\end{macro}
\acmdm*{\@afterpackageloaded}
This executes \ang{code} only after \ang{package} has been loaded. This has been optimized from the \pkgm{afterpackage} to avoid filling up the hash table with hooks that are \fx{relax}'ed or indeed undefined, and to warn the user if \ang{package} was not eventually loaded. If at the start of document, \ang{package} has not been loaded, a warning message is entered in the log file. Use the following \fx{\@ensurepackageloaded} macro if you really need an error message in this case.
\begin{macro}
\@ensurepackageloaded{|vang(packages)}
\end{macro}
\acmdm*{\@ensurepackageloaded}
This will issue an error at start of document if any member of the comma-separated list \ang{packages} wasn't loaded before then. This command can be used to signpost those packages that must be loaded later.
\macrosection{Commands restricted to package and preamble}
\begin{macro}
\SKV@onlypreamble|redplus{|vang(list)}
\SKV@onlypackage
\end{macro}
\acmdm*{\SKV@onlypreamble,\SKV@onlypackage}
The \latex kernel's macro \fx{\@onlypreamble} accepts only one command at a time (\ie, you can't give it a list of preamble commands in one go), and the error message \acmdm{\@notprerr} is not that precise, since it doesn't indicate the command that has been wrongly placed in the document's body. The use of \fx{\@onlypreamble} in a style or class file can be monotonous if the file has many preamble commands. The macro \fx{\SKV@onlypreamble} takes a comma-separated list \ang{list} of commands at once and gives precise error messages related to the incorrectly located commands. The \ang{list} may be populated with nil, one, or more control sequences. The plus sign~(\RedPlus) means that elements of \ang{list} are control sequence names instead of control sequences.
\begin{example}
\SKV@onlypreamble{\macroa, \macrob, \macroc}
\SKV@onlypreamble|redplus{macroa, macrob, macroc}
\end{example}
All preamble commands can be collected together in one \fx{\SKV@onlypreamble}, preferably at the end of the style or class file.
The function \fx{\SKV@onlypackage} may be used to restrict commands to packages only. For example, the following restricts the command \fx{\x} to packages only:
\begin{example}
\def\x#1{\SKV@onlypackage\usearg{#1}}
\end{example}
\macrosection{Extended \texttt{\@bs aftergroup} and \texttt{\@bs afterassignment}}
\begin{macro}
\SKV@aftergroup{|vang(code)}
\SKV@aftergroup|redstar{|vang(code)}
\SKV@afterassignment{|vang(code)}
\SKV@afterassignment|redstar{|vang(code)}
\end{macro}
\acmdm*{\SKV@aftergroup,\SKV@aftergroup*,\SKV@afterassignment,\SKV@afterassignment*}
\tex's \fx{\aftergroup} and \fx{\afterassignment} don't accept arbitrary code. The commands \fx{\SKV@aftergroup} and \fx{\SKV@afterassignment} execute the arbitrary \ang{code} after a group or assignment. The starred variants expand \ang{code} once before the assignment or before exiting the group. These commands don't accumulate the group and assignment counters indefinitely: the counters are initialized after each group or each assignment.
Some examples follow:
\begin{example}
\let\gobblex\@firstofone
\def\protected@mydef{%
\let\@@protect\protect
\let\protect\@unexpandable@protect
\SKV@afterassignment{%
\restore@protect
\let\gobblex\@gobble
}%
\edef
}
\def\aa{aaa} \def\bb{bbb} \def\xx{xxx} \def\yy{yyy}
|makered(\begin{document})
\begingroup
\SKV@aftergroup{\par\aa***\bb}%
\SKV@aftergroup{\par\bb***\aa}%
\begingroup
\SKV@aftergroup{\par\xx+++\yy}%
\SKV@aftergroup{\par\yy+++\xx}%
\endgroup
\endgroup
|makered(\end{document})
\end{example}
\acmd*{\begin\{document\}}
\macrosection{List processing}
\begin{macro}
\SKV@for@a{|vang(list)}|vang(cmd){|vang(function)}
\SKV@for@b|vang(listcmd)|vang(cmd){|vang(function)}
\end{macro}
\acmdm*{\SKV@for@a,\SKV@for@b}
These are fast for-loops that accept general list parsers and allow for list breaks, as well as give the remainder of the list if a break occurs within the list. Elements of \ang{list} are stored in \ang{cmd}, and \ang{function} is executed for each element of \ang{list}. \ang{list}, which is populated by parser-separated elements, is not expanded before the iteration; \ang{listcmd}, on the other hand, is expanded once before the commencement of the loop. The list parser is dynamically declarable via
\begin{macro}
\SKV@CommandGenParser{|vang(parser)} |orr
\skvoptions{genparser=|vang(parser)}
\end{macro}
\acmdm*{\SKV@CommandGenParser}
Also, these iteration macros use the more powerful \acmd{\SKV@ifblank} to check whether or not \ang{list} is empty or blank. The commands \fx{\SKV@for@a} and \fx{\SKV@for@b} are robust, but in expansion contexts, both \ang{cmd} and \ang{function} will need to be protected. The \ang{parser} persists in effect until it is changed by another call to \fx{\SKV@CommandGenParser} or \acmd{\skvoptions} as above.
\Note One snag with a generic list parser like \fx{\SKV@CommandGenParser} is that the user must always remember to call it and set the right parser before beginning an iteration, otherwise there might be unpleasant results, since a previous call to \fx{\SKV@CommandGenParser} might have set a parser that is no longer valid. To obviate this type of situation, the following commands are also provided in the \pkg{skeyval}:
\begin{macro}
\SKV@for[|vang(parser)]{|vang(list)}|vang(cmd){|vang(function)}
\SKV@for|redstar[|vang(parser)]|vang(listcmd)|vang(cmd){|vang(function)}
\end{macro}
\acmdm*{\SKV@for,\SKV@for*}
The \ang{parser} appears as an optional argument in these commands and its default value is ``\fx{,}'' (comma). These commands allow the user to provide the \ang{parser} with every call. The unstarred and starred versions of \fx{\SKV@for} are equivalent to \fx{\SKV@for@a} and \fx{\SKV@for@b}, respectively. Both sets (\fx{\SKV@for@a} and \fx{\SKV@for@b} \amdvert\ \fx{\SKV@for} and \fx{\SKV@for}\redstar) may be needed in different circumstances. In applications where the \ang{parser} is fixed, the commands \fx{\SKV@for@a} and \fx{\SKV@for@b} are faster than \fx{\SKV@for} and \fx{\SKV@for}\redstar\ because in the former cases the \ang{parser} would then need to be set only once: each call to \fx{\SKV@for} or \fx{\SKV@for}\redstar, whether or not the optional \ang{parser} is provided, resets the \ang{parser}.
The list parser itself is available in \acmd{\parser}, which can be used in \ang{function}. An example follows:
\begin{example}
\SKV@CommandGenParser{;}
\SKV@for@a{a;b;c;d}\cmd{\if a\cmd `\cmd'\ is `a'\parser
\else\space `\cmd'\ isn't `a'\parser\fi}.
\end{example}
This list can be broken after, say, elements ``\fx{a}'' and ``\fx{b}'', as follows:
\begin{example}
\SKV@for@a{a;b;|makered(listbreak);c;d}\cmd
{\if a\cmd `\cmd'\ is `a'\parser\else\space `\cmd'\
isn't `a'\parser\fi},
\end{example}
upon which the remainder of the list is accessible from \acmd{\SKV@remainder}.
\begin{macro}
\SKV@tfor@a{|vang(list)}|vang(cmd){|vang(function)}
\SKV@tfor@b|vang(listcmd)|vang(cmd){|vang(function)}
\end{macro}
\acmdm*{\SKV@tfor@a,\SKV@tfor@b}
The first of these (\ie, \fx{\SKV@tfor@a}) is equivalent to \latex kernel's \acmdm{\@tfor}, which loops over \ang{list} token-wise (character or control sequence token), but these two macros have been prompted by the following rationale. Note that \ang{list} is not a comma-separated list! In \fx{\SKV@tfor@b}, \ang{listcmd} is expanded once before the commencement of the loop. The two commands \fx{\SKV@tfor@a} and \fx{\SKV@tfor@b} are both robust.
The \acmdm{\@break@tfor} of the \latex kernel allows the user to break out of the \fx{\@tfor} loop but provides no mechanism for saving the remainder of the \ang{list} upon breaking the list. Secondly, I have had trouble breaking out of simple \fx{\@tfor} loops. For example, the following fails: \latex complains of ``extra \string\fi'', the reason being obvious.
\begin{example}
\def\one{One}\def\two{Two}\def\three{Three}
\@tfor\x:=\one\two|makered(\@break@tfor)\three\do{\x}
\end{example}
Thirdly, if the content of \fx{\x} above is sanitized/detokenized in the loop before being used in \ang{function} (or sanitized in the \ang{function} itself), then \fx{\@break@tfor} can't break the loop. Consider the following:
\begin{example}
\@tfor\x:=\one\two|makered(\@break@tfor)\three\do{%
\edef\x{\detokenize\expandafter{\x}}%
}
\end{example}
Clearly, \fx{\@break@tfor} can't break this loop. The macros \fx{\SKV@tfor@a} and \fx{\SKV@tfor@b} circumvent these problems. Additionally, they
\begin{inenum}[(a)]
\item reorder the arguments such that \ang{list} comes before \ang{cmd}, and
\item remove the need for the usual delimitating tokens, thereby making their syntaxes mimic those of \acmd{\SKV@for@a} and \acmd{\SKV@for@b}.
\end{inenum}
In the following, the remainder of the list (namely, \fx{\three}) can be accessed from the macro \acmd{\SKV@remainder}:
\begin{example}
\SKV@tfor@a{\one\two|makered(\listbreak)\three}\x{%
\edef\x{\detokenize\expandafter{\x}}%
}
\end{example}
\begin{macro}
\SKV@tfor{|vang(list)}|vang(cmd){|vang(function)}
\SKV@tfor|redstar|vang(listcmd)|vang(cmd){|vang(function)}
\end{macro}
\acmdm*{\SKV@tfor,\SKV@tfor*}
These are equivalent to \fx{\SKV@tfor@a} and \fx{\SKV@tfor@b} respectively.
\macrosection{Hook management}
\macrosubsection{Hooking to user-defined macros}
\begin{macro}
\SKV@appto|redstar|redplus|redclam|vang(cs){|vang(content)}
\end{macro}
\acmdm*{\SKV@appto,\SKV@appto*,\SKV@appto*+}
This appends \ang{content} to \ang{cs}. If \ang{cs} was previously undefined, it is initialized with \ang{content}. The star (\RedStar) sign directs \fx{\SKV@appto} to expand \ang{content} once before appending \ang{content} to \ang{cs}. The plus (\RedPlus) sign means that \ang{cs} is a control sequence name instead of a control sequence, while the exclamation mark (\RedClam) instructs \fx{\SKV@appto} to append \ang{content} to \ang{cs} globally (to escape local groups). This command is robust, but fragile arguments must be protected in expansion contexts.
Except for the initialization of undefined \ang{cs}, \fx{\SKV@appto}\redclam\ is equivalent to \latex's \acmdm{\g@addto@macro}.
The following non-generic, less powerful, forms of \fx{\SKV@appto} are also available, but they don't have the starred (\RedStar) variants:
\begin{macro}
\apptomac|vang(cs){|vang(content)}
|tto \SKV@appto|vang(cs){|vang(content)}
\gapptomac|vang(cs){|vang(content)}
|tto \SKV@appto|redclam|vang(cs){|vang(content)}
\csapptomac{|vang(name)}{|vang(content)}
|tto \SKV@appto|redplus{|vang(name)}{|vang(content)}
\csgapptomac{|vang(name)}{|vang(content)}
|tto \SKV@appto|redplus|redclam{|vang(name)}{|vang(content)}
\end{macro}
\acmdm*{\apptomac,\gapptomac,\csapptomac,\csgapptomac}
\bigskip
\begin{macro}
\SKV@prepto|redstar|redplus|redclam|vang(cs){|vang(content)}
\end{macro}
\acmdm*{\SKV@prepto,\SKV@prepto*,\SKV@prepto*+}
This prepends \ang{content} to \ang{cs}. If \ang{cs} was previously undefined, it is initialized with \ang{content}. The star (\RedStar) sign directs \fx{\SKV@prepto} to expand \ang{content} once before prepending it to \ang{cs}. The plus (\RedPlus) sign means that \ang{cs} is a control sequence name instead of a control sequence, while the exclamation mark (\RedClam) instructs \fx{\SKV@prepto} to prepend \ang{content} to \ang{cs} globally (to escape local groups). This command is robust, but fragile arguments must be protected in expansion contexts.
Again, the following non-generic versions of \fx{\SKV@prepto} are available, but they don't have the starred (\RedStar) variants:
\begin{macro}
\preptomac|vang(cs){|vang(content)}
|tto \SKV@prepto|vang(cs){|vang(content)}
\gpreptomac|vang(cs){|vang(content)}
|tto \SKV@prepto|redclam|vang(cs){|vang(content)}
\cspreptomac{|vang(name)}{|vang(content)}
|tto \SKV@prepto|redplus{|vang(name)}{|vang(content)}
\csgpreptomac{|vang(name)}{|vang(content)}
|tto \SKV@prepto|redplus|redclam{|vang(name)}{|vang(content)}
\end{macro}
\acmdm*{\preptomac,\gpreptomac,\cspreptomac,\csgpreptomac}
\bigskip
\begin{macro}
\SKV@addtolist|redplus|redclam|redleft[|vang(parser)]|vang(csa)|vang(csb)
\end{macro}
\acmdm*{\SKV@addtolist,\SKV@addtolist+,\SKV@addtolist+<}
This adds the contents of the macro \ang{csb} to the list in the container \ang{csa}. The plus sign~(\RedPlus) means that \ang{csa} is a control sequence name (instead of a control sequence); the exclamation mark~(\RedClam) directs \fx{\SKV@addtolist} to add the contents of \ang{csb} to \ang{csa} globally (to escape local groups); and the left angle (\RedLeft), if present, instructs \fx{\SKV@addtolist} to prepend the contents of \ang{csb} to the left of the contents of \ang{csa}, instead of appending to the right by default. The optional argument \ang{parser} is the list parser, ie, the separator of the instances in \ang{csa}. Its default value is ``,'' (comma).
\macrosubsection{Package and document hooks}
\begin{macro}
\SKV@AtPackageEnd{|vang(code)}
\SKV@AtClassEnd{|vang(code)}
\end{macro}
\acmdm*{\SKV@AtPackageEnd,\SKV@AtClassEnd}
These are the robust versions of the well-known \latex hooks \acmd{\AtEndOfPackage} and \acmd{\AtEndOfClass}.
\begin{macro}
\SKV@BeforePackageEnd{|vang(code)} |label(befpkgend)
\SKV@BeforeClassEnd{|vang(code)} |label(befclsend)
\SKV@AfterPackageEnd{|vang(code)}
\SKV@AfterClassEnd{|vang(code)}
\end{macro}
\acmdm*{\SKV@BeforePackageEnd,\SKV@BeforeClassEnd,\SKV@AfterPackageEnd,
\SKV@AfterClassEnd}
The first two of these hook to just before \acmd{\AtEndOfPackage} or \acmd{\AtEndOfClass}; the third and fourth hook to just after \fx{\AtEndOfPackage} or \acmd{\AtEndOfClass}. They are all robust. These commands have been necessitated by some tasks in the \pkg{skeyval}, but may be useful in some other contexts.
\begin{macro}
\SKV@AtDocumentStart{|vang(code)}
\end{macro}
\acmdm*{\SKV@AtDocumentStart}
This is the robust version of the \latex hook \acmdm{\AtBeginDocument}. It can be used in expansion contexts without protection, but fragile arguments within it must be protected.
\begin{macro}
\SKV@BeforeDocumentStart{|vang(code)}|label(beforedocstart)
\SKV@AfterDocumentStart{|vang(code)}|label(afterdocstart)
\end{macro}
\acmdm*{\SKV@BeforeDocumentStart,\SKV@AfterDocumentStart}
These provide two more document hooks. They are both robust. The command \fx{\SKV@BeforeDocumentStart} differs from \fx{\AtBeginDocument} in that the former is executed right at
the end of the preamble, before the main auxiliary file (as written on the previous \latex
run) is read and prior to the execution of any \fx{\AtBeginDocument} code. It isn't possible
to write to the auxiliary file at the point \fx{\SKV@BeforeDocumentStart} is executed.
\fx{\SKV@AfterDocumentStart} differs from \fx{\AtBeginDocument} in the sense that the former is executed at the tag end of \acmd{\begin\{document\}}, after the execution of any \fx{\AtBeginDocument} code. Commands whose scope are restricted to the document's preamble with \acmd{\@onlypreamble} or \acmd{\SKV@onlypreamble} are no longer committable when \fx{\SKV@AfterDocumentStart} is being executed.
\begin{macro}
\SKV@AtDocumentEnd{|vang(code)}
\SKV@BeforeLastPage{|vang(code)}
\SKV@AfterLastPage{|vang(code)}
\SKV@AfterDocumentEnd{|vang(code)}
\end{macro}
\acmdm*{\SKV@AtDocumentEnd,\SKV@BeforeLastPage,\SKV@AfterLastPage,
\SKV@AfterDocumentEnd}
The last three of these are wrappers developed based on the \pkgm{atveryend}, which provides a consistent mechanism for \acmd{\enddocument} methods. The macro
\fx{\SKV@AtDocumentEnd} is the robust equivalent of \acmd{\AtEndDocument}. The macro \fx{\SKV@BeforeLastPage} appends \ang{code} after the \acmd{\@enddocumenthook} but before the last \acmd{\clearpage}, and thus before the last shipout. The command \fx{\SKV@AfterLastPage} executes \ang{code} after the last \acmd{\clearpage} invoked within \acmd{\enddocument}, \ie, after the last shipout but before the main auxiliary file is closed. This is, \eg, the right instance to record the last document page in the auxiliary file.
The command \fx{\SKV@AfterDocumentEnd} appends \ang{code} to the very end of the document, after all of the end-of-document codes have been executed (\ie, after the main .aux file of the current pass has been read and all \acmd{\AtEndDocument} codes have been effected, except font and label/reference warnings).
\macrosection{Inputting files}
\begin{macro}
\InputFileOnce[|vang(path)]{|vang(file)}
\InputFileOnce|redstar[|vang(path)]{|vang(file)}
\end{macro}
\acmdm*{\InputFileOnce}
The unstarred variant of this command inputs \ang{file} on \ang{path} but only once in one \latex pass. The argument \ang{path} is optional and its default value is the current/document's environment/directory. If \ang{file} had previously been read, a warning message is entered in the transcript log file (if the package option \acmd{verbose} is selected) and the input is aborted. If \ang{file} doesn't exist on \ang{path}, as many as desired opportunities are given to the user to type in the correct filename on the screen, or enter ``no'' to continue with the \latex pass without inputting the file.
If the user wants to input \ang{file} more than once in one document, then he should use the starred (\RedStar) variant of \fx{\InputFileOnce}.
\section{References}
All the \texorlatex packages cited in this guide are available on \ctan.
\section{Version history}
\label{sec:version-hist}
The following change history highlights significant changes that affect user utilities and interfaces; mutations of technical nature are not documented in this section. The numbers on the right-hand side of the following lists are section numbers; the star sign (\RedStar) means the subject features in the package but is not reflected anywhere in this user guide.
\begin{versionhist}
\begin{version}{0.1}{2010/01/01}
\item First public release under the name \pkg{keyreader}\xsecref
\item Introduced complementary native-boolean keys \secref{sec:comp-boolkeys}
\item Provided machinery for reading multiple keys of all kinds from just one command \secref{sec:def-multiple-keys}
\end{version}
\begin{version}{0.2}{2010/01/10}
\item Fixed a bug and optimized the \acmd{\define@keylist} loop \secref{sec:def-multiple-keys}
\end{version}
\begin{version}{0.3}{2010/01/20}
\item Introduced toggles and toggle-boolean keys \secref{sec:toggles}
\end{version}
\begin{version}{0.4}{2010/02/01}
\item Introduced complementary toggle-boolean keys \secref{sec:comptogkeys}
\end{version}
\begin{version}{0.5}{2010/02/23}
\item Changed the name of the package from \pkg{keyreader} to \pkg{skeyval}\xsecref
\item Introduced the following macros\secref{sec:status-keys}
\begin{veritem}
\ifkeydefined, \ifkeyreserved, \ifkeysuspended
\end{veritem}
\acmd*{\ifkeydefined,\ifkeyreserved,\ifkeysuspended}
\item Provided the following facilities \secref{sec:avoiding-redef}
\begin{veritem}
\newordkey, \newcmdkey, \newboolkey, \newchoicekey,
\newtogkey, \define@biboolkeys, \newbiboolkeys,
\define@bitogkeys, \newbitogkeys, \define@uniboolkeys,
\newuniboolkeys, \define@unitogkeys, \newunitogkeys,
\define@biuniboolkeys, \newbiuniboolkeys,
\define@biunitogkeys, \newbiunitogkeys
\end{veritem}
\acmd*{\newordkey,\newcmdkey,\newboolkey,\newchoicekey,\newtogkey,
\define@biboolkeys,\newbiboolkeys,\define@bitogkeys,\newbitogkeys,
\define@uniboolkeys,\newuniboolkeys,\define@unitogkeys,\newunitogkeys,
\define@biuniboolkeys,\newbiuniboolkeys,\define@biunitogkeys,\newbiunitogkeys}
\item Provided mechanisms for disabling, localizing, reserving, unreserving, suspending, restoring, and removing keys \secref{sec:disable-reserv-keys}
\item Redefined a few of \pkg{xkeyval}'s internal macros \xsecref
\item Normalization of key-value lists before parsing \secref{sec:list-normal}
\item Included some developer macros \secref{sec:misce-commands}
\end{version}
\begin{version}{0.6}{2010/03/30}
\item Modified the mechanics of the internal macros of the following \secref{sec:reserve-keys}
\begin{veritem}
\ReserveKeyPrefixNames, \ReserveKeyPrefixNames|redstar,
\ReserveMacroPrefixNames, \ReserveMacroPrefixNames|redstar,
\ReserveFamilyNames, \ReserveFamilyNames|redstar
\end{veritem}
\acmd*{\ReserveKeyPrefixNames,\ReserveMacroPrefixNames,\ReserveFamilyNames,
\ReserveKeyPrefixNames*,\ReserveMacroPrefixNames*,\ReserveFamilyNames*}
\item Introduced the following macros \secref{sec:misce-commands}
\begin{veritem}
\SKV@AtPackageEnd, \SKV@BeforePackageEnd,
\SKV@AfterPackageEnd, \SKV@AtDocumentEnd,
\SKV@BeforeLastPage, \SKV@AfterLastPage,
\SKV@AfterDocumentEnd, \SKV@onlypreamble,
\SKV@onlypackage, \SKV@ifdraft, \SKV@iffinal,
\SKV@ifpdf, \@ensurepackageloaded, \InputFileOnce,
\newswitch, \defswitch, etc.
\end{veritem}
\acmd*{\SKV@AtPackageEnd,\SKV@BeforePackageEnd,\SKV@AfterPackageEnd,
\SKV@AtDocumentEnd,\SKV@BeforeLastPage,\SKV@AfterLastPage,\InputFileOnce,
\SKV@AfterDocumentEnd,\SKV@onlypreamble,\SKV@ifdraft,\SKV@iffinal,\SKV@ifpdf,
\@ensurepackageloaded}
\item Alert the user if \pkg{skeyval} is loaded before \acmd{\documentclass} \secref{sec:loading-package}
\item Introduced ``user-value'' keys \secref{sec:uservaluekeys}
\item Extended the pointer system of the \pkg{xkeyval} \secref{sec:pointer-mech}
\item Corrected a bug in the \pkg{xkeyval} which, if \acmd{\setkeys} is nested in a class file, gives non-empty \acmdm{\@unusedoptionlist} even if all the options of \acmd{\documentclass} have been used \xsecref
\end{version}
\begin{version}{0.7}{2010/05/05}
\item Native-boolean and toggle-boolean keys now accept \fx{on} and \fx{off} as values,
in addition to \fx{true} and \fx{false} \secref*{sec:toggle-booleans}{sec:switches}
\item Replaced the former \acmd{\NewIfs} with \acmd{\NewBooleans} and redefined \fx{\NewIfs} \secref{sec:biboolkeys}
\item Introduced \acmd{\DeclareKeyCommand} \xsecref
\end{version}
\begin{version}{0.71}{2010/05/06}
\item Corrected a bug in one of the internal conditional tests \xsecref
\item Removed \fx{\DeclareKeyCommand} to create a separate \pkg{skeycommand} \xsecref
\end{version}
\begin{version}{0.72}{2010/05/21}
\item The parameter character is made temporarily innocent when the arguments of \fx{\define@keylist} and \fx{\newkeylist} are being absorbed \secref{sec:def-multiple-keys}
\item Debugged why, \eg, \fx{#1} in the following definition would refer to the wrong quantity in the \pkg{xkeyval}:
\xsecref
\begin{veritem}
\define@boolkey[KV]{fam}[mp@]{keya}[true]{\def\x{#1}}
\end{veritem}
\end{version}
\end{versionhist}
\newpage
\IndexPreamble{Index numbers refer to page numbers.}
\IndexPreambleFormat{\centering}
\IndexColumns\tw@
\printindex
\end{document}
%%% End of file skeyval-guide.tex %%%
|