fattr.tex.pairs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. % font set Computer Modern, Latin Modern, Bera
  2. % font family CMRoman, CMTypewriter, CMSansSerif
  3. %
  4. % font feature slant, weight, width
  5. % font attribute sl, it, bold, cond
  6. %
  7. % fontfile
  8. %
  9. % Font features and attributes:
  10. %
  11. % size design point size
  12. % encoding ot1, oml, oms, omx, t1, ts1, t2a
  13. % slant up, sl, it, ui, cursive
  14. % weight lt, med, semib, bold, bx,
  15. % width cond, normal, ext
  16. % figures oldfigures, liningfigures
  17. % caps normalcaps, allcaps, smallcaps, nocaps
  18. \input eplain
  19. \catcode`@=11
  20. %
  21. % \fsz:CMRoman/<OT1>/<up>/<med>/<normal>/<liningfigures>/<normalcaps>
  22. % ->
  23. % cmr5/5,cmr7/7,cmr8/8,cmr9/9,cmr10/10,cmr12/12,cmr17/17,.
  24. %
  25. % {CMRoman}{b}{bx}
  26. % {OML,CMRoman}{m}{up}
  27. % {OML,CMRoman}{bx}{up}
  28. % {OML,CMRoman}{b}{bx}
  29. % {CMSans}{it}{sl}
  30. % {CMSans}{b}{bx}
  31. % {CMSans,OML}{}{CMRoman}
  32. % {ConcreteRoman}{b}{LMSans,b}
  33. % {OT1,CMMath}{}{CMRoman,n}
  34. % {OMX,CMMath}{bx}{m}
  35. %
  36. %
  37. %
  38. %
  39. % Font-related logging. Meanings of \ftracelevel values are:
  40. %
  41. % 0 - none
  42. % 1 - warning
  43. % 2 - debug
  44. % 3 - verbose
  45. \newcount\ftracelevel
  46. \ftracelevel=1
  47. %
  48. \def\f@warning{\f@trace0 }%
  49. \def\f@debug {\f@trace1 }%
  50. \def\f@verbose{\f@trace2 }%
  51. \def\f@trace#1{%
  52. \ifnum#1<\ftracelevel
  53. \expandafter\message
  54. \else
  55. \expandafter\gobble
  56. \fi
  57. }%
  58. %
  59. %
  60. %
  61. % Construction of font filter strings.
  62. %
  63. % \fontsubstpre{MATCH-ATTR}{REM-FEATURES}{ADD-OR-MOD-ATTRS}
  64. %
  65. % Install a new font substitution to be applied before other font
  66. % substitutions.
  67. \def\fontsubstpre{%
  68. \let\fontsubst@mklist\fontsubst@pre
  69. \@fontsubst
  70. }%
  71. %
  72. % \fontsubstpost{MATCH-ATTR}{REM-FEATURES}{ADD-OR-MOD-ATTRS}
  73. %
  74. % Install a new font substitution to be applied after other font
  75. % substitutions.
  76. \def\fontsubstpost{%
  77. \let\fontsubst@mklist\fontsubst@post
  78. \@fontsubst
  79. }%
  80. %
  81. % \@fontsubst{MATCH-ATTR}{REM-FEATURES}{ADD-OR-MOD-ATTRS}
  82. \def\@fontsubst{%
  83. % Construct the match string in \fontsubst@match@list.
  84. \f@mk@falist\fontsubst@\fontsubst@match@list%{MATCH-ATTR}
  85. }%
  86. %
  87. % \fontsubst@{REM-FEATURES}{ADD-OR-MOD-ATTRS}
  88. \def\fontsubst@{%
  89. % Construct the rem string in \fontsubst@rem@list.
  90. \f@mk@flist\fontsubst@@\fontsubst@rem@list%{REM-FEATURES}
  91. }%
  92. %
  93. % \fontsubst@{ADD-OR-MOD-ATTRS}
  94. \def\fontsubst@@{%
  95. % Construct the add string in \fontsubst@add@list.
  96. \f@mk@falist\fontsubst@fin\fontsubst@add@list%{ADD-OR-MOD-ATTRS}
  97. }%
  98. %
  99. \def\fontsubst@fin{%
  100. % Add the new substitution to either head or tail of the current
  101. % substitution list.
  102. \let\@end\relax
  103. \edef\f@subst@list{\fontsubst@mklist}%
  104. }%
  105. %
  106. \def\fontsubst@pre{%
  107. \fontsubst@match@list \@end
  108. \fontsubst@rem@list \@end
  109. \fontsubst@add@list \@end
  110. \f@subst@list
  111. }%
  112. %
  113. \def\fontsubst@post{%
  114. \f@subst@list
  115. \fontsubst@match@list \@end
  116. \fontsubst@rem@list \@end
  117. \fontsubst@add@list \@end
  118. }%
  119. %
  120. % Initialize the font substitution list to empty.
  121. \let\f@subst@list\empty
  122. %
  123. % Given the name of an attribute, return index of the attribute
  124. % in \tempa and index of the attribute's feature in \tempb.
  125. \def\f@get@af#1{%
  126. % Get attribute's index.
  127. \expandafter\let\expandafter\tempa\csname fa:#1\endcsname
  128. \ifx\tempa\relax
  129. \errmessage{Undefined font attribute `#1'}%
  130. \fi
  131. % Get feature index for the attribute.
  132. \expandafter\let\expandafter\tempb\csname faf:#1\endcsname
  133. \ifx\tempb\relax
  134. \errmessage{Undefined font attribute `#1'}%
  135. \fi
  136. }%
  137. %
  138. % Given a comma-separated list of attributes #3, construct a string
  139. % (saving it in macro #2) as a sequence of `F.A,' specs, where F is
  140. % the index of the feature to which attribute belongs, and A is the
  141. % index of the attribute. After that, call #1.
  142. \def\f@mk@falist#1#2#3{%
  143. \let#2\empty % Start with a clean slate.
  144. \let\do\relax
  145. \for\f@i:=#3\do{%
  146. \f@get@af\f@i
  147. \edef#2{#2\do\tempb.\tempa,}% Append the spec to the list.
  148. }%
  149. #1%
  150. }%
  151. %
  152. % Given a comma-separated list of features #3, construct a string
  153. % (saving it in macro #2) as a sequence of `F,' specs, where F is the
  154. % feature index. After that, call #1.
  155. \def\f@mk@flist#1#2#3{%
  156. \let#2\empty
  157. \let\do\relax
  158. \for\f@i:=#3\do{%
  159. \expandafter\let\expandafter\temp\csname ff:\f@i\endcsname
  160. \ifx\temp\relax
  161. \errmessage{Undefined font feature `\f@i'}%
  162. \fi
  163. \edef#2{#2\do\temp,}%
  164. }%
  165. #1%
  166. }%
  167. %
  168. % \fori{FROM-INCL}{TO-EXCL}{EXEC}
  169. \def\fori#1#2#3{%
  170. \count@=#1\relax
  171. \loop
  172. #3\relax
  173. \advance\count@ by1
  174. \ifnum\count@<#2\repeat
  175. }%
  176. %
  177. %
  178. %
  179. % Font feature manipulations.
  180. %
  181. % \setfont{ATTRS}
  182. \def\setfont{%
  183. % Empty \ff0, \ff1, ..., \ff<ffeature_count - 1>.
  184. \ff@reset
  185. \addfontattrs % Substitutes and sets the font.
  186. }%
  187. %
  188. % \modfont{REM-FEATURES}{ADD-OR-MOD-ATTRS}
  189. \def\modfont#1{%
  190. \unsetfontfeatures{#1}%
  191. \addfontattrs % Substitutes and sets the font.
  192. }%
  193. %
  194. % \addfontattrs{ADD-OR-MOD-ATTRS}
  195. \def\addfontattrs#1{%
  196. % For each feature with attribute in #1, set \ff<f> to <a>, where
  197. % <f> is the feature index and <a> is the attribute index.
  198. \for\f@i:=#1\do{%
  199. \f@get@af\f@i
  200. \expandafter\let\csname ff\tempb\endcsname \tempa
  201. }%
  202. % Substitute the font.
  203. \f@subst
  204. % Set the font, if we've found one.
  205. }%
  206. %
  207. % \remfontfeatures{REM-FEATURES}
  208. \def\remfontfeatures#1{%
  209. \unsetfontfeatures{#1}%
  210. % Substitute the font.
  211. \f@subst
  212. % Set the font, if we've found one.
  213. }%
  214. %
  215. \def\unsetfontfeatures#1{%
  216. % Unset \ff<f> for each feature <f> in #1.
  217. \for\f@i:=#1\do{%
  218. \expandafter\let\expandafter\temp\csname ff:\f@i\endcsname
  219. \ifx\temp\relax
  220. \errmessage{Undefined font feature `\f@i'}%
  221. \fi
  222. \expandafter\let \csname ff\temp\endcsname \empty
  223. }%
  224. }%
  225. %
  226. % Pretty-print the current settings of font features.
  227. \def\dumpfontfeatures{%
  228. \def\fa@{}% This will be used for features which are not set,
  229. % for which \ffN is \empty.
  230. \message{^^JCurrent font features: (}%
  231. \fori0\ffeatcount{\message{%
  232. \csname ff@\the\count@\endcsname.%
  233. \expandafter\dump@ff\expandafter{\csname ff\the\count@\endcsname}}}%
  234. \message{)}%
  235. }%
  236. \def\dump@ff#1{\csname fa@#1\endcsname}%
  237. %
  238. %
  239. %
  240. % Generic filter parsing macros. Configure by defining these
  241. % callbacks (before running \f@run@filter on the filter string):
  242. %
  243. % \f@do@filter@match#1.#2, - match the pair filter/attribute
  244. % \f@do@filter@rem - unset feature `F,'
  245. % \f@do@filter@add - add the pair `F.A,'
  246. % \f@end@filter@add - action at the end of the filter.
  247. %
  248. % We could avoid adding font feature together with an attribute and
  249. % use a construct like \csname ff@\csname faf:A\endcsname\endcsname
  250. % to get the feature corresponding to attribute A. But this would
  251. % fail with an incomprehensible error message (`missing \endcsname')
  252. % if \csname faf:A\endcsname is undefined, so we'd have to test this
  253. % before each use. To avoid the overhead, we just add the font
  254. % feature index to the font filter.
  255. %
  256. % \f@run@filter
  257. % [MATCH-ATTR\@end REM-FEATURES\@end ADD-OR-MOD-ATTRS\@end [...]]\relax
  258. \def\f@run@filter{%
  259. \let\do\f@do@filter@match
  260. \let\@end\f@run@filter@rem
  261. }%
  262. \def\f@run@filter@again{\f@verbose{^^J)}\f@run@filter}%
  263. %
  264. % \f@run@filter@rem REM-FEATURES\@end ADD-OR-MOD-ATTRS\@end ... \relax
  265. \def\f@run@filter@rem{%
  266. \let\do\f@do@filter@rem
  267. \let\@end\f@run@filter@add
  268. }%
  269. %
  270. % \f@run@filter@add ADD-OR-MOD-ATTRS\@end ... \relax
  271. \def\f@run@filter@add{%
  272. \let\do\f@do@filter@add
  273. \let\@end\f@end@filter@add
  274. }%
  275. %
  276. \def\f@filter@gobble@this#1\@end#2\@end#3\@end{\f@run@filter@again}%
  277. \def\f@filter@gobble@all#1\relax{}%
  278. %
  279. %
  280. %
  281. % Filter parsing callbacks for font substitution.
  282. %
  283. % Apply only the first font substitution matching the current font.
  284. \def\f@subst@once{%
  285. \let\f@do@filter@match\f@subst@match@init
  286. \let\f@do@filter@rem\f@subst@rem
  287. \let\f@do@filter@add\f@subst@add
  288. \let\f@end@filter@add\f@subst@nomore
  289. \expandafter\f@run@filter \f@subst@list \relax
  290. }%
  291. %
  292. % Apply all font substitutions in order, allowing substitutions to be
  293. % chained.
  294. \def\f@subst{%
  295. \let\f@do@filter@match\f@subst@match@init
  296. \let\f@do@filter@rem\f@subst@rem
  297. \let\f@do@filter@add\f@subst@add
  298. \let\f@end@filter@add\f@run@filter@again
  299. \expandafter\f@run@filter \f@subst@list \relax
  300. }%
  301. %
  302. % Match one feature.
  303. \def\f@subst@match@init{%
  304. \f@verbose{^^J(}%
  305. \let\do\f@subst@match
  306. \do
  307. }%
  308. %
  309. \def\f@subst@match#1.#2,{%
  310. \f@verbose{^^Jmatching \csname ff@#1\endcsname.\csname fa@#2\endcsname}%
  311. % This funky way to compare the two numbers takes care of \ff#1
  312. % being \empty. However, keep in mind that if \ff#1 is undefined,
  313. % the following will make it a \relax.
  314. \ifnum 1#2=1\csname ff#1\endcsname \else
  315. \f@verbose{^^J skipping unmatched
  316. \csname ff@#1\endcsname.\csname fa@#2\endcsname}%
  317. \expandafter\f@filter@gobble@this % Skip to the next filter.
  318. \fi
  319. }%
  320. %
  321. % Remove one feature.
  322. \def\f@subst@rem#1,{%
  323. \f@verbose{^^Junsetting \csname ff@#1\endcsname}%
  324. \expandafter\let\csname ff#1\endcsname \empty
  325. }%
  326. %
  327. % Add attribute #2 (which must belong to feature #1).
  328. \def\f@subst@add#1.#2,{%
  329. \f@verbose{^^Jadding \csname ff@#1\endcsname.\csname fa@#2\endcsname}%
  330. \expandafter\def\csname ff#1\endcsname{#2}%
  331. }%
  332. %
  333. \def\f@subst@nomore{\f@verbose{^^J)}\f@filter@gobble@all}%
  334. %
  335. %
  336. %
  337. % Filter parsing callbacks for pretty-printing the current font filter
  338. % string.
  339. %
  340. %\def\dumpfontfilter{%
  341. %}%
  342. % Pretty-print the current font filter string.
  343. \def\dumpfontfilter{\f@dump@filter\f@subst@list}%
  344. %
  345. % Pretty-print the given font filter string.
  346. \def\f@dump@filter#1{%
  347. \message{^^J(}%
  348. \let\do\space
  349. \expandafter\f@dump@filter@#1\relax
  350. }%
  351. %
  352. \def\f@dump@filter@#1\@end#2\@end#3\@end#4\relax{%
  353. \message{^^J=#1^^J-#2^^J+#3^^J}%
  354. \def\temp{#4}%
  355. \ifx\temp\empty
  356. \message{^^J)}%
  357. \expandafter\f@filter@gobble@all
  358. \else
  359. \expandafter\f@dump@filter@
  360. \fi
  361. #4\relax
  362. }%
  363. %
  364. %
  365. %
  366. % Defining new font features.
  367. %
  368. \newcount\fcacheidx % Font cache index.
  369. \newcount\ffeatcount % Font feature count.
  370. \let\ff@reset\empty % We'll build this up as we add font features.
  371. %
  372. % \newfontattr FONTFEATURE FONTATTR
  373. \def\newfontattr #1 #2 {%
  374. % Define a new font attribute, if it's not defined yet.
  375. \expandafter\ifx\csname fa:#2\endcsname \relax
  376. \else
  377. \errmessage{Font attribute `#2' already defined as part
  378. of font feature `\csname ff@\csname faf:#2\endcsname\endcsname'}%
  379. \fi
  380. \expandafter\xdef\csname fa:#2\endcsname{\the\fcacheidx}%
  381. \expandafter\xdef\csname fa@\the\fcacheidx\endcsname{#2}%
  382. % Invalidate current font cache (and update index for the next font
  383. % attribute).
  384. \global\advance\fcacheidx by1
  385. %
  386. % Define a new font feature, if it's not defined yet.
  387. \expandafter\ifx\csname ff:#1\endcsname \relax
  388. \expandafter\xdef\csname ff:#1\endcsname{\the\ffeatcount}%
  389. \expandafter\xdef\csname ff@\the\ffeatcount\endcsname{#1}%
  390. % Update \ff@reset to clear the new font feature cell \ffN.
  391. \toks@=\expandafter{\ff@reset}%
  392. \xdef\ff@reset{\the\toks@
  393. \let\expandafter\noexpand\csname ff\the\ffeatcount\endcsname
  394. \noexpand\empty}%
  395. % Set \ffN to \empty, otherwise it will be set to \relax the first
  396. % time we try to access it through \csname...\endcsname, and we
  397. % depend on it to be either a number or \empty.
  398. \global\expandafter\let\csname ff\the\ffeatcount\endcsname \empty
  399. %
  400. \global\advance\ffeatcount by1
  401. % We've added a new font feature, so we should invalidate current
  402. % font cache. But we've already done so above when adding the new
  403. % font attribute.
  404. %\global\advance\fcacheidx by1
  405. \fi
  406. % Assign the font attribute to the font feature.
  407. \expandafter\xdef\csname faf:#2\endcsname{\csname ff:#1\endcsname}%
  408. }%
  409. %
  410. % \newfontfamily FONTSET FONTFAMILY
  411. \def\newfontfamily #1 #2 {%
  412. \f@def{fset}{#1}{ffam}{#2}{Font family}%
  413. \f@defadd{fset:#1}{#2}%
  414. }%
  415. %
  416. % \f@def {PARENT-PREFIX} {PARENT-NAME} {CHILD-PREFIX} {CHILD-NAME} {CHILD-DESCR}
  417. \def\f@def#1#2#3#4#5{%
  418. % Define parent.
  419. \expandafter\gdef\csname #1:#2\endcsname
  420. \expandafter\ifx\csname#1:#2\endcsname\relax
  421. \expandafter\gdef\csname#1:#2\endcsname{}%
  422. \else
  423. \let\do\space
  424. \errmessage{#3 #2 already defined as `\csname#1:#2\endcsname'}%
  425. \fi
  426. }%
  427. \ftracelevel=3
  428. \newfontattr family CMRoman
  429. \newfontattr family CMTypewriter
  430. \newfontattr family CMSansSerif
  431. \newfontattr encoding OT1
  432. \newfontattr encoding OML
  433. \newfontattr encoding OMS
  434. \newfontattr encoding OMX
  435. \newfontattr slant up
  436. \newfontattr slant sl
  437. \newfontattr slant it
  438. \newfontattr slant ui
  439. %\expandafter\def\csname ff:family\endcsname{0}%
  440. %\expandafter\def\csname ff:encoding\endcsname{1}%
  441. %\expandafter\def\csname ff:slant\endcsname{2}%
  442. %
  443. %\expandafter\def\csname fa:CMRoman\endcsname{0}%
  444. %\expandafter\def\csname fa:CMTypewriter\endcsname{1}%
  445. %\expandafter\def\csname fa:CMSansSerif\endcsname{2}%
  446. %
  447. %\expandafter\def\csname fa:OT1\endcsname{3}%
  448. %\expandafter\def\csname fa:OML\endcsname{4}%
  449. %\expandafter\def\csname fa:OMS\endcsname{5}%
  450. %\expandafter\def\csname fa:OMX\endcsname{6}%
  451. %
  452. %\expandafter\def\csname fa:up\endcsname{7}%
  453. %\expandafter\def\csname fa:sl\endcsname{8}%
  454. %\expandafter\def\csname fa:it\endcsname{9}%
  455. %\expandafter\def\csname fa:ui\endcsname{10}%
  456. %
  457. %\ffeatcount=3
  458. %\fattrcount=11
  459. %
  460. %\expandafter\def\csname faf:CMRoman\endcsname{0}%
  461. %\expandafter\def\csname faf:CMTypewriter\endcsname{0}%
  462. %\expandafter\def\csname faf:CMSansSerif\endcsname{0}%
  463. %
  464. %\expandafter\def\csname faf:OT1\endcsname{1}%
  465. %\expandafter\def\csname faf:OML\endcsname{1}%
  466. %\expandafter\def\csname faf:OMS\endcsname{1}%
  467. %\expandafter\def\csname faf:OMX\endcsname{1}%
  468. %
  469. %\expandafter\def\csname faf:up\endcsname{2}%
  470. %\expandafter\def\csname faf:sl\endcsname{2}%
  471. %\expandafter\def\csname faf:it\endcsname{2}%
  472. %\expandafter\def\csname faf:ui\endcsname{2}%
  473. \let\do\relax
  474. \fontsubstpre{CMRoman}{slant}{OT1}
  475. \message{^^J\f@subst@list}
  476. \fontsubstpre{up}{}{CMRoman,OML}
  477. \message{^^J\f@subst@list}
  478. \fontsubstpost{CMSansSerif}{}{OMX}
  479. \message{^^J\f@subst@list}
  480. \fontsubstpost{CMTypewriter}{encoding}{}
  481. \message{^^J\f@subst@list}
  482. \fontsubstpost{CMRoman,up,OML}{slant}{OT1}
  483. \message{^^J\f@subst@list}
  484. \fontsubstpre{it,CMTypewriter,OMX}{family,encoding}{OT1}
  485. \message{^^J\f@subst@list}
  486. \fontsubstpost{it,CMTypewriter,OMX}{encoding,family}{ui,OMS}
  487. \message{^^J\f@subst@list}
  488. % 0.0, 2.9, 1.5
  489. \setfont{CMRoman,it,OMS}% -> , 4, 9
  490. \dumpfontfeatures
  491. % 0.1, 2.9, 1.5
  492. %\setfont{CMTypewriter,it,OMS}% -> 1, , 9
  493. %% 0.2, 2.9, 1.5
  494. %\setfont{CMSansSerif,it,OMS}% -> 2, 6, 9
  495. %% 0.1, 2.9, 1.6
  496. %\setfont{CMTypewriter,it,OMX}% -> , 5, 10
  497. %% 0.0, 2.7, 1.3
  498. %\setfont{CMRoman,up,OT1}% -> , 4, 7
  499. % 0.0, 2.7, 1.4
  500. %\setfont{CMRoman,up,OML}% -> 0, 3,
  501. \dumpfontfilter
  502. %% 0.0, 2.9, 1.4
  503. %\setfont{CMRoman,it,OML}% -> , 4, 9
  504. %\dumpffs
  505. %\modfont{}{CMTypewriter}% -> 1, 4, 9 -> 1, , 9
  506. %\dumpffs
  507. %\modfont{slant}{ui,CMSansSerif}% -> 2, , 10 ->
  508. %\dumpffs
  509. \bye
  510. % \setfont{CMRoman,b,sl}
  511. % \modfont{}{up} % CMRoman,b,up
  512. \def\test{ii,iv,iii,i}
  513. \def\i{0}
  514. \def\ii{1}
  515. \def\iii{2}
  516. \def\iv{3}
  517. \count0=2147483647
  518. \count@=-1
  519. % \f@sort{MAX-ITEM-IDX}{ITEMS}{ITEM-CS-PREFIX}
  520. \def\f@sort#1#2#3{%
  521. \let\f@sorted\empty
  522. % Empty \f@sort0, \f@sort1, ..., \f@sort<MAX-ITEM-IDX>.
  523. \fori{0}{#1}{\expandafter\let\csname f@sort\the\count@\endcsname \empty}%
  524. % Set \f@sort<X>, where <X> is the value of \<ITEM-CS-PREFIX><ITEM>.
  525. \for\f@sort@i:=#2\do{%
  526. \expandafter\edef\csname f@sort\csname#3\f@sort@i\endcsname\endcsname{%
  527. \csname \f@sort@i\endcsname,%
  528. }%
  529. }%
  530. % Combine all \f@sort<X> into \f@sorted.
  531. \fori{0}{#1}{%
  532. \edef\f@sorted{%
  533. \f@sorted
  534. \csname f@sort\the\count@\endcsname
  535. }%
  536. }%
  537. }%
  538. \f@sort{4}{\test}{}
  539. \show\f@sorted
  540. \bye
  541. % \f@def {PREFIX} {NAME} {DESCR}
  542. \f@def#1#2#3{%
  543. \expandafter\ifx\csname#1:#2\endcsname\relax
  544. \expandafter\gdef\csname#1:#2\endcsname{}%
  545. \else
  546. \let\do\space
  547. \errmessage{#3 #2 already defined as `\csname#1:#2\endcsname'}%
  548. \fi
  549. }%
  550. % \f@defadd {PARENT} {CHILD}
  551. \f@defadd#1#2{%
  552. \let\do\relax
  553. \expandafter\edef\expandafter\temp\expandafter{%
  554. \csname #1\endcsname \do #2}%
  555. \global\expandafter\let\csname #1\endcsname \temp
  556. }%
  557. % \newfontset FONTSET
  558. \def\newfontset #1 {%
  559. \f@def{fset}{#1}{Font set}
  560. }%
  561. % \newfontfamily FONTSET FONTFAMILY
  562. \def\newfontfamily #1 #2 {%
  563. \f@def{ffam}{#2}{Font family}%
  564. \f@defadd{fset:#1}{#2}%
  565. }%
  566. % \newfontfeature FONTFEATURE
  567. \def\newfontfeature #1 {%
  568. \f@def{ff}{#1}{Font feature}%
  569. }%
  570. % \newfontattr FONTFEATURE FONTATTR
  571. \def\newfontattr #1 #2 {%
  572. \f@def{fa}{#2}{Font attribute}%
  573. \f@defadd{ff:#1}{#2}%
  574. }%
  575. % \newfont FONTFAMILY SIZE ENCODING ATTRIBUTES
  576. \def\newfont #1 #2 #3 #4 {%
  577. }%
  578. \def\f@addattrchar#1#2{%
  579. \bgroup
  580. \uccode`a=#2%
  581. \uppercase{%
  582. \egroup
  583. \xdef#1{a#1}%
  584. }%
  585. }%
  586. \def\fori#1#2#3{%
  587. \count@=#1\relax
  588. \loop
  589. #3\relax
  590. \advance\count@ by1
  591. \ifnum\count@<#2\repeat
  592. }%
  593. \def\f@resetattrs#1{%
  594. \gdef#1{fa:}%
  595. \fori{0}{20}{\f@addattrchar#1{`\*}}%
  596. }%
  597. \newcount\numfontfeatures
  598. \f@resetattrs\f@attributes
  599. \show\f@attributes
  600. \bye