%D \module %D [ file=core-fld, %D version=1997.05.18, %D title=\CONTEXT\ Core Macros, %D subtitle=Fill in fields, %D author=Hans Hagen, %D date=\currentdate, %D copyright={PRAGMA / Hans Hagen \& Ton Otten}] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. % \appendtocommalist versus \addtocommalist % % * as default trigger in radiofields ? % % beware: weblink plugin truncates on length, while save as doesn't; % more precise: (1) first time right string is sent, (2) % internal string truncated, (3) second time truncated % string is sent. \writestatus{loading}{Context Field Macros} % messages \definemessageconstant{fields} \unprotect %D First we hook fields into the (viewer based) layering mechanism %D (implemented as properties). \ifx\currentlayerproperty\undefined\else \let\currentlayerproperty\empty\fi \appendtoks \doif\@@iafieldlayer\v!auto {\def\@@iafieldlayer{\currentlayerproperty}}% \to \everysetupinteraction \setupinteraction [\c!fieldlayer=\v!auto] % auto by default %D Internal command, linked to \type{\definesymbol}. \def\dogetfieldsymbol#1% {\getobject{SYM}{#1}} \def\dopresetfieldsymbol#1% {\checkobjectreferences \doifobjectfoundelse{SYM}{#1} {} {\settightobject{SYM}{#1}\hbox{\symbol[#1]}% \flushatshipout {\setbox0\hbox{\hskip-\maxdimen\getobject{SYM}{#1}}% \smashbox0\box0}}} \def\presetfieldsymbols[#1]% slow {\def\dopresetfieldsymbols##1% {\processcommalist[##1]\dopresetfieldsymbol}% \@EA\processcommalist\@EA[#1]\dopresetfieldsymbols} \def\definedefaultsymbols {\definesymbol[defaultyes][$\times$]% \definesymbol[defaultno][$\cdot$]} \def\resetfieldsymbol[#1]% for experimental usage only {\resetobject{SYM}{#1}} %D The interface to the specials. DEFAULT NOG ANDERS \def\preparefieldvariables % evt \def's at the outer level (test) or \edef's here for fast testing {\let\@@DriverFieldNumber \@@fdn \let\@@DriverFieldStyle \@@fdstyle \let\@@DriverFieldColor \@@fdcolor \let\@@DriverFieldBackgroundColor\@@fdfieldbackgroundcolor \let\@@DriverFieldFrameColor \@@fdfieldframecolor \let\@@DriverFieldLayer \@@fdfieldlayer \let\@@DriverFieldOption \@@fdoption \let\@@DriverFieldAlign \@@fdalign \let\@@DriverFieldClickIn \@@fdclickin \let\@@DriverFieldClickOut \@@fdclickout \let\@@DriverFieldRegionIn \@@fdregionin \let\@@DriverFieldRegionOut \@@fdregionout \let\@@DriverFieldAfterKey \@@fdafterkey \let\@@DriverFieldFormat \@@fdformat \let\@@DriverFieldValidate \@@fdvalidate \let\@@DriverFieldCalculate \@@fdcalculate \let\@@DriverFieldFocusIn \@@fdfocusin \let\@@DriverFieldFocusOut \@@fdfocusout} % todo : remove arguments, consider DriverField a namespace \def\presetlinefield {\preparefieldvariables \dopresetlinefield {\@@DriverFieldName} {\@@DriverFieldWidth} {\@@DriverFieldHeight} {\@@DriverFieldDefault} {\@@DriverFieldNumber} {\@@DriverFieldStyle,\@@DriverFieldColor,\@@DriverFieldBackgroundColor,\@@DriverFieldFrameColor} {\@@DriverFieldOption} {\@@DriverFieldAlign} {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,% \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,% \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}} \def\presettextfield {\preparefieldvariables \dopresettextfield {\@@DriverFieldName} {\@@DriverFieldWidth} {\@@DriverFieldHeight} {\@@DriverFieldDefault} {\@@DriverFieldNumber} {\@@DriverFieldStyle,\@@DriverFieldColor,\@@DriverFieldBackgroundColor,\@@DriverFieldFrameColor} {\@@DriverFieldOption} {\@@DriverFieldAlign} {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,% \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,% \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}} \def\presetchoicefield {\preparefieldvariables \dopresetchoicefield {\@@DriverFieldName} {\@@DriverFieldWidth} {\@@DriverFieldHeight} {\@@DriverFieldDefault} {\@@DriverFieldStyle,\@@DriverFieldColor,\@@DriverFieldBackgroundColor,\@@DriverFieldFrameColor} {\@@DriverFieldOption} {\@@DriverFieldValues} {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,% \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,% \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}} \def\presetpopupfield {\preparefieldvariables \dopresetpopupfield {\@@DriverFieldName} {\@@DriverFieldWidth} {\@@DriverFieldHeight} {\@@DriverFieldDefault} {\@@DriverFieldStyle,\@@DriverFieldColor,\@@DriverFieldBackgroundColor,\@@DriverFieldFrameColor} {\@@DriverFieldOption} {\@@DriverFieldValues} {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,% \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,% \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}} \def\presetcombofield {\preparefieldvariables \dopresetcombofield {\@@DriverFieldName} {\@@DriverFieldWidth} {\@@DriverFieldHeight} {\@@DriverFieldDefault} {\@@DriverFieldStyle,\@@DriverFieldColor,\@@DriverFieldBackgroundColor,\@@DriverFieldFrameColor} {\@@DriverFieldOption} {\@@DriverFieldValues} {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,% \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,% \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}} \def\presetcheckfield {\preparefieldvariables \presetfieldsymbols[\@@DriverFieldValues]% \dopresetcheckfield {\@@DriverFieldName} {\@@DriverFieldWidth} {\@@DriverFieldHeight} {\@@DriverFieldDefault} {\@@DriverFieldOption} {\@@DriverFieldValues} {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,% \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,% \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}} \def\presetpushfield {\preparefieldvariables %\edef\@@DriverFieldValues{{\@@DriverFieldValues}}% makes sure {a,b,c} is passed \presetfieldsymbols[\@@DriverFieldValues]% \dopresetpushfield {\@@DriverFieldName} {\@@DriverFieldWidth} {\@@DriverFieldHeight} {\@@DriverFieldDefault} {\@@DriverFieldOption} {\@@DriverFieldValues} {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,% \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,% \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}} \def\presetradiofield {\preparefieldvariables \presetfieldsymbols[\@@DriverFieldValues]% \dopresetradiofield {\@@DriverFieldName} {\@@DriverFieldWidth} {\@@DriverFieldHeight} {\@@DriverFieldDefault} {\@@DriverFieldOption} {\@@DriverFieldRoot} {\@@DriverFieldValues} {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,% \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,% \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}} \def\presetradiorecord {\preparefieldvariables \dopresetradiorecord {\@@DriverFieldName} {\@@DriverFieldDefault} {\@@DriverFieldOption} {\@@DriverFieldKids} {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,% \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,% \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}} \def\setfieldmodes#1#2#3% {\xdef\@@DriverFieldMode{#1}% % 0 1 2 3 \xdef\@@DriverFieldFree{#2}% % 0 1 \xdef\@@DriverFieldAuto{#3}} % 0 1 \newevery\everysetfield\relax \def\doiffieldelse#1{\doifdefinedelse{fielddata#1}} \def\setfield#1#2#3#4#5#6#7#8#9% {\bgroup \doglobal\increment\numberoffields \iftracefields \doglobal\addtocommalist{#1}\collectedfields \fi \the\everysetfield \setxvalue{fielddata#1}% kortere tag #7 needs expansion etc {\noexpand\dosetfield{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}}% \egroup} \def\dosetfield#1#2#3#4#5#6#7#8#9% {\xdef\@@DriverFieldName {#1}% \xdef\@@DriverFieldType {#2}% \xdef\@@DriverFieldRoot {#3}% \xdef\@@DriverFieldParent {#4}% \xdef\@@DriverFieldKids {#5}% \xdef\@@DriverFieldGroup {#6}% \setfieldmodes #7% \bgroup \def\par{\string\n\string\n}% \xdef\@@DriverFieldValues {#8}% \xdef\@@DriverFieldDefault{#9}% \egroup} \def\changefield#1% {\setfield{#1}\@@DriverFieldType\@@DriverFieldRoot\@@DriverFieldParent\@@DriverFieldKids\@@DriverFieldGroup {\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}\@@DriverFieldValues\@@DriverFieldDefault} \def\getfield#1% name {\doifundefinedelse{fielddata#1} {\dosetfield{#1}\empty\empty\empty\empty\empty{\empty00}\empty\empty} {\getvalue{fielddata#1}}} \newif\iftracefields \tracefieldsfalse \let\tracefields\tracefieldstrue \def\doshowfields[#1]% todo: tabulate van maken en runtime {\bgroup \switchtobodyfont[8pt,tt]% \doifsomething{#1}{\def\collectedfields{#1}}% \ifx\collectedfields\empty \par specify [fieldlist] or say \type{\tracefieldstrue} first\par \else \def\normalizedfieldmode##1##2##3% {\ifcase0##2 \else\sl\fi \ifcase0##1 loner\or parent\or clone\or copy\fi}% \def\dosetfield##1##2##3##4##5##6##7##8##9% {##1&##2&##3&##4&##5&##6&\normalizedfieldmode##7&##8&##9\cr}% \halign {&##\strut\hss\quad\cr \noalign{\hrule}% NAME &TYPE &ROOT & PARENT&KIDS &GROUP & MODE &VALUES&DEFAULT\cr \noalign{\hrule}% \@EA\globalprocesscommalist\@EA[\collectedfields]\getfield \noalign{\hrule}}% \fi \egroup} \def\showfields {\dosingleempty\doshowfields} \def\dologfields[#1]% {\bgroup \immediate\openout\scratchwrite=fields.log \doifsomething{#1}{\def\collectedfields{#1}}% \ifx\colledtedfields\empty \immediate\write\scratchwrite{use \tracefieldstrue}% \else \def\normalizedfieldmode##1##2##3% {\edef\@@DriverFieldMode {\ifcase##1 loner \or parent \or clone \or copy \fi \ifcase##2 \else(done)\fi}}% \def\dosetfield##1##2##3##4##5##6##7##8##9% {\normalizedfieldmode##7% \immediate\write\scratchwrite {N=##1 / T=##2 / R=##3 / P=##4 / K=##5 / G=##6 / M=\@@DriverFieldMode\space/ V=##8 / D=##9}}% \processcommacommand[\collectedfields]\getfield \fi \immediate\closeout\scratchwrite \egroup} \def\logfields {\dosingleempty\doLogFields} %D \starttyping %D \definefield [name] [type] [group] [values] [default] %D %D \definefield [WWWW] [text] [textsetup] [default text] %D \definefield [XXXX] [push] [pushsetup] [yes,no] [yes] %D \definefield [XXXX] [check] [checksetup] [yes,no] [yes] %D \definefield [YYYY] [combo] [combosetup] [a,b,c,d] [b] %D \definefield [ZZZZ] [radio] [radiosetup] [W,X,Y,Z] [Y] %D %D \definesubfield [W] [subsetup] [p,q] %D \definesubfield [X,Y] [subsetup] [p,r] %D \definesubfield [Z] [subsetup] [y,z] %D %D evt \definemainfield ... wanneer geplaatst voor subs gegeven %D %D \clonefield [XXXX] [XX,YY] [mysetup] [on,off] %D \clonefield [Z] [AA,BB] [somesetup] [true,false] %D \clonefield [Z] [CC,DD] [anothersetup] %D %D \copyfield [XXXX] [PP,QQ,RR] %D %D \field[XXXX] %D \fitfield[XXXX] %D \stoptyping \newif\ifdefinemainfield \definemainfieldfalse %D We need to keep track of cloned (related) fields and so by %D maintaining lists of field clones. %D %D The first alternative used a two pass data list and was %D implemented as follows: %D %D \starttyping %D \def\getmainfieldkids#1% %D {\let\@@DriverFieldKids\empty %D \ifdefinemainfield %D \definetwopasslist{fld:#1}% defined by system %D \doloop %D {\gettwopassdata{fld:#1}% %D \iftwopassdatafound %D %\addtocommalist\twopassdata\@@DriverFieldKids %D \appendtocommalist\twopassdata\@@DriverFieldKids %D \else %D \exitloop %D \fi}% %D \fi} %D \stoptyping %D %D However, the next alternative is much faster when we have %D a field with thousands of clones, something not that %D imaginary. %D %D \starttyping %D \def\getmainfieldkids#1% %D {\let\@@DriverFieldKids\empty %D \ifdefinemainfield %D \definetwopasslist{fld:#1}% runtime defined by system %D \getnamedtwopassdatalist{fld:#1}\@@DriverFieldKids %D \fi} %D \stoptyping %D %D The data is written by file using: %D %D \starttyping %D \newcounter\nofmainfieldkids %D %D \def\setmainfieldkid#1#2% %D {\doglobal\increment\nofmainfieldkids %D \savetwopassdata{fld:#1}{\nofmainfieldkids}{#2}} %D \stoptyping %D %D The trade of of this mechanism is that for each cloned or %D copied field, the uitlity file is to be read in order to %D fetch the data. %D %D The next, much faster alternative uses a dedicated % %D reference mechanism. \def\setmainfieldkid#1#2% {\immediatewriteutilitycommand{\fieldreference{#1}{#2}}} \def\checkfieldreferences {\startnointerference \protectlabels \doutilities{fieldreferences}\jobname\empty\relax\relax \global\let\checkfieldreferences\relax \stopnointerference} \def\setfieldreferences {\def\fieldreference##1##2% {\ifundefined{\r!widget##1}% \setxvalue{\r!widget##1}{##2}% \else \edef\!!stringa{\getvalue{\r!widget##1}}% \setxvalue{\r!widget##1}{\!!stringa,##2}% \fi}} \def\resetfieldreferences {\let\fieldreference\gobbletwoarguments} \def\getmainfieldkids#1% {\checkfieldreferences \ifdefinemainfield \doifundefinedelse{\r!widget#1}% {\let\@@DriverFieldKids\empty} {\@EA\let\@EA\@@DriverFieldKids\csname\r!widget#1\endcsname}% \else \let\@@DriverFieldKids\empty \fi} \resetfieldreferences %D Of course it costs a few more tokens to implement, but it's %D worth the memory: running for instance the 2000 page %D english examns publishing on demand document went down from %D 1350 seconds to less than 950 on a 650 Mhz pentium. \def\definefield {\definemainfieldfalse\doquintupleempty\dodefinefield} \def\definemainfield {\definemainfieldtrue \doquintupleempty\dodefinefield} \let\collectedfields\empty \newcounter\numberoffields \newcounter\totalnumberoffields \def\savenumberoffields {\ifcase\numberoffields\relax\else \savecurrentvalue\totalnumberoffields\numberoffields \fi} \appendtoks \savenumberoffields \to \everybye % \everylastshipout % \def\presetfieldreferences % {\ifnum\totalnumberoffields>0 % \definereference[AtOpenInitializeForm][\v!ResetForm]% % \fi} % % \definereference[AtOpenInitializeForm][\v!geen] % % \appendtoks \presetfieldreferences \to \everycheckreferences \def\dodefinefield[#1][#2][#3][#4][#5]% {\ifsecondargument \edef\currentfieldname{#1}% just in case we're inside a loop \doifundefinedelse{define#2field} {\writestatus\m!fields{unknown field type #2}} {\doifundefined{fielddata\currentfieldname} {\getmainfieldkids\currentfieldname \ifdefinemainfield \ifx\@@DriverFieldKids\empty \let\@@DriverFieldMode\fieldlonermode \else \let\@@DriverFieldMode\fieldparentmode \fi \def\@@DriverFieldAuto{1}% \else \let\@@DriverFieldMode\fieldlonermode \def\@@DriverFieldAuto{0}% \fi \def\@@DriverFieldFree{0}% \getvalue{define#2field}{\currentfieldname}{#2}{#3}{#4}{#5}}}% \else \writestatus\m!fields{pass fieldname and fieldtype}% \fi} \def\definelinefield#1#2#3#4#5% {\setfield{#1}{#2}{}{}{\@@DriverFieldKids}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{}{#4}} \let\definetextfield=\definelinefield \def\definechoicefield#1#2#3#4#5% {\doifelsenothing{#4} {\def\@@DriverFieldValues{yes,no}} {\def\@@DriverFieldValues{#4}}% \doifelsenothing{#5} {\dogetcommacommandelement2\from\@@DriverFieldValues \to\@@DriverFieldDefault \dogetcommacommandelement1\from\@@DriverFieldDefault\to\@@DriverFieldDefault} {\def\@@DriverFieldDefault{#5}}% \setfield{#1}{#2}{}{}{\@@DriverFieldKids}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{\@@DriverFieldValues}{\@@DriverFieldDefault}} \let\definepopupfield=\definechoicefield \let\definecombofield=\definechoicefield %\def\definecheckfield#1#2#3#4#5% % {\doifelsenothing{#4} % {\definedefaultsymbols % \def\@@DriverFieldValues{defaultyes}} % {\def\@@DriverFieldValues{#4}}% % \doifelsenothing{#5} % {\dogetcommacommandelement2\from\@@DriverFieldValues\to\@@DriverFieldDefault % \dogetcommacommandelement1\from\@@DriverFieldDefault\to\@@DriverFieldDefault} % {\def\@@DriverFieldDefault{#5}}% % \setfield{#1}{#2}{}{}{\@@DriverFieldKids}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{\@@DriverFieldValues}{\@@DriverFieldDefault}} %D Since these fields have an on/off state only, we pass 1/0 %D to the driver as default values. \def\definecheckfield#1#2#3#4#5% {\doifelsenothing{#4} {\definedefaultsymbols \def\@@DriverFieldValues{defaultyes}} {\def\@@DriverFieldValues{#4}}% \doifelsenothing{#5} {\def\@@DriverFieldDefault{2}} {\dogetcommacommandelement1\from\@@DriverFieldValues\to\@@DriverFieldDefault \doifinstringelse{#5}{\@@DriverFieldDefault} {\def\@@DriverFieldDefault{1}} {\def\@@DriverFieldDefault{0}}}% \setfield {#1}{#2}{}{}{\@@DriverFieldKids}{#3}% {\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}% {\@@DriverFieldValues}{\@@DriverFieldDefault}} \let\definepushfield=\definecheckfield \def\defineradiofield#1#2#3#4#5% {\iffourthargument \doifelsenothing{#5} {\dogetcommacommandelement1\from#4\to\SavedFieldDefault \dogetcommacommandelement1\from\SavedFieldDefault\to\SavedFieldDefault} {\def\SavedFieldDefault{#5}}% % when opt works % \@EA\beforesplitstring\SavedFieldDefault\at=>\to\SavedFieldDefault \ifx\@@DriverFieldKids\empty \setfield{#1}{#2}{}{}{#4}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{}{\SavedFieldDefault}% \else \setfield{#1}{#2}{}{}{#4,\@@DriverFieldKids}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{}{\SavedFieldDefault}% \fi % \def\docommand##1% {\doifelse{##1}\SavedFieldDefault {\def\@@DriverFieldDefault{##1}}% {\let\@@DriverFieldDefault\empty}% \setfield{##1}{#2}{#1}{}{}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{}{\@@DriverFieldDefault}}% % when opt works % \def\docommand##1% % {\@EA\beforesplitstring##1\at=>\to\FieldValue % \doifelse\FieldValue\SavedFieldDefault % {\let\@@DriverFieldDefault\FieldValue}% % {\let\@@DriverFieldDefault\empty}% % \setfield\FieldValue{#2}{#1}{}{}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{}{\@@DriverFieldDefault}}% \processcommalist[#4]\docommand \else \writestatus\m!fields{pass values too}% \fi} \def\definesubfield {\dotripleempty\dodefinesubfield} \def\dodefinesubfield[#1][#2][#3]% for the moment only radio ones {\ifsecondargument \def\docommand##1% {\getfield{##1}% \ifx\@@DriverFieldType\empty \writestatus\m!fields{unknown field ##1}% to do \else \doifsomething{#2} {\edef\@@DriverFieldGroup{#2}}% \doifelsenothing{#3} {\definedefaultsymbols \def\@@DriverFieldValues{defaultyes}} {\def\@@DriverFieldValues{#3}}% \changefield{##1}% \fi}% \processcommalist[#1]\docommand \else \writestatus\m!fields{pass fieldname, setupgroup, values and default}% \fi} \def\doclonefield[#1][#2][#3][#4]% parent children setupgroup values {\ifsecondargument \getfield{#1}% \iftrialtypesetting\else \ifx\@@DriverFieldType\empty \writestatus\m!fields{unknown field #1}% \else \let\@@DriverFieldMode\fieldparentmode %\def\docommand##1{\addtocommalist{##1}\@@DriverFieldKids}% \def\docommand##1{\appendtocommalist{##1}\@@DriverFieldKids}% \processcommalist[#2]\docommand \changefield{#1}% \let\@@DriverFieldAutoParent\@@DriverFieldAuto \def\@@DriverFieldParent{#1}% \let\@@DriverFieldKids\empty \let\@@DriverFieldRoot\empty \let\@@DriverFieldMode\fieldchildmode \def\@@DriverFieldFree{0}% \def\@@DriverFieldAuto{0}% \doifsomething{#3}{\edef\@@DriverFieldGroup{#3}}% \doifsomething{#4}{\edef\@@DriverFieldValues{#4}}% \def\docommand##1% {\ifcase\@@DriverFieldAutoParent\else \setmainfieldkid{\@@DriverFieldParent}{##1}% \fi \changefield{##1}}% \processcommalist[#2]\docommand \fi \fi \else \writestatus\m!fields{pass parent field and clones}% \fi} \def\clonefield {\doquadrupleempty\doclonefield} \def\docopyfield[#1][#2]% parent children {\ifsecondargument \getfield{#1}% \iftrialtypesetting\else \ifx\@@DriverFieldType\empty \writestatus\m!fields{unknown field #1}% \else \let\@@DriverFieldMode\fieldparentmode %\def\docommand##1{\addtocommalist{##1}\@@DriverFieldKids}% \def\docommand##1{\appendtocommalist{##1}\@@DriverFieldKids}% \processcommalist[#2]\docommand \changefield{#1}% \let\@@DriverFieldAutoParent\@@DriverFieldAuto \def\@@DriverFieldParent{#1}% \let\@@DriverFieldKids\empty \let\@@DriverFieldRoot\empty \let\@@DriverFieldMode\fieldcopymode \def\@@DriverFieldFree{0}% \def\@@DriverFieldAuto{0}%