HTML.pm 262 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812
  1. # $Id$
  2. # HTML.pm: output tree as HTML.
  3. #
  4. # Copyright 2011, 2012, 2013, 2014, 2015,
  5. # 2016 Free Software Foundation, Inc.
  6. #
  7. # This program is free software; you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation; either version 3 of the License,
  10. # or (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. #
  20. # Original author: Patrice Dumas <pertusus@free.fr>
  21. package Texinfo::Convert::HTML;
  22. use 5.00405;
  23. # See 'The "Unicode Bug"' under 'perlunicode' man page. This means
  24. # that regular expressions will treat characters 128-255 in a Perl string
  25. # the same regardless of whether the string is using a UTF-8 encoding.
  26. # For older Perls, you can use utf8::upgrade on the strings, where the
  27. # difference matters.
  28. use if $] >= 5.012, feature => 'unicode_strings';
  29. use strict;
  30. use Texinfo::Convert::Converter;
  31. use Texinfo::Common;
  32. use Texinfo::Convert::Texinfo;
  33. use Texinfo::Convert::Text;
  34. use Texinfo::Convert::Unicode;
  35. use Texinfo::Convert::NodeNameNormalization;
  36. use Carp qw(cluck);
  37. require Exporter;
  38. use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  39. @ISA = qw(Exporter Texinfo::Convert::Converter);
  40. # Items to export into callers namespace by default. Note: do not export
  41. # names by default without a very good reason. Use EXPORT_OK instead.
  42. # Do not simply export all your public functions/methods/constants.
  43. # This allows declaration use Texinfo::Convert::HTML ':all';
  44. # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
  45. # will save memory.
  46. %EXPORT_TAGS = ( 'all' => [ qw(
  47. convert
  48. convert_tree
  49. output
  50. output_internal_links
  51. ) ] );
  52. @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
  53. @EXPORT = qw(
  54. );
  55. $VERSION = '6.3.90';
  56. # misc commands that are of use for formatting.
  57. my %formatting_misc_commands = %Texinfo::Convert::Text::formatting_misc_commands;
  58. my %no_brace_commands = %Texinfo::Common::no_brace_commands;
  59. my %accent_commands = %Texinfo::Common::accent_commands;
  60. my %misc_commands = %Texinfo::Common::misc_commands;
  61. my %sectioning_commands = %Texinfo::Common::sectioning_commands;
  62. my %def_commands = %Texinfo::Common::def_commands;
  63. my %ref_commands = %Texinfo::Common::ref_commands;
  64. my %brace_commands = %Texinfo::Common::brace_commands;
  65. my %block_commands = %Texinfo::Common::block_commands;
  66. my %menu_commands = %Texinfo::Common::menu_commands;
  67. my %root_commands = %Texinfo::Common::root_commands;
  68. my %preformatted_commands = %Texinfo::Common::preformatted_commands;
  69. my %explained_commands = %Texinfo::Common::explained_commands;
  70. my %item_container_commands = %Texinfo::Common::item_container_commands;
  71. my %raw_commands = %Texinfo::Common::raw_commands;
  72. my %format_raw_commands = %Texinfo::Common::format_raw_commands;
  73. my %inline_commands = %Texinfo::Common::inline_commands;
  74. my %inline_format_commands = %Texinfo::Common::inline_format_commands;
  75. my %code_style_commands = %Texinfo::Common::code_style_commands;
  76. my %regular_font_style_commands = %Texinfo::Common::regular_font_style_commands;
  77. my %preformatted_code_commands = %Texinfo::Common::preformatted_code_commands;
  78. my %default_index_commands = %Texinfo::Common::default_index_commands;
  79. my %style_commands = %Texinfo::Common::style_commands;
  80. my %align_commands = %Texinfo::Common::align_commands;
  81. my %region_commands = %Texinfo::Common::region_commands;
  82. my %context_brace_commands = %Texinfo::Common::context_brace_commands;
  83. my %letter_no_arg_commands = %Texinfo::Common::letter_no_arg_commands;
  84. foreach my $def_command (keys(%def_commands)) {
  85. $formatting_misc_commands{$def_command} = 1 if ($misc_commands{$def_command});
  86. }
  87. # FIXME remove raw commands?
  88. my %format_context_commands = (%block_commands, %root_commands);
  89. foreach my $misc_context_command('tab', 'item', 'itemx', 'headitem') {
  90. $format_context_commands{$misc_context_command} = 1;
  91. }
  92. my %composition_context_commands = (%preformatted_commands, %root_commands,
  93. %menu_commands, %align_commands);
  94. $composition_context_commands{'float'} = 1;
  95. my %pre_class_types;
  96. # FIXME allow customization? (also in DocBook)
  97. my %upper_case_commands = ( 'sc' => 1 );
  98. sub in_math($)
  99. {
  100. my $self = shift;
  101. return $self->{'document_context'}->[-1]->{'math'};
  102. }
  103. # set if in menu or preformatted command
  104. sub in_preformatted($)
  105. {
  106. my $self = shift;
  107. my $context = $self->{'document_context'}->[-1]->{'composition_context'}->[-1];
  108. if ($preformatted_commands{$context}
  109. or $pre_class_types{$context}
  110. or ($menu_commands{$context} and $self->_in_preformatted_in_menu())) {
  111. return $context;
  112. } else {
  113. return undef;
  114. }
  115. }
  116. sub in_upper_case($)
  117. {
  118. my $self = shift;
  119. return $self->{'document_context'}->[-1]->{'formatting_context'}->[-1]->{'upper_case'};
  120. }
  121. sub in_space_protected($)
  122. {
  123. my $self = shift;
  124. return $self->{'document_context'}->[-1]->{'formatting_context'}->[-1]->{'space_protected'};
  125. }
  126. sub in_code($)
  127. {
  128. my $self = shift;
  129. return $self->{'document_context'}->[-1]->{'monospace'}->[-1];
  130. }
  131. sub in_string($)
  132. {
  133. my $self = shift;
  134. return $self->{'document_context'}->[-1]->{'string'};
  135. }
  136. sub in_verbatim($)
  137. {
  138. my $self = shift;
  139. return $self->{'document_context'}->[-1]->{'verbatim'};
  140. }
  141. sub in_raw($)
  142. {
  143. my $self = shift;
  144. return $self->{'document_context'}->[-1]->{'raw'};
  145. }
  146. sub paragraph_number($)
  147. {
  148. my $self = shift;
  149. return $self->{'document_context'}->[-1]->{'formatting_context'}->[-1]->{'paragraph_number'};
  150. }
  151. sub preformatted_number($)
  152. {
  153. my $self = shift;
  154. return $self->{'document_context'}->[-1]->{'formatting_context'}->[-1]->{'preformatted_number'};
  155. }
  156. sub top_format($)
  157. {
  158. my $self = shift;
  159. return $self->{'document_context'}->[-1]->{'formats'}->[-1];
  160. }
  161. sub commands_stack($)
  162. {
  163. my $self = shift;
  164. return @{$self->{'document_context'}->[-1]->{'commands'}};
  165. }
  166. sub preformatted_classes_stack($)
  167. {
  168. my $self = shift;
  169. return @{$self->{'document_context'}->[-1]->{'preformatted_classes'}};
  170. }
  171. sub in_align($)
  172. {
  173. my $self = shift;
  174. my $context
  175. = $self->{'document_context'}->[-1]->{'composition_context'}->[-1];
  176. if ($align_commands{$context}) {
  177. return $context;
  178. } else {
  179. return undef;
  180. }
  181. }
  182. # $COMMAND should be a tree element which is a possible target of a link.
  183. #
  184. # Returns a hash that may have these keys set:
  185. # 'target': A unique string representing the target. Used as argument to
  186. # 'name' attribute inside <a>.
  187. # 'node_filename', 'section_filename',
  188. # 'misc_filename', 'filename'. Possibly others.
  189. #
  190. # Some functions cache their results in these hashes.
  191. sub _get_target($$)
  192. {
  193. my $self = shift;
  194. my $command = shift;
  195. my $target;
  196. if (!defined($command)) {
  197. cluck("_get_target command not defined");
  198. }
  199. if ($self->{'targets'}->{$command}) {
  200. $target = $self->{'targets'}->{$command};
  201. } elsif ($command->{'cmdname'}
  202. # This should only happen for @*heading*, root_commands targets should
  203. # already be set.
  204. and $sectioning_commands{$command->{'cmdname'}}
  205. and !$root_commands{$command->{'cmdname'}}) {
  206. $target = $self->_new_sectioning_command_target($command);
  207. }
  208. return $target;
  209. }
  210. # API for the elements formatting
  211. sub command_id($$)
  212. {
  213. my $self = shift;
  214. my $command = shift;
  215. my $target = $self->_get_target($command);
  216. if ($target) {
  217. return $target->{'target'};
  218. } else {
  219. return undef;
  220. }
  221. }
  222. sub command_contents_target($$$)
  223. {
  224. my $self = shift;
  225. my $command = shift;
  226. my $contents_or_shortcontents = shift;
  227. $contents_or_shortcontents = 'shortcontents'
  228. if ($contents_or_shortcontents eq 'summarycontents');
  229. my $target = $self->_get_target($command);
  230. if ($target) {
  231. return $target->{$contents_or_shortcontents .'_target'};
  232. } else {
  233. return undef;
  234. }
  235. }
  236. # Return href target for linking to this command
  237. sub command_target($$)
  238. {
  239. my $self = shift;
  240. my $command = shift;
  241. if ($command->{'extra'}
  242. and $command->{'extra'}->{'associated_node'}) {
  243. $command = $command->{'extra'}->{'associated_node'};
  244. }
  245. my $target = $self->_get_target($command);
  246. if ($target) {
  247. return $target->{'target'};
  248. } else {
  249. return undef;
  250. }
  251. }
  252. sub command_filename($$)
  253. {
  254. my $self = shift;
  255. my $command = shift;
  256. my $target = $self->_get_target($command);
  257. if ($target) {
  258. if (defined($target->{'filename'})) {
  259. return $target->{'filename'};
  260. }
  261. my ($element, $root_command) = $self->_get_element($command, 1);
  262. if (defined($root_command)) {
  263. $target->{'root_command'} = $root_command;
  264. }
  265. if (defined($element)) {
  266. $target->{'element'} = $element;
  267. $target->{'filename'} = $element->{'filename'};
  268. return $element->{'filename'};
  269. }
  270. }
  271. return undef;
  272. }
  273. sub command_element($$)
  274. {
  275. my $self = shift;
  276. my $command = shift;
  277. my $target = $self->_get_target($command);
  278. if ($target) {
  279. $self->command_filename($command);
  280. return $target->{'element'};
  281. }
  282. return undef;
  283. }
  284. sub command_element_command($$)
  285. {
  286. my $self = shift;
  287. my $command = shift;
  288. my ($element, $root_command) = $self->_get_element($command);
  289. #my $element = $self->command_element($command);
  290. if ($element and $element->{'extra'}) {
  291. return $element->{'extra'}->{'element_command'};
  292. }
  293. return undef;
  294. }
  295. sub element_command($$)
  296. {
  297. my $self = shift;
  298. my $element = shift;
  299. if ($element and $element->{'extra'}) {
  300. if ($element->{'extra'}->{'element_command'}) {
  301. return $element->{'extra'}->{'element_command'};
  302. } elsif ($element->{'extra'}->{'special_element'}) {
  303. return $element;
  304. }
  305. }
  306. return undef;
  307. }
  308. sub command_node($$)
  309. {
  310. my $self = shift;
  311. my $command = shift;
  312. my $target = $self->_get_target($command);
  313. if ($target) {
  314. $self->command_filename($command);
  315. my $root_command = $target->{'root_command'};
  316. if (defined($root_command)) {
  317. if ($root_command->{'cmdname'} and $root_command->{'cmdname'} eq 'node') {
  318. return $root_command;
  319. }
  320. if ($root_command->{'extra'} and $root_command->{'extra'}->{'associated_node'}) {
  321. return $root_command->{'extra'}->{'associated_node'};
  322. }
  323. }
  324. }
  325. return undef;
  326. }
  327. # Return string for linking to $COMMAND with <a href>
  328. sub command_href($$;$$)
  329. {
  330. my $self = shift;
  331. my $command = shift;
  332. my $filename = shift;
  333. my $link_command = shift;
  334. $filename = $self->{'current_filename'} if (!defined($filename));
  335. if ($command->{'manual_content'} or $command->{'top_node_up'}) {
  336. return $self->_external_node_href($command, $filename, $link_command);
  337. }
  338. my $target = $self->command_target($command);
  339. return '' if (!defined($target));
  340. my $href = '';
  341. my $target_filename = $self->command_filename($command);
  342. if (!defined($target_filename)) {
  343. # Happens if there are no pages, for example if OUTPUT is set to ''
  344. # as in the test cases. Also for things in @titlepage when
  345. # titlepage is not output.
  346. if ($self->{'elements'} and $self->{'elements'}->[0]
  347. and defined($self->{'elements'}->[0]->{'filename'})) {
  348. # In that case use the first page.
  349. $target_filename = $self->{'elements'}->[0]->{'filename'};
  350. }
  351. }
  352. if (defined($target_filename)) {
  353. if (!defined($filename)
  354. or $filename ne $target_filename) {
  355. $href .= $target_filename;
  356. }
  357. }
  358. $href .= '#' . $target if ($target ne '');
  359. return $href;
  360. }
  361. my %contents_command_element_name = (
  362. 'contents' => 'Contents',
  363. 'shortcontents' => 'Overview',
  364. 'summarycontents' => 'Overview',
  365. );
  366. sub command_contents_href($$$$)
  367. {
  368. my $self = shift;
  369. my $command = shift;
  370. my $contents_or_shortcontents = shift;
  371. my $filename = shift;
  372. my $href;
  373. my $name = $contents_command_element_name{$contents_or_shortcontents};
  374. my $target = $self->command_contents_target($command, $contents_or_shortcontents);
  375. my $target_element = $self->special_element($name);
  376. my $target_filename;
  377. # !defined happens when called as convert() and not output()
  378. if (defined($target_element)) {
  379. $target_filename = $self->command_filename($target_element);
  380. }
  381. if (defined($target_filename) and
  382. (!defined($filename)
  383. or $filename ne $target_filename)) {
  384. $href .= $target_filename;
  385. }
  386. $href .= '#' . $target if ($target ne '');
  387. return $href;
  388. }
  389. # Return text to be used for a hyperlink to $COMMAND.
  390. # $TYPE refers to the type of value returned from this function:
  391. # 'text' - return text
  392. # 'tree' - return a tree
  393. # 'tree_nonumber' - return tree representing text without a chapter number
  394. # being included.
  395. # 'string'
  396. sub command_text($$;$)
  397. {
  398. my $self = shift;
  399. my $command = shift;
  400. my $type = shift;
  401. if (!defined($type)) {
  402. $type = 'text';
  403. }
  404. if (!defined($command)) {
  405. cluck "in command_text($type) command not defined";
  406. }
  407. if ($command->{'manual_content'} or $command->{'top_node_up'}) {
  408. my $node_content = [];
  409. $node_content = $command->{'node_content'}
  410. if (defined($command->{'node_content'}));
  411. my $tree;
  412. if ($command->{'manual_content'}) {
  413. $tree = {'type' => '_code',
  414. 'contents' => [{'text' => '('}, @{$command->{'manual_content'}},
  415. {'text' => ')'}, @$node_content]};
  416. } else {
  417. $tree = {'type' => '_code',
  418. 'contents' => $node_content};
  419. }
  420. if ($type eq 'tree') {
  421. return $tree;
  422. } else {
  423. if ($type eq 'string') {
  424. $tree = {'type' => '_string',
  425. 'contents' => [$tree]};
  426. }
  427. my $result = $self->convert_tree_new_formatting_context(
  428. $tree, $command->{'cmdname'});
  429. return $result;
  430. }
  431. }
  432. my $target = $self->_get_target($command);
  433. if ($target) {
  434. my $explanation;
  435. $explanation = "command_text \@$command->{'cmdname'}"
  436. if ($command->{'cmdname'});
  437. if (defined($target->{$type})) {
  438. return $target->{$type};
  439. }
  440. my $tree;
  441. if (!$target->{'tree'}) {
  442. if ($command->{'extra'}
  443. and $command->{'extra'}->{'special_element'}) {
  444. my $special_element = $command->{'extra'}->{'special_element'};
  445. $tree = $self->get_conf('SPECIAL_ELEMENTS_NAME')->{$special_element};
  446. $explanation = "command_text $special_element";
  447. } elsif ($command->{'cmdname'} and ($command->{'cmdname'} eq 'node'
  448. or $command->{'cmdname'} eq 'anchor')) {
  449. $tree = {'type' => '_code',
  450. 'contents' => $command->{'extra'}->{'node_content'}};
  451. } elsif ($command->{'cmdname'} and ($command->{'cmdname'} eq 'float')) {
  452. $tree = $self->_float_type_number($command);
  453. } elsif ($command->{'extra'}->{'missing_argument'}) {
  454. if ($type eq 'tree' or $type eq 'tree_nonumber') {
  455. return {};
  456. } else {
  457. return '';
  458. }
  459. } else {
  460. if (!$command->{'extra'}->{'misc_content'}) {
  461. cluck "No misc_content: "
  462. .Texinfo::Common::_print_current($command);
  463. }
  464. if (defined($command->{'number'})
  465. and ($self->get_conf('NUMBER_SECTIONS')
  466. or !defined($self->get_conf('NUMBER_SECTIONS')))) {
  467. if ($command->{'cmdname'} eq 'appendix' and $command->{'level'} == 1) {
  468. $tree = $self->gdt('Appendix {number} {section_title}',
  469. {'number' => {'text' => $command->{'number'}},
  470. 'section_title'
  471. => {'contents'
  472. => $command->{'extra'}->{'misc_content'}}});
  473. } else {
  474. $tree = $self->gdt('{number} {section_title}',
  475. {'number' => {'text' => $command->{'number'}},
  476. 'section_title'
  477. => {'contents'
  478. => $command->{'extra'}->{'misc_content'}}});
  479. }
  480. } else {
  481. $tree = {'contents' => [@{$command->{'extra'}->{'misc_content'}}]};
  482. }
  483. $target->{'tree_nonumber'}
  484. = {'contents' => $command->{'extra'}->{'misc_content'}};
  485. }
  486. $target->{'tree'} = $tree;
  487. } else {
  488. $tree = $target->{'tree'};
  489. }
  490. return $target->{'tree_nonumber'} if ($type eq 'tree_nonumber'
  491. and $target->{'tree_nonumber'});
  492. return $tree if ($type eq 'tree' or $type eq 'tree_nonumber');
  493. $self->_new_document_context($command->{'cmdname'});
  494. if ($type eq 'string') {
  495. $tree = {'type' => '_string',
  496. 'contents' => [$tree]};
  497. }
  498. if ($type =~ /^(.*)_nonumber$/) {
  499. $tree = $target->{'tree_nonumber'}
  500. if (defined($target->{'tree_nonumber'}));
  501. }
  502. $self->{'ignore_notice'}++;
  503. $target->{$type} = $self->_convert($tree, $explanation);
  504. $self->{'ignore_notice'}--;
  505. pop @{$self->{'document_context'}};
  506. return $target->{$type};
  507. }
  508. return undef;
  509. }
  510. # Return the element in the tree that $LABEL refers to.
  511. sub label_command($$)
  512. {
  513. my $self = shift;
  514. my $label = shift;
  515. return $self->{'labels'}->{$label};
  516. }
  517. sub special_element($$)
  518. {
  519. my $self = shift;
  520. my $type = shift;
  521. return $self->{'special_elements_types'}->{$type};
  522. }
  523. sub global_element($$)
  524. {
  525. my $self = shift;
  526. my $type = shift;
  527. return $self->{'global_target_elements'}->{$type};
  528. }
  529. # it is considered 'top' only if element corresponds to @top or
  530. # element is a node
  531. sub element_is_top($$)
  532. {
  533. my $self = shift;
  534. my $element = shift;
  535. return ($self->{'global_target_elements'}->{'Top'}
  536. and $self->{'global_target_elements'}->{'Top'} eq $element
  537. and $element->{'extra'}
  538. and (($element->{'extra'}->{'section'}
  539. and $element->{'extra'}->{'section'}->{'cmdname'} eq 'top')
  540. or ($element->{'extra'}->{'element_command'}
  541. and $element->{'extra'}->{'element_command'}->{'cmdname'} eq 'node')));
  542. }
  543. sub default_formatting_function($$)
  544. {
  545. my $self = shift;
  546. my $format = shift;
  547. return $self->{'default_formatting_functions'}->{$format};
  548. }
  549. sub get_value($$)
  550. {
  551. my $self = shift;
  552. my $value = shift;
  553. if (defined($self->{'parser'})
  554. and exists ($self->{'parser'}->{'values'}->{$value})) {
  555. return $self->{'parser'}->{'values'}->{$value};
  556. } else {
  557. return undef;
  558. }
  559. }
  560. sub convert_tree_new_formatting_context($$;$$)
  561. {
  562. my $self = shift;
  563. my $tree = shift;
  564. my $context_string = shift;
  565. my $multiple_pass = shift;
  566. if (defined($context_string)) {
  567. $self->_new_document_context($context_string);
  568. }
  569. if ($multiple_pass) {
  570. $self->{'ignore_notice'}++;
  571. push @{$self->{'multiple_pass'}}, $multiple_pass;
  572. }
  573. my $result = $self->convert_tree($tree);
  574. if (defined($context_string)) {
  575. pop @{$self->{'document_context'}};
  576. }
  577. if ($multiple_pass) {
  578. $self->{'ignore_notice'}--;
  579. pop @{$self->{'multiple_pass'}};
  580. }
  581. return $result;
  582. }
  583. # see http://www.w3.org/TR/REC-html40/types.html#type-links
  584. my %BUTTONS_REL =
  585. (
  586. 'Top', 'start',
  587. 'Contents', 'contents',
  588. 'Overview', '',
  589. 'Index', 'index',
  590. 'This', '',
  591. 'Back', 'prev',
  592. 'FastBack', '',
  593. 'Prev', 'prev',
  594. 'Up', 'up',
  595. 'Next', 'next',
  596. 'NodeUp', 'up',
  597. 'NodeNext', 'next',
  598. 'NodePrev', 'prev',
  599. 'NodeForward', '',
  600. 'NodeBack', '',
  601. 'Forward', 'next',
  602. 'FastForward', '',
  603. 'About' , 'help',
  604. 'First', '',
  605. 'Last', '',
  606. 'NextFile', 'next',
  607. 'PrevFile', 'prev',
  608. );
  609. my %BUTTONS_ACCESSKEY =
  610. (
  611. 'Top', '',
  612. 'Contents', '',
  613. 'Overview', '',
  614. 'Index', '',
  615. 'This', '',
  616. 'Back', 'p',
  617. 'FastBack', '',
  618. 'Prev', 'p',
  619. 'Up', 'u',
  620. 'Next', 'n',
  621. 'NodeUp', 'u',
  622. 'NodeNext', 'n',
  623. 'NodePrev', 'p',
  624. 'NodeForward', '',
  625. 'NodeBack', '',
  626. 'Forward', 'n',
  627. 'FastForward', '',
  628. 'About' , '',
  629. 'First', '',
  630. 'Last', '',
  631. 'NextFile', '',
  632. 'PrevFile', '',
  633. );
  634. my %BUTTONS_EXAMPLE =
  635. (
  636. 'Top', ' &nbsp; ',
  637. 'Contents', ' &nbsp; ',
  638. 'Overview', ' &nbsp; ',
  639. 'Index', ' &nbsp; ',
  640. 'This', '1.2.3',
  641. 'Back', '1.2.2',
  642. 'FastBack', '1',
  643. 'Prev', '1.2.2',
  644. 'Up', '1.2',
  645. 'Next', '1.2.4',
  646. 'NodeUp', '1.2',
  647. 'NodeNext', '1.2.4',
  648. 'NodePrev', '1.2.2',
  649. 'NodeForward', '1.2.4',
  650. 'NodeBack', '1.2.2',
  651. 'Forward', '1.2.4',
  652. 'FastForward', '2',
  653. 'About', ' &nbsp; ',
  654. 'First', '1.',
  655. 'Last', '1.2.4',
  656. 'NextFile', ' &nbsp; ',
  657. 'PrevFile', ' &nbsp; ',
  658. );
  659. my (%BUTTONS_TEXT, %BUTTONS_GOTO, %BUTTONS_NAME, %SPECIAL_ELEMENTS_NAME);
  660. sub _translate_names($)
  661. {
  662. my $self = shift;
  663. #print STDERR "encoding_name: ".$self->get_conf('OUTPUT_ENCODING_NAME')." documentlanguage: ".$self->get_conf('documentlanguage')."\n";
  664. %BUTTONS_TEXT = (
  665. 'Top', $self->gdt('Top'),
  666. 'Contents', $self->gdt('Contents'),
  667. 'Overview', $self->gdt('Overview'),
  668. 'Index', $self->gdt('Index'),
  669. ' ', ' &nbsp; ',
  670. 'This', $self->gdt('current'),
  671. 'Back', ' &lt; ',
  672. 'FastBack', ' &lt;&lt; ',
  673. 'Prev', $self->gdt('Prev'),
  674. 'Up', $self->gdt(' Up '),
  675. 'Next', $self->gdt('Next'),
  676. #'NodeUp', $self->gdt('Node up'),
  677. 'NodeUp', $self->gdt('Up'),
  678. #'NodeNext', $self->gdt('Next node'),
  679. 'NodeNext', $self->gdt('Next'),
  680. #'NodePrev', $self->gdt('Previous node'),
  681. 'NodePrev', $self->gdt('Previous'),
  682. 'NodeForward', $self->gdt('Forward node'),
  683. 'NodeBack', $self->gdt('Back node'),
  684. 'Forward', ' &gt; ',
  685. 'FastForward', ' &gt;&gt; ',
  686. 'About', ' ? ',
  687. 'First', ' |&lt; ',
  688. 'Last', ' &gt;| ',
  689. 'NextFile', $self->gdt('Next file'),
  690. 'PrevFile', $self->gdt('Previous file'),
  691. );
  692. #%BUTTONS_TEXT = %NAVIGATION_TEXT;
  693. %BUTTONS_GOTO = (
  694. 'Top', $self->gdt('Cover (top) of document'),
  695. 'Contents', $self->gdt('Table of contents'),
  696. 'Overview', $self->gdt('Short table of contents'),
  697. 'Index', $self->gdt('Index'),
  698. 'This', $self->gdt('Current section'),
  699. 'Back', $self->gdt('Previous section in reading order'),
  700. 'FastBack', $self->gdt('Beginning of this chapter or previous chapter'),
  701. 'Prev', $self->gdt('Previous section on same level'),
  702. 'Up', $self->gdt('Up section'),
  703. 'Next', $self->gdt('Next section on same level'),
  704. 'NodeUp', $self->gdt('Up node'),
  705. 'NodeNext', $self->gdt('Next node'),
  706. 'NodePrev', $self->gdt('Previous node'),
  707. 'NodeForward', $self->gdt('Next node in node reading order'),
  708. 'NodeBack', $self->gdt('Previous node in node reading order'),
  709. 'Forward', $self->gdt('Next section in reading order'),
  710. 'FastForward', $self->gdt('Next chapter'),
  711. 'About' , $self->gdt('About (help)'),
  712. 'First', $self->gdt('First section in reading order'),
  713. 'Last', $self->gdt('Last section in reading order'),
  714. 'NextFile', $self->gdt('Forward section in next file'),
  715. 'PrevFile', $self->gdt('Back section in previous file'),
  716. );
  717. %BUTTONS_NAME = (
  718. 'Top', $self->gdt('Top'),
  719. 'Contents', $self->gdt('Contents'),
  720. 'Overview', $self->gdt('Overview'),
  721. 'Index', $self->gdt('Index'),
  722. ' ', ' ',
  723. 'This', $self->gdt('This'),
  724. 'Back', $self->gdt('Back'),
  725. 'FastBack', $self->gdt('FastBack'),
  726. 'Prev', $self->gdt('Prev'),
  727. 'Up', $self->gdt('Up'),
  728. 'Next', $self->gdt('Next'),
  729. 'NodeUp', $self->gdt('NodeUp'),
  730. 'NodeNext', $self->gdt('NodeNext'),
  731. 'NodePrev', $self->gdt('NodePrev'),
  732. 'NodeForward', $self->gdt('NodeForward'),
  733. 'NodeBack', $self->gdt('NodeBack'),
  734. 'Forward', $self->gdt('Forward'),
  735. 'FastForward', $self->gdt('FastForward'),
  736. 'About', $self->gdt('About'),
  737. 'First', $self->gdt('First'),
  738. 'Last', $self->gdt('Last'),
  739. 'NextFile', $self->gdt('NextFile'),
  740. 'PrevFile', $self->gdt('PrevFile'),
  741. );
  742. %SPECIAL_ELEMENTS_NAME = (
  743. 'About' => $self->gdt('About This Document'),
  744. 'Contents' => $self->gdt('Table of Contents'),
  745. 'Overview' => $self->gdt('Short Table of Contents'),
  746. 'Footnotes' => $self->gdt('Footnotes'),
  747. );
  748. # delete the tree and formatted results for special elements
  749. # such that they are redone with the new tree when needed.
  750. foreach my $special_element (keys (%SPECIAL_ELEMENTS_NAME)) {
  751. if ($self->{'special_elements_types'}->{$special_element} and
  752. $self->{'targets'}->{$self->{'special_elements_types'}->{$special_element}}) {
  753. my $target
  754. = $self->{'targets'}->{$self->{'special_elements_types'}->{$special_element}};
  755. foreach my $key ('text', 'string', 'tree') {
  756. delete $target->{$key};
  757. }
  758. }
  759. }
  760. foreach my $hash (\%BUTTONS_TEXT, \%BUTTONS_GOTO, \%BUTTONS_NAME) {
  761. foreach my $button (keys (%$hash)) {
  762. if (ref($hash->{$button})) {
  763. $hash->{$button} = $self->convert_tree_new_formatting_context(
  764. $hash->{$button}, "button $button");
  765. }
  766. }
  767. }
  768. if ($self->{'commands_translation'}) {
  769. my %translated_commands;
  770. foreach my $context ('normal', 'preformatted', 'string') {
  771. foreach my $command (keys(%{$self->{'commands_translation'}->{$context}})) {
  772. $translated_commands{$command} = 1;
  773. delete $self->{'commands_formatting'}->{$context}->{$command};
  774. if (defined($self->{'commands_translation'}->{$context}->{$command})) {
  775. $self->{'commands_formatting'}->{$context}->{$command}
  776. = $self->gdt($self->{'commands_translation'}->{$context}->{$command},
  777. undef, 'translated_text');
  778. }
  779. }
  780. }
  781. foreach my $command(keys(%translated_commands)) {
  782. $self->_complete_commands_formatting($command);
  783. }
  784. }
  785. }
  786. # insert here name of icon images for buttons
  787. # Icons are used, if ICONS and resp. value are set
  788. my %ACTIVE_ICONS = (
  789. 'Top', '',
  790. 'Contents', '',
  791. 'Overview', '',
  792. 'Index', '',
  793. 'This', '',
  794. 'Back', '',
  795. 'FastBack', '',
  796. 'Prev', '',
  797. 'Up', '',
  798. 'Next', '',
  799. 'NodeUp', '',
  800. 'NodeNext', '',
  801. 'NodePrev', '',
  802. 'NodeForward', '',
  803. 'NodeBack', '',
  804. 'Forward', '',
  805. 'FastForward', '',
  806. 'About' , '',
  807. 'First', '',
  808. 'Last', '',
  809. 'NextFile', '',
  810. 'PrevFile', '',
  811. ' ', '',
  812. );
  813. # insert here name of icon images for these, if button is inactive
  814. my %PASSIVE_ICONS = (
  815. 'Top', '',
  816. 'Contents', '',
  817. 'Overview', '',
  818. 'Index', '',
  819. 'This', '',
  820. 'Back', '',
  821. 'FastBack', '',
  822. 'Prev', '',
  823. 'Up', '',
  824. 'Next', '',
  825. 'NodeUp', '',
  826. 'NodeNext', '',
  827. 'NodePrev', '',
  828. 'NodeForward', '',
  829. 'NodeBack', '',
  830. 'Forward', '',
  831. 'FastForward', '',
  832. 'About', '',
  833. 'First', '',
  834. 'Last', '',
  835. 'NextFile', '',
  836. 'PrevFile', '',
  837. );
  838. my %defaults = (
  839. 'ENABLE_ENCODING' => 0,
  840. 'SHOW_MENU' => 1,
  841. 'OUTPUT_ENCODING_NAME' => 'utf-8',
  842. #'encoding_name' => undef,
  843. #'perl_encoding' => undef,
  844. 'OUTFILE' => undef,
  845. 'SUBDIR' => undef,
  846. 'USE_NODES' => 1,
  847. 'INLINE_CONTENTS' => 1,
  848. 'SPLIT' => 'node',
  849. # if set style is added in attribute.
  850. 'INLINE_CSS_STYLE' => 0,
  851. # if set, no css is used.
  852. 'NO_CSS' => 0,
  853. # if set, use node anchors for sections targets
  854. 'USE_NODE_TARGET' => 1,
  855. 'OPEN_QUOTE_SYMBOL' => '&lsquo;',
  856. 'CLOSE_QUOTE_SYMBOL' => '&rsquo;',
  857. 'USE_ISO' => 1,
  858. # file name used for Top node when NODE_FILENAMES is true
  859. 'TOP_NODE_FILE' => 'index',
  860. 'NODE_FILE_EXTENSION' => 'html',
  861. 'EXTENSION' => 'html',
  862. 'TOP_NODE_FILE_TARGET' => 'index',
  863. 'TRANSLITERATE_FILE_NAMES' => 1,
  864. 'USE_LINKS' => 1,
  865. 'USE_NUMERIC_ENTITY' => 1,
  866. 'ENABLE_ENCODING_USE_ENTITY' => 1,
  867. 'DATE_IN_HEADER' => 0,
  868. 'AVOID_MENU_REDUNDANCY' => 0,
  869. 'HEADERS' => 1,
  870. 'DO_ABOUT' => 0,
  871. 'USE_ACCESSKEY' => 1,
  872. 'USE_REL_REV' => 1,
  873. 'NODE_NAME_IN_MENU' => 1,
  874. 'NODE_NAME_IN_INDEX' => 1,
  875. 'XREF_USE_NODE_NAME_ARG' => undef,
  876. 'XREF_USE_FLOAT_LABEL' => 0,
  877. 'OVERVIEW_LINK_TO_TOC' => 1,
  878. 'COMPLEX_FORMAT_IN_TABLE' => 0,
  879. 'WORDS_IN_PAGE' => 300,
  880. 'SECTION_BUTTONS' => [[ 'NodeNext', \&_default_node_direction ],
  881. [ 'NodePrev', \&_default_node_direction ],
  882. [ 'NodeUp', \&_default_node_direction ], ' ',
  883. 'Contents', 'Index'],
  884. 'LINKS_BUTTONS' => ['Top', 'Index', 'Contents', 'About',
  885. 'NodeUp', 'NextFile', 'PrevFile'],
  886. # 'TOP_BUTTONS' => ['Back', 'Forward', ' ',
  887. # 'Contents', 'Index', 'About'],
  888. #
  889. # 'MISC_BUTTONS' => [ 'Top', 'Contents', 'Index', 'About' ],
  890. # 'CHAPTER_BUTTONS' => [ 'FastBack', 'FastForward', ' ',
  891. # ' ', ' ', ' ', ' ',
  892. # 'Top', 'Contents', 'Index', 'About', ],
  893. # 'SECTION_FOOTER_BUTTONS' => [ 'FastBack', 'Back', 'Up', 'Forward', 'FastForward' ],
  894. # 'NODE_FOOTER_BUTTONS' => [ 'FastBack', 'Back', 'Up', 'Forward', 'FastForward' ],
  895. 'misc_elements_targets' => {
  896. 'Overview' => 'SEC_Overview',
  897. 'Contents' => 'SEC_Contents',
  898. 'Footnotes' => 'SEC_Foot',
  899. 'About' => 'SEC_About',
  900. 'Top' => 'SEC_Top',
  901. },
  902. 'misc_pages_file_string' => {
  903. 'Contents' => '_toc',
  904. 'Overview' => '_ovr',
  905. 'Footnotes' => '_fot',
  906. 'About' => '_abt',
  907. },
  908. 'frame_pages_file_string' => {
  909. 'Frame' => '_frame',
  910. 'Toc_Frame' => '_toc_frame',
  911. },
  912. 'misc_elements_order' => ['Footnotes', 'Contents', 'Overview', 'About'],
  913. 'DOCTYPE' => '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
  914. 'FRAMESET_DOCTYPE' => '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">',
  915. 'DEFAULT_RULE' => '<hr>',
  916. 'BIG_RULE' => '<hr>',
  917. 'MENU_SYMBOL' => '&bull;',
  918. 'MENU_ENTRY_COLON' => ':',
  919. 'INDEX_ENTRY_COLON' => ':',
  920. 'BODYTEXT' => undef,
  921. 'documentlanguage' => 'en',
  922. 'xrefautomaticsectiontitle' => 'off',
  923. 'SHOW_TITLE' => 1,
  924. 'USE_TITLEPAGE_FOR_TITLE' => 0,
  925. 'MONOLITHIC' => 1,
  926. 'CHAPTER_HEADER_LEVEL' => 2,
  927. 'MAX_HEADER_LEVEL' => 4,
  928. 'FOOTNOTE_END_HEADER_LEVEL' => 4,
  929. 'FOOTNOTE_SEPARATE_HEADER_LEVEL' => 4,
  930. 'BUTTONS_REL' => \%BUTTONS_REL,
  931. 'BUTTONS_ACCESSKEY' => \%BUTTONS_ACCESSKEY,
  932. 'BUTTONS_EXAMPLE' => \%BUTTONS_EXAMPLE,
  933. 'BUTTONS_GOTO' => \%BUTTONS_GOTO,
  934. 'BUTTONS_NAME' => \%BUTTONS_NAME,
  935. 'BUTTONS_TEXT' => \%BUTTONS_TEXT,
  936. 'ACTIVE_ICONS' => \%ACTIVE_ICONS,
  937. 'PASSIVE_ICONS' => \%PASSIVE_ICONS,
  938. 'SPECIAL_ELEMENTS_NAME' => \%SPECIAL_ELEMENTS_NAME,
  939. 'SPECIAL_ELEMENTS_CLASS' => {
  940. 'About' => 'about',
  941. 'Contents' => 'contents',
  942. 'Overview' => 'shortcontents',
  943. 'Footnotes' => 'footnotes',
  944. },
  945. 'output_format' => 'html',
  946. );
  947. foreach my $buttons ('CHAPTER_BUTTONS', 'SECTION_FOOTER_BUTTONS', 'NODE_FOOTER_BUTTONS',
  948. 'MISC_BUTTONS', 'TOP_BUTTONS') {
  949. $defaults{$buttons} = [@{$defaults{'SECTION_BUTTONS'}}];
  950. }
  951. sub converter_defaults($$)
  952. {
  953. my $self = shift;
  954. my $conf = shift;
  955. if (defined($conf->{'TEXI2HTML'})) {
  956. _set_variables_texi2html();
  957. }
  958. return %defaults;
  959. }
  960. my $NO_BULLET_LIST_STYLE = 'list-style: none';
  961. my $NO_BULLET_LIST_CLASS = 'no-bullet';
  962. my $NO_BULLET_LIST_ATTRIBUTE = ' class="'.$NO_BULLET_LIST_CLASS.'"';
  963. my $MENU_PRE_STYLE = 'font-family: serif';
  964. my %css_map = (
  965. "ul.$NO_BULLET_LIST_CLASS" => "$NO_BULLET_LIST_STYLE",
  966. 'pre.menu-comment' => "$MENU_PRE_STYLE",
  967. 'pre.menu-preformatted' => "$MENU_PRE_STYLE",
  968. 'a.summary-letter' => 'text-decoration: none',
  969. 'blockquote.smallquotation' => 'font-size: smaller',
  970. 'pre.display' => 'font-family: inherit',
  971. 'pre.smalldisplay' => 'font-family: inherit; font-size: smaller',
  972. 'pre.smallexample' => 'font-size: smaller',
  973. 'span.sansserif' => 'font-family: sans-serif; font-weight: normal',
  974. 'span.roman' => 'font-family: initial; font-weight: normal',
  975. 'span.nolinebreak' => 'white-space: nowrap',
  976. 'kbd' => 'font-style: oblique',
  977. );
  978. $css_map{'pre.format'} = $css_map{'pre.display'};
  979. $css_map{'pre.smallformat'} = $css_map{'pre.smalldisplay'};
  980. $css_map{'pre.smalllisp'} = $css_map{'pre.smallexample'};
  981. my %preformatted_commands_context = %preformatted_commands;
  982. $preformatted_commands_context{'verbatim'} = 1;
  983. my %pre_class_commands;
  984. foreach my $preformatted_command (keys(%preformatted_commands_context)) {
  985. $pre_class_commands{$preformatted_command} = $preformatted_command;
  986. }
  987. $pre_class_commands{'menu'} = 'menu-preformatted';
  988. $pre_class_types{'menu_comment'} = 'menu-comment';
  989. my %indented_preformatted_commands;
  990. foreach my $indented_format ('example', 'display', 'lisp') {
  991. $indented_preformatted_commands{$indented_format} = 1;
  992. $indented_preformatted_commands{"small$indented_format"} = 1;
  993. $css_map{"div.$indented_format"} = 'margin-left: 3.2em';
  994. $css_map{"div.small$indented_format"} = 'margin-left: 3.2em';
  995. }
  996. $css_map{"blockquote.indentedblock"} = 'margin-right: 0em';
  997. $css_map{"blockquote.smallindentedblock"}
  998. = 'margin-right: 0em; font-size: smaller';
  999. # types that are in code style in the default case
  1000. my %default_code_types = (
  1001. '_code' => 1,
  1002. );
  1003. # default specification of arguments formatting
  1004. my %default_commands_args = (
  1005. 'email' => [['monospace', 'monospacestring'], ['normal']],
  1006. 'anchor' => [['monospacestring']],
  1007. 'uref' => [['monospacestring'], ['normal'], ['normal']],
  1008. 'url' => [['monospacestring'], ['normal'], ['normal']],
  1009. 'printindex' => [[]],
  1010. 'sp' => [[]],
  1011. 'inforef' => [['monospace'],['normal'],['monospacetext']],
  1012. 'xref' => [['monospace'],['normal'],['normal'],['monospacetext'],['normal']],
  1013. 'pxref' => [['monospace'],['normal'],['normal'],['monospacetext'],['normal']],
  1014. 'ref' => [['monospace'],['normal'],['normal'],['monospacetext'],['normal']],
  1015. 'image' => [['monospacetext'],['monospacetext'],['monospacetext'],['string', 'normal'],['monospacetext']],
  1016. # FIXME shouldn't it better not to convert if later ignored?
  1017. 'inlinefmt' => [['monospacetext'],['normal']],
  1018. 'inlinefmtifelse' => [['monospacetext'],['normal'],['normal']],
  1019. 'inlineraw' => [['monospacetext'],['raw']],
  1020. 'inlineifclear' => [['monospacetext'],['normal']],
  1021. 'inlineifset' => [['monospacetext'],['normal']],
  1022. 'item' => [[]],
  1023. 'itemx' => [[]],
  1024. );
  1025. foreach my $explained_command (keys(%explained_commands)) {
  1026. $default_commands_args{$explained_command}
  1027. = [['normal'], ['string']];
  1028. }
  1029. # Default for the function references used for the formatting
  1030. # of commands.
  1031. my %default_commands_conversion;
  1032. sub default_commands_conversion($$)
  1033. {
  1034. my $self = shift;
  1035. my $command = shift;
  1036. return $default_commands_conversion{$command};
  1037. }
  1038. my %kept_misc_commands;
  1039. my @informative_global_commands = ('contents', 'shortcontents',
  1040. 'summarycontents', 'allowcodebreaks', 'documentlanguage',
  1041. 'footnotestyle', 'documentencoding',
  1042. 'xrefautomaticsectiontitle', 'deftypefnnewline');
  1043. # taken from global
  1044. # 'documentencoding'
  1045. # 'novalidate'
  1046. foreach my $misc_command(@informative_global_commands,
  1047. 'verbatiminclude', 'insertcopying', 'printindex', 'listoffloats',
  1048. 'author', 'subtitle',
  1049. 'title', keys(%default_index_commands),
  1050. keys(%formatting_misc_commands)) {
  1051. $kept_misc_commands{$misc_command} = 1;
  1052. }
  1053. sub converter_global_commands($)
  1054. {
  1055. return @informative_global_commands;
  1056. }
  1057. my %contents_commands = (
  1058. 'contents' => 1,
  1059. 'shortcontents' => 1,
  1060. 'summarycontents' => 1,
  1061. );
  1062. #my %ignored_misc_commands;
  1063. foreach my $misc_command (keys(%misc_commands)) {
  1064. # $ignored_misc_commands{$misc_command} = 1
  1065. $default_commands_conversion{$misc_command} = undef
  1066. unless ($kept_misc_commands{$misc_command});
  1067. }
  1068. foreach my $ignored_brace_commands ('caption', 'shortcaption',
  1069. 'hyphenation', 'sortas') {
  1070. #$ignored_commands{$ignored_brace_commands} = 1;
  1071. $default_commands_conversion{$ignored_brace_commands} = undef;
  1072. }
  1073. # commands that leads to advancing the paragraph number. This is mostly
  1074. #used to determine the first line, in fact.
  1075. my %advance_paragraph_count_commands;
  1076. foreach my $command (keys(%block_commands)) {
  1077. next if ($menu_commands{$command}
  1078. or $block_commands{$command} eq 'raw');
  1079. $advance_paragraph_count_commands{$command} = 1;
  1080. }
  1081. foreach my $ignored_block_commands ('ignore', 'macro', 'rmacro', 'copying',
  1082. 'documentdescription', 'titlepage', 'direntry') {
  1083. #$ignored_commands{$ignored_block_commands} = 1;
  1084. $default_commands_conversion{$ignored_block_commands} = undef;
  1085. };
  1086. # Formatting of commands without args
  1087. # The hash holding the defaults for the formatting of
  1088. # most commands without args
  1089. my %default_commands_formatting;
  1090. foreach my $command (keys(%{$Texinfo::Convert::Converter::default_xml_commands_formatting{'normal'}})) {
  1091. $default_commands_formatting{'normal'}->{$command} =
  1092. $Texinfo::Convert::Converter::default_xml_commands_formatting{'normal'}->{$command};
  1093. }
  1094. $default_commands_formatting{'normal'}->{' '} = '&nbsp;';
  1095. $default_commands_formatting{'normal'}->{"\t"} = '&nbsp;';
  1096. $default_commands_formatting{'normal'}->{"\n"} = '&nbsp;';
  1097. my %default_commands_translation;
  1098. # possible example of use, right now not used, as the generic
  1099. # translated command with gdt tree is used.
  1100. #$default_commands_translation{'normal'}->{'error'} = 'error--&gt;';
  1101. ## This is used to have gettext pick up the chain to be translated
  1102. #if (0) {
  1103. # my $not_existing;
  1104. # $not_existing->gdt('error--&gt;');
  1105. #}
  1106. #foreach my $command (keys(%{$default_commands_formatting{'normal'}})) {
  1107. # $default_commands_formatting{'preformatted'}->{$command} =
  1108. # $default_commands_formatting{'normal'}->{$command};
  1109. # $default_commands_formatting{'string'}->{$command} =
  1110. # $default_commands_formatting{'normal'}->{$command};
  1111. #}
  1112. $default_commands_formatting{'normal'}->{'enddots'}
  1113. = '<small class="enddots">...</small>';
  1114. $default_commands_formatting{'preformatted'}->{'enddots'} = '...';
  1115. $default_commands_formatting{'normal'}->{'*'} = '<br>';
  1116. $default_commands_formatting{'preformatted'}->{'*'} = "\n";
  1117. sub _convert_no_arg_command($$$)
  1118. {
  1119. my $self = shift;
  1120. my $cmdname = shift;
  1121. my $command = shift;
  1122. if ($cmdname eq 'click' and $command->{'extra'}
  1123. and exists($command->{'extra'}->{'clickstyle'})) {
  1124. my $click_cmdname = $command->{'extra'}->{'clickstyle'};
  1125. if (($self->in_preformatted() or $self->in_math()
  1126. and $self->{'commands_formatting'}->{'preformatted'}->{$click_cmdname})
  1127. or ($self->in_string() and
  1128. $self->{'commands_formatting'}->{'string'}->{$click_cmdname})
  1129. or ($self->{'commands_formatting'}->{'normal'}->{$click_cmdname})) {
  1130. $cmdname = $click_cmdname;
  1131. }
  1132. }
  1133. if ($self->in_upper_case() and $letter_no_arg_commands{$cmdname}
  1134. and $self->{'commands_formatting'}->{'normal'}->{uc($cmdname)}) {
  1135. $cmdname = uc($cmdname);
  1136. }
  1137. my $result;
  1138. if ($self->{'translated_commands'}->{$cmdname}) {
  1139. return $self->convert_tree(
  1140. $self->gdt($self->{'translated_commands'}->{$cmdname}));
  1141. }
  1142. if ($self->in_preformatted() or $self->in_math()) {
  1143. $result = $self->{'commands_formatting'}->{'preformatted'}->{$cmdname};
  1144. } elsif ($self->in_string()) {
  1145. $result = $self->{'commands_formatting'}->{'string'}->{$cmdname};
  1146. } else {
  1147. $result = $self->{'commands_formatting'}->{'normal'}->{$cmdname};
  1148. }
  1149. return $result;
  1150. }
  1151. foreach my $command(keys(%{$default_commands_formatting{'normal'}})) {
  1152. $default_commands_conversion{$command} = \&_convert_no_arg_command;
  1153. }
  1154. sub _convert_today_command($$$)
  1155. {
  1156. my $self = shift;
  1157. my $cmdname = shift;
  1158. my $command = shift;
  1159. my $tree = $self->Texinfo::Common::expand_today();
  1160. return $self->convert_tree($tree);
  1161. }
  1162. $default_commands_conversion{'today'} = \&_convert_today_command;
  1163. # style commands
  1164. my %quoted_style_commands;
  1165. foreach my $quoted_command ('samp') {
  1166. $quoted_style_commands{$quoted_command} = 1;
  1167. }
  1168. my %style_attribute_commands;
  1169. $style_attribute_commands{'normal'} = {
  1170. 'b' => 'b',
  1171. 'cite' => 'cite',
  1172. 'code' => 'code',
  1173. 'command' => 'code',
  1174. 'dfn' => 'em',
  1175. 'emph' => 'em',
  1176. 'env' => 'code',
  1177. 'file' => 'samp',
  1178. 'headitemfont' => 'b', # not really that, in fact it is
  1179. # in <th> rather than <td>
  1180. 'i' => 'i',
  1181. 'slanted' => 'i',
  1182. 'sansserif' => 'span class="sansserif"',
  1183. 'kbd' => 'kbd',
  1184. 'option' => 'samp',
  1185. 'r' => 'span class="roman"',
  1186. 'samp' => 'samp',
  1187. 'sc' => 'small',
  1188. 'strong' => 'strong',
  1189. 'sub' => 'sub',
  1190. 'sup' => 'sup',
  1191. 't' => 'tt',
  1192. 'var' => 'var',
  1193. 'verb' => 'tt',
  1194. 'math' => 'em',
  1195. };
  1196. my %style_commands_formatting;
  1197. # this weird construct does like uniq, it avoids duplicates.
  1198. # it is required since math is not in the %style_commands as it is
  1199. # in context command.
  1200. my @all_style_commands = keys %{{ map { $_ => 1 }
  1201. (keys(%style_commands), keys(%{$style_attribute_commands{'normal'}}),
  1202. 'dmn') }};
  1203. foreach my $command(@all_style_commands) {
  1204. # default is no attribute.
  1205. if ($style_attribute_commands{'normal'}->{$command}) {
  1206. $style_commands_formatting{'normal'}->{$command}->{'attribute'}
  1207. = $style_attribute_commands{'normal'}->{$command};
  1208. $style_commands_formatting{'preformatted'}->{$command}->{'attribute'}
  1209. = $style_attribute_commands{'normal'}->{$command};
  1210. }
  1211. if ($style_attribute_commands{'preformatted'}->{$command}) {
  1212. $style_commands_formatting{'preformatted'}->{$command}->{'attribute'} =
  1213. $style_attribute_commands{'preformatted'}->{$command};
  1214. }
  1215. if ($quoted_style_commands{$command}) {
  1216. foreach my $context ('normal', 'string', 'preformatted') {
  1217. $style_commands_formatting{$context}->{$command}->{'quote'} = 1;
  1218. }
  1219. }
  1220. $default_commands_conversion{$command} = \&_convert_style_command;
  1221. }
  1222. delete $style_commands_formatting{'preformatted'}->{'sc'}->{'attribute'};
  1223. delete $style_commands_formatting{'preformatted'}->{'sc'};
  1224. sub _parse_attribute($)
  1225. {
  1226. my $element = shift;
  1227. return ('', '', '') if (!defined($element));
  1228. my ($class, $attributes) = ('', '');
  1229. if ($element =~ /^(\w+)(\s+.*)/)
  1230. {
  1231. $element = $1;
  1232. $attributes = $2;
  1233. if ($attributes =~ s/^\s+class=\"([^\"]+)\"//) {
  1234. $class = $1;
  1235. }
  1236. }
  1237. return ($element, $class, $attributes);
  1238. }
  1239. sub _convert_style_command($$$$)
  1240. {
  1241. my $self = shift;
  1242. my $cmdname = shift;
  1243. my $command = shift;
  1244. my $args = shift;
  1245. my $text = $args->[0]->{'normal'};
  1246. if (!defined($text)) {
  1247. # happens with bogus @-commands without argument, like @strong something
  1248. #cluck "text not defined in _convert_style_command";
  1249. return '';
  1250. }
  1251. # handle the effect of kbdinputstyle
  1252. if ($cmdname eq 'kbd' and $command->{'extra'}
  1253. and $command->{'extra'}->{'code'}) {
  1254. $cmdname = 'code';
  1255. }
  1256. my $attribute_hash = {};
  1257. if ($self->in_preformatted()) {
  1258. $attribute_hash = $self->{'style_commands_formatting'}->{'preformatted'};
  1259. } elsif (!$self->in_string()) {
  1260. $attribute_hash = $self->{'style_commands_formatting'}->{'normal'};
  1261. }
  1262. if (defined($attribute_hash->{$cmdname})) {
  1263. if (defined($attribute_hash->{$cmdname}->{'attribute'})) {
  1264. my ($style, $class, $attribute_text)
  1265. = _parse_attribute ($attribute_hash->{$cmdname}->{'attribute'});
  1266. my $open = $self->_attribute_class($style, $class);
  1267. if ($open ne '') {
  1268. $text = $open . "$attribute_text>"
  1269. . $text . "</$style>";
  1270. } elsif ($attribute_text ne '') {
  1271. $text = "<$style $attribute_text>". $text . "</$style>";
  1272. }
  1273. }
  1274. if (defined($attribute_hash->{$cmdname}->{'quote'})) {
  1275. $text = $self->get_conf('OPEN_QUOTE_SYMBOL') . $text
  1276. . $self->get_conf('CLOSE_QUOTE_SYMBOL');
  1277. }
  1278. }
  1279. return $text;
  1280. }
  1281. sub _convert_w_command($$$$)
  1282. {
  1283. my $self = shift;
  1284. my $cmdname = shift;
  1285. my $command = shift;
  1286. my $args = shift;
  1287. my $text = $args->[0]->{'normal'};
  1288. if (!defined($text)) {
  1289. $text = '';
  1290. }
  1291. if ($self->in_string) {
  1292. return $text;
  1293. } else {
  1294. return $text . '<!-- /@w -->';
  1295. }
  1296. }
  1297. $default_commands_conversion{'w'} = \&_convert_w_command;
  1298. sub _convert_value_command($$$$)
  1299. {
  1300. my $self = shift;
  1301. my $cmdname = shift;
  1302. my $command = shift;
  1303. my $args = shift;
  1304. return $self->convert_tree($self->gdt('@{No value for `{value}\'@}',
  1305. {'value' => $command->{'type'}}));
  1306. }
  1307. $default_commands_conversion{'value'} = \&_convert_value_command;
  1308. sub _convert_email_command($$$$)
  1309. {
  1310. my $self = shift;
  1311. my $cmdname = shift;
  1312. my $command = shift;
  1313. my $args = shift;
  1314. my $mail_arg = shift @$args;
  1315. my $text_arg = shift @$args;
  1316. my $mail = '';
  1317. my $mail_string = '';
  1318. if (defined($mail_arg)) {
  1319. $mail = $mail_arg->{'monospace'};
  1320. $mail_string = $mail_arg->{'monospacestring'};
  1321. }
  1322. my $text = '';
  1323. if (defined($text_arg)) {
  1324. $text = $text_arg->{'normal'};
  1325. }
  1326. $text = $mail unless ($text ne '');
  1327. return $text if ($mail eq '');
  1328. if ($self->in_string()) {
  1329. return "$mail_string ($text)";
  1330. } else {
  1331. return "<a href=\"mailto:$mail_string\">$text</a>";
  1332. }
  1333. }
  1334. $default_commands_conversion{'email'} = \&_convert_email_command;
  1335. sub _convert_explained_command($$$$)
  1336. {
  1337. my $self = shift;
  1338. my $cmdname = shift;
  1339. my $command = shift;
  1340. my $args = shift;
  1341. my $with_explanation;
  1342. my $explanation_result;
  1343. my $explanation_string;
  1344. my $normalized_type
  1345. = Texinfo::Convert::NodeNameNormalization::normalize_node(
  1346. {'contents' =>
  1347. $command->{'extra'}->{'brace_command_contents'}->[0]});
  1348. if ($args->[1] and defined($args->[1]->{'string'})
  1349. and $args->[1]->{'string'} =~ /\S/) {
  1350. $with_explanation = 1;
  1351. $explanation_string = $args->[1]->{'string'};
  1352. # Convert the expanation of the acronym. Must do this before we save
  1353. # the explanation for the future, otherwise we get infinite recursion
  1354. # for recursively-defined acronyms.
  1355. $explanation_result = $self->convert_tree( $args->[1]->{'tree'} );
  1356. $self->{'explained_commands'}->{$cmdname}->{$normalized_type} =
  1357. $command->{'extra'}->{'brace_command_contents'}->[1];
  1358. } elsif ($command->{'extra'}->{'explanation_contents'}) {
  1359. if (@{$command->{'extra'}->{'explanation_contents'}}) {
  1360. $explanation_string = $self->convert_tree_new_formatting_context(
  1361. {'type' => '_string',
  1362. 'contents' => $command->{'extra'}->{'explanation_contents'}},
  1363. $cmdname, $cmdname);
  1364. }
  1365. } elsif ($self->{'explained_commands'}->{$cmdname}->{$normalized_type}) {
  1366. $explanation_string = $self->convert_tree_new_formatting_context(
  1367. {'type' => '_string',
  1368. 'contents' => $self->{'explained_commands'}
  1369. ->{$cmdname}->{$normalized_type}},
  1370. $cmdname, $cmdname);
  1371. $command->{'extra'}->{'explanation_contents'}
  1372. = $self->{'explained_commands'}->{$cmdname}->{$normalized_type};
  1373. } else {
  1374. # Avoid ever giving an explanation for this element. This prevents
  1375. # infinite recursion for a recursively-defined acronym, when an
  1376. # @acronym within the explanation could end up referring to the
  1377. # containing @acronym.
  1378. $command->{'extra'}->{'explanation_contents'} = [];
  1379. }
  1380. my $result = $args->[0]->{'normal'};
  1381. if (!$self->in_string()) {
  1382. if (defined($explanation_string)) {
  1383. $result = "<$cmdname title=\"$explanation_string\">".$result;
  1384. } else {
  1385. $result = "<$cmdname>".$result;
  1386. }
  1387. $result .= "</$cmdname>";
  1388. }
  1389. if ($with_explanation) {
  1390. $result = $self->convert_tree($self->gdt('{explained_string} ({explanation})',
  1391. {'explained_string' => {'type' => '_converted',
  1392. 'text' => $result},
  1393. 'explanation' => {'type' => '_converted',
  1394. 'text' => $explanation_result}}));
  1395. }
  1396. return $result;
  1397. }
  1398. foreach my $explained_command (keys(%explained_commands)) {
  1399. $default_commands_conversion{$explained_command}
  1400. = \&_convert_explained_command;
  1401. }
  1402. sub _convert_anchor_command($$$$)
  1403. {
  1404. my $self = shift;
  1405. my $cmdname = shift;
  1406. my $command = shift;
  1407. my $args = shift;
  1408. my $id = $self->command_id($command);
  1409. if (defined($id) and $id ne '' and !@{$self->{'multiple_pass'}}
  1410. and !$self->in_string()) {
  1411. return "<a name=\"$id\"></a>";
  1412. }
  1413. return '';
  1414. }
  1415. $default_commands_conversion{'anchor'} = \&_convert_anchor_command;
  1416. my $foot_num;
  1417. my $foot_lines;
  1418. my $NO_NUMBER_FOOTNOTE_SYMBOL = '*';
  1419. my $footid_base = 'FOOT';
  1420. my $docid_base = 'DOCF';
  1421. # to avoid duplicate names, use a prefix that cannot happen in anchors
  1422. my $target_prefix = "t_h";
  1423. my %footnote_id_numbers;
  1424. sub _convert_footnote_command($$$$)
  1425. {
  1426. my $self = shift;
  1427. my $cmdname = shift;
  1428. my $command = shift;
  1429. my $args = shift;
  1430. my $number_in_doc;
  1431. $foot_num++;
  1432. if ($self->get_conf('NUMBER_FOOTNOTES')) {
  1433. $number_in_doc = $foot_num;
  1434. } else {
  1435. $number_in_doc = $NO_NUMBER_FOOTNOTE_SYMBOL;
  1436. }
  1437. return "($number_in_doc)" if ($self->in_string());
  1438. #print STDERR "FOOTNOTE $command\n";
  1439. my $footid = $self->command_target($command);
  1440. # happens for bogus footnotes
  1441. if (!defined($footid)) {
  1442. return '';
  1443. }
  1444. # ID for linking back to the main text from the footnote.
  1445. my $docid = $footid;
  1446. $docid =~ s/^$footid_base/$docid_base/;
  1447. my $document_filename;
  1448. my $footnote_filename;
  1449. if ($self->get_conf('footnotestyle') eq 'separate') {
  1450. $footnote_filename = $self->command_filename($command);
  1451. $document_filename = $self->{'current_filename'};
  1452. $footnote_filename = '' if (!defined($footnote_filename));
  1453. $document_filename = '' if (!defined($document_filename));
  1454. if ($document_filename eq $footnote_filename) {
  1455. $document_filename = $footnote_filename = '';
  1456. }
  1457. } else {
  1458. $document_filename = $footnote_filename = '';
  1459. }
  1460. my $footnote_text;
  1461. if ($args->[0]) {
  1462. $footnote_text = $args->[0]->{'normal'};
  1463. } else {
  1464. $footnote_text = '';
  1465. }
  1466. chomp ($footnote_text);
  1467. $footnote_text .= "\n";
  1468. if (@{$self->{'multiple_pass'}}) {
  1469. $footid = $target_prefix.$self->{'multiple_pass'}->[-1].'_'.$footid.'_'.$foot_num;
  1470. $docid = $target_prefix.$self->{'multiple_pass'}->[-1].'_'.$docid.'_'.$foot_num;
  1471. } else {
  1472. if (!defined($footnote_id_numbers{$footid})) {
  1473. $footnote_id_numbers{$footid} = $foot_num;
  1474. } else {
  1475. # This should rarely happen, except for @footnote is @copying and
  1476. # multiple @insertcopying...
  1477. # Here it is not checked that there is no clash with another anchor.
  1478. # However, unless there are more than 1000 footnotes this should not
  1479. # happen.
  1480. $footid .= '_'.$foot_num;
  1481. $docid .= '_'.$foot_num;
  1482. }
  1483. }
  1484. $foot_lines .= '<h3>' .
  1485. "<a name=\"$footid\" href=\"$document_filename#$docid\">($number_in_doc)</a></h3>\n"
  1486. . $footnote_text;
  1487. my $footnote_number_text;
  1488. if ($self->in_preformatted()) {
  1489. $footnote_number_text = "($number_in_doc)";
  1490. } else {
  1491. $footnote_number_text = "<sup>$number_in_doc</sup>";
  1492. }
  1493. return "<a name=\"$docid\" href=\"$footnote_filename#$footid\">$footnote_number_text</a>";
  1494. }
  1495. $default_commands_conversion{'footnote'} = \&_convert_footnote_command;
  1496. sub _convert_uref_command($$$$)
  1497. {
  1498. my $self = shift;
  1499. my $cmdname = shift;
  1500. my $command = shift;
  1501. my $args = shift;
  1502. my @args = @$args;
  1503. my $url_arg = shift @args;
  1504. my $text_arg = shift @args;
  1505. my $replacement_arg = shift @args;
  1506. my ($url, $text, $replacement);
  1507. $url = $url_arg->{'monospacestring'} if defined($url_arg);
  1508. $text = $text_arg->{'normal'} if defined($text_arg);
  1509. $replacement = $replacement_arg->{'normal'} if defined($replacement_arg);
  1510. $text = $replacement if (defined($replacement) and $replacement ne '');
  1511. $text = $url if (!defined($text) or $text eq '');
  1512. return $text if (!defined($url) or $url eq '');
  1513. return "$text ($url)" if ($self->in_string());
  1514. return "<a href=\"$url\">$text</a>";
  1515. }
  1516. $default_commands_conversion{'uref'} = \&_convert_uref_command;
  1517. $default_commands_conversion{'url'} = \&_convert_uref_command;
  1518. my @image_files_extensions = ('.png', '.jpg', '.jpeg', '.gif');
  1519. sub _convert_image_command($$$$)
  1520. {
  1521. my $self = shift;
  1522. my $cmdname = shift;
  1523. my $command = shift;
  1524. my $args = shift;
  1525. my @extensions = @image_files_extensions;
  1526. if (defined($args->[0]->{'monospacetext'}) and $args->[0]->{'monospacetext'} ne '') {
  1527. my $basefile = $args->[0]->{'monospacetext'};
  1528. return $basefile if ($self->in_string());
  1529. my $extension;
  1530. if (defined($args->[4]) and defined($args->[4]->{'monospacetext'})) {
  1531. $extension = $args->[4]->{'monospacetext'};
  1532. unshift @extensions, ("$extension", ".$extension");
  1533. }
  1534. my $image_file;
  1535. foreach my $extension (@extensions) {
  1536. if ($self->Texinfo::Common::locate_include_file ($basefile.$extension)) {
  1537. # use the basename and not the file found. It is agreed that it is
  1538. # better, since in any case the files are moved.
  1539. $image_file = $basefile.$extension;
  1540. last;
  1541. }
  1542. }
  1543. if (!defined($image_file) or $image_file eq '') {
  1544. if (defined($extension) and $extension ne '') {
  1545. $image_file = "$basefile.$extension";
  1546. } else {
  1547. $image_file = "$basefile.jpg";
  1548. }
  1549. #cluck "err ($self->{'ignore_notice'})";
  1550. $self->line_warn(sprintf(
  1551. $self->__("\@image file `%s' (for HTML) not found, using `%s'"),
  1552. $basefile, $image_file), $command->{'line_nr'});
  1553. }
  1554. if (defined($self->get_conf('IMAGE_LINK_PREFIX'))) {
  1555. $image_file = $self->get_conf('IMAGE_LINK_PREFIX') . $image_file;
  1556. }
  1557. if ($self->in_preformatted()) {
  1558. my $alt_text;
  1559. if (defined($args->[3]) and defined($args->[3]->{'normal'})) {
  1560. $alt_text = $args->[3]->{'normal'};
  1561. }
  1562. if (!defined($alt_text) or ($alt_text eq '')) {
  1563. $alt_text = $self->protect_text($basefile);
  1564. }
  1565. return "[ $alt_text ]";
  1566. } else {
  1567. my $alt_string;
  1568. if (defined($args->[3]) and defined($args->[3]->{'string'})) {
  1569. $alt_string = $args->[3]->{'string'};
  1570. }
  1571. if (!defined($alt_string) or ($alt_string eq '')) {
  1572. $alt_string = $self->protect_text($basefile);
  1573. }
  1574. return "<img src=\"".$self->protect_text($image_file)."\" alt=\"$alt_string\">";
  1575. }
  1576. }
  1577. return '';
  1578. }
  1579. $default_commands_conversion{'image'} = \&_convert_image_command;
  1580. #sub _convert_math_command($$$$)
  1581. #{
  1582. # my $self = shift;
  1583. # my $cmdname = shift;
  1584. # my $command = shift;
  1585. # my $args = shift;
  1586. #
  1587. # return $args->[0]->{'normal'};
  1588. #}
  1589. #$default_commands_conversion{'math'} = \&_convert_math_command;
  1590. sub _convert_accent_command($$$$)
  1591. {
  1592. my $self = shift;
  1593. my $cmdname = shift;
  1594. my $command = shift;
  1595. my $args = shift;
  1596. return $self->xml_accents($command, $self->in_upper_case());
  1597. }
  1598. foreach my $command (keys(%accent_commands)) {
  1599. $default_commands_conversion{$command} = \&_convert_accent_command;
  1600. }
  1601. # key is formatted as code since it is in code_style_commands
  1602. sub _convert_key_command($$$$)
  1603. {
  1604. my $self = shift;
  1605. my $cmdname = shift;
  1606. my $command = shift;
  1607. my $args = shift;
  1608. my $text = $args->[0]->{'normal'};
  1609. if (!defined($text)) {
  1610. # happens with bogus @-commands without argument, like @strong something
  1611. return '';
  1612. }
  1613. if ($self->in_string()) {
  1614. return $text;
  1615. }
  1616. #return $self->protect_text('<') .$text .$self->protect_text('>');
  1617. my $class = $cmdname;
  1618. if (!$self->in_code()) {
  1619. return $self->_attribute_class('tt', $class).'>'.$text .'</tt>';;
  1620. } else {
  1621. my $open = $self->_attribute_class('span', $class);
  1622. if ($open ne '') {
  1623. return $open.'>'.$text.'</span>';
  1624. } else {
  1625. return $text;
  1626. }
  1627. }
  1628. }
  1629. $default_commands_conversion{'key'} = \&_convert_key_command;
  1630. # argument is formatted as code since indicateurl is in code_style_commands
  1631. sub _convert_indicateurl_command($$$$)
  1632. {
  1633. my $self = shift;
  1634. my $cmdname = shift;
  1635. my $command = shift;
  1636. my $args = shift;
  1637. my $text = $args->[0]->{'normal'};
  1638. if (!defined($text)) {
  1639. # happens with bogus @-commands without argument, like @strong something
  1640. return '';
  1641. }
  1642. if (!$self->in_string()) {
  1643. return $self->get_conf('OPEN_QUOTE_SYMBOL').'<code>' .$text
  1644. .'</code>'.$self->get_conf('CLOSE_QUOTE_SYMBOL');
  1645. } else {
  1646. return $self->get_conf('OPEN_QUOTE_SYMBOL').$text.
  1647. $self->get_conf('CLOSE_QUOTE_SYMBOL');
  1648. }
  1649. }
  1650. $default_commands_conversion{'indicateurl'} = \&_convert_indicateurl_command;
  1651. sub _convert_ctrl_command($$$$)
  1652. {
  1653. my $self = shift;
  1654. my $cmdname = shift;
  1655. my $command = shift;
  1656. my $args = shift;
  1657. my $text = $args->[0]->{'normal'};
  1658. if (!defined($text)) {
  1659. # happens with bogus @-commands without argument, like @strong something
  1660. return '';
  1661. }
  1662. return $self->protect_text('^') .$text;
  1663. }
  1664. $default_commands_conversion{'ctrl'} = \&_convert_ctrl_command;
  1665. sub _convert_titlefont_command($$$$)
  1666. {
  1667. my $self = shift;
  1668. my $cmdname = shift;
  1669. my $command = shift;
  1670. my $args = shift;
  1671. my $text = $args->[0]->{'normal'};
  1672. if (!defined($text)) {
  1673. # happens with bogus @-commands without argument, like @strong something
  1674. return '';
  1675. }
  1676. return &{$self->{'format_heading_text'}}($self, 'titlefont', $text, 0, $command);
  1677. }
  1678. $default_commands_conversion{'titlefont'} = \&_convert_titlefont_command;
  1679. sub _convert_U_command($$$$)
  1680. {
  1681. my $self = shift;
  1682. my $cmdname = shift;
  1683. my $command = shift;
  1684. my $args = shift;
  1685. my $arg = $args->[0]->{'normal'};
  1686. my $res;
  1687. if (defined($arg) && $arg) {
  1688. # checks on the value already done in Parser, just output it here.
  1689. $res = "&#x$arg;";
  1690. } else {
  1691. $res = '';
  1692. }
  1693. return $res;
  1694. }
  1695. $default_commands_conversion{'U'} = \&_convert_U_command;
  1696. sub _default_comment($$) {
  1697. my $self = shift;
  1698. my $text = shift;
  1699. return $self->xml_comment(' '.$text);
  1700. }
  1701. sub protect_text($$) {
  1702. my $self = shift;
  1703. my $text = shift;
  1704. return &{$self->{'format_protect_text'}}($self, $text);
  1705. }
  1706. sub _default_protect_text($$) {
  1707. my $self = shift;
  1708. my $text = shift;
  1709. my $result = $self->xml_protect_text($text);
  1710. $result =~ s/\f/&#12;/g;
  1711. return $result;
  1712. }
  1713. sub _default_heading_text($$$$$)
  1714. {
  1715. my $self = shift;
  1716. my $cmdname = shift;
  1717. my $text = shift;
  1718. my $level = shift;
  1719. my $command = shift;
  1720. return '' if ($text !~ /\S/);
  1721. # This should seldom happen.
  1722. if ($self->in_string()) {
  1723. $text .= "\n" unless ($cmdname eq 'titlefont');
  1724. return $text;
  1725. }
  1726. my $class;
  1727. if ($cmdname eq 'node') {
  1728. $class = 'node-heading';
  1729. } else {
  1730. $class = $cmdname;
  1731. }
  1732. my $align = '';
  1733. $align = ' align="center"' if ($cmdname eq 'centerchap' or $cmdname eq 'settitle');
  1734. if ($level < 1) {
  1735. $level = 1;
  1736. } elsif ($level > $self->get_conf('MAX_HEADER_LEVEL')) {
  1737. $level = $self->get_conf('MAX_HEADER_LEVEL');
  1738. }
  1739. my $result = $self->_attribute_class("h$level", $class) ."$align>$text</h$level>";
  1740. # titlefont appears inline in text, so no end of line is
  1741. # added. The end of line should be added by the user if needed.
  1742. $result .= "\n" unless ($cmdname eq 'titlefont');
  1743. $result .= $self->get_conf('DEFAULT_RULE') . "\n"
  1744. if ($cmdname eq 'part'
  1745. and defined($self->get_conf('DEFAULT_RULE'))
  1746. and $self->get_conf('DEFAULT_RULE') ne '');
  1747. return $result;
  1748. }
  1749. # Associated to a button
  1750. sub _default_node_direction($$)
  1751. {
  1752. my $self = shift;
  1753. my $direction = shift;
  1754. my $result = undef;
  1755. my $href = $self->_element_direction($self->{'current_element'},
  1756. $direction, 'href');
  1757. my $node = $self->_element_direction($self->{'current_element'},
  1758. $direction, 'node');
  1759. my $anchor;
  1760. if (defined($href) and defined($node) and $node =~ /\S/) {
  1761. my $anchor_attributes = $self->_direction_href_attributes($direction);
  1762. $anchor = "<a href=\"$href\"${anchor_attributes}>$node</a>";
  1763. #} elsif (defined($node) and $node =~ /\S/) {
  1764. # $anchor = $node;
  1765. #} else {
  1766. }
  1767. if (defined($anchor)) {
  1768. # i18n
  1769. $result = $self->get_conf('BUTTONS_TEXT')->{$direction}.": $anchor";
  1770. }
  1771. return $result;
  1772. }
  1773. # how to create IMG tag
  1774. # this is only used in html, and only if ICONS is set and the button
  1775. # is active.
  1776. sub _default_button_icon_img($$$;$)
  1777. {
  1778. my $self = shift;
  1779. my $button = shift;
  1780. my $icon = shift;
  1781. my $name = shift;
  1782. return '' if (!defined($icon));
  1783. $button = "" if (!defined ($button));
  1784. $name = '' if (!defined($name));
  1785. my $alt = '';
  1786. if ($name ne '') {
  1787. if ($button ne '') {
  1788. $alt = "$button: $name";
  1789. } else {
  1790. $alt = $name;
  1791. }
  1792. } else {
  1793. $alt = $button;
  1794. }
  1795. return qq{<img src="$icon" border="0" alt="$alt" align="middle">};
  1796. }
  1797. sub _direction_href_attributes($$)
  1798. {
  1799. my $self = shift;
  1800. my $direction = shift;
  1801. my $href_attributes = '';
  1802. if ($self->get_conf('USE_ACCESSKEY')
  1803. and $self->get_conf('BUTTONS_ACCESSKEY')) {
  1804. my $accesskey = $self->get_conf('BUTTONS_ACCESSKEY')->{$direction};
  1805. if (defined($accesskey) and ($accesskey ne '')) {
  1806. $href_attributes = " accesskey=\"$accesskey\"";
  1807. }
  1808. }
  1809. if ($self->get_conf('USE_REL_REV') and $self->get_conf('BUTTONS_REL')) {
  1810. my $button_rel = $self->get_conf('BUTTONS_REL')->{$direction};
  1811. if (defined($button_rel) and ($button_rel ne '')) {
  1812. $href_attributes .= " rel=\"$button_rel\"";
  1813. }
  1814. }
  1815. return $href_attributes;
  1816. }
  1817. sub _default_button_formatting($$)
  1818. {
  1819. my $self = shift;
  1820. my $button = shift;
  1821. my ($active, $passive);
  1822. if (ref($button) eq 'CODE') {
  1823. $active = &$button($self);
  1824. } elsif (ref($button) eq 'SCALAR') {
  1825. $active = "$$button" if defined($$button);
  1826. } elsif (ref($button) eq 'ARRAY' and scalar(@$button == 2)) {
  1827. my $text = $button->[1];
  1828. my $button_href = $button->[0];
  1829. # verify that $button_href is simple text and text is a reference
  1830. if (defined($button_href) and !ref($button_href)
  1831. and defined($text) and (ref($text) eq 'SCALAR') and defined($$text)) {
  1832. # use given text
  1833. my $href = $self->_element_direction($self->{'current_element'},
  1834. $button_href, 'href');
  1835. if ($href) {
  1836. my $anchor_attributes = $self->_direction_href_attributes($button_href);
  1837. $active = "<a href=\"$href\"${anchor_attributes}>$$text</a>";
  1838. } else {
  1839. $passive = $$text;
  1840. }
  1841. # button_href is simple text and text is a reference on code
  1842. } elsif (defined($button_href) and !ref($button_href)
  1843. and defined($text) and (ref($text) eq 'CODE')) {
  1844. $active = &$text($self, $button_href);
  1845. # button_href is simple text and text is also a simple text
  1846. } elsif (defined($button_href) and !ref($button_href)
  1847. and defined($text) and !ref($text)) {
  1848. if ($text =~ s/^->\s*//) {
  1849. $active = $self->_element_direction($self->{'current_element'},
  1850. $button_href, $text);
  1851. } else {
  1852. my $href = $self->_element_direction($self->{'current_element'},
  1853. $button_href, 'href');
  1854. my $text_formatted = $self->_element_direction($self->{'current_element'},
  1855. $button_href, $text);
  1856. if ($href) {
  1857. my $anchor_attributes = $self->_direction_href_attributes($button_href);
  1858. $active = "<a href=\"$href\"${anchor_attributes}>$text_formatted</a>";
  1859. } else {
  1860. $passive = $text_formatted;
  1861. }
  1862. }
  1863. }
  1864. } elsif ($button eq ' ') {
  1865. # handle space button
  1866. if ($self->get_conf('ICONS') and $self->get_conf('ACTIVE_ICONS')
  1867. and defined($self->get_conf('ACTIVE_ICONS')->{$button})
  1868. and $self->get_conf('ACTIVE_ICONS')->{$button} ne '') {
  1869. my $button_name = $self->get_conf('BUTTONS_NAME')->{$button};
  1870. $active = &{$self->{'format_button_icon_img'}}($self, $button_name,
  1871. $self->get_conf('ACTIVE_ICONS')->{' '});
  1872. } else {
  1873. $active = $self->get_conf('BUTTONS_TEXT')->{$button};
  1874. }
  1875. } else {
  1876. my $href = $self->_element_direction($self->{'current_element'},
  1877. $button, 'href');
  1878. if ($href) {
  1879. # button is active
  1880. my $btitle = '';
  1881. if ($self->get_conf('BUTTONS_GOTO')
  1882. and defined($self->get_conf('BUTTONS_GOTO')->{$button})) {
  1883. $btitle = ' title="' . $self->get_conf('BUTTONS_GOTO')->{$button} . '"';
  1884. }
  1885. if ($self->get_conf('USE_ACCESSKEY') and $self->get_conf('BUTTONS_ACCESSKEY')) {
  1886. my $accesskey = $self->get_conf('BUTTONS_ACCESSKEY')->{$button};
  1887. if (defined($accesskey) and $accesskey ne '') {
  1888. $btitle .= " accesskey=\"$accesskey\"";
  1889. }
  1890. }
  1891. if ($self->get_conf('USE_REL_REV') and ($self->get_conf('BUTTONS_REL'))) {
  1892. my $button_rel = $self->get_conf('BUTTONS_REL')->{$button};
  1893. if (defined($button_rel) and $button_rel ne '') {
  1894. $btitle .= " rel=\"$button_rel\"";
  1895. }
  1896. }
  1897. my $use_icon;
  1898. if ($self->get_conf('ICONS') and $self->get_conf('ACTIVE_ICONS')
  1899. and $self->get_conf('BUTTONS_NAME')) {
  1900. my $active_icon = $self->get_conf('ACTIVE_ICONS')->{$button};
  1901. my $button_name = $self->get_conf('BUTTONS_NAME')->{$button};
  1902. if (defined($active_icon) and $active_icon ne ''
  1903. and defined($button_name)) {
  1904. # use icon
  1905. $active = "<a href=\"$href\"${btitle}>".
  1906. &{$self->{'format_button_icon_img'}}($self, $button_name, $active_icon,
  1907. $self->_element_direction($self->{'current_element'},
  1908. $button, 'string')) ."</a>";
  1909. $use_icon = 1;
  1910. }
  1911. }
  1912. if (!$use_icon) {
  1913. # use text
  1914. $active = '[' . "<a href=\"$href\"${btitle}>".
  1915. $self->get_conf('BUTTONS_TEXT')->{$button}."</a>" . ']';
  1916. }
  1917. } else {
  1918. # button is passive
  1919. my $use_icon;
  1920. if ($self->get_conf('ICONS') and $self->get_conf('PASSIVE_ICONS')
  1921. and $self->get_conf('BUTTONS_NAME')) {
  1922. my $passive_icon = $self->get_conf('PASSIVE_ICONS')->{$button};
  1923. my $button_name = $self->get_conf('BUTTONS_NAME')->{$button};
  1924. if ($passive_icon and $passive_icon ne '') {
  1925. $passive = &{$self->{'format_button_icon_img'}}($self, $button_name,
  1926. $passive_icon,
  1927. $self->_element_direction($self->{'current_element'},
  1928. $button, 'string'));
  1929. $use_icon = 1;
  1930. }
  1931. }
  1932. if (!$use_icon) {
  1933. $passive = '[' . $self->get_conf('BUTTONS_TEXT')->{$button} . ']';
  1934. }
  1935. }
  1936. }
  1937. return ($active, $passive);
  1938. }
  1939. my %html_default_node_directions;
  1940. foreach my $node_directions ('NodeNext', 'NodePrev', 'NodeUp') {
  1941. $html_default_node_directions{$node_directions} = 1;
  1942. }
  1943. sub _default_navigation_header_panel($$$$;$)
  1944. {
  1945. my $self = shift;
  1946. my $buttons = shift;
  1947. my $cmdname = shift;
  1948. my $command = shift;
  1949. my $vertical = shift;
  1950. # if VERTICAL_HEAD_NAVIGATION, the buttons are in a vertical table which
  1951. # is itself in the first column of a table opened in header_navigation
  1952. #my $vertical = $self->get_conf('VERTICAL_HEAD_NAVIGATION');
  1953. my $first_button = 1;
  1954. my $result = '';
  1955. if ($self->get_conf('HEADER_IN_TABLE')) {
  1956. $result .= $self->_attribute_class('table', 'header')
  1957. .' cellpadding="1" cellspacing="1" border="0">'."\n";
  1958. $result .= "<tr>" unless $vertical;
  1959. } else {
  1960. $result .= $self->_attribute_class('div', 'header').">\n<p>\n";
  1961. }
  1962. foreach my $button (@$buttons) {
  1963. if ($self->get_conf('HEADER_IN_TABLE')) {
  1964. $result .= qq{<tr valign="top" align="left">\n} if $vertical;
  1965. $result .= qq{<td valign="middle" align="left">};
  1966. }
  1967. my $direction;
  1968. if (ref($button) eq 'ARRAY'
  1969. and defined($button->[0]) and !ref($button->[0])) {
  1970. $direction = $button->[0];
  1971. } elsif (defined($button) and !ref($button)) {
  1972. $direction = $button;
  1973. }
  1974. my ($active, $passive) = &{$self->{'format_button'}}($self, $button);
  1975. if ($self->get_conf('HEADER_IN_TABLE')) {
  1976. if (defined($active)) {
  1977. $first_button = 0 if ($first_button);
  1978. $result .= $active;
  1979. } elsif (defined($passive)) {
  1980. $first_button = 0 if ($first_button);
  1981. $result .= $passive;
  1982. }
  1983. $result .= "</td>\n";
  1984. $result .= "</tr>\n" if $vertical;
  1985. } elsif (defined($active)) {
  1986. # only active buttons are print out when not in table
  1987. if (defined($direction)
  1988. and $html_default_node_directions{$direction} and !$first_button) {
  1989. $active = ', ' .$active;
  1990. }
  1991. $result .= $active;
  1992. $first_button = 0 if ($first_button);
  1993. }
  1994. }
  1995. if ($self->get_conf('HEADER_IN_TABLE')) {
  1996. $result .= "</tr>" unless $vertical;
  1997. $result .= "</table>\n";
  1998. } else {
  1999. $result .= "</p>\n</div>\n";
  2000. }
  2001. return $result;
  2002. }
  2003. sub _default_navigation_header($$$$)
  2004. {
  2005. my $self = shift;
  2006. my $buttons = shift;
  2007. my $cmdname = shift;
  2008. my $command = shift;
  2009. my $result = '';
  2010. if ($self->get_conf('VERTICAL_HEAD_NAVIGATION')) {
  2011. $result .= '<table border="0" cellpadding="0" cellspacing="0">
  2012. <tr valign="top">
  2013. <td align="left">
  2014. ';
  2015. }
  2016. $result .= &{$self->{'format_navigation_header_panel'}}($self, $buttons,
  2017. $cmdname, $command,
  2018. $self->get_conf('VERTICAL_HEAD_NAVIGATION'));
  2019. if ($self->get_conf('VERTICAL_HEAD_NAVIGATION')) {
  2020. $result .= '</td>
  2021. <td align="left">
  2022. ';
  2023. } elsif ($self->get_conf('SPLIT') eq 'node') {
  2024. $result .= $self->get_conf('DEFAULT_RULE')."\n";
  2025. }
  2026. return $result;
  2027. }
  2028. sub _default_element_header($$$$)
  2029. {
  2030. my $self = shift;
  2031. my $cmdname = shift;
  2032. my $command = shift;
  2033. my $element = shift;
  2034. my $result = '';
  2035. print STDERR "Element $element (@{$element->{'contents'}}) ".
  2036. Texinfo::Structuring::_print_element_command_texi($element) ."\n"
  2037. if ($self->get_conf('DEBUG'));
  2038. # Do the heading if the command is the first command in the element
  2039. if (($element->{'contents'}->[0] eq $command
  2040. or (!$element->{'contents'}->[0]->{'cmdname'}
  2041. and $element->{'contents'}->[1] eq $command))
  2042. # and there is more than one element
  2043. and ($element->{'element_next'} or $element->{'element_prev'})) {
  2044. my $is_top = $self->element_is_top($element);
  2045. my $first_in_page = (defined($element->{'filename'})
  2046. and $self->{'counter_in_file'}->{$element->{'filename'}} == 1);
  2047. my $previous_is_top = ($element->{'element_prev'}
  2048. and $self->element_is_top($element->{'element_prev'}));
  2049. print STDERR "Header ($previous_is_top, $is_top, $first_in_page): "
  2050. .Texinfo::Structuring::_print_root_command_texi($command)."\n"
  2051. if ($self->get_conf('DEBUG'));
  2052. if ($is_top) {
  2053. # use TOP_BUTTONS for top.
  2054. $result .= &{$self->{'format_navigation_header'}}($self,
  2055. $self->get_conf('TOP_BUTTONS'), $cmdname, $command)
  2056. if ($self->get_conf('SPLIT') or $self->get_conf('HEADERS'));
  2057. } else {
  2058. if ($first_in_page and !$self->get_conf('HEADERS')) {
  2059. if ($self->get_conf('SPLIT') eq 'chapter') {
  2060. $result .= &{$self->{'format_navigation_header'}}($self,
  2061. $self->get_conf('CHAPTER_BUTTONS'), $cmdname, $command);
  2062. $result .= $self->get_conf('DEFAULT_RULE') ."\n"
  2063. if (defined($self->get_conf('DEFAULT_RULE'))
  2064. and !$self->get_conf('VERTICAL_HEAD_NAVIGATION'));
  2065. } elsif ($self->get_conf('SPLIT') eq 'section') {
  2066. $result .= &{$self->{'format_navigation_header'}}($self,
  2067. $self->get_conf('SECTION_BUTTONS'), $cmdname, $command);
  2068. }
  2069. }
  2070. if (($first_in_page or $previous_is_top)
  2071. and $self->get_conf('HEADERS')) {
  2072. $result .= &{$self->{'format_navigation_header'}}($self,
  2073. $self->get_conf('SECTION_BUTTONS'), $cmdname, $command);
  2074. } elsif($self->get_conf('HEADERS') or $self->get_conf('SPLIT') eq 'node') {
  2075. # got to do this here, as it isn't done otherwise since
  2076. # navigation_header is not called
  2077. $result .= &{$self->{'format_navigation_header_panel'}}($self,
  2078. $self->get_conf('SECTION_BUTTONS'), $cmdname, $command);
  2079. }
  2080. }
  2081. }
  2082. return $result;
  2083. }
  2084. sub _convert_heading_command($$$$$)
  2085. {
  2086. my $self = shift;
  2087. my $cmdname = shift;
  2088. my $command = shift;
  2089. my $args = shift;
  2090. my $content = shift;
  2091. my $result = '';
  2092. # not clear that it may really happen
  2093. if ($self->in_string) {
  2094. $result .= $self->command_string($command) ."\n" if ($cmdname ne 'node');
  2095. $result .= $content if (defined($content));
  2096. return $result;
  2097. }
  2098. my $element_id = $self->command_id($command);
  2099. $result .= "<a name=\"$element_id\"></a>\n"
  2100. if (defined($element_id) and $element_id ne '');
  2101. print STDERR "Process $command "
  2102. .Texinfo::Structuring::_print_root_command_texi($command)."\n"
  2103. if ($self->get_conf('DEBUG'));
  2104. my $element;
  2105. if ($Texinfo::Common::root_commands{$command->{'cmdname'}}
  2106. and $command->{'parent'}
  2107. and $command->{'parent'}->{'type'}
  2108. and $command->{'parent'}->{'type'} eq 'element') {
  2109. $element = $command->{'parent'};
  2110. }
  2111. if ($element) {
  2112. $result .= &{$self->{'format_element_header'}}($self, $cmdname,
  2113. $command, $element);
  2114. }
  2115. my $heading_level;
  2116. # node is used as heading if there is nothing else.
  2117. if ($cmdname eq 'node') {
  2118. if (!$element or (!$element->{'extra'}->{'section'}
  2119. and $element->{'extra'}->{'node'}
  2120. and $element->{'extra'}->{'node'} eq $command
  2121. # bogus node may not have been normalized
  2122. and defined($command->{'extra'}->{'normalized'}))) {
  2123. if ($command->{'extra'}->{'normalized'} eq 'Top') {
  2124. $heading_level = 0;
  2125. } else {
  2126. $heading_level = 3;
  2127. }
  2128. }
  2129. } else {
  2130. $heading_level = $command->{'level'};
  2131. }
  2132. my $heading = $self->command_text($command);
  2133. # $heading not defined may happen if the command is a @node, for example
  2134. # if there is an error in the node.
  2135. if (defined($heading) and $heading ne '' and defined($heading_level)) {
  2136. if ($self->get_conf('TOC_LINKS')
  2137. and $Texinfo::Common::root_commands{$cmdname}
  2138. and $Texinfo::Common::sectioning_commands{$cmdname}) {
  2139. my $content_href = $self->command_contents_href($command, 'contents',
  2140. $self->{'current_filename'});
  2141. if ($content_href) {
  2142. $heading = "<a href=\"$content_href\">$heading</a>";
  2143. }
  2144. }
  2145. if ($self->in_preformatted()) {
  2146. $result .= '<strong>'.$heading.'</strong>'."\n";
  2147. } else {
  2148. # if the level was changed, set the command name right
  2149. if ($cmdname ne 'node'
  2150. and $heading_level ne $Texinfo::Common::command_structuring_level{$cmdname}) {
  2151. $cmdname
  2152. = $Texinfo::Common::level_to_structuring_command{$cmdname}->[$heading_level];
  2153. }
  2154. $result .= &{$self->{'format_heading_text'}}($self, $cmdname, $heading,
  2155. $heading_level +$self->get_conf('CHAPTER_HEADER_LEVEL') -1, $command);
  2156. }
  2157. }
  2158. $result .= $content if (defined($content));
  2159. if ($cmdname ne 'node'
  2160. and $self->{'current_node'}
  2161. and !$self->{'seenmenus'}->{$self->{'current_node'}}) {
  2162. $self->{'seenmenus'}->{$self->{'current_node'}} = 1;
  2163. # Generate a menu for this node.
  2164. my $menu_text;
  2165. my $menu_node = Texinfo::Structuring::menu_of_node (undef,
  2166. $command->{'extra'}{'associated_node'});
  2167. if ($menu_node) {
  2168. $menu_text = _convert ($self, $menu_node);
  2169. if ($menu_text) {
  2170. $result .= $menu_text;
  2171. $result .= "\n";
  2172. }
  2173. }
  2174. }
  2175. return $result;
  2176. }
  2177. foreach my $command (keys(%sectioning_commands), 'node') {
  2178. $default_commands_conversion{$command} = \&_convert_heading_command;
  2179. }
  2180. sub _convert_raw_command($$$$)
  2181. {
  2182. my $self = shift;
  2183. my $cmdname = shift;
  2184. my $command = shift;
  2185. my $content = shift;
  2186. if ($cmdname eq $self->{'output_format'}) {
  2187. return $content;
  2188. }
  2189. $self->line_warn(sprintf($self->__("raw format %s is not converted"),
  2190. $cmdname), $command->{'line_nr'});
  2191. return $self->protect_text($content);
  2192. }
  2193. foreach my $command (keys(%format_raw_commands)) {
  2194. $default_commands_conversion{$command} = \&_convert_raw_command;
  2195. }
  2196. sub _convert_inline_command($$$$)
  2197. {
  2198. my $self = shift;
  2199. my $cmdname = shift;
  2200. my $command = shift;
  2201. my $args = shift;
  2202. my $format_arg = shift @$args;
  2203. my $format;
  2204. if (defined($format_arg)) {
  2205. $format = $format_arg->{'monospacetext'};
  2206. }
  2207. return '' if (!defined($format) or $format eq '');
  2208. my $arg_index = undef;
  2209. if ($inline_format_commands{$cmdname}) {
  2210. if ($cmdname eq 'inlinefmtifelse'
  2211. and ! $self->{'expanded_formats_hash'}->{$format}) {
  2212. $arg_index = 1;
  2213. } elsif ($self->{'expanded_formats_hash'}->{$format}) {
  2214. $arg_index = 0;
  2215. }
  2216. } elsif (defined($command->{'extra'}->{'expand_index'})) {
  2217. $arg_index = 0;
  2218. }
  2219. if (defined($arg_index) and $arg_index < scalar(@$args)) {
  2220. my $text_arg = $args->[$arg_index];
  2221. if ($text_arg) {
  2222. if ($text_arg->{'normal'}) {
  2223. return $text_arg->{'normal'};
  2224. } elsif ($text_arg->{'raw'}) {
  2225. return $text_arg->{'raw'};
  2226. }
  2227. }
  2228. }
  2229. return '';
  2230. }
  2231. foreach my $command (keys(%inline_commands)) {
  2232. $default_commands_conversion{$command} = \&_convert_inline_command;
  2233. }
  2234. sub _indent_with_table ($)
  2235. {
  2236. my $content = shift;
  2237. return '<table><tr><td>&nbsp;</td><td>'.$content."</td></tr></table>\n";
  2238. }
  2239. my $html_menu_entry_index = 0;
  2240. sub _convert_preformatted_command($$$$)
  2241. {
  2242. my $self = shift;
  2243. my $cmdname = shift;
  2244. my $command = shift;
  2245. my $content = shift;
  2246. if ($cmdname eq 'menu') {
  2247. $html_menu_entry_index = 0;
  2248. }
  2249. if ($content ne '' and !$self->in_string()) {
  2250. if ($self->get_conf('COMPLEX_FORMAT_IN_TABLE')) {
  2251. if ($indented_preformatted_commands{$cmdname}) {
  2252. return _indent_with_table ($content);
  2253. } else {
  2254. return $content."\n";
  2255. }
  2256. } else {
  2257. return $self->_attribute_class('div', $cmdname).">\n".$content.'</div>'."\n";
  2258. }
  2259. } else {
  2260. return $content;
  2261. }
  2262. }
  2263. foreach my $preformatted_command (keys(%preformatted_commands)) {
  2264. $default_commands_conversion{$preformatted_command}
  2265. = \&_convert_preformatted_command;
  2266. }
  2267. sub _convert_indented_command($$$$)
  2268. {
  2269. my $self = shift;
  2270. my $cmdname = shift;
  2271. my $command = shift;
  2272. my $content = shift;
  2273. if ($content ne '' and !$self->in_string()) {
  2274. if ($self->get_conf('COMPLEX_FORMAT_IN_TABLE')) {
  2275. return _indent_with_table ($content);
  2276. } else {
  2277. return $self->_attribute_class('blockquote', $cmdname).">\n"
  2278. .$content.'</blockquote>'."\n";
  2279. }
  2280. } else {
  2281. return $content;
  2282. }
  2283. }
  2284. $default_commands_conversion{'indentedblock'} = \&_convert_indented_command;
  2285. $default_commands_conversion{'smallindentedblock'}
  2286. = \&_convert_indented_command;
  2287. sub _convert_verbatim_command($$$$)
  2288. {
  2289. my $self = shift;
  2290. my $cmdname = shift;
  2291. my $command = shift;
  2292. my $content = shift;
  2293. if (!$self->in_string) {
  2294. return $self->_attribute_class('pre', $cmdname).'>'
  2295. .$content . '</pre>';
  2296. } else {
  2297. return $content;
  2298. }
  2299. }
  2300. $default_commands_conversion{'verbatim'} = \&_convert_verbatim_command;
  2301. sub _convert_verbatiminclude_command($$$$)
  2302. {
  2303. my $self = shift;
  2304. my $cmdname = shift;
  2305. my $command = shift;
  2306. my $args = shift;
  2307. my $verbatim_include_verbatim
  2308. = $self->Texinfo::Common::expand_verbatiminclude($command);
  2309. if (defined($verbatim_include_verbatim)) {
  2310. return $self->convert_tree($verbatim_include_verbatim);
  2311. } else {
  2312. return '';
  2313. }
  2314. }
  2315. $default_commands_conversion{'verbatiminclude'}
  2316. = \&_convert_verbatiminclude_command;
  2317. sub _convert_command_noop($$$$)
  2318. {
  2319. my $self = shift;
  2320. my $cmdname = shift;
  2321. my $command = shift;
  2322. my $content = shift;
  2323. return $content;
  2324. }
  2325. $default_commands_conversion{'raggedright'} = \&_convert_command_noop;
  2326. $default_commands_conversion{'flushleft'} = \&_convert_command_noop;
  2327. $default_commands_conversion{'flushright'} = \&_convert_command_noop;
  2328. $default_commands_conversion{'group'} = \&_convert_command_noop;
  2329. sub _convert_sp_command($$$$)
  2330. {
  2331. my $self = shift;
  2332. my $cmdname = shift;
  2333. my $command = shift;
  2334. my $args = shift;
  2335. if (defined($command->{'extra'}->{'misc_args'}->[0])) {
  2336. my $sp_nr = $command->{'extra'}->{'misc_args'}->[0];
  2337. if ($self->in_preformatted() or $self->in_string()) {
  2338. return "\n" x $sp_nr;
  2339. } else {
  2340. return "<br>\n" x $sp_nr;
  2341. }
  2342. }
  2343. }
  2344. $default_commands_conversion{'sp'} = \&_convert_sp_command;
  2345. sub _convert_exdent_command($$$$)
  2346. {
  2347. my $self = shift;
  2348. my $cmdname = shift;
  2349. my $command = shift;
  2350. my $args = shift;
  2351. # FIXME do something better with css and span?
  2352. my $preformatted = $self->in_preformatted();
  2353. if ($self->in_preformatted() or $self->in_string()) {
  2354. return $self->_convert_preformatted_type($cmdname, $command,
  2355. $args->[0]->{'normal'} ."\n");
  2356. } else {
  2357. # ignore alignment information
  2358. return "<p>".$args->[0]->{'normal'} ."\n</p>";
  2359. }
  2360. }
  2361. $default_commands_conversion{'exdent'} = \&_convert_exdent_command;
  2362. sub _convert_center_command($$$$)
  2363. {
  2364. my $self = shift;
  2365. my $cmdname = shift;
  2366. my $command = shift;
  2367. my $args = shift;
  2368. if ($self->in_string()) {
  2369. return $self->_convert_preformatted_type($cmdname, $command,
  2370. $args->[0]->{'normal'}."\n");
  2371. } else {
  2372. return "<div align=\"center\">".$args->[0]->{'normal'}."\n</div>";
  2373. }
  2374. }
  2375. $default_commands_conversion{'center'} = \&_convert_center_command;
  2376. sub _convert_author_command($$$$)
  2377. {
  2378. my $self = shift;
  2379. my $cmdname = shift;
  2380. my $command = shift;
  2381. my $args = shift;
  2382. return '' if (!$args->[0] or !$command->{'extra'}->{'titlepage'});
  2383. if (!$self->in_string()) {
  2384. return "<strong>$args->[0]->{'normal'}</strong><br>\n";
  2385. } else {
  2386. return $args->[0]->{'normal'}."\n";
  2387. }
  2388. }
  2389. $default_commands_conversion{'author'} = \&_convert_author_command;
  2390. sub _convert_title_command($$$$)
  2391. {
  2392. my $self = shift;
  2393. my $cmdname = shift;
  2394. my $command = shift;
  2395. my $args = shift;
  2396. return '' if (!$args->[0]);
  2397. if (!$self->in_string()) {
  2398. return "<h1>$args->[0]->{'normal'}</h1>\n";
  2399. } else {
  2400. return $args->[0]->{'normal'};
  2401. }
  2402. }
  2403. $default_commands_conversion{'title'} = \&_convert_title_command;
  2404. sub _convert_subtitle_command($$$$)
  2405. {
  2406. my $self = shift;
  2407. my $cmdname = shift;
  2408. my $command = shift;
  2409. my $args = shift;
  2410. return '' if (!$args->[0]);
  2411. if (!$self->in_string()) {
  2412. return "<h3 align=\"right\">$args->[0]->{'normal'}</h3>\n";
  2413. } else {
  2414. return $args->[0]->{'normal'};
  2415. }
  2416. }
  2417. $default_commands_conversion{'subtitle'} = \&_convert_subtitle_command;
  2418. sub _convert_insertcopying_command($$$$)
  2419. {
  2420. my $self = shift;
  2421. my $cmdname = shift;
  2422. my $command = shift;
  2423. if ($self->{'extra'} and $self->{'extra'}->{'copying'}) {
  2424. return $self->convert_tree({'contents'
  2425. => $self->{'extra'}->{'copying'}->{'contents'}});
  2426. }
  2427. return '';
  2428. }
  2429. $default_commands_conversion{'insertcopying'}
  2430. = \&_convert_insertcopying_command;
  2431. sub _convert_listoffloats_command($$$$)
  2432. {
  2433. my $self = shift;
  2434. my $cmdname = shift;
  2435. my $command = shift;
  2436. my $args = shift;
  2437. if (!$self->in_string()
  2438. and $command->{'extra'} and $command->{'extra'}->{'type'}
  2439. and defined($command->{'extra'}->{'type'}->{'normalized'})
  2440. and $self->{'floats'}
  2441. and $self->{'floats'}->{$command->{'extra'}->{'type'}->{'normalized'}}
  2442. and @{$self->{'floats'}->{$command->{'extra'}->{'type'}->{'normalized'}}}) {
  2443. my $listoffloats_name = $command->{'extra'}->{'type'}->{'normalized'};
  2444. my $result = $self->_attribute_class('dl', 'listoffloats').">\n" ;
  2445. foreach my $float (@{$self->{'floats'}->{$listoffloats_name}}) {
  2446. my $float_href = $self->command_href($float);
  2447. next if (!$float_href);
  2448. $result .= '<dt>';
  2449. my $float_text = $self->command_text($float);
  2450. if (defined($float_text) and $float_text ne '') {
  2451. if ($float_href) {
  2452. $result .= "<a href=\"$float_href\">$float_text</a>";
  2453. } else {
  2454. $result .= $float_text;
  2455. }
  2456. }
  2457. $result .= '</dt>';
  2458. my $caption;
  2459. if ($float->{'extra'}->{'shortcaption'}) {
  2460. $caption = $float->{'extra'}->{'shortcaption'};
  2461. } elsif ($float->{'extra'}->{'caption'}) {
  2462. $caption = $float->{'extra'}->{'caption'};
  2463. }
  2464. my $caption_text;
  2465. if ($caption) {
  2466. $caption_text = $self->convert_tree_new_formatting_context(
  2467. $caption->{'args'}->[0], $cmdname, 'listoffloats');
  2468. } else {
  2469. $caption_text = '';
  2470. }
  2471. $result .= '<dd>'.$caption_text.'</dd>'."\n";
  2472. }
  2473. return $result . "</dl>\n";
  2474. } else {
  2475. return '';
  2476. }
  2477. }
  2478. $default_commands_conversion{'listoffloats'} = \&_convert_listoffloats_command;
  2479. sub _in_preformatted_in_menu($)
  2480. {
  2481. my $self = shift;
  2482. return 1 if ($self->get_conf('SIMPLE_MENU'));
  2483. my @pre_classes = $self->preformatted_classes_stack();
  2484. foreach my $pre_class (@pre_classes) {
  2485. return 1 if ($preformatted_commands{$pre_class});
  2486. }
  2487. return 0;
  2488. }
  2489. sub _convert_menu_command($$$$)
  2490. {
  2491. my $self = shift;
  2492. my $cmdname = shift;
  2493. my $command = shift;
  2494. my $content = shift;
  2495. return $content if ($cmdname eq 'detailmenu');
  2496. $html_menu_entry_index = 0;
  2497. if ($content !~ /\S/) {
  2498. return '';
  2499. }
  2500. if ($self->in_string()) {
  2501. return $content;
  2502. }
  2503. my $begin_row = '';
  2504. my $end_row = '';
  2505. if ($self->_in_preformatted_in_menu()) {
  2506. $begin_row = '<tr><td>';
  2507. $end_row = '</td></tr>';
  2508. }
  2509. if ($self->{'current_node'}) {
  2510. $self->{'seenmenus'}->{$self->{'current_node'}} = 1;
  2511. }
  2512. return $self->_attribute_class('table', 'menu')
  2513. ." border=\"0\" cellspacing=\"0\">${begin_row}\n"
  2514. . $content . "${end_row}</table>\n";
  2515. }
  2516. $default_commands_conversion{'menu'} = \&_convert_menu_command;
  2517. $default_commands_conversion{'detailmenu'} = \&_convert_menu_command;
  2518. sub _convert_float_command($$$$$)
  2519. {
  2520. my $self = shift;
  2521. my $cmdname = shift;
  2522. my $command = shift;
  2523. my $args = shift;
  2524. my $content = shift;
  2525. my ($caption, $prepended) = Texinfo::Common::float_name_caption($self,
  2526. $command);
  2527. my $caption_text = '';
  2528. my $prepended_text;
  2529. if ($self->in_string()) {
  2530. if ($prepended) {
  2531. $prepended_text = $self->convert_tree_new_formatting_context(
  2532. $prepended, 'float prepended');
  2533. } else {
  2534. $prepended_text = '';
  2535. }
  2536. if ($caption) {
  2537. $caption_text = $self->convert_tree_new_formatting_context(
  2538. {'contents' => $caption->{'args'}->[0]->{'contents'}},
  2539. 'float caption');
  2540. }
  2541. return $prepended.$content.$caption_text;
  2542. }
  2543. my $id = $self->command_id($command);
  2544. my $label;
  2545. if (defined($id) and $id ne '') {
  2546. $label = "<a name=\"$id\"></a>";
  2547. } else {
  2548. $label = '';
  2549. }
  2550. if ($prepended) {
  2551. if ($caption) {
  2552. # prepend the prepended tree to the first paragraph
  2553. my @caption_original_contents = @{$caption->{'args'}->[0]->{'contents'}};
  2554. my @caption_contents;
  2555. my $new_paragraph;
  2556. while (@caption_original_contents) {
  2557. my $content = shift @caption_original_contents;
  2558. if ($content->{'type'} and $content->{'type'} eq 'paragraph') {
  2559. %{$new_paragraph} = %{$content};
  2560. $new_paragraph->{'contents'} = [@{$content->{'contents'}}];
  2561. unshift (@{$new_paragraph->{'contents'}}, {'cmdname' => 'strong',
  2562. 'args' => [{'type' => 'brace_command_arg',
  2563. 'contents' => [$prepended]}]});
  2564. push @caption_contents, $new_paragraph;
  2565. last;
  2566. } else {
  2567. push @caption_contents, $content;
  2568. }
  2569. }
  2570. push @caption_contents, @caption_original_contents;
  2571. if ($new_paragraph) {
  2572. $caption_text = $self->convert_tree_new_formatting_context(
  2573. {'contents' => \@caption_contents}, 'float caption');
  2574. $prepended_text = '';
  2575. }
  2576. }
  2577. if ($caption_text eq '') {
  2578. $prepended_text = $self->convert_tree_new_formatting_context(
  2579. $prepended, 'float prepended');
  2580. if ($prepended_text ne '') {
  2581. $prepended_text = '<p><strong>'.$prepended_text.'</strong></p>';
  2582. }
  2583. }
  2584. } else {
  2585. $prepended_text = '';
  2586. }
  2587. if ($caption and $caption_text eq '') {
  2588. $caption_text = $self->convert_tree_new_formatting_context(
  2589. $caption->{'args'}->[0], 'float caption');
  2590. }
  2591. if ($prepended_text.$caption_text ne '') {
  2592. $prepended_text = $self->_attribute_class('div','float-caption'). '>'
  2593. . $prepended_text;
  2594. $caption_text .= '</div>';
  2595. }
  2596. return $self->_attribute_class('div','float'). '>' .$label."\n".$content.
  2597. $prepended_text.$caption_text . '</div>';
  2598. }
  2599. $default_commands_conversion{'float'} = \&_convert_float_command;
  2600. sub _convert_quotation_command($$$$$)
  2601. {
  2602. my $self = shift;
  2603. my $cmdname = shift;
  2604. my $command = shift;
  2605. my $args = shift;
  2606. my $content = shift;
  2607. my $class = '';
  2608. $class = $cmdname if ($cmdname ne 'quotation');
  2609. my $attribution = '';
  2610. if ($command->{'extra'} and $command->{'extra'}->{'authors'}) {
  2611. foreach my $author (@{$command->{'extra'}->{'authors'}}) {
  2612. my $centered_author = $self->gdt("\@center --- \@emph{{author}}\n",
  2613. {'author' => $author->{'extra'}->{'misc_content'}});
  2614. $centered_author->{'parent'} = $command;
  2615. $attribution .= $self->convert_tree($centered_author);
  2616. }
  2617. }
  2618. if (!$self->in_string()) {
  2619. return $self->_attribute_class('blockquote', $class).">\n" .$content
  2620. ."</blockquote>\n" . $attribution;
  2621. } else {
  2622. return $content.$attribution;
  2623. }
  2624. }
  2625. $default_commands_conversion{'quotation'} = \&_convert_quotation_command;
  2626. $default_commands_conversion{'smallquotation'} = \&_convert_quotation_command;
  2627. sub _convert_cartouche_command($$$$)
  2628. {
  2629. my $self = shift;
  2630. my $cmdname = shift;
  2631. my $command = shift;
  2632. my $content = shift;
  2633. if ($content =~ /\S/ and !$self->in_string()) {
  2634. return $self->_attribute_class('table', 'cartouche')
  2635. ." border=\"1\"><tr><td>\n". $content ."</td></tr></table>\n";
  2636. }
  2637. return $content;
  2638. }
  2639. $default_commands_conversion{'cartouche'} = \&_convert_cartouche_command;
  2640. sub _convert_itemize_command($$$$)
  2641. {
  2642. my $self = shift;
  2643. my $cmdname = shift;
  2644. my $command = shift;
  2645. my $content = shift;
  2646. if ($self->in_string()) {
  2647. return $content;
  2648. }
  2649. if ($command->{'extra'}->{'command_as_argument'}
  2650. and $command->{'extra'}->{'command_as_argument'}->{'cmdname'} eq 'bullet') {
  2651. return "<ul>\n" . $content. "</ul>\n";
  2652. } else {
  2653. return $self->_attribute_class('ul',$NO_BULLET_LIST_CLASS).">\n"
  2654. . $content . "</ul>\n";
  2655. }
  2656. }
  2657. $default_commands_conversion{'itemize'} = \&_convert_itemize_command;
  2658. sub _convert_enumerate_command($$$$)
  2659. {
  2660. my $self = shift;
  2661. my $cmdname = shift;
  2662. my $command = shift;
  2663. my $content = shift;
  2664. if ($self->in_string()) {
  2665. return $content;
  2666. }
  2667. if ($content eq '') {
  2668. return '';
  2669. }
  2670. my $specification = $command->{'extra'}{'enumerate_specification'};
  2671. if (defined $specification) {
  2672. my ($start, $type);
  2673. if ($specification =~ /^\d*$/ and $specification ne '1') {
  2674. $start = $specification;
  2675. } elsif ($specification =~ /^[A-Z]$/) {
  2676. $start = 1 + ord($specification) - ord('A');
  2677. $type = 'A';
  2678. } elsif ($specification =~ /^[a-z]$/) {
  2679. $start = 1 + ord($specification) - ord('a');
  2680. $type = 'a';
  2681. }
  2682. if (defined $type and defined $start) {
  2683. return "<ol type=\"$type\" start=\"$start\">\n" . $content . "</ol>\n";
  2684. } elsif (defined $start) {
  2685. return "<ol start=\"$start\">\n" . $content . "</ol>\n";
  2686. }
  2687. }
  2688. return "<ol>\n" . $content . "</ol>\n";
  2689. }
  2690. $default_commands_conversion{'enumerate'} = \&_convert_enumerate_command;
  2691. sub _convert_multitable_command($$$$)
  2692. {
  2693. my $self = shift;
  2694. my $cmdname = shift;
  2695. my $command = shift;
  2696. my $content = shift;
  2697. if ($self->in_string()) {
  2698. return $content;
  2699. }
  2700. if ($content =~ /\S/) {
  2701. return "<table>\n" . $content . "</table>\n";
  2702. } else {
  2703. return '';
  2704. }
  2705. }
  2706. $default_commands_conversion{'multitable'} = \&_convert_multitable_command;
  2707. sub _convert_xtable_command($$$$)
  2708. {
  2709. my $self = shift;
  2710. my $cmdname = shift;
  2711. my $command = shift;
  2712. my $content = shift;
  2713. if ($self->in_string()) {
  2714. return $content;
  2715. }
  2716. if ($content ne '') {
  2717. return "<dl compact=\"compact\">\n" . $content . "</dl>\n";
  2718. } else {
  2719. return '';
  2720. }
  2721. }
  2722. $default_commands_conversion{'table'} = \&_convert_xtable_command;
  2723. $default_commands_conversion{'ftable'} = \&_convert_xtable_command;
  2724. $default_commands_conversion{'vtable'} = \&_convert_xtable_command;
  2725. sub _convert_item_command($$$$)
  2726. {
  2727. my $self = shift;
  2728. my $cmdname = shift;
  2729. my $command = shift;
  2730. my $content = shift;
  2731. if ($self->in_string()) {
  2732. return $content;
  2733. }
  2734. if ($command->{'parent'}->{'cmdname'}
  2735. and $command->{'parent'}->{'cmdname'} eq 'itemize') {
  2736. my $prepend ;
  2737. my $itemize = $command->{'parent'};
  2738. if ($itemize->{'extra'}->{'command_as_argument'}
  2739. and $itemize->{'extra'}->{'command_as_argument'}->{'cmdname'} eq 'bullet') {
  2740. $prepend = '';
  2741. } else {
  2742. # Setting multiple expansion should not be needed, except in
  2743. # case of invalid constructs
  2744. $prepend = $self->convert_tree_new_formatting_context(
  2745. {'contents' => $itemize->{'extra'}->{'block_command_line_contents'}->[0]},
  2746. $command->{'cmdname'}, 'item_prepended');
  2747. }
  2748. if ($content =~ /\S/) {
  2749. return '<li>' . $prepend .' '. $content . '</li>';
  2750. } else {
  2751. return '';
  2752. }
  2753. } elsif ($command->{'parent'}->{'cmdname'}
  2754. and $command->{'parent'}->{'cmdname'} eq 'enumerate') {
  2755. if ($content =~ /\S/) {
  2756. return '<li>' . ' ' . $content . '</li>';
  2757. } else {
  2758. return '';
  2759. }
  2760. } elsif ($command->{'parent'}->{'type'}
  2761. and $command->{'parent'}->{'type'} eq 'table_term') {
  2762. # FIXME instead use the code of Plaintext or DocBook.
  2763. my $args = $content;
  2764. if ($args->[0]) {
  2765. my $tree = $self->_table_item_content_tree($command,
  2766. [$args->[0]->{'tree'}]);
  2767. my $result = $self->convert_tree ($tree);
  2768. foreach my $command_name (reverse($self->commands_stack())) {
  2769. if ($preformatted_code_commands{$command_name}) {
  2770. $result = '<tt>' .$result. '</tt>';
  2771. last;
  2772. }
  2773. }
  2774. my $index_id = $self->command_id ($command);
  2775. if (defined($index_id) and $index_id ne '') {
  2776. $result .= "\n<a name=\"$index_id\"></a>\n";
  2777. }
  2778. return '<dt>' .$result. '</dt>' . "\n";
  2779. } else {
  2780. return '';
  2781. }
  2782. } elsif ($command->{'parent'}->{'type'}
  2783. and $command->{'parent'}->{'type'} eq 'row') {
  2784. return $self->_convert_tab_command ($cmdname, $command, $content);
  2785. }
  2786. return '';
  2787. }
  2788. $default_commands_conversion{'item'} = \&_convert_item_command;
  2789. $default_commands_conversion{'headitem'} = \&_convert_item_command;
  2790. $default_commands_conversion{'itemx'} = \&_convert_item_command;
  2791. sub _convert_tab_command ($$$$)
  2792. {
  2793. my $self = shift;
  2794. my $cmdname = shift;
  2795. my $command = shift;
  2796. my $content = shift;
  2797. my $cell_nr = $command->{'extra'}->{'cell_number'};
  2798. my $row = $command->{'parent'};
  2799. my $row_cmdname = $row->{'contents'}->[0]->{'cmdname'};
  2800. my $multitable = $row->{'parent'}->{'parent'};
  2801. my $fractions = '';
  2802. if ($multitable->{'extra'}->{'columnfractions'} and
  2803. exists($multitable->{'extra'}->{'columnfractions'}->[$cell_nr-1])) {
  2804. my $fraction = sprintf('%d', 100*$multitable->{'extra'}->{'columnfractions'}->[$cell_nr-1]);
  2805. $fractions = " width=\"$fraction%\"";
  2806. }
  2807. $content =~ s/^\s*//;
  2808. $content =~ s/\s*$//;
  2809. if ($self->in_string()) {
  2810. return $content;
  2811. }
  2812. if ($row_cmdname eq 'headitem') {
  2813. return "<th${fractions}>" . $content . '</th>';
  2814. } else {
  2815. return "<td${fractions}>" . $content . '</td>';
  2816. }
  2817. }
  2818. $default_commands_conversion{'tab'} = \&_convert_tab_command;
  2819. sub _convert_xref_commands($$$$)
  2820. {
  2821. my $self = shift;
  2822. my $cmdname = shift;
  2823. my $root = shift;
  2824. my $args = shift;
  2825. my $tree;
  2826. my $name;
  2827. if ($cmdname ne 'inforef'
  2828. and defined($args->[2]->{'normal'}) and $args->[2]->{'normal'} ne '') {
  2829. $name = $args->[2]->{'normal'};
  2830. } elsif (defined($args->[1]->{'normal'}) and $args->[1]->{'normal'} ne '') {
  2831. $name = $args->[1]->{'normal'}
  2832. }
  2833. if ($cmdname eq 'inforef') {
  2834. $args->[3] = $args->[2];
  2835. $args->[2] = undef;
  2836. }
  2837. my $file_arg_tree;
  2838. my $file = '';
  2839. if (defined($args->[3]->{'monospacetext'})
  2840. and $args->[3]->{'monospacetext'} ne '') {
  2841. $file_arg_tree = $args->[3]->{'tree'};
  2842. $file = $args->[3]->{'monospacetext'};
  2843. }
  2844. my $book = '';
  2845. $book = $args->[4]->{'normal'} if (defined($args->[4]->{'normal'}));
  2846. # internal reference
  2847. if ($cmdname ne 'inforef' and $book eq '' and $file eq ''
  2848. and $root->{'extra'}->{'node_argument'}
  2849. and defined($root->{'extra'}->{'node_argument'}->{'normalized'})
  2850. and !$root->{'extra'}->{'node_argument'}->{'manual_content'}
  2851. and $self->{'labels'}
  2852. and $self->{'labels'}->{$root->{'extra'}->{'node_argument'}->{'normalized'}}) {
  2853. my $node
  2854. = $self->label_command($root->{'extra'}->{'node_argument'}->{'normalized'});
  2855. # This is the node if USE_NODES, otherwise this may be the sectioning
  2856. # command (if the sectioning command is really associated to the node)
  2857. my $command = $self->command_element_command($node);
  2858. $command = $node if (!$node->{'extra'}->{'associated_section'}
  2859. or $node->{'extra'}->{'associated_section'} ne $command);
  2860. my $href = $self->command_href($command, undef, $root);
  2861. if (!defined($name)) {
  2862. if ($self->get_conf('xrefautomaticsectiontitle') eq 'on'
  2863. and $node->{'extra'}->{'associated_section'}) {
  2864. $command = $node->{'extra'}->{'associated_section'};
  2865. $name = $self->command_text($command, 'text_nonumber');
  2866. } elsif ($node->{'cmdname'} eq 'float') {
  2867. if (!$self->get_conf('XREF_USE_FLOAT_LABEL')) {
  2868. $name = $self->command_text($command);
  2869. }
  2870. if (!defined($name) or $name eq '') {
  2871. if (defined($args->[0]->{'monospace'})) {
  2872. $name = $args->[0]->{'monospace'};
  2873. } else {
  2874. $name = '';
  2875. }
  2876. }
  2877. } elsif (!$self->get_conf('XREF_USE_NODE_NAME_ARG')
  2878. and (defined($self->get_conf('XREF_USE_NODE_NAME_ARG'))
  2879. or !$self->in_preformatted())) {
  2880. $name = $self->command_text($command, 'text_nonumber');
  2881. #die "$command $command->{'normalized'}" if (!defined($name));
  2882. } elsif (defined($args->[0]->{'monospace'})) {
  2883. $name = $args->[0]->{'monospace'};
  2884. } else {
  2885. $name = '';
  2886. }
  2887. }
  2888. my $reference = $name;
  2889. $reference = "<a href=\"$href\">$name</a>" if ($href ne ''
  2890. and !$self->in_string());
  2891. # maybe use {'extra'}->{'node_argument'}?
  2892. my $is_section = ($command->{'cmdname'} ne 'node'
  2893. and $command->{'cmdname'} ne 'anchor'
  2894. and $command->{'cmdname'} ne 'float');
  2895. if ($cmdname eq 'pxref') {
  2896. if ($is_section) {
  2897. $tree = $self->gdt('see section {reference_name}',
  2898. { 'reference_name' => {'type' => '_converted', 'text' => $reference} });
  2899. } else {
  2900. $tree = $self->gdt('see {reference_name}',
  2901. { 'reference_name' => {'type' => '_converted', 'text' => $reference} });
  2902. }
  2903. } elsif ($cmdname eq 'xref' or $cmdname eq 'inforef') {
  2904. if ($is_section) {
  2905. $tree = $self->gdt('See section {reference_name}',
  2906. { 'reference_name' => {'type' => '_converted', 'text' => $reference} });
  2907. } else {
  2908. $tree = $self->gdt('See {reference_name}',
  2909. { 'reference_name' => {'type' => '_converted', 'text' => $reference} });
  2910. }
  2911. } elsif ($cmdname eq 'ref') {
  2912. $tree = $self->gdt('{reference_name}',
  2913. { 'reference_name' => {'type' => '_converted', 'text' => $reference} });
  2914. }
  2915. } else {
  2916. # external reference
  2917. my $node_entry = {};
  2918. $node_entry->{'node_content'} = $root->{'extra'}->{'node_argument'}->{'node_content'}
  2919. if ($root->{'extra'}->{'node_argument'}
  2920. and $root->{'extra'}->{'node_argument'}->{'node_content'});
  2921. $node_entry->{'normalized'} = $root->{'extra'}->{'node_argument'}->{'normalized'}
  2922. if ($root->{'extra'}->{'node_argument'}
  2923. and exists($root->{'extra'}->{'node_argument'}->{'normalized'}));
  2924. # file argument takes precedence over the file in the node (file)node entry
  2925. if (defined($file_arg_tree) and $file ne '') {
  2926. $node_entry->{'manual_content'} = $file_arg_tree->{'contents'};
  2927. } elsif ($root->{'extra'}->{'node_argument'}
  2928. and $root->{'extra'}->{'node_argument'}->{'manual_content'}) {
  2929. $node_entry->{'manual_content'}
  2930. = $root->{'extra'}->{'node_argument'}->{'manual_content'};
  2931. my $file_with_node_tree = {'type' => '_code',
  2932. 'contents' => [@{$node_entry->{'manual_content'}}]};
  2933. $file = $self->convert_tree($file_with_node_tree, 'node file in ref');
  2934. }
  2935. my $href = $self->command_href($node_entry, undef, $root);
  2936. if ($book eq '') {
  2937. if (!defined($name)) {
  2938. my $node_name = $self->command_text($node_entry);
  2939. $name = $node_name;
  2940. } elsif ($file ne '') {
  2941. $name = "($file)$name";
  2942. }
  2943. } elsif (!defined($name) and $node_entry->{'node_content'}) {
  2944. my $node_no_file_tree = {'type' => '_code',
  2945. 'contents' => [@{$node_entry->{'node_content'}}]};
  2946. my $node_name = $self->convert_tree($node_no_file_tree, 'node in ref');
  2947. if (defined($node_name) and ($self->get_conf('KEEP_TOP_EXTERNAL_REF')
  2948. or $node_name ne 'Top')) {
  2949. $name = $node_name;
  2950. }
  2951. }
  2952. # not exactly sure when it happens. Something like @ref{(file),,,Manual}?
  2953. $name = $args->[0]->{'monospace'}
  2954. if (!defined($name)
  2955. # FIXME could it really be Top?
  2956. and ($self->get_conf('KEEP_TOP_EXTERNAL_REF')
  2957. or $args->[0]->{'monospace'} ne 'Top'));
  2958. $name = '' if (!defined($name));
  2959. my $reference = $name;
  2960. my $book_reference = '';
  2961. if (!$self->in_string() and $href ne '') {
  2962. if ($name ne '') {
  2963. $reference = "<a href=\"$href\">$name</a>";
  2964. } elsif ($book ne '') {
  2965. $book_reference = "<a href=\"$href\">$book</a>";
  2966. }
  2967. }
  2968. if ($cmdname eq 'pxref') {
  2969. if (($book ne '') and ($href ne '') and ($reference ne '')) {
  2970. $tree = $self->gdt('see {reference} in @cite{{book}}',
  2971. { 'reference' => {'type' => '_converted', 'text' => $reference},
  2972. 'book' => {'type' => '_converted', 'text' => $book }});
  2973. } elsif ($book_reference ne '') {
  2974. $tree = $self->gdt('see @cite{{book_reference}}',
  2975. { 'book_reference' => {'type' => '_converted',
  2976. 'text' => $book_reference }});
  2977. } elsif (($book ne '') and ($reference ne '')) {
  2978. $tree = $self->gdt('see `{section}\' in @cite{{book}}',
  2979. { 'section' => {'type' => '_converted', 'text' => $reference},
  2980. 'book' => {'type' => '_converted', 'text' => $book }});
  2981. } elsif ($book ne '') { # should seldom or even never happen
  2982. $tree = $self->gdt('see @cite{{book}}',
  2983. {'book' => {'type' => '_converted', 'text' => $book }});
  2984. } elsif ($href ne '') {
  2985. $tree = $self->gdt('see {reference}',
  2986. { 'reference' => {'type' => '_converted', 'text' => $reference} });
  2987. } elsif ($reference ne '') {
  2988. $tree = $self->gdt('see `{section}\'', {
  2989. 'section' => {'type' => '_converted', 'text' => $reference} });
  2990. }
  2991. } elsif ($cmdname eq 'xref' or $cmdname eq 'inforef') {
  2992. if (($book ne '') and ($href ne '') and ($reference ne '')) {
  2993. $tree = $self->gdt('See {reference} in @cite{{book}}',
  2994. { 'reference' => {'type' => '_converted', 'text' => $reference},
  2995. 'book' => {'type' => '_converted', 'text' => $book }});
  2996. } elsif ($book_reference ne '') {
  2997. $tree = $self->gdt('See @cite{{book_reference}}',
  2998. { 'book_reference' => {'type' => '_converted',
  2999. 'text' => $book_reference }});
  3000. } elsif (($book ne '') and ($reference ne '')) {
  3001. $tree = $self->gdt('See `{section}\' in @cite{{book}}',
  3002. { 'section' => {'type' => '_converted', 'text' => $reference},
  3003. 'book' => {'type' => '_converted', 'text' => $book }});
  3004. } elsif ($book ne '') { # should seldom or even never happen
  3005. $tree = $self->gdt('See @cite{{book}}',
  3006. {'book' => {'type' => '_converted', 'text' => $book }});
  3007. } elsif ($href ne '') {
  3008. $tree = $self->gdt('See {reference}',
  3009. { 'reference' => {'type' => '_converted', 'text' => $reference} });
  3010. } elsif ($reference ne '') {
  3011. $tree = $self->gdt('See `{section}\'', {
  3012. 'section' => {'type' => '_converted', 'text' => $reference} });
  3013. }
  3014. } else {
  3015. if (($book ne '') and ($href ne '') and ($reference ne '')) {
  3016. $tree = $self->gdt('{reference} in @cite{{book}}',
  3017. { 'reference' => {'type' => '_converted', 'text' => $reference},
  3018. 'book' => {'type' => '_converted', 'text' => $book }});
  3019. } elsif ($book_reference ne '') {
  3020. $tree = $self->gdt('@cite{{book_reference}}',
  3021. { 'book_reference' => {'type' => '_converted',
  3022. 'text' => $book_reference }});
  3023. } elsif (($book ne '') and ($reference ne '')) {
  3024. $tree = $self->gdt('`{section}\' in @cite{{book}}',
  3025. { 'section' => {'type' => '_converted', 'text' => $reference},
  3026. 'book' => {'type' => '_converted', 'text' => $book }});
  3027. } elsif ($book ne '') { # should seldom or even never happen
  3028. $tree = $self->gdt('@cite{{book}}',
  3029. {'book' => {'type' => '_converted', 'text' => $book }});
  3030. } elsif ($href ne '') {
  3031. $tree = $self->gdt('{reference}',
  3032. { 'reference' => {'type' => '_converted', 'text' => $reference} });
  3033. } elsif ($reference ne '') {
  3034. $tree = $self->gdt('`{section}\'', {
  3035. 'section' => {'type' => '_converted', 'text' => $reference} });
  3036. }
  3037. }
  3038. if (!defined($tree)) {
  3039. # May happen if there is no argument
  3040. #die "external: $cmdname, ($args), '$name' '$file' '$book' '$href' '$reference'. tree undef";
  3041. return '';
  3042. }
  3043. }
  3044. return $self->convert_tree($tree);
  3045. }
  3046. foreach my $command(keys(%ref_commands)) {
  3047. $default_commands_conversion{$command} = \&_convert_xref_commands;
  3048. }
  3049. sub _convert_index_command($$$$)
  3050. {
  3051. my $self = shift;
  3052. my $cmdname = shift;
  3053. my $command = shift;
  3054. my $args = shift;
  3055. my $index_id = $self->command_id($command);
  3056. if (defined($index_id) and $index_id ne ''
  3057. and !@{$self->{'multiple_pass'}}
  3058. and !$self->in_string()) {
  3059. my $result = "<a name=\"$index_id\"></a>";
  3060. $result .= "\n" unless ($self->in_preformatted());
  3061. return $result;
  3062. }
  3063. return '';
  3064. }
  3065. $default_commands_conversion{'cindex'} = \&_convert_index_command;
  3066. my %formatted_index_entries;
  3067. sub _convert_printindex_command($$$$)
  3068. {
  3069. my $self = shift;
  3070. my $cmdname = shift;
  3071. my $command = shift;
  3072. my $args = shift;
  3073. my $index_name;
  3074. if ($command->{'extra'} and $command->{'extra'}->{'misc_args'}
  3075. and defined($command->{'extra'}->{'misc_args'}->[0])) {
  3076. $index_name = $command->{'extra'}->{'misc_args'}->[0];
  3077. } else {
  3078. return '';
  3079. }
  3080. if (!$self->{'index_entries_by_letter'}
  3081. or !$self->{'index_entries_by_letter'}->{$index_name}
  3082. or !@{$self->{'index_entries_by_letter'}->{$index_name}}) {
  3083. return '';
  3084. }
  3085. #foreach my $letter_entry (@{$self->{'index_entries_by_letter'}->{$index_name}}) {
  3086. # print STDERR "IIIIIII $letter_entry->{'letter'}\n";
  3087. # foreach my $index_entry (@{$letter_entry->{'entries'}}) {
  3088. # print STDERR " ".join('|', keys(%$index_entry))."||| $index_entry->{'key'}\n";
  3089. # }
  3090. #}
  3091. return '' if ($self->in_string());
  3092. $self->_new_document_context($cmdname);
  3093. my $result = '';
  3094. # First do the summary letters linking to the letters done below
  3095. my %letter_id;
  3096. my @non_alpha = ();
  3097. my @alpha = ();
  3098. # collect the links
  3099. my $symbol_idx = 0;
  3100. foreach my $letter_entry (@{$self->{'index_entries_by_letter'}->{$index_name}}) {
  3101. my $letter = $letter_entry->{'letter'};
  3102. my $index_element_id = $self->_element_direction($self->{'current_element'},
  3103. 'This', 'target');
  3104. if (!defined($index_element_id)) {
  3105. $index_element_id = $target_prefix;
  3106. }
  3107. my $is_symbol = $letter !~ /^[[:alpha:]]/;
  3108. my $identifier;
  3109. if ($is_symbol) {
  3110. $symbol_idx++;
  3111. $identifier = $index_element_id . "_${index_name}_symbol-$symbol_idx";
  3112. } else {
  3113. $identifier = $index_element_id . "_${index_name}_letter-${letter}";
  3114. }
  3115. $letter_id{$letter} = $identifier;
  3116. my $summary_letter_link = $self->_attribute_class('a', 'summary-letter')
  3117. ." href=\"#$identifier\"><b>".$self->protect_text($letter).'</b></a>';
  3118. if ($is_symbol) {
  3119. push @non_alpha, $summary_letter_link;
  3120. } else {
  3121. push @alpha, $summary_letter_link;
  3122. }
  3123. }
  3124. # Format the summary letters
  3125. my $join = '';
  3126. my $non_alpha_text = '';
  3127. my $alpha_text = '';
  3128. $join = " &nbsp; \n<br>\n" if (@non_alpha and @alpha);
  3129. if (@non_alpha) {
  3130. $non_alpha_text = join("\n &nbsp; \n", @non_alpha) . "\n";
  3131. }
  3132. if (@alpha) {
  3133. $alpha_text = join("\n &nbsp; \n", @alpha) . "\n &nbsp; \n";
  3134. }
  3135. # format the summary
  3136. my $summary = "<table><tr><th valign=\"top\">"
  3137. . $self->convert_tree($self->gdt('Jump to')) .": &nbsp; </th><td>" .
  3138. $non_alpha_text . $join . $alpha_text . "</td></tr></table>\n";
  3139. $result .= $summary;
  3140. # now format the index entries
  3141. $result .= $self->_attribute_class('table', "index-$index_name")
  3142. ." border=\"0\">\n" . "<tr><td></td><th align=\"left\">"
  3143. . $self->convert_tree($self->gdt('Index Entry'))
  3144. . "</th><td>&nbsp;</td><th align=\"left\"> "
  3145. . $self->convert_tree($self->gdt('Section'))
  3146. ."</th></tr>\n" . "<tr><td colspan=\"4\"> ".$self->get_conf('DEFAULT_RULE')
  3147. ."</td></tr>\n";
  3148. foreach my $letter_entry (@{$self->{'index_entries_by_letter'}->{$index_name}}) {
  3149. my $letter = $letter_entry->{'letter'};
  3150. my $entries_text = '';
  3151. foreach my $index_entry_ref (@{$letter_entry->{'entries'}}) {
  3152. # to avoid double error messages set ignore_notice if an entry was
  3153. # already formatted once, for example if there are multiple printindex.
  3154. my $already_formatted;
  3155. if (!$formatted_index_entries{$index_entry_ref}) {
  3156. $formatted_index_entries{$index_entry_ref} = 1;
  3157. } else {
  3158. $already_formatted = 1;
  3159. $self->{'ignore_notice'}++;
  3160. }
  3161. my $entry;
  3162. if ($index_entry_ref->{'in_code'}) {
  3163. $entry = $self->convert_tree({'type' => '_code',
  3164. 'contents' => $index_entry_ref->{'content'}});
  3165. } else {
  3166. $entry = $self->convert_tree({'contents' => $index_entry_ref->{'content'}});
  3167. }
  3168. if ($already_formatted) {
  3169. $self->{'ignore_notice'}--;
  3170. }
  3171. next if ($entry !~ /\S/);
  3172. $entry = '<code>' .$entry .'</code>' if ($index_entry_ref->{'in_code'});
  3173. my $entry_href = $self->command_href($index_entry_ref->{'command'});
  3174. my $associated_command;
  3175. if ($self->get_conf('NODE_NAME_IN_INDEX')) {
  3176. $associated_command = $index_entry_ref->{'node'};
  3177. if (!defined($associated_command)) {
  3178. $associated_command
  3179. = $self->command_node($index_entry_ref->{'command'});
  3180. }
  3181. }
  3182. if (!$associated_command) {
  3183. $associated_command
  3184. = $self->command_element_command($index_entry_ref->{'command'});
  3185. if (!$associated_command) {
  3186. # Use Top if not associated command found
  3187. $associated_command
  3188. = $self->element_command($self->global_element('Top'));
  3189. }
  3190. }
  3191. my ($associated_command_href, $associated_command_text);
  3192. if ($associated_command) {
  3193. $associated_command_href = $self->command_href($associated_command);
  3194. $associated_command_text = $self->command_text($associated_command);
  3195. }
  3196. $entries_text .= '<tr><td></td><td valign="top">'
  3197. . "<a href=\"$entry_href\">$entry</a>" .
  3198. $self->get_conf('INDEX_ENTRY_COLON') .
  3199. '</td><td>&nbsp;</td><td valign="top">';
  3200. $entries_text .= "<a href=\"$associated_command_href\">$associated_command_text</a>"
  3201. if ($associated_command_href);
  3202. $entries_text .= "</td></tr>\n";
  3203. }
  3204. # a letter and associated indice entries
  3205. $result .= '<tr><th>' .
  3206. "<a name=\"$letter_id{$letter}\">".$self->protect_text($letter).'</a>'
  3207. . "</th><td></td><td></td></tr>\n" . $entries_text .
  3208. "<tr><td colspan=\"4\"> ".$self->get_conf('DEFAULT_RULE')."</td></tr>\n";
  3209. }
  3210. $result .= "</table>\n";
  3211. pop @{$self->{'document_context'}};
  3212. return $result .$summary;
  3213. }
  3214. $default_commands_conversion{'printindex'} = \&_convert_printindex_command;
  3215. sub _contents_inline_element($$$)
  3216. {
  3217. my $self = shift;
  3218. my $cmdname = shift;
  3219. my $command = shift;
  3220. my $content = &{$self->{'format_contents'}}($self, $cmdname, $command);
  3221. if ($content) {
  3222. my $result = '';
  3223. my $element_name = $contents_command_element_name{$cmdname};
  3224. my $special_element
  3225. = $self->special_element($element_name);
  3226. my $heading;
  3227. if ($special_element) {
  3228. my $id = $self->command_id($special_element);
  3229. if ($id ne '') {
  3230. $result .= "<a name=\"$id\"></a>\n";
  3231. }
  3232. $heading = $self->command_text($special_element);
  3233. } else {
  3234. # happens when called as convert() and not output()
  3235. #cluck "$cmdname special element not defined";
  3236. $heading
  3237. = $self->convert_tree ($self->get_conf('SPECIAL_ELEMENTS_NAME')->{$element_name});
  3238. }
  3239. my $class = $self->get_conf('SPECIAL_ELEMENTS_CLASS')->{$element_name};
  3240. $result .= &{$self->{'format_heading_text'}}($self, $class.'-heading',
  3241. $heading, $self->get_conf('CHAPTER_HEADER_LEVEL'))."\n";
  3242. $result .= $content . "\n";
  3243. return $result;
  3244. }
  3245. return '';
  3246. }
  3247. sub _convert_informative_command($$$$)
  3248. {
  3249. my $self = shift;
  3250. my $cmdname = shift;
  3251. my $command = shift;
  3252. return '' if ($self->in_string());
  3253. $cmdname = 'shortcontents' if ($cmdname eq 'summarycontents');
  3254. $self->_informative_command($command);
  3255. if ($self->get_conf('INLINE_CONTENTS')
  3256. and ($cmdname eq 'contents' or $cmdname eq 'shortcontents')
  3257. and $self->get_conf($cmdname)
  3258. and $self->{'structuring'} and $self->{'structuring'}->{'sectioning_root'}
  3259. and scalar(@{$self->{'structuring'}->{'sections_list'}}) > 1) {
  3260. return $self->_contents_inline_element($cmdname, $command);
  3261. }
  3262. if ($cmdname eq 'documentlanguage') {
  3263. $self->_translate_names();
  3264. }
  3265. return '';
  3266. }
  3267. foreach my $informative_command (@informative_global_commands) {
  3268. $default_commands_conversion{$informative_command}
  3269. = \&_convert_informative_command;
  3270. }
  3271. # Keys are tree element types, values are function references to convert
  3272. # elements of that type. Can be overridden with
  3273. # Texinfo::Config::texinfo_types_conversion.
  3274. my %default_types_conversion;
  3275. sub default_types_conversion($$)
  3276. {
  3277. my $self = shift;
  3278. my $type = shift;
  3279. return $default_types_conversion{$type};
  3280. }
  3281. # Ignored commands
  3282. foreach my $type ('empty_line_after_command', 'preamble',
  3283. 'preamble_before_setfilename',
  3284. 'empty_spaces_after_command', 'spaces_at_end',
  3285. 'empty_spaces_before_argument', 'empty_spaces_before_paragraph',
  3286. 'empty_spaces_after_close_brace') {
  3287. $default_types_conversion{$type} = undef;
  3288. }
  3289. my %paragraph_style = (
  3290. 'center' => 'center',
  3291. 'flushleft' => 'left',
  3292. 'flushright' => 'right',
  3293. );
  3294. sub _quotation_arg_to_prepend($$)
  3295. {
  3296. my $self = shift;
  3297. my $command = shift;
  3298. if ($command->{'parent'} and $command->{'parent'}->{'cmdname'}
  3299. and ($command->{'parent'}->{'cmdname'} eq 'quotation'
  3300. or $command->{'parent'}->{'cmdname'} eq 'smallquotation')
  3301. and $command->{'parent'}->{'extra'}
  3302. and $command->{'parent'}->{'extra'}->{'block_command_line_contents'}) {
  3303. return $self->convert_tree($self->gdt('@b{{quotation_arg}:} ',
  3304. {'quotation_arg' =>
  3305. $command->{'parent'}->{'extra'}->{'block_command_line_contents'}->[0]}));
  3306. }
  3307. return undef;
  3308. }
  3309. sub _convert_paragraph_type($$$$)
  3310. {
  3311. my $self = shift;
  3312. my $type = shift;
  3313. my $command = shift;
  3314. my $content = shift;
  3315. if ($self->paragraph_number() == 1) {
  3316. my $in_format = $self->top_format();
  3317. if ($in_format) {
  3318. # no first paragraph in those environment to avoid extra spacing
  3319. if ($in_format eq 'itemize'
  3320. or $in_format eq 'enumerate'
  3321. or $in_format eq 'multitable') {
  3322. return $content;
  3323. } else {
  3324. my $prepended = $self->_quotation_arg_to_prepend($command);
  3325. $content = $prepended.$content if (defined($prepended));
  3326. }
  3327. }
  3328. }
  3329. return $content if ($self->in_string());
  3330. if ($content =~ /\S/) {
  3331. my $align = $self->in_align();
  3332. if ($align and $paragraph_style{$align}) {
  3333. return "<p align=\"$paragraph_style{$align}\">".$content."</p>";
  3334. } else {
  3335. return "<p>".$content."</p>";
  3336. }
  3337. } else {
  3338. return '';
  3339. }
  3340. }
  3341. $default_types_conversion{'paragraph'} = \&_convert_paragraph_type;
  3342. sub _preformatted_class()
  3343. {
  3344. my $self = shift;
  3345. my $pre_class;
  3346. my @pre_classes = $self->preformatted_classes_stack();
  3347. foreach my $class (@pre_classes) {
  3348. # FIXME maybe add or $pre_class eq 'menu-preformatted' to override
  3349. # 'menu-preformatted' with 'menu-comment'?
  3350. $pre_class = $class unless ($pre_class
  3351. and $preformatted_code_commands{$pre_class}
  3352. and !($preformatted_code_commands{$class}
  3353. or $class eq 'menu-preformatted'));
  3354. }
  3355. return $pre_class;
  3356. }
  3357. sub _convert_preformatted_type($$$$)
  3358. {
  3359. my $self = shift;
  3360. my $type = shift;
  3361. my $command = shift;
  3362. my $content = shift;
  3363. if (!defined($content)) {
  3364. cluck "content undef in _convert_preformatted_type "
  3365. .Texinfo::Common::_print_current($command);
  3366. }
  3367. my $current = $command;
  3368. # !defined preformatted_number may happen if there is something before the
  3369. # first preformatted. For example an @exdent.
  3370. if ($self->preformatted_number() and $self->preformatted_number() == 1) {
  3371. my $prepended = $self->_quotation_arg_to_prepend($command);
  3372. $content = $prepended.$content if (defined($prepended));
  3373. }
  3374. return '' if ($content eq '');
  3375. return $content if ($type eq 'rawpreformatted');
  3376. my $pre_class = $self->_preformatted_class();
  3377. if ($self->top_format() eq 'multitable') {
  3378. $content =~ s/^\s*//;
  3379. $content =~ s/\s*$//;
  3380. }
  3381. # menu_entry_description is always in a preformatted container
  3382. # in the tree, as the whole menu is meant to be an
  3383. # environment where spaces and newlines are preserved.
  3384. #
  3385. # However, if not in preformatted block command (nor in SIMPLE_MENU),
  3386. # we don't preserve spaces and newlines in menu_entry_description,
  3387. # instead the whole menu_entry is in a table, so here, not <pre>
  3388. if ($command->{'parent'}->{'type'}
  3389. and $command->{'parent'}->{'type'} eq 'menu_entry_description'
  3390. and !$self->_in_preformatted_in_menu()) {
  3391. return $content;
  3392. }
  3393. if ($self->in_string()) {
  3394. return $content;
  3395. }
  3396. $content =~ s/^\n/\n\n/; # a newline immediately after a <pre> is ignored.
  3397. my $result = $self->_attribute_class('pre', $pre_class).">".$content."</pre>";
  3398. # this may happen with lines without textual content
  3399. # between a def* and def*x.
  3400. if ($command->{'parent'}->{'cmdname'}
  3401. and $command->{'parent'}->{'cmdname'} =~ /^def/) {
  3402. $result = '<dd>'.$result.'</dd>';
  3403. }
  3404. return $result;
  3405. }
  3406. $default_types_conversion{'preformatted'} = \&_convert_preformatted_type;
  3407. $default_types_conversion{'rawpreformatted'} = \&_convert_preformatted_type;
  3408. sub _convert_bracketed_type($$$$) {
  3409. my $self = shift;
  3410. my $type = shift;
  3411. my $command = shift;
  3412. my $content = shift;
  3413. #print STDERR "$self $type $command $content\n";
  3414. return '{'.$content.'}';
  3415. }
  3416. $default_types_conversion{'bracketed'} = \&_convert_bracketed_type;
  3417. sub _convert_definfoenclose_type($$$$) {
  3418. my $self = shift;
  3419. my $type = shift;
  3420. my $command = shift;
  3421. my $content = shift;
  3422. return $self->protect_text($command->{'extra'}->{'begin'}) . $content
  3423. .$self->protect_text($command->{'extra'}->{'end'});
  3424. }
  3425. $default_types_conversion{'definfoenclose_command'}
  3426. = \&_convert_definfoenclose_type;
  3427. sub _convert_text($$$)
  3428. {
  3429. my $self = shift;
  3430. my $type = shift;
  3431. my $command = shift;
  3432. my $text = shift;
  3433. if ($self->in_verbatim()) {
  3434. return $self->protect_text($text);
  3435. }
  3436. return $text if ($self->in_raw());
  3437. $text = uc($text) if ($self->in_upper_case());
  3438. $text = $self->protect_text($text);
  3439. if ($self->get_conf('ENABLE_ENCODING') and
  3440. !$self->get_conf('ENABLE_ENCODING_USE_ENTITY')
  3441. and $self->get_conf('OUTPUT_ENCODING_NAME')
  3442. and $self->get_conf('OUTPUT_ENCODING_NAME') eq 'utf-8') {
  3443. $text = Texinfo::Convert::Unicode::unicode_text($text,
  3444. ($self->in_code() or $self->in_math()));
  3445. } elsif (!$self->in_code() and !$self->in_math()) {
  3446. if ($self->get_conf('USE_ISO')) {
  3447. $text =~ s/---/\&mdash\;/g;
  3448. $text =~ s/--/\&ndash\;/g;
  3449. $text =~ s/``/\&ldquo\;/g;
  3450. $text =~ s/''/\&rdquo\;/g;
  3451. $text =~ s/'/\&rsquo\;/g;
  3452. $text =~ s/`/\&lsquo\;/g;
  3453. } else {
  3454. $text =~ s/``/&quot;/g;
  3455. $text =~ s/''/&quot;/g;
  3456. $text =~ s/---/\x{1F}/g;
  3457. $text =~ s/--/-/g;
  3458. $text =~ s/\x{1F}/--/g;
  3459. }
  3460. }
  3461. $text = $self->_protect_space($text);
  3462. return $text;
  3463. }
  3464. $default_types_conversion{'text'} = \&_convert_text;
  3465. sub _simplify_text_for_comparison($)
  3466. {
  3467. my $text = shift;
  3468. $text =~ s/[^\w]//g;
  3469. return $text;
  3470. }
  3471. sub _convert_row_type($$$$) {
  3472. my $self = shift;
  3473. my $type = shift;
  3474. my $command = shift;
  3475. my $content = shift;
  3476. return $content if ($self->in_string());
  3477. if ($content =~ /\S/) {
  3478. my $row_cmdname = $command->{'contents'}->[0]->{'cmdname'};
  3479. if ($row_cmdname eq 'headitem') {
  3480. return '<thead><tr>' . $content . '</tr></thead>' . "\n";
  3481. } else {
  3482. return '<tr>' . $content . '</tr>' . "\n";
  3483. }
  3484. } else {
  3485. return '';
  3486. }
  3487. }
  3488. $default_types_conversion{'row'} = \&_convert_row_type;
  3489. sub _convert_menu_entry_type($$$)
  3490. {
  3491. my $self = shift;
  3492. my $type = shift;
  3493. my $command = shift;
  3494. my $href;
  3495. my $node;
  3496. my $section;
  3497. my $node_entry = $command->{'extra'}->{'menu_entry_node'};
  3498. # external node
  3499. my $external_node;
  3500. if ($node_entry->{'manual_content'}) {
  3501. $href = $self->command_href($node_entry, undef, $command);
  3502. $external_node = 1;
  3503. } else {
  3504. $node = $self->label_command($node_entry->{'normalized'});
  3505. # if !NODE_NAME_IN_MENU, we pick the associated section, except if
  3506. # the node is the element command
  3507. if ($node->{'extra'}->{'associated_section'}
  3508. and !$self->get_conf('NODE_NAME_IN_MENU')
  3509. and !($self->command_element_command($node) eq $node)) {
  3510. $section = $node->{'extra'}->{'associated_section'};
  3511. $href = $self->command_href($section, undef, $command);
  3512. } else {
  3513. $href = $self->command_href($node, undef, $command);
  3514. }
  3515. }
  3516. $html_menu_entry_index++;
  3517. my $accesskey = '';
  3518. $accesskey = " accesskey=\"$html_menu_entry_index\""
  3519. if ($self->get_conf('USE_ACCESSKEY') and $html_menu_entry_index < 10);
  3520. my $MENU_SYMBOL = $self->get_conf('MENU_SYMBOL');
  3521. my $MENU_ENTRY_COLON = $self->get_conf('MENU_ENTRY_COLON');
  3522. if ($self->_in_preformatted_in_menu() or $self->in_string()) {
  3523. my $result = '';
  3524. my $i = 0;
  3525. my @args = @{$command->{'args'}};
  3526. while (@args) {
  3527. last if ($args[0]->{'type'}
  3528. and $args[0]->{'type'} eq 'menu_entry_description');
  3529. my $arg = shift @args;
  3530. if ($arg->{'type'} and $arg->{'type'} eq 'menu_entry_node') {
  3531. my $name = $self->convert_tree(
  3532. {'type' => '_code', 'contents' => $arg->{'contents'}});
  3533. if ($href ne '' and !$self->in_string()) {
  3534. $result .= "<a href=\"$href\"$accesskey>".$name."</a>";
  3535. } else {
  3536. $result .= $name;
  3537. }
  3538. } elsif ($arg->{'type'} and $arg->{'type'} eq 'menu_entry_leading_text') {
  3539. my $text = $arg->{'text'};
  3540. $text =~ s/\*/$MENU_SYMBOL/;
  3541. $result .= $text;
  3542. } else {
  3543. $result .= $self->convert_tree($arg, "menu_arg preformatted [$i]");
  3544. }
  3545. $i++;
  3546. }
  3547. my $description = '';
  3548. foreach my $arg (@args) {
  3549. $description .= $self->convert_tree($arg, "menu_arg preformatted [$i]");
  3550. $i++;
  3551. }
  3552. if (!$self->get_conf('SIMPLE_MENU')) {
  3553. $description =~ s/^<pre[^>]*>//;
  3554. $description =~ s/<\/pre>$//;
  3555. }
  3556. $result = $result . $description;
  3557. if (!$self->get_conf('SIMPLE_MENU')) {
  3558. my $pre_class = $self->_preformatted_class();
  3559. $result = $self->_attribute_class('pre', $pre_class).">".$result."</pre>";
  3560. }
  3561. return $result;
  3562. }
  3563. my $name;
  3564. my $name_no_number;
  3565. if ($section) {
  3566. #my $section_name = $self->command_text($section);
  3567. $name = $self->command_text($section);
  3568. $name_no_number = $self->command_text($section, 'text_nonumber');
  3569. if ($href ne '' and $name ne '') {
  3570. #$name = "<a href=\"$href\"$accesskey>".$section_name."</a>";
  3571. $name = "<a href=\"$href\"$accesskey>".$name."</a>";
  3572. }# else {
  3573. # $name = $section_name;
  3574. #}
  3575. #$name = "$MENU_SYMBOL ".$name if ($section_name eq $name_no_number);
  3576. }
  3577. if (!defined($name) or $name eq '') {
  3578. if ($command->{'extra'}->{'menu_entry_name'}) {
  3579. $name = $self->convert_tree($command->{'extra'}->{'menu_entry_name'});
  3580. }
  3581. if (!defined($name) or $name eq '') {
  3582. if ($node_entry->{'manual_content'}) {
  3583. $name = $self->command_text($node_entry);
  3584. } else {
  3585. $name = $self->convert_tree({'type' => '_code',
  3586. 'contents' => $node_entry->{'node_content'}},
  3587. "menu_arg name");
  3588. }
  3589. }
  3590. $name =~ s/^\s*//;
  3591. $name_no_number = $name;
  3592. if ($href ne '') {
  3593. $name = "<a href=\"$href\"$accesskey>".$name."</a>";
  3594. }
  3595. $name = "$MENU_SYMBOL ".$name;
  3596. }
  3597. my $description = '';
  3598. if ($command->{'extra'}->{'menu_entry_description'}) {
  3599. $description = $self->convert_tree ($command->{'extra'}->{'menu_entry_description'},
  3600. "menu_arg description");
  3601. if ($self->get_conf('AVOID_MENU_REDUNDANCY')) {
  3602. $description = '' if (_simplify_text_for_comparison($name_no_number)
  3603. eq _simplify_text_for_comparison($description));
  3604. }
  3605. }
  3606. return "<tr><td align=\"left\" valign=\"top\">$name$MENU_ENTRY_COLON</td><td>&nbsp;&nbsp;</td><td align=\"left\" valign=\"top\">$description</td></tr>\n";
  3607. }
  3608. $default_types_conversion{'menu_entry'} = \&_convert_menu_entry_type;
  3609. sub _convert_menu_comment_type($$$$)
  3610. {
  3611. my $self = shift;
  3612. my $type = shift;
  3613. my $command = shift;
  3614. my $content = shift;
  3615. if ($self->_in_preformatted_in_menu() or $self->in_string()) {
  3616. return $content;
  3617. } else {
  3618. return "<tr><th colspan=\"3\" align=\"left\" valign=\"top\">".$content
  3619. ."</th></tr>";
  3620. }
  3621. }
  3622. $default_types_conversion{'menu_comment'} = \&_convert_menu_comment_type;
  3623. sub _convert_before_item_type($$$$)
  3624. {
  3625. my $self = shift;
  3626. my $type = shift;
  3627. my $command = shift;
  3628. my $content = shift;
  3629. return '' if ($content !~ /\S/);
  3630. return $content if ($self->in_string());
  3631. my $top_format = $self->top_format();
  3632. if ($top_format eq 'itemize' or $top_format eq 'enumerate') {
  3633. return '<li>'. $content .'</li>';
  3634. } elsif ($top_format eq 'table' or $top_format eq 'vtable'
  3635. or $top_format eq 'ftable') {
  3636. return '<dd>'. $content .'</dd>'."\n";
  3637. } elsif ($top_format eq 'multitable') {
  3638. $content =~ s/^\s*//;
  3639. $content =~ s/\s*$//;
  3640. return '<tr><td>'.$content.'</td></tr>'."\n";
  3641. }
  3642. }
  3643. $default_types_conversion{'before_item'} = \&_convert_before_item_type;
  3644. sub _convert_def_line_type($$$$)
  3645. {
  3646. my $self = shift;
  3647. my $type = shift;
  3648. my $command = shift;
  3649. my $content = shift;
  3650. if ($self->in_string()) {
  3651. return $self->protect_text(Texinfo::Convert::Text::convert(
  3652. $command, Texinfo::Common::_convert_text_options($self)));
  3653. }
  3654. my $index_label = '';
  3655. my $index_id = $self->command_id($command);
  3656. if (defined($index_id) and $index_id ne '' and !@{$self->{'multiple_pass'}}) {
  3657. $index_label = "<a name=\"$index_id\"></a>";
  3658. }
  3659. my $arguments
  3660. = Texinfo::Common::definition_arguments_content($command);
  3661. if (!$self->get_conf('DEF_TABLE')) {
  3662. my $tree;
  3663. my $command_name;
  3664. if ($Texinfo::Common::def_aliases{$command->{'extra'}->{'def_command'}}) {
  3665. $command_name = $Texinfo::Common::def_aliases{$command->{'extra'}->{'def_command'}};
  3666. } else {
  3667. $command_name = $command->{'extra'}->{'def_command'};
  3668. }
  3669. my $name;
  3670. if ($command->{'extra'}->{'def_parsed_hash'}->{'name'}) {
  3671. $name = $command->{'extra'}->{'def_parsed_hash'}->{'name'};
  3672. } else {
  3673. $name = '';
  3674. }
  3675. my $category;
  3676. if ($command->{'extra'}->{'def_parsed_hash'}->{'category'}) {
  3677. $category = $command->{'extra'}->{'def_parsed_hash'}->{'category'};
  3678. } else {
  3679. $category = '';
  3680. }
  3681. if ($command_name eq 'deffn'
  3682. or $command_name eq 'defvr'
  3683. or $command_name eq 'deftp'
  3684. or (($command_name eq 'deftypefn'
  3685. or $command_name eq 'deftypevr')
  3686. and !$command->{'extra'}->{'def_parsed_hash'}->{'type'})
  3687. or (($command_name eq 'defop'
  3688. or ($command_name eq 'deftypeop'
  3689. and !$command->{'extra'}->{'def_parsed_hash'}->{'type'})
  3690. or $command_name eq 'defcv'
  3691. or ($command_name eq 'deftypecv'
  3692. and !$command->{'extra'}->{'def_parsed_hash'}->{'type'}))
  3693. and !$command->{'extra'}->{'def_parsed_hash'}->{'class'})) {
  3694. if ($arguments) {
  3695. $tree = $self->gdt("{category}: \@strong{{name}} \@emph{{arguments}}", {
  3696. 'category' => $category,
  3697. 'name' => $name,
  3698. 'arguments' => $arguments});
  3699. } else {
  3700. $tree = $self->gdt("{category}: \@strong{{name}}", {
  3701. 'category' => $category,
  3702. 'name' => $name});
  3703. }
  3704. } elsif ($command_name eq 'deftypefn'
  3705. or $command_name eq 'deftypevr'
  3706. or (($command_name eq 'deftypeop'
  3707. or $command_name eq 'deftypecv')
  3708. and !$command->{'extra'}->{'def_parsed_hash'}->{'class'})) {
  3709. if ($arguments) {
  3710. my $strings = {
  3711. 'category' => $category,
  3712. 'name' => $name,
  3713. 'type' => $command->{'extra'}->{'def_parsed_hash'}->{'type'},
  3714. 'arguments' => $arguments};
  3715. if ($self->get_conf('deftypefnnewline') eq 'on') {
  3716. $tree
  3717. = $self->gdt("{category}:\@* \@emph{{type}}\@* \@strong{{name}} \@emph{{arguments}}",
  3718. $strings);
  3719. } else {
  3720. $tree
  3721. = $self->gdt("{category}: \@emph{{type}} \@strong{{name}} \@emph{{arguments}}",
  3722. $strings);
  3723. }
  3724. } else {
  3725. my $strings = {
  3726. 'category' => $category,
  3727. 'type' => $command->{'extra'}->{'def_parsed_hash'}->{'type'},
  3728. 'name' => $name};
  3729. if ($self->get_conf('deftypefnnewline') eq 'on') {
  3730. $tree = $self->gdt("{category}:\@* \@emph{{type}}\@* \@strong{{name}}",
  3731. $strings);
  3732. } else {
  3733. $tree = $self->gdt("{category}: \@emph{{type}} \@strong{{name}}",
  3734. $strings);
  3735. }
  3736. }
  3737. } elsif ($command_name eq 'defcv'
  3738. or ($command_name eq 'deftypecv'
  3739. and !$command->{'extra'}->{'def_parsed_hash'}->{'type'})) {
  3740. if ($arguments) {
  3741. $tree = $self->gdt("{category} of {class}: \@strong{{name}} \@emph{{arguments}}", {
  3742. 'category' => $category,
  3743. 'name' => $name,
  3744. 'class' => $command->{'extra'}->{'def_parsed_hash'}->{'class'},
  3745. 'arguments' => $arguments});
  3746. } else {
  3747. $tree = $self->gdt("{category} of {class}: \@strong{{name}}", {
  3748. 'category' => $category,
  3749. 'class' => $command->{'extra'}->{'def_parsed_hash'}->{'class'},
  3750. 'name' => $name});
  3751. }
  3752. } elsif ($command_name eq 'defop'
  3753. or ($command_name eq 'deftypeop'
  3754. and !$command->{'extra'}->{'def_parsed_hash'}->{'type'})) {
  3755. if ($arguments) {
  3756. $tree = $self->gdt("{category} on {class}: \@strong{{name}} \@emph{{arguments}}", {
  3757. 'category' => $category,
  3758. 'name' => $name,
  3759. 'class' => $command->{'extra'}->{'def_parsed_hash'}->{'class'},
  3760. 'arguments' => $arguments});
  3761. } else {
  3762. $tree = $self->gdt("{category} on {class}: \@strong{{name}}", {
  3763. 'category' => $category,
  3764. 'class' => $command->{'extra'}->{'def_parsed_hash'}->{'class'},
  3765. 'name' => $name});
  3766. }
  3767. } elsif ($command_name eq 'deftypeop') {
  3768. if ($arguments) {
  3769. my $strings = {
  3770. 'category' => $category,
  3771. 'name' => $name,
  3772. 'class' => $command->{'extra'}->{'def_parsed_hash'}->{'class'},
  3773. 'type' => $command->{'extra'}->{'def_parsed_hash'}->{'type'},
  3774. 'arguments' => $arguments};
  3775. if ($self->get_conf('deftypefnnewline') eq 'on') {
  3776. $tree
  3777. = $self->gdt("{category} on {class}:\@* \@emph{{type}}\@* \@strong{{name}} \@emph{{arguments}}",
  3778. $strings);
  3779. } else {
  3780. $tree
  3781. = $self->gdt("{category} on {class}: \@emph{{type}} \@strong{{name}} \@emph{{arguments}}",
  3782. $strings);
  3783. }
  3784. } else {
  3785. my $strings = {
  3786. 'category' => $category,
  3787. 'type' => $command->{'extra'}->{'def_parsed_hash'}->{'type'},
  3788. 'class' => $command->{'extra'}->{'def_parsed_hash'}->{'class'},
  3789. 'name' => $name};
  3790. if ($self->get_conf('deftypefnnewline') eq 'on') {
  3791. $tree
  3792. = $self->gdt("{category} on {class}:\@* \@emph{{type}}\@* \@strong{{name}}",
  3793. $strings);
  3794. } else {
  3795. $tree
  3796. = $self->gdt("{category} on {class}: \@emph{{type}} \@strong{{name}}",
  3797. $strings);
  3798. }
  3799. }
  3800. } elsif ($command_name eq 'deftypecv') {
  3801. if ($arguments) {
  3802. my $strings = {
  3803. 'category' => $category,
  3804. 'name' => $name,
  3805. 'class' => $command->{'extra'}->{'def_parsed_hash'}->{'class'},
  3806. 'type' => $command->{'extra'}->{'def_parsed_hash'}->{'type'},
  3807. 'arguments' => $arguments};
  3808. if ($self->get_conf('deftypefnnewline') eq 'on') {
  3809. $tree
  3810. = $self->gdt("{category} of {class}:\@* \@emph{{type}}\@* \@strong{{name}} \@emph{{arguments}}",
  3811. $strings);
  3812. } else {
  3813. $tree
  3814. = $self->gdt("{category} of {class}: \@emph{{type}} \@strong{{name}} \@emph{{arguments}}",
  3815. $strings);
  3816. }
  3817. } else {
  3818. my $strings = {
  3819. 'category' => $category,
  3820. 'type' => $command->{'extra'}->{'def_parsed_hash'}->{'type'},
  3821. 'class' => $command->{'extra'}->{'def_parsed_hash'}->{'class'},
  3822. 'name' => $name};
  3823. if ($self->get_conf('deftypefnnewline') eq 'on') {
  3824. $tree
  3825. = $self->gdt("{category} of {class}:\@* \@emph{{type}}\@* \@strong{{name}}",
  3826. $strings);
  3827. } else {
  3828. $tree
  3829. = $self->gdt("{category} of {class}: \@emph{{type}} \@strong{{name}}",
  3830. $strings);
  3831. }
  3832. }
  3833. }
  3834. return '<dt>'.$index_label.$self->convert_tree({'type' => '_code',
  3835. 'contents' => [$tree]}) . "</dt>\n";
  3836. } else {
  3837. my $category_prepared = '';
  3838. if ($command->{'extra'} and $command->{'extra'}->{'def_args'}
  3839. and @{$command->{'extra'}->{'def_args'}}) {
  3840. my $parsed_definition_category
  3841. = Texinfo::Common::definition_category ($self, $command);
  3842. if ($parsed_definition_category) {
  3843. $category_prepared = $self->convert_tree({'type' => '_code',
  3844. 'contents' => [$parsed_definition_category]});
  3845. }
  3846. }
  3847. my $arguments_text = '';
  3848. if ($arguments) {
  3849. $arguments_text = $self->convert_tree({'type' => '_code',
  3850. 'contents' => $arguments});
  3851. $arguments_text = '<em> ' . $arguments_text . '</em>'
  3852. if ($arguments_text =~ /\S/);
  3853. }
  3854. my $def_type = '';
  3855. my $type_name = '';
  3856. if ($command->{'extra'}->{'def_parsed_hash'}->{'type'}) {
  3857. $def_type = $self->convert_tree({'type' => '_code',
  3858. 'contents' => [$command->{'extra'}->{'def_parsed_hash'}->{'type'}]});
  3859. }
  3860. $type_name = " <em>$def_type</em>" if ($def_type ne '');
  3861. my $name = '';
  3862. if ($command->{'extra'}->{'def_parsed_hash'}->{'name'}) {
  3863. $name = $self->convert_tree({'type' => '_code',
  3864. 'contents' => [$command->{'extra'}->{'def_parsed_hash'}->{'name'}]});
  3865. }
  3866. $type_name .= ' <strong>' . $name . '</strong>' if ($name ne '');
  3867. $type_name .= $arguments_text;
  3868. return "<tr><td align=\"left\">" . $type_name .
  3869. "</td><td align=\"right\">" . $category_prepared .
  3870. $index_label . "</td></tr>\n";
  3871. }
  3872. }
  3873. $default_types_conversion{'def_line'} = \&_convert_def_line_type;
  3874. sub _convert_def_item_type($$$$)
  3875. {
  3876. my $self = shift;
  3877. my $type = shift;
  3878. my $command = shift;
  3879. my $content = shift;
  3880. return $content if ($self->in_string());
  3881. if ($content =~ /\S/) {
  3882. if (! $self->get_conf('DEF_TABLE')) {
  3883. return '<dd>' . $content . '</dd>';
  3884. } else {
  3885. return '<tr><td colspan="2">' . $content . '</td></tr>';
  3886. }
  3887. }
  3888. }
  3889. $default_types_conversion{'def_item'} = \&_convert_def_item_type;
  3890. $default_types_conversion{'inter_def_item'} = \&_convert_def_item_type;
  3891. sub _convert_def_command($$$$) {
  3892. my $self = shift;
  3893. my $cmdname = shift;
  3894. my $command = shift;
  3895. my $content = shift;
  3896. return $content if ($self->in_string());
  3897. #print STDERR "IIII $self $cmdname command $command args $args content $content\n";
  3898. if (!$self->get_conf('DEF_TABLE')) {
  3899. return "<dl>\n". $content ."</dl>\n";
  3900. } else {
  3901. return "<table width=\"100%\">\n" . $content . "</table>\n";
  3902. }
  3903. }
  3904. foreach my $command (keys(%def_commands)) {
  3905. $default_commands_conversion{$command} = \&_convert_def_command;
  3906. }
  3907. sub _convert_table_item_type($$$$)
  3908. {
  3909. my $self = shift;
  3910. my $type = shift;
  3911. my $command = shift;
  3912. my $content = shift;
  3913. return $content if ($self->in_string());
  3914. if ($content =~ /\S/) {
  3915. return '<dd>' . $content . '</dd>'."\n";
  3916. }
  3917. }
  3918. $default_types_conversion{'table_item'} = \&_convert_table_item_type;
  3919. $default_types_conversion{'inter_item'} = \&_convert_table_item_type;
  3920. # This type is the only one present if there are no elements. It is
  3921. # therefore used to do the formatting of the element in case there are no
  3922. # element.
  3923. sub _convert_root_text_type($$$$)
  3924. {
  3925. my $self = shift;
  3926. my $type = shift;
  3927. my $command = shift;
  3928. my $content = shift;
  3929. my $result = $content;
  3930. #$result =~ s/^\s*//;
  3931. # if there is no element, the parent should not be an element
  3932. if (!$command->{'parent'}
  3933. or !$command->{'parent'}->{'type'}
  3934. or $command->{'parent'}->{'type'} ne 'element') {
  3935. $result .= &{$self->{'format_footnotes_text'}}($self);
  3936. $result .= $self->get_conf('DEFAULT_RULE') ."\n",
  3937. if ($self->get_conf('PROGRAM_NAME_IN_FOOTER')
  3938. and defined($self->get_conf('DEFAULT_RULE'))
  3939. and !$self->in_string());
  3940. }
  3941. return $result;
  3942. }
  3943. $default_types_conversion{'text_root'} = \&_convert_root_text_type;
  3944. # Convert @titlepage. Falls back to simpletitle.
  3945. sub _default_titlepage($)
  3946. {
  3947. my $self = shift;
  3948. my $titlepage_text;
  3949. if ($self->{'extra'}->{'titlepage'}) {
  3950. $titlepage_text = $self->convert_tree({'contents'
  3951. => $self->{'extra'}->{'titlepage'}->{'contents'}});
  3952. } elsif ($self->{'simpletitle_tree'}) {
  3953. my $title_text = $self->convert_tree_new_formatting_context(
  3954. $self->{'simpletitle_tree'}, 'simpletitle_string');
  3955. $titlepage_text = &{$self->{'format_heading_text'}}($self, 'settitle', $title_text,
  3956. 0, {'cmdname' => 'settitle',
  3957. 'contents' => $self->{'simpletitle_tree'}->{'contents'}});
  3958. }
  3959. my $result = '';
  3960. $result .= $titlepage_text.$self->get_conf('DEFAULT_RULE')."\n"
  3961. if (defined($titlepage_text));
  3962. return $result;
  3963. }
  3964. sub _print_title($)
  3965. {
  3966. my $self = shift;
  3967. my $result = '';
  3968. if ($self->get_conf('SHOW_TITLE')) {
  3969. if ($self->get_conf('USE_TITLEPAGE_FOR_TITLE')) {
  3970. $result .= &{$self->{'format_titlepage'}}($self);
  3971. } else {
  3972. if ($self->{'simpletitle_tree'}) {
  3973. my $title_text = $self->convert_tree_new_formatting_context(
  3974. $self->{'simpletitle_tree'}, 'simpletitle_string');
  3975. $result .= &{$self->{'format_heading_text'}}($self, 'settitle', $title_text,
  3976. 0, {'cmdname' => 'settitle',
  3977. 'contents' => $self->{'simpletitle_tree'}->{'contents'}});
  3978. }
  3979. }
  3980. }
  3981. return $result;
  3982. }
  3983. # Function for converting the top-level elements in the conversion: a section
  3984. # or a node. $ELEMENT was created in this module (in _prepare_elements), with
  3985. # type 'element' (it's not a tree element created by the parser). $CONTENT
  3986. # is the contents of the node/section, already converted.
  3987. sub _convert_element_type($$$$)
  3988. {
  3989. my $self = shift;
  3990. my $type = shift;
  3991. my $element = shift;
  3992. my $content = shift;
  3993. if ($self->in_string()) {
  3994. if (defined($content)) {
  3995. return $content;
  3996. } else {
  3997. return '';
  3998. }
  3999. }
  4000. my $result = '';
  4001. my $special_element;
  4002. if ($element->{'extra'}->{'special_element'}) {
  4003. $special_element = $element->{'extra'}->{'special_element'};
  4004. my $id = $self->command_id($element);
  4005. if ($id ne '') {
  4006. $result .= "<a name=\"$id\"></a>\n";
  4007. }
  4008. if ($self->get_conf('HEADERS')
  4009. # first in page
  4010. or $self->{'counter_in_file'}->{$element->{'filename'}} == 1) {
  4011. $result .= &{$self->{'format_navigation_header'}}($self,
  4012. $self->get_conf('MISC_BUTTONS'), undef, $element);
  4013. }
  4014. my $heading = $self->command_text($element);
  4015. my $element_name = $element->{'extra'}->{'special_element'};
  4016. my $class = $self->get_conf('SPECIAL_ELEMENTS_CLASS')->{$element_name};
  4017. my $level = $self->get_conf('CHAPTER_HEADER_LEVEL');
  4018. if ($element_name eq 'Footnotes') {
  4019. $level = $self->get_conf('FOOTNOTE_SEPARATE_HEADER_LEVEL');
  4020. }
  4021. $result .= &{$self->{'format_heading_text'}}($self, $class.'-heading',
  4022. $heading, $level)."\n";
  4023. my $special_element_body .= &{$self->{'format_special_element_body'}}
  4024. ($self, $special_element, $element);
  4025. # This may happen with footnotes in regions that are not expanded,
  4026. # like @copying or @titlepage
  4027. if ($special_element_body eq '') {
  4028. return '';
  4029. }
  4030. $result .= $special_element_body;
  4031. } elsif (!$element->{'element_prev'}) {
  4032. $result .= $self->_print_title();
  4033. if (!$element->{'element_next'}) {
  4034. # only one element
  4035. my $foot_text = &{$self->{'format_footnotes_text'}}($self);
  4036. return $result.$content.$foot_text.$self->get_conf('DEFAULT_RULE')."\n";
  4037. }
  4038. }
  4039. $result .= $content unless ($special_element);
  4040. $result .= &{$self->{'format_element_footer'}}($self, $type,
  4041. $element, $content);
  4042. return $result;
  4043. }
  4044. sub _default_element_footer($$$$)
  4045. {
  4046. my $self = shift;
  4047. my $type = shift;
  4048. my $element = shift;
  4049. my $content = shift;
  4050. my $result = '';
  4051. my $is_top = $self->element_is_top($element);
  4052. my $next_is_top = ($element->{'element_next'}
  4053. and $self->element_is_top($element->{'element_next'}));
  4054. my $next_is_special = (defined($element->{'element_next'})
  4055. and $element->{'element_next'}->{'extra'}->{'special_element'});
  4056. # no 'parent' defined happens if there are no pages, and there are elements
  4057. # which should only happen when called with $self->{'output_file'}
  4058. # set to ''.
  4059. #print STDERR "$element $element->{'filename'} $self->{'file_counters'}->{$element->{'filename'}}\n";
  4060. #print STDERR "next: $element->{'element_next'}->{'filename'}\n" if ($element->{'element_next'});
  4061. my $end_page = (!$element->{'element_next'}
  4062. or (defined($element->{'filename'})
  4063. and $element->{'filename'} ne $element->{'element_next'}->{'filename'}
  4064. and $self->{'file_counters'}->{$element->{'filename'}} == 1));
  4065. #my $end_page = (!$element->{'element_next'}
  4066. # or (defined($element->{'parent'})
  4067. # and $element->{'parent'} ne $element->{'element_next'}->{'parent'}));
  4068. my $is_special = $element->{'extra'}->{'special_element'};
  4069. if (($end_page or $next_is_top or $next_is_special or $is_top)
  4070. and $self->get_conf('VERTICAL_HEAD_NAVIGATION')
  4071. and ($self->get_conf('SPLIT') ne 'node'
  4072. or $self->get_conf('HEADERS') or $is_special or $is_top)) {
  4073. $result .= "</td>
  4074. </tr>
  4075. </table>"."\n";
  4076. }
  4077. my $rule = '';
  4078. my $buttons;
  4079. my $maybe_in_page;
  4080. if (($is_top or $is_special)
  4081. and ($self->get_conf('SPLIT') or !$self->get_conf('MONOLITHIC'))
  4082. and ($end_page
  4083. and ($self->get_conf('HEADERS')
  4084. or ($self->get_conf('SPLIT') and $self->get_conf('SPLIT') ne 'node')))) {
  4085. if ($is_top) {
  4086. $buttons = $self->get_conf('TOP_BUTTONS');
  4087. } else {
  4088. $buttons = $self->get_conf('MISC_BUTTONS');
  4089. }
  4090. } elsif ($end_page and $self->get_conf('SPLIT') eq 'section') {
  4091. $buttons = $self->get_conf('SECTION_FOOTER_BUTTONS');
  4092. } elsif ($end_page and $self->get_conf('SPLIT') eq 'chapter') {
  4093. $buttons = $self->get_conf('CHAPTER_BUTTONS');
  4094. } elsif ($self->get_conf('SPLIT') eq 'node') {
  4095. if ($self->get_conf('HEADERS')) {
  4096. my $no_footer_word_count;
  4097. if ($self->get_conf('WORDS_IN_PAGE')) {
  4098. my @cnt = split(/\W*\s+\W*/, $content);
  4099. if (scalar(@cnt) < $self->get_conf('WORDS_IN_PAGE')) {
  4100. $no_footer_word_count = 1;
  4101. }
  4102. }
  4103. $buttons = $self->get_conf('NODE_FOOTER_BUTTONS')
  4104. unless ($no_footer_word_count);
  4105. }
  4106. } else {
  4107. $maybe_in_page = 1;
  4108. }
  4109. if ($maybe_in_page or $is_top or $is_special
  4110. or ($end_page and ($self->get_conf('SPLIT') eq 'chapter'
  4111. or $self->get_conf('SPLIT') eq 'section'))
  4112. or ($self->get_conf('SPLIT') eq 'node' and $self->get_conf('HEADERS'))) {
  4113. $rule = $self->get_conf('DEFAULT_RULE');
  4114. }
  4115. if (!$end_page and ($is_top or $next_is_top or ($next_is_special
  4116. and !$is_special))) {
  4117. $rule = $self->get_conf('BIG_RULE');
  4118. }
  4119. # FIXME the following condition is almost a duplication of end_page
  4120. # except that the file counter needs not be 1
  4121. if ((!$element->{'element_next'}
  4122. or (defined($element->{'filename'})
  4123. and $element->{'filename'} ne $element->{'element_next'}->{'filename'}))
  4124. and $self->get_conf('footnotestyle') eq 'end') {
  4125. $result .= &{$self->{'format_footnotes_text'}}($self);
  4126. }
  4127. if (!$self->get_conf('PROGRAM_NAME_IN_FOOTER')
  4128. and !$buttons and !$maybe_in_page) {
  4129. # no rule in that case
  4130. } else {
  4131. $result .= "$rule\n" if ($rule);
  4132. }
  4133. if ($buttons) {
  4134. $result .= &{$self->{'format_navigation_header_panel'}}($self, $buttons,
  4135. undef, $element);
  4136. }
  4137. return $result;
  4138. }
  4139. $default_types_conversion{'element'} = \&_convert_element_type;
  4140. sub _new_document_context($$)
  4141. {
  4142. my $self = shift;
  4143. my $cmdname = shift;
  4144. push @{$self->{'document_context'}},
  4145. {'cmdname' => $cmdname,
  4146. 'formatting_context' => [{'cmdname' => $cmdname}],
  4147. 'composition_context' => ['raggedright'],
  4148. 'formats' => [],
  4149. 'monospace' => [0],
  4150. };
  4151. }
  4152. # Functions accessed with e.g. 'format_heading_text' for 'heading_text'.
  4153. my %default_formatting_references = (
  4154. 'heading_text' => \&_default_heading_text,
  4155. 'comment' => \&_default_comment,
  4156. 'protect_text' => \&_default_protect_text,
  4157. 'css_lines' => \&_default_css_lines,
  4158. 'begin_file' => \&_default_begin_file,
  4159. 'node_redirection_page' => \&_default_node_redirection_page,
  4160. 'end_file' => \&_default_end_file,
  4161. 'special_element_body' => \&_default_special_element_body,
  4162. 'footnotes_text' => \&_default_footnotes_text,
  4163. 'program_string' => \&_default_program_string,
  4164. 'titlepage' => \&_default_titlepage,
  4165. 'navigation_header' => \&_default_navigation_header,
  4166. 'navigation_header_panel' => \&_default_navigation_header_panel,
  4167. 'element_header' => \&_default_element_header,
  4168. 'element_footer' => \&_default_element_footer,
  4169. 'button' => \&_default_button_formatting,
  4170. 'button_icon_img' => \&_default_button_icon_img,
  4171. 'external_href' => \&_default_external_href,
  4172. 'contents' => \&_default_contents,
  4173. 'frame_files' => \&_default_frame_files,
  4174. );
  4175. sub _use_entity_is_entity($$)
  4176. {
  4177. my $self = shift;
  4178. my $text = shift;
  4179. return 0 if (!$self->get_conf('ENABLE_ENCODING_USE_ENTITY'));
  4180. return 1 if ($text =~ /^&/ and $text =~ /;$/);
  4181. }
  4182. sub _complete_commands_formatting($$)
  4183. {
  4184. my $self = shift;
  4185. my $command = shift;
  4186. if (!defined ($self->{'commands_formatting'}->{'normal'}->{$command})) {
  4187. $self->{'commands_formatting'}->{'normal'}->{$command} = '';
  4188. }
  4189. if (!defined ($self->{'commands_formatting'}->{'preformatted'}->{$command})) {
  4190. $self->{'commands_formatting'}->{'preformatted'}->{$command} =
  4191. $self->{'commands_formatting'}->{'normal'}->{$command};
  4192. }
  4193. if (!defined ($self->{'commands_formatting'}->{'string'}->{$command})) {
  4194. $self->{'commands_formatting'}->{'string'}->{$command} =
  4195. $self->{'commands_formatting'}->{'preformatted'}->{$command};
  4196. }
  4197. }
  4198. my %htmlxref_entries = (
  4199. 'node' => [ 'node', 'section', 'chapter', 'mono' ],
  4200. 'section' => [ 'section', 'chapter','node', 'mono' ],
  4201. 'chapter' => [ 'chapter', 'section', 'node', 'mono' ],
  4202. 'mono' => [ 'mono', 'chapter', 'section', 'node' ],
  4203. );
  4204. sub _parse_htmlxref_files($$)
  4205. {
  4206. my $self = shift;
  4207. my $files = shift;
  4208. my $htmlxref;
  4209. foreach my $file (@$files) {
  4210. print STDERR "html refs config file: $file\n" if ($self->get_conf('DEBUG'));
  4211. unless (open (HTMLXREF, $file)) {
  4212. $self->document_warn(
  4213. sprintf($self->__("could not open html refs config file %s: %s"),
  4214. $file, $!));
  4215. next;
  4216. }
  4217. my $line_nr = 0;
  4218. my %variables;
  4219. while (my $hline = <HTMLXREF>) {
  4220. my $line = $hline;
  4221. $line_nr++;
  4222. next if $hline =~ /^\s*#/;
  4223. #$hline =~ s/[#]\s.*//;
  4224. $hline =~ s/^\s*//;
  4225. next if $hline =~ /^\s*$/;
  4226. chomp ($hline);
  4227. if ($hline =~ s/^\s*(\w+)\s*=\s*//) {
  4228. # handle variables
  4229. my $var = $1;
  4230. my $re = join '|', map { quotemeta $_ } keys %variables;
  4231. $hline =~ s/\$\{($re)\}/defined $variables{$1} ? $variables{$1}
  4232. : "\${$1}"/ge;
  4233. $variables{$var} = $hline;
  4234. next;
  4235. }
  4236. my @htmlxref = split /\s+/, $hline;
  4237. my $manual = shift @htmlxref;
  4238. my $split_or_mono = shift @htmlxref;
  4239. #print STDERR "$split_or_mono $Texi2HTML::Config::htmlxref_entries{$split_or_mono} $line_nr\n";
  4240. if (!defined($split_or_mono)) {
  4241. $self->file_line_warn($self->__("missing type"), $file, $line_nr);
  4242. next;
  4243. } elsif (!defined($htmlxref_entries{$split_or_mono})) {
  4244. $self->file_line_warn(sprintf($self->__("unrecognized type: %s"),
  4245. $split_or_mono), $file, $line_nr);
  4246. next;
  4247. }
  4248. my $href = shift @htmlxref;
  4249. next if (exists($htmlxref->{$manual}->{$split_or_mono}));
  4250. if (defined($href)) { # substitute 'variables'
  4251. my $re = join '|', map { quotemeta $_ } keys %variables;
  4252. $href =~ s/\$\{($re)\}/defined $variables{$1} ? $variables{$1}
  4253. : "\${$1}"/ge;
  4254. $href =~ s/\/*$// if ($split_or_mono ne 'mono');
  4255. }
  4256. $htmlxref->{$manual}->{$split_or_mono} = $href;
  4257. }
  4258. if (!close (HTMLXREF)) {
  4259. $self->document_warn(sprintf($self->__(
  4260. "error on closing html refs config file %s: %s"),
  4261. $file, $!));
  4262. }
  4263. }
  4264. return $htmlxref;
  4265. }
  4266. sub converter_initialize($)
  4267. {
  4268. my $self = shift;
  4269. if ($self->get_conf('SHORTEXTN')) {
  4270. $self->set_conf('EXTENSION', 'htm');
  4271. }
  4272. $foot_num = 0;
  4273. $foot_lines = '';
  4274. %formatted_index_entries = ();
  4275. %footnote_id_numbers = ();
  4276. %{$self->{'css_map'}} = %css_map;
  4277. $self->{'htmlxref'} = {};
  4278. if ($self->{'htmlxref_files'}) {
  4279. $self->{'htmlxref'} = _parse_htmlxref_files($self,
  4280. $self->{'htmlxref_files'});
  4281. }
  4282. foreach my $type (keys(%default_types_conversion)) {
  4283. if (exists($Texinfo::Config::texinfo_types_conversion{$type})) {
  4284. $self->{'types_conversion'}->{$type}
  4285. = $Texinfo::Config::texinfo_types_conversion{$type};
  4286. } else {
  4287. $self->{'types_conversion'}->{$type}
  4288. = $default_types_conversion{$type};
  4289. }
  4290. }
  4291. # FIXME API with a function call? Used in cvs.init.
  4292. foreach my $type (keys(%default_code_types)) {
  4293. $self->{'code_types'}->{$type} = $default_code_types{$type};
  4294. }
  4295. if ($Texinfo::Config::texinfo_code_types) {
  4296. foreach my $type (keys(%$Texinfo::Config::texinfo_code_types)) {
  4297. $self->{'code_types'}->{$type}
  4298. = $Texinfo::Config::texinfo_code_types->{$type};
  4299. }
  4300. }
  4301. # FIXME put value in a category in Texinfo::Common?
  4302. foreach my $command (keys(%misc_commands), keys(%brace_commands),
  4303. keys (%block_commands), keys(%no_brace_commands), 'value') {
  4304. if (exists($Texinfo::Config::texinfo_commands_conversion{$command})) {
  4305. $self->{'commands_conversion'}->{$command}
  4306. = $Texinfo::Config::texinfo_commands_conversion{$command};
  4307. } else {
  4308. if (!$self->get_conf('SHOW_MENU')
  4309. and ($command eq 'menu' or $command eq 'detailmenu')) {
  4310. $self->{'commands_conversion'}->{$command} = undef;
  4311. } elsif ($format_raw_commands{$command}
  4312. and !$self->{'expanded_formats_hash'}->{$command}) {
  4313. } elsif (exists($default_commands_conversion{$command})) {
  4314. $self->{'commands_conversion'}->{$command}
  4315. = $default_commands_conversion{$command};
  4316. if ($command eq 'menu' and $self->get_conf('SIMPLE_MENU')) {
  4317. $self->{'commands_conversion'}->{$command}
  4318. = $default_commands_conversion{'example'};
  4319. }
  4320. }
  4321. }
  4322. }
  4323. foreach my $context ('normal', 'preformatted', 'string') {
  4324. foreach my $command (keys(%{$default_commands_formatting{'normal'}})) {
  4325. if (exists ($Texinfo::Config::commands_formatting{$context}->{$command})) {
  4326. $self->{'commands_formatting'}->{$context}->{$command}
  4327. = $Texinfo::Config::commands_formatting{$context}->{$command};
  4328. } else {
  4329. if (defined($default_commands_formatting{$context}->{$command})) {
  4330. if ($self->get_conf('ENABLE_ENCODING')
  4331. and Texinfo::Convert::Unicode::unicode_for_brace_no_arg_command(
  4332. $command, $self->get_conf('OUTPUT_ENCODING_NAME'))
  4333. and !$self->_use_entity_is_entity($default_commands_formatting{$context}->{$command})) {
  4334. $self->{'commands_formatting'}->{$context}->{$command}
  4335. = Texinfo::Convert::Unicode::unicode_for_brace_no_arg_command(
  4336. $command, $self->get_conf('OUTPUT_ENCODING_NAME'))
  4337. } else {
  4338. $self->{'commands_formatting'}->{$context}->{$command}
  4339. = $default_commands_formatting{$context}->{$command};
  4340. }
  4341. }
  4342. }
  4343. if (exists ($Texinfo::Config::commands_translation{$context}->{$command})) {
  4344. $self->{'commands_translation'}->{$context}->{$command}
  4345. = $Texinfo::Config::commands_translation{$context}->{$command};
  4346. delete $self->{'translated_commands'}->{$command};
  4347. } elsif (defined($default_commands_translation{$context}->{$command})) {
  4348. $self->{'commands_translation'}->{$context}->{$command}
  4349. = $default_commands_translation{$context}->{$command};
  4350. delete $self->{'translated_commands'}->{$command};
  4351. }
  4352. }
  4353. }
  4354. # set sane defaults in case there is none and the default formatting
  4355. # function is used
  4356. foreach my $command (keys(%{$default_commands_formatting{'normal'}})) {
  4357. if ($self->{'commands_conversion'}->{$command}
  4358. and $self->{'commands_conversion'}->{$command}
  4359. eq $default_commands_conversion{$command}) {
  4360. $self->_complete_commands_formatting($command);
  4361. }
  4362. }
  4363. foreach my $context (keys(%style_commands_formatting)) {
  4364. foreach my $command (keys(%{$style_commands_formatting{$context}})) {
  4365. if (exists ($Texinfo::Config::style_commands_formatting{$context}->{$command})) {
  4366. $self->{'style_commands_formatting'}->{$context}->{$command}
  4367. = $Texinfo::Config::style_commands_formatting{$context}->{$command};
  4368. } elsif (exists($style_commands_formatting{$context}->{$command})) {
  4369. $self->{'style_commands_formatting'}->{$context}->{$command}
  4370. = $style_commands_formatting{$context}->{$command};
  4371. }
  4372. }
  4373. }
  4374. foreach my $command (keys %{$self->{'commands_conversion'}}) {
  4375. if (exists($Texinfo::Config::commands_args{$command})) {
  4376. $self->{'commands_args'}->{$command}
  4377. = $Texinfo::Config::commands_args{$command};
  4378. } elsif (exists($default_commands_args{$command})) {
  4379. $self->{'commands_args'}->{$command} = $default_commands_args{$command};
  4380. }
  4381. }
  4382. foreach my $formatting_reference (keys(%default_formatting_references)) {
  4383. $self->{'default_formatting_functions'}->{$formatting_reference}
  4384. = $default_formatting_references{$formatting_reference};
  4385. if (defined($Texinfo::Config::texinfo_formatting_references{$formatting_reference})) {
  4386. $self->{"format_".$formatting_reference}
  4387. = $Texinfo::Config::texinfo_formatting_references{$formatting_reference};
  4388. } else {
  4389. $self->{"format_".$formatting_reference}
  4390. = $default_formatting_references{$formatting_reference};
  4391. }
  4392. }
  4393. if ($Texinfo::Config::renamed_nodes) {
  4394. %{$self->{'renamed_nodes'}} = %{$Texinfo::Config::renamed_nodes};
  4395. }
  4396. $self->{'document_context'} = [];
  4397. $self->{'multiple_pass'} = [];
  4398. $self->_new_document_context('_toplevel_context');
  4399. if ($self->get_conf('SPLIT') and $self->get_conf('SPLIT') ne 'chapter'
  4400. and $self->get_conf('SPLIT') ne 'section'
  4401. and $self->get_conf('SPLIT') ne 'node') {
  4402. $self->force_conf('SPLIT', 'node');
  4403. }
  4404. return $self;
  4405. }
  4406. # the entry point for _convert
  4407. sub convert_tree($$;$)
  4408. {
  4409. my $self = shift;
  4410. my $element = shift;
  4411. my $explanation = shift;
  4412. return $self->_convert($element, $explanation);
  4413. }
  4414. sub _normalized_to_id($)
  4415. {
  4416. my $id = shift;
  4417. if (!defined($id)) {
  4418. cluck "_normalized_to_id id not defined";
  4419. return '';
  4420. }
  4421. $id =~ s/^([0-9_])/g_t$1/;
  4422. return $id;
  4423. }
  4424. sub _default_css_lines ($)
  4425. {
  4426. my $self = shift;
  4427. return if ($self->get_conf('NO_CSS'));
  4428. my $css_refs = $self->get_conf('CSS_REFS');
  4429. return if (!@{$self->{'css_import_lines'}} and !@{$self->{'css_rule_lines'}}
  4430. and !keys(%{$self->{'css_map'}}) and !@$css_refs);
  4431. my $css_text = "<style type=\"text/css\">\n<!--\n";
  4432. $css_text .= join('',@{$self->{'css_import_lines'}}) . "\n"
  4433. if (@{$self->{'css_import_lines'}});
  4434. foreach my $css_rule (sort(keys(%{$self->{'css_map'}}))) {
  4435. next unless ($self->{'css_map'}->{$css_rule});
  4436. $css_text .= "$css_rule {$self->{'css_map'}->{$css_rule}}\n";
  4437. }
  4438. $css_text .= join('',@{$self->{'css_rule_lines'}}) . "\n"
  4439. if (@{$self->{'css_rule_lines'}});
  4440. $css_text .= "-->\n</style>\n";
  4441. foreach my $ref (@$css_refs) {
  4442. $css_text .= "<link rel=\"stylesheet\" type=\"text/css\" href=\"$ref\">\n";
  4443. }
  4444. $self->set_conf('CSS_LINES', $css_text);
  4445. }
  4446. sub _process_css_file($$$)
  4447. {
  4448. my $self = shift;
  4449. my $fh =shift;
  4450. my $file = shift;
  4451. my $in_rules = 0;
  4452. my $in_comment = 0;
  4453. my $in_import = 0;
  4454. my $in_string = 0;
  4455. my $rules = [];
  4456. my $imports = [];
  4457. my $line_nr = 0;
  4458. while (my $line = <$fh>) {
  4459. $line_nr++;
  4460. #print STDERR "Line: $line";
  4461. if ($in_rules) {
  4462. push @$rules, $line;
  4463. next;
  4464. }
  4465. my $text = '';
  4466. while (1) {
  4467. #sleep 1;
  4468. #print STDERR "${text}!in_comment $in_comment in_rules $in_rules in_import $in_import in_string $in_string: $line";
  4469. if ($in_comment) {
  4470. if ($line =~ s/^(.*?\*\/)//) {
  4471. $text .= $1;
  4472. $in_comment = 0;
  4473. } else {
  4474. push @$imports, $text . $line;
  4475. last;
  4476. }
  4477. } elsif (!$in_string and $line =~ s/^\///) {
  4478. if ($line =~ s/^\*//) {
  4479. $text .= '/*';
  4480. $in_comment = 1;
  4481. } else {
  4482. push (@$imports, $text. "\n") if ($text ne '');
  4483. push (@$rules, '/' . $line);
  4484. $in_rules = 1;
  4485. last;
  4486. }
  4487. } elsif (!$in_string and $in_import and $line =~ s/^([\"\'])//) {
  4488. # strings outside of import start rules
  4489. $text .= "$1";
  4490. $in_string = quotemeta("$1");
  4491. } elsif ($in_string and $line =~ s/^(\\$in_string)//) {
  4492. $text .= $1;
  4493. } elsif ($in_string and $line =~ s/^($in_string)//) {
  4494. $text .= $1;
  4495. $in_string = 0;
  4496. } elsif ((! $in_string and !$in_import)
  4497. and ($line =~ s/^([\\]?\@import)$//
  4498. or $line =~ s/^([\\]?\@import\s+)//)) {
  4499. $text .= $1;
  4500. $in_import = 1;
  4501. } elsif (!$in_string and $in_import and $line =~ s/^\;//) {
  4502. $text .= ';';
  4503. $in_import = 0;
  4504. } elsif (($in_import or $in_string) and $line =~ s/^(.)//) {
  4505. $text .= $1;
  4506. } elsif (!$in_import and $line =~ s/^([^\s])//) {
  4507. push (@$imports, $text. "\n") if ($text ne '');
  4508. push (@$rules, $1 . $line);
  4509. $in_rules = 1;
  4510. last;
  4511. } elsif ($line =~ s/^(\s)//) {
  4512. $text .= $1;
  4513. } elsif ($line eq '') {
  4514. push (@$imports, $text);
  4515. last;
  4516. }
  4517. }
  4518. }
  4519. #file_line_warn (__("string not closed in css file"), $file) if ($in_string);
  4520. #file_line_warn (__("--css-file ended in comment"), $file) if ($in_comment);
  4521. #file_line_warn (__("\@import not finished in css file"), $file) if ($in_import and !$in_comment and !$in_string);
  4522. $self->file_line_warn(sprintf($self->__("string not closed in css file"),
  4523. $file, $line_nr)) if ($in_string);
  4524. $self->file_line_warn(sprintf($self->__("--css-include ended in comment"),
  4525. $file, $line_nr)) if ($in_comment);
  4526. $self->file_line_warn(sprintf($self->__("\@import not finished in css file"),
  4527. $file, $line_nr))
  4528. if ($in_import and !$in_comment and !$in_string);
  4529. return ($imports, $rules);
  4530. }
  4531. sub _prepare_css($)
  4532. {
  4533. my $self = shift;
  4534. return if ($self->get_conf('NO_CSS'));
  4535. my @css_import_lines;
  4536. my @css_rule_lines;
  4537. my $css_files = $self->get_conf('CSS_FILES');
  4538. foreach my $file (@$css_files) {
  4539. my $css_file_fh;
  4540. my $css_file;
  4541. if ($file eq '-') {
  4542. $css_file_fh = \*STDIN;
  4543. $css_file = '-';
  4544. } else {
  4545. $css_file = $self->Texinfo::Common::locate_include_file($file);
  4546. unless (defined($css_file)) {
  4547. $self->document_warn(sprintf(
  4548. $self->__("CSS file %s not found"), $file));
  4549. next;
  4550. }
  4551. # FIXME use open_out?
  4552. unless (open (CSSFILE, $css_file)) {
  4553. $self->document_warn(sprintf($self->__(
  4554. "could not open --include-file %s: %s"),
  4555. $css_file, $!));
  4556. next;
  4557. }
  4558. $css_file_fh = \*CSSFILE;
  4559. }
  4560. my ($import_lines, $rules_lines);
  4561. ($import_lines, $rules_lines)
  4562. = $self->_process_css_file ($css_file_fh, $css_file);
  4563. if (!close($css_file_fh)) {
  4564. $self->document_warn(sprintf($self->__("error on closing CSS file %s: %s"),
  4565. $css_file, $!));
  4566. }
  4567. push @css_import_lines, @$import_lines;
  4568. push @css_rule_lines, @$rules_lines;
  4569. }
  4570. if ($self->get_conf('DEBUG')) {
  4571. if (@css_import_lines) {
  4572. print STDERR "# css import lines\n";
  4573. foreach my $line (@css_import_lines) {
  4574. print STDERR "$line";
  4575. }
  4576. }
  4577. if (@css_rule_lines) {
  4578. print STDERR "# css rule lines\n";
  4579. foreach my $line (@css_rule_lines) {
  4580. print STDERR "$line";
  4581. }
  4582. }
  4583. }
  4584. $self->{'css_import_lines'} = \@css_import_lines;
  4585. $self->{'css_rule_lines'} = \@css_rule_lines;
  4586. }
  4587. # Get the name of a file containing a node, as well as the anchor within
  4588. # that file to link to that node. Argument is the 'extra' value on
  4589. # an element hash, or something that looks like it.
  4590. sub _node_id_file($$)
  4591. {
  4592. my $self = shift;
  4593. my $node_info = shift;
  4594. my $target;
  4595. my $normalized;
  4596. if ($node_info->{'normalized'}) {
  4597. $normalized = $node_info->{'normalized'};
  4598. } elsif ($node_info->{'node_content'}) {
  4599. $normalized = Texinfo::Convert::NodeNameNormalization::normalize_node (
  4600. { 'contents' => $node_info->{'node_content'} });
  4601. }
  4602. if (defined($normalized)) {
  4603. $target = _normalized_to_id($normalized);
  4604. } else {
  4605. $target = '';
  4606. }
  4607. # to find out the Top node, one could check $node_info->{'normalized'}
  4608. if (defined($Texinfo::Config::node_target_name)) {
  4609. $target = &$Texinfo::Config::node_target_name($node_info, $target);
  4610. }
  4611. my $filename = $self->_node_filename($node_info);
  4612. return ($filename, $target);
  4613. }
  4614. sub _new_sectioning_command_target($$)
  4615. {
  4616. my $self = shift;
  4617. my $command = shift;
  4618. my ($normalized_name, $filename)
  4619. = $self->_sectioning_command_normalized_filename($command);
  4620. my $target_base = _normalized_to_id($normalized_name);
  4621. if ($target_base !~ /\S/ and $command->{'cmdname'} eq 'top'
  4622. and defined($self->{'misc_elements_targets'}->{'Top'})) {
  4623. $target_base = $self->{'misc_elements_targets'}->{'Top'};
  4624. }
  4625. my $nr=1;
  4626. my $target = $target_base;
  4627. if ($target ne '') {
  4628. while ($self->{'seen_ids'}->{$target}) {
  4629. $target = $target_base.'-'.$nr;
  4630. $nr++;
  4631. # Avoid integer overflow
  4632. die if ($nr == 0);
  4633. }
  4634. }
  4635. # These are undefined if the $target is set to ''.
  4636. my $target_contents;
  4637. my $target_shortcontents;
  4638. if ($Texinfo::Common::sectioning_commands{$command->{'cmdname'}}) {
  4639. if ($target ne '') {
  4640. my $target_base_contents = $target;
  4641. $target_base_contents =~ s/^g_t//;
  4642. $target_contents = 'toc-'.$target_base_contents;
  4643. my $toc_nr = $nr -1;
  4644. while ($self->{'seen_ids'}->{$target_contents}) {
  4645. $target_contents = 'toc-'.$target_base_contents.'-'.$toc_nr;
  4646. $toc_nr++;
  4647. # Avoid integer overflow
  4648. die if ($toc_nr == 0);
  4649. }
  4650. $target_shortcontents = 'stoc-'.$target_base_contents;
  4651. my $target_base_shortcontents = $target_base;
  4652. $target_base_shortcontents =~ s/^g_t//;
  4653. my $stoc_nr = $nr -1;
  4654. while ($self->{'seen_ids'}->{$target_shortcontents}) {
  4655. $target_shortcontents = 'stoc-'.$target_base_shortcontents
  4656. .'-'.$stoc_nr;
  4657. $stoc_nr++;
  4658. # Avoid integer overflow
  4659. die if ($stoc_nr == 0);
  4660. }
  4661. }
  4662. }
  4663. if (defined($Texinfo::Config::sectioning_command_target_name)) {
  4664. ($target, $target_contents,
  4665. $target_shortcontents, $filename)
  4666. = &$Texinfo::Config::sectioning_command_target_name($self,
  4667. $command, $target,
  4668. $target_contents,
  4669. $target_shortcontents,
  4670. $filename);
  4671. }
  4672. if ($self->get_conf('DEBUG')) {
  4673. print STDERR "Register $command->{'cmdname'} $target\n";
  4674. }
  4675. $self->{'targets'}->{$command} = {
  4676. 'target' => $target,
  4677. 'section_filename' => $filename,
  4678. };
  4679. $self->{'seen_ids'}->{$target} = 1;
  4680. if (defined($target_contents)) {
  4681. $self->{'targets'}->{$command}->{'contents_target'} = $target_contents;
  4682. } else {
  4683. $self->{'targets'}->{$command}->{'contents_target'} = '';
  4684. }
  4685. if (defined($target_shortcontents)) {
  4686. $self->{'targets'}->{$command}->{'shortcontents_target'}
  4687. = $target_shortcontents;
  4688. } else {
  4689. $self->{'targets'}->{$command}->{'shortcontents_target'} = '';
  4690. }
  4691. return $self->{'targets'}->{$command};
  4692. }
  4693. # This set 2 unrelated things.
  4694. # * The targets and id of sectioning elements
  4695. # * the target, id and normalized filename of 'labels', ie everything that
  4696. # may be the target of a ref, like @node, @float, @anchor...
  4697. # conversion to HTML is done on-demand, upon call to command_text.
  4698. sub _set_root_commands_targets_node_files($$)
  4699. {
  4700. my $self = shift;
  4701. my $elements = shift;
  4702. my $no_unidecode;
  4703. $no_unidecode = 1 if (defined($self->get_conf('USE_UNIDECODE'))
  4704. and !$self->get_conf('USE_UNIDECODE'));
  4705. if ($self->{'labels'}) {
  4706. foreach my $root_command (values(%{$self->{'labels'}})) {
  4707. my ($filename, $target) = $self->_node_id_file($root_command->{'extra'});
  4708. $filename .= '.'.$self->get_conf('NODE_FILE_EXTENSION')
  4709. if (defined($self->get_conf('NODE_FILE_EXTENSION'))
  4710. and $self->get_conf('NODE_FILE_EXTENSION') ne '');
  4711. if (defined($Texinfo::Config::node_file_name)) {
  4712. $filename = &$Texinfo::Config::node_file_name($self, $root_command,
  4713. $filename);
  4714. }
  4715. if ($self->get_conf('DEBUG')) {
  4716. print STDERR "Register label($root_command) $target, $filename\n";
  4717. }
  4718. $self->{'targets'}->{$root_command} = {'target' => $target,
  4719. 'node_filename' => $filename};
  4720. $self->{'seen_ids'}->{$target} = 1;
  4721. }
  4722. }
  4723. if ($elements) {
  4724. foreach my $element (@$elements) {
  4725. foreach my $root_command(@{$element->{'contents'}}) {
  4726. # this happens for type 'text_root' which precedes the
  4727. # root commands. The target may also already be set for top node.
  4728. next if (!defined($root_command->{'cmdname'})
  4729. or $self->{'targets'}->{$root_command});
  4730. if ($Texinfo::Common::sectioning_commands{$root_command->{'cmdname'}}) {
  4731. $self->_new_sectioning_command_target($root_command);
  4732. }
  4733. }
  4734. }
  4735. }
  4736. }
  4737. sub _get_element($$;$);
  4738. # If $find_container is set, the element that holds the command is found,
  4739. # otherwise the element that holds the command content is found. This is
  4740. # mostly relevant for footnote only.
  4741. sub _get_element($$;$)
  4742. {
  4743. my $self = shift;
  4744. my $command = shift;
  4745. my $find_container = shift;
  4746. my $current = $command;
  4747. my ($element, $root_command);
  4748. while (1) {
  4749. if ($current->{'type'}) {
  4750. if ($current->{'type'} eq 'element') {
  4751. return ($current, $root_command);
  4752. }
  4753. }
  4754. if ($current->{'cmdname'}) {
  4755. if ($root_commands{$current->{'cmdname'}}) {
  4756. $root_command = $current;
  4757. return ($element, $root_command) if defined($element);
  4758. } elsif ($region_commands{$current->{'cmdname'}}) {
  4759. if ($current->{'cmdname'} eq 'copying'
  4760. and $self->{'extra'} and $self->{'extra'}->{'insertcopying'}) {
  4761. foreach my $insertcopying(@{$self->{'extra'}->{'insertcopying'}}) {
  4762. my ($element, $root_command)
  4763. = $self->_get_element($insertcopying, $find_container);
  4764. return ($element, $root_command)
  4765. if (defined($element) or defined($root_command));
  4766. }
  4767. } elsif ($current->{'cmdname'} eq 'titlepage'
  4768. and $self->get_conf('USE_TITLEPAGE_FOR_TITLE')
  4769. and $self->get_conf('SHOW_TITLE')
  4770. and $self->{'elements'}->[0]) {
  4771. return ($self->{'elements'}->[0],
  4772. $self->{'elements'}->[0]->{'extra'}->{'element_command'});
  4773. }
  4774. die "Problem $element, $root_command" if (defined($element)
  4775. or defined($root_command));
  4776. return (undef, undef);
  4777. } elsif ($current->{'cmdname'} eq 'footnote'
  4778. and $self->{'special_elements_types'}->{'Footnotes'}
  4779. and $find_container) {
  4780. # in that case there is no root_command
  4781. $element = $self->{'special_elements_types'}->{'Footnotes'};
  4782. return ($element);
  4783. }
  4784. }
  4785. if ($current->{'parent'}) {
  4786. $current = $current->{'parent'};
  4787. } else {
  4788. return ($element, $root_command);
  4789. }
  4790. }
  4791. }
  4792. sub _set_pages_files($$)
  4793. {
  4794. my $self = shift;
  4795. my $elements = shift;
  4796. my $special_elements = shift;
  4797. # Ensure that the document has pages
  4798. return undef if (!defined($elements) or !@$elements);
  4799. my $extension = '';
  4800. $extension = '.'.$self->get_conf('EXTENSION')
  4801. if (defined($self->get_conf('EXTENSION'))
  4802. and $self->get_conf('EXTENSION') ne '');
  4803. if (!$self->get_conf('SPLIT')) {
  4804. foreach my $element (@$elements) {
  4805. if (!defined($element->{'filename'})) {
  4806. $element->{'filename'} = $self->{'output_filename'};
  4807. $element->{'out_filename'} = $self->{'output_file'};
  4808. }
  4809. }
  4810. } else {
  4811. my $node_top;
  4812. #my $section_top;
  4813. $node_top = $self->{'labels'}->{'Top'} if ($self->{'labels'});
  4814. #$section_top = $self->{'extra'}->{'top'} if ($self->{'extra'});
  4815. my $top_node_filename = $self->_top_node_filename();
  4816. # first determine the top node file name.
  4817. if ($self->get_conf('NODE_FILENAMES') and $node_top
  4818. and defined($top_node_filename)) {
  4819. my ($node_top_element) = $self->_get_element($node_top);
  4820. die "BUG: No element for top node" if (!defined($node_top));
  4821. $self->_set_element_file($node_top_element, $top_node_filename);
  4822. }
  4823. my $file_nr = 0;
  4824. my $previous_page;
  4825. foreach my $element(@$elements) {
  4826. # For Top node.
  4827. next if (defined($element->{'filename'}));
  4828. if (!$element->{'extra'}->{'first_in_page'}) {
  4829. cluck ("No first_in_page for $element\n");
  4830. }
  4831. if (!defined($element->{'extra'}->{'first_in_page'}->{'filename'})) {
  4832. my $file_element = $element->{'extra'}->{'first_in_page'};
  4833. if ($self->get_conf('NODE_FILENAMES')) {
  4834. foreach my $root_command (@{$file_element->{'contents'}}) {
  4835. if ($root_command->{'cmdname'}
  4836. and $root_command->{'cmdname'} eq 'node') {
  4837. my $node_filename;
  4838. # double node are not normalized, they are handled here
  4839. if (!defined($root_command->{'extra'}->{'normalized'})
  4840. or !defined($self->{'labels'}->{$root_command->{'extra'}->{'normalized'}})) {
  4841. $node_filename = 'unknown_node';
  4842. $node_filename .= '.'.$self->get_conf('NODE_FILE_EXTENSION')
  4843. if (defined($self->get_conf('NODE_FILE_EXTENSION'))
  4844. and $self->get_conf('NODE_FILE_EXTENSION') ne '');
  4845. } else {
  4846. if (!defined($self->{'targets'}->{$root_command})
  4847. or !defined($self->{'targets'}->{$root_command}->{'node_filename'})) {
  4848. # Could have been a double node, thus use equivalent node.
  4849. # However since double nodes are not normalized, in fact it
  4850. # never happens.
  4851. $root_command
  4852. = $self->{'labels'}->{$root_command->{'extra'}->{'normalized'}};
  4853. }
  4854. $node_filename
  4855. = $self->{'targets'}->{$root_command}->{'node_filename'};
  4856. }
  4857. $self->_set_element_file($file_element, $node_filename);
  4858. last;
  4859. }
  4860. }
  4861. if (!defined($file_element->{'filename'})) {
  4862. # use section to do the file name if there is no node
  4863. my $command = $self->element_command($file_element);
  4864. if ($command) {
  4865. if ($command->{'cmdname'} eq 'top' and !$node_top
  4866. and defined($top_node_filename)) {
  4867. $self->_set_element_file($file_element, $top_node_filename);
  4868. } else {
  4869. $self->_set_element_file($file_element,
  4870. $self->{'targets'}->{$command}->{'section_filename'});
  4871. }
  4872. } else {
  4873. # when everything else has failed
  4874. if ($file_nr == 0 and !$node_top
  4875. and defined($top_node_filename)) {
  4876. $self->_set_element_file($file_element, $top_node_filename);
  4877. } else {
  4878. my $filename = $self->{'document_name'} . "_$file_nr";
  4879. $filename .= $extension;
  4880. $self->_set_element_file($element, $filename);
  4881. }
  4882. $file_nr++;
  4883. }
  4884. }
  4885. } else {
  4886. my $filename = $self->{'document_name'} . "_$file_nr";
  4887. $filename .= '.'.$self->get_conf('EXTENSION')
  4888. if (defined($self->get_conf('EXTENSION'))
  4889. and $self->get_conf('EXTENSION') ne '');
  4890. $self->_set_element_file($file_element, $filename);
  4891. $file_nr++;
  4892. }
  4893. }
  4894. $element->{'filename'}
  4895. = $element->{'extra'}->{'first_in_page'}->{'filename'};
  4896. $element->{'out_filename'}
  4897. = $element->{'extra'}->{'first_in_page'}->{'out_filename'};
  4898. }
  4899. }
  4900. foreach my $element (@$elements) {
  4901. if (defined($Texinfo::Config::element_file_name)) {
  4902. # NOTE the information that it is associated with @top or @node Top
  4903. # may be determined with $self->element_is_top($element);
  4904. my $filename = &$Texinfo::Config::element_file_name($self, $element,
  4905. $element->{'filename'});
  4906. $self->_set_element_file($element, $filename) if (defined($filename));
  4907. }
  4908. $self->{'file_counters'}->{$element->{'filename'}}++;
  4909. print STDERR "Page $element ".Texinfo::Structuring::_print_element_command_texi($element).": $element->{'filename'}($self->{'file_counters'}->{$element->{'filename'}})\n"
  4910. if ($self->get_conf('DEBUG'));
  4911. }
  4912. if ($special_elements) {
  4913. my $previous_element = $elements->[-1];
  4914. foreach my $element (@$special_elements) {
  4915. my $filename
  4916. = $self->{'targets'}->{$element}->{'misc_filename'};
  4917. if (defined($filename)) {
  4918. $self->_set_element_file($element, $filename);
  4919. $self->{'file_counters'}->{$element->{'filename'}}++;
  4920. print STDERR "Special page $element: $element->{'filename'}($self->{'file_counters'}->{$element->{'filename'}})\n"
  4921. if ($self->get_conf('DEBUG'));
  4922. }
  4923. $element->{'element_prev'} = $previous_element;
  4924. $previous_element->{'element_next'} = $element;
  4925. $previous_element = $element;
  4926. }
  4927. }
  4928. }
  4929. # $ROOT is a parsed Texinfo tree. Return a list of the "elements" we need to
  4930. # output in the HTML file(s). Each "element" is what can go in one HTML file,
  4931. # such as the content between @node lines in the Texinfo source.
  4932. sub _prepare_elements($$)
  4933. {
  4934. my $self = shift;
  4935. my $root = shift;
  4936. my $elements;
  4937. # do that now to have it available for formatting
  4938. # NOTE this calls Convert::Converter::_informative_command on all the
  4939. # @informative_global commands.
  4940. # Thus sets among others language and encodings.
  4941. $self->_set_global_multiple_commands(-1);
  4942. $self->_translate_names();
  4943. if ($self->get_conf('USE_NODES')) {
  4944. $elements = Texinfo::Structuring::split_by_node($root);
  4945. } else {
  4946. $elements = Texinfo::Structuring::split_by_section($root);
  4947. }
  4948. $self->{'elements'} = $elements
  4949. if (defined($elements));
  4950. # This may be done as soon as elements are available.
  4951. $self->_prepare_global_targets($elements);
  4952. # Do that before the other elements, to be sure that special page ids
  4953. # are registered before elements id are.
  4954. my $special_elements
  4955. = $self->_prepare_special_elements($elements);
  4956. $self->{'special_elements'} = $special_elements
  4957. if (defined($special_elements));
  4958. #if ($elements) {
  4959. # foreach my $element(@{$elements}) {
  4960. # print STDERR "ELEMENT $element->{'type'}: $element\n";
  4961. # }
  4962. #}
  4963. $self->_set_root_commands_targets_node_files($elements);
  4964. return ($elements, $special_elements);
  4965. }
  4966. sub _prepare_special_elements($$)
  4967. {
  4968. my $self = shift;
  4969. my $elements = shift;
  4970. my %do_special;
  4971. # FIXME let the user decide how @*contents are treated?
  4972. if ($self->{'structuring'} and $self->{'structuring'}->{'sectioning_root'}
  4973. and scalar(@{$self->{'structuring'}->{'sections_list'}}) > 1) {
  4974. foreach my $cmdname ('contents', 'shortcontents') {
  4975. my $type = $contents_command_element_name{$cmdname};
  4976. if ($self->get_conf($cmdname)) {
  4977. if (not $self->get_conf('INLINE_CONTENTS')) {
  4978. $do_special{$type} = 1;
  4979. }
  4980. }
  4981. }
  4982. }
  4983. if ($self->{'extra'}->{'footnote'}
  4984. and $self->get_conf('footnotestyle') eq 'separate'
  4985. and $elements and scalar(@$elements) > 1) {
  4986. $do_special{'Footnotes'} = 1;
  4987. }
  4988. if ((!defined($self->get_conf('DO_ABOUT'))
  4989. and $elements and scalar(@$elements) > 1
  4990. and ($self->get_conf('SPLIT') or $self->get_conf('HEADERS')))
  4991. or ($self->get_conf('DO_ABOUT'))) {
  4992. $do_special{'About'} = 1;
  4993. }
  4994. my $extension = '';
  4995. $extension = $self->get_conf('EXTENSION')
  4996. if (defined($self->get_conf('EXTENSION')));
  4997. my $special_elements = [];
  4998. foreach my $type (@{$self->{'misc_elements_order'}}) {
  4999. next unless ($do_special{$type});
  5000. my $element = {'type' => 'element',
  5001. 'extra' => {'special_element' => $type,
  5002. }};
  5003. $element->{'extra'}->{'directions'}->{'This'} = $element;
  5004. $self->{'special_elements_types'}->{$type} = $element;
  5005. push @$special_elements, $element;
  5006. my $target = $self->{'misc_elements_targets'}->{$type};
  5007. my $default_filename;
  5008. if ($self->get_conf('SPLIT') or !$self->get_conf('MONOLITHIC')) {
  5009. $default_filename = $self->{'document_name'}.
  5010. $self->{'misc_pages_file_string'}->{$type};
  5011. $default_filename .= '.'.$extension if (defined($extension));
  5012. } else {
  5013. $default_filename = undef;
  5014. }
  5015. my $filename;
  5016. if (defined($Texinfo::Config::special_element_target_file_name)) {
  5017. ($target, $filename)
  5018. = &$Texinfo::Config::special_element_target_file_name(
  5019. $self,
  5020. $element,
  5021. $target,
  5022. $default_filename);
  5023. }
  5024. $filename = $default_filename if (!defined($filename));
  5025. if ($self->get_conf('DEBUG')) {
  5026. my $fileout = $filename;
  5027. $fileout = 'UNDEF' if (!defined($fileout));
  5028. print STDERR "Add special $element $type: target $target,\n".
  5029. " filename $fileout\n"
  5030. }
  5031. if ($self->get_conf('SPLIT') or !$self->get_conf('MONOLITHIC')
  5032. or (defined($filename) ne defined($default_filename))
  5033. or (defined($filename) and $filename ne $default_filename)) {
  5034. $self->_set_element_file($element, $filename);
  5035. print STDERR "NEW page for $type ($filename)\n" if ($self->get_conf('DEBUG'));
  5036. }
  5037. $self->{'targets'}->{$element} = {'target' => $target,
  5038. 'misc_filename' => $filename,
  5039. };
  5040. $self->{'seen_ids'}->{$target} = 1;
  5041. }
  5042. if ($self->get_conf('FRAMES')) {
  5043. foreach my $type (keys(%{$self->{'frame_pages_file_string'}})) {
  5044. my $default_filename;
  5045. $default_filename = $self->{'document_name'}.
  5046. $self->{'frame_pages_file_string'}->{$type};
  5047. $default_filename .= '.'.$extension if (defined($extension));
  5048. my $element = {'type' => 'element',
  5049. 'extra' => {'special_element' => $type,
  5050. }};
  5051. # only the filename is used
  5052. my ($target, $filename);
  5053. if (defined($Texinfo::Config::special_element_target_file_name)) {
  5054. ($target, $filename)
  5055. = &$Texinfo::Config::special_element_target_file_name(
  5056. $self,
  5057. $element,
  5058. $target,
  5059. $default_filename);
  5060. }
  5061. $filename = $default_filename if (!defined($filename));
  5062. $self->{'frame_pages_filenames'}->{$type} = $filename;
  5063. }
  5064. }
  5065. return $special_elements;
  5066. }
  5067. sub _prepare_contents_elements($)
  5068. {
  5069. my $self = shift;
  5070. if ($self->{'structuring'} and $self->{'structuring'}->{'sectioning_root'}
  5071. and scalar(@{$self->{'structuring'}->{'sections_list'}}) > 1) {
  5072. foreach my $cmdname ('contents', 'shortcontents') {
  5073. my $type = $contents_command_element_name{$cmdname};
  5074. if ($self->get_conf($cmdname)) {
  5075. my $default_filename;
  5076. if ($self->get_conf('INLINE_CONTENTS')) {
  5077. if ($self->{'extra'} and $self->{'extra'}->{$cmdname}) {
  5078. foreach my $command(@{$self->{'extra'}->{$cmdname}}) {
  5079. my ($element, $root_command)
  5080. = $self->_get_element($command);
  5081. if (defined($element)) {
  5082. $default_filename = $element->{'filename'};
  5083. last;
  5084. }
  5085. }
  5086. } else {
  5087. next;
  5088. }
  5089. } else { # in this case, there should already be a special element
  5090. # if needed, done together with the other special elements.
  5091. next;
  5092. }
  5093. my $element = {'type' => 'element',
  5094. 'extra' => {'special_element' => $type}};
  5095. $self->{'special_elements_types'}->{$type} = $element;
  5096. my $target = $self->{'misc_elements_targets'}->{$type};
  5097. my $filename;
  5098. if (defined($Texinfo::Config::special_element_target_file_name)) {
  5099. ($target, $filename)
  5100. = &$Texinfo::Config::special_element_target_file_name(
  5101. $self,
  5102. $element,
  5103. $target,
  5104. $default_filename);
  5105. }
  5106. $filename = $default_filename if (!defined($filename));
  5107. print STDERR "Add content $element $type: target $target,\n".
  5108. " filename $filename\n" if ($self->get_conf('DEBUG'));
  5109. $self->{'targets'}->{$element} = {'target' => $target,
  5110. 'misc_filename' => $filename,
  5111. 'filename' => $filename,
  5112. };
  5113. }
  5114. }
  5115. }
  5116. }
  5117. # Associate elements with the global targets, First, Last, Top, Index.
  5118. sub _prepare_global_targets($$)
  5119. {
  5120. my $self = shift;
  5121. my $elements = shift;
  5122. $self->{'global_target_elements'}->{'First'} = $elements->[0];
  5123. $self->{'global_target_elements'}->{'Last'} = $elements->[-1];
  5124. # It is always the first printindex, even if it is not output (for example
  5125. # it is in @copying and @titlepage, which are certainly wrong constructs).
  5126. if ($self->{'extra'} and $self->{'extra'}->{'printindex'}) {
  5127. my ($element, $root_command)
  5128. = $self->_get_element($self->{'extra'}->{'printindex'}->[0]);
  5129. if (defined($element)) {
  5130. if ($root_command and $root_command->{'cmdname'} eq 'node'
  5131. and $element->{'extra'}->{'section'}) {
  5132. $root_command = $element->{'extra'}->{'section'};
  5133. }
  5134. if ($root_command and $root_command->{'cmdname'} ne 'node') {
  5135. while ($root_command->{'level'} > 1
  5136. and $root_command->{'section_up'}
  5137. and $root_command->{'section_up'}->{'parent'}) {
  5138. $root_command = $root_command->{'section_up'};
  5139. $element = $root_command->{'parent'};
  5140. }
  5141. }
  5142. $self->{'global_target_elements'}->{'Index'} = $element;
  5143. }
  5144. }
  5145. my $node_top;
  5146. $node_top = $self->{'labels'}->{'Top'} if ($self->{'labels'});
  5147. my $section_top;
  5148. $section_top = $self->{'extra'}->{'top'} if ($self->{'extra'});
  5149. if ($section_top) {
  5150. $self->{'global_target_elements'}->{'Top'} = $section_top->{'parent'};
  5151. } elsif ($node_top) {
  5152. my $element_top = $node_top->{'parent'};
  5153. if (!$element_top) {
  5154. die "No parent for node_top: ".Texinfo::Common::_print_current($node_top);
  5155. }
  5156. $self->{'global_target_elements'}->{'Top'} = $element_top;
  5157. } else {
  5158. $self->{'global_target_elements'}->{'Top'} = $elements->[0];
  5159. }
  5160. if ($self->get_conf('DEBUG')) {
  5161. print STDERR "GLOBAL DIRECTIONS:\n";
  5162. foreach my $global_direction ('First', 'Last', 'Index', 'Top') {
  5163. if (defined($self->{'global_target_elements'}->{$global_direction})) {
  5164. print STDERR "$global_direction($self->{'global_target_elements'}->{$global_direction}): ".
  5165. Texinfo::Structuring::_print_element_command_texi(
  5166. $self->{'global_target_elements'}->{$global_direction})."\n";
  5167. }
  5168. }
  5169. }
  5170. }
  5171. sub _prepare_index_entries($)
  5172. {
  5173. my $self = shift;
  5174. if ($self->{'parser'}) {
  5175. my $no_unidecode;
  5176. $no_unidecode = 1 if (defined($self->get_conf('USE_UNIDECODE'))
  5177. and !$self->get_conf('USE_UNIDECODE'));
  5178. my $index_names = $self->{'parser'}->indices_information();
  5179. $self->{'index_names'} = $index_names;
  5180. my $merged_index_entries
  5181. = Texinfo::Structuring::merge_indices($index_names);
  5182. $self->{'index_entries_by_letter'}
  5183. = $self->Texinfo::Structuring::sort_indices_by_letter($merged_index_entries,
  5184. $index_names);
  5185. $self->{'index_entries'} = $merged_index_entries;
  5186. foreach my $index_name (sort(keys(%$index_names))) {
  5187. foreach my $index_entry (@{$index_names->{$index_name}->{'index_entries'}}) {
  5188. my $region = '';
  5189. $region = "$index_entry->{'region'}->{'cmdname'}-"
  5190. if (defined($index_entry->{'region'}));
  5191. my @contents = @{$index_entry->{'content_normalized'}};
  5192. my $trimmed_contents
  5193. = Texinfo::Common::trim_spaces_comment_from_content(\@contents);
  5194. my $normalized_index =
  5195. Texinfo::Convert::NodeNameNormalization::transliterate_texinfo(
  5196. {'contents' => \@contents}, $no_unidecode);
  5197. my $target_base = "index-" . $region .$normalized_index;
  5198. my $nr=1;
  5199. my $target = $target_base;
  5200. while ($self->{'seen_ids'}->{$target}) {
  5201. $target = $target_base.'-'.$nr;
  5202. $nr++;
  5203. # Avoid integer overflow
  5204. die if ($nr == 0);
  5205. }
  5206. $self->{'seen_ids'}->{$target} = 1;
  5207. $self->{'targets'}->{$index_entry->{'command'}} = {'target' => $target,
  5208. };
  5209. }
  5210. }
  5211. }
  5212. }
  5213. sub _prepare_footnotes($)
  5214. {
  5215. my $self = shift;
  5216. if ($self->{'extra'}->{'footnote'}) {
  5217. my $footnote_nr = 0;
  5218. foreach my $footnote (@{$self->{'extra'}->{'footnote'}}) {
  5219. $footnote_nr++;
  5220. my $nr = $footnote_nr;
  5221. my $footid = $footid_base.$nr;
  5222. my $docid = $docid_base.$nr;
  5223. while ($self->{'seen_ids'}->{$docid} or $self->{'seen_ids'}->{$footid}) {
  5224. $nr++;
  5225. $footid = $footid_base.$nr;
  5226. $docid = $docid_base.$nr;
  5227. # Avoid integer overflow
  5228. die if ($nr == 0);
  5229. }
  5230. $self->{'seen_ids'}->{$footid} = 1;
  5231. $self->{'seen_ids'}->{$docid} = 1;
  5232. $self->{'targets'}->{$footnote} = { 'target' => $footid };
  5233. print STDERR "Enter footnote $footnote: target $footid, nr $footnote_nr\n"
  5234. .Texinfo::Convert::Texinfo::convert($footnote)."\n"
  5235. if ($self->get_conf('DEBUG'));
  5236. }
  5237. }
  5238. }
  5239. # TODO this encapsulates some information.
  5240. # The encapsulation and API should be more consistent for
  5241. # the overall module.
  5242. sub _htmlxref($$)
  5243. {
  5244. my $self = shift;
  5245. my $file = shift;
  5246. return $self->{'htmlxref'}->{$file};
  5247. }
  5248. sub _external_node_href($$$$)
  5249. {
  5250. my $self = shift;
  5251. my $external_node = shift;
  5252. my $filename = shift;
  5253. my $link_command = shift;
  5254. # This only overrides an implicit pointer to (dir) as the Top node's Up.
  5255. # It has no effect if a pointer is explicitly specified,
  5256. # or if implicit pointers aren't being created (e.g., just a Top node).
  5257. if ($external_node->{'top_node_up'}
  5258. and defined($self->get_conf('TOP_NODE_UP_URL'))) {
  5259. return $self->get_conf('TOP_NODE_UP_URL');
  5260. }
  5261. # In addition to that implicit (dir) as the Top node's Up, replace all
  5262. # other references to external file "dir" with the same TOP_NODE_UP_URL.
  5263. if (defined($self->get_conf('TOP_NODE_UP_URL'))
  5264. and $external_node->{'manual_content'}[0]->{'text'} eq "dir") {
  5265. return $self->get_conf('TOP_NODE_UP_URL');
  5266. }
  5267. #print STDERR "external_node: ".join('|', keys(%$external_node))."\n";
  5268. my ($target_filebase, $target) = $self->_node_id_file($external_node);
  5269. my $xml_target = _normalized_to_id($target);
  5270. my $default_target_split = $self->get_conf('EXTERNAL_CROSSREF_SPLIT');
  5271. my $extension = '';
  5272. $extension = "." . $self->get_conf('NODE_FILE_EXTENSION')
  5273. if (defined($self->get_conf('NODE_FILE_EXTENSION'))
  5274. and $self->get_conf('NODE_FILE_EXTENSION') ne '');
  5275. my $target_split;
  5276. my $file;
  5277. if ($external_node->{'manual_content'}) {
  5278. my $manual_name = Texinfo::Convert::Text::convert(
  5279. {'contents' => $external_node->{'manual_content'}},
  5280. { 'code' => 1,
  5281. Texinfo::Common::_convert_text_options($self)});
  5282. my $manual_base = $manual_name;
  5283. $manual_base =~ s/\.[^\.]*$//;
  5284. $manual_base =~ s/^.*\///;
  5285. my $document_split = $self->get_conf('SPLIT');
  5286. $document_split = 'mono' if (!$document_split);
  5287. my $split_found;
  5288. my $href;
  5289. my $htmlxref_info = $self->_htmlxref($manual_base);
  5290. if ($htmlxref_info) {
  5291. foreach my $split_ordered (@{$htmlxref_entries{$document_split}}) {
  5292. if (defined($htmlxref_info->{$split_ordered})) {
  5293. $split_found = $split_ordered;
  5294. $href = $htmlxref_info->{$split_ordered};
  5295. last;
  5296. }
  5297. }
  5298. }
  5299. if (defined($split_found)) {
  5300. $target_split = 1 unless ($split_found eq 'mono');
  5301. } else { # nothing specified for that manual, use default
  5302. $target_split = $default_target_split;
  5303. if ($self->get_conf('CHECK_HTMLXREF')
  5304. and !$external_node->{'top_node_up'}) {
  5305. if (defined($link_command) and $link_command->{'line_nr'}) {
  5306. $self->line_warn(sprintf($self->__(
  5307. "no htmlxref.cnf entry found for `%s'"), $manual_name),
  5308. $link_command->{'line_nr'});
  5309. } elsif (!$self->{'check_htmlxref_already_warned'}->{$manual_name}) {
  5310. $self->document_warn(sprintf($self->__(
  5311. "no htmlxref.cnf entry found for `%s'"), $manual_name),
  5312. );
  5313. }
  5314. $self->{'check_htmlxref_already_warned'}->{$manual_name} = 1;
  5315. }
  5316. }
  5317. if ($target_split) {
  5318. if (defined($href)) {
  5319. $file = $href;
  5320. } elsif (defined($self->get_conf('EXTERNAL_DIR'))) {
  5321. $file = $self->get_conf('EXTERNAL_DIR')."/$manual_base";
  5322. } elsif ($self->get_conf('SPLIT')) {
  5323. $file = "../$manual_base";
  5324. }
  5325. $file .= "/";
  5326. } else {# target not split
  5327. if (defined($href)) {
  5328. $file = $href;
  5329. } else {
  5330. if (defined($self->get_conf('EXTERNAL_DIR'))) {
  5331. $file = $self->get_conf('EXTERNAL_DIR')."/$manual_base";
  5332. } elsif ($self->get_conf('SPLIT')) {
  5333. $file = "../$manual_base";
  5334. } else {
  5335. $file = $manual_base;
  5336. }
  5337. $file .= $extension;
  5338. }
  5339. }
  5340. } else {
  5341. $file = '';
  5342. $target_split = $default_target_split;
  5343. }
  5344. if ($target eq '') {
  5345. if ($target_split) {
  5346. if (defined($self->get_conf('TOP_NODE_FILE_TARGET'))) {
  5347. return $file . $self->get_conf('TOP_NODE_FILE_TARGET')
  5348. . $extension;# . '#Top';
  5349. } else {
  5350. return $file;# . '#Top';
  5351. }
  5352. } else {
  5353. return $file . '#Top';
  5354. }
  5355. }
  5356. if (! $target_split) {
  5357. return $file . '#' . $xml_target;
  5358. } else {
  5359. my $file_basename;
  5360. if ($target eq 'Top' and defined($self->get_conf('TOP_NODE_FILE_TARGET'))) {
  5361. $file_basename = $self->get_conf('TOP_NODE_FILE_TARGET');
  5362. } else {
  5363. $file_basename = $target_filebase;
  5364. }
  5365. return $file . $file_basename . $extension . '#' . $xml_target;
  5366. }
  5367. }
  5368. my %valid_types = (
  5369. 'href' => 1,
  5370. 'string' => 1,
  5371. 'text' => 1,
  5372. 'tree' => 1,
  5373. 'target' => 1,
  5374. 'node' => 1,
  5375. );
  5376. foreach my $no_number_type ('text', 'tree', 'string') {
  5377. $valid_types{$no_number_type .'_nonumber'} = 1;
  5378. }
  5379. sub _element_direction($$$$;$)
  5380. {
  5381. my $self = shift;
  5382. my $element = shift;
  5383. my $direction = shift;
  5384. my $type = shift;
  5385. my $filename = shift;
  5386. my $element_target;
  5387. my $command;
  5388. my $target;
  5389. $filename = $self->{'current_filename'} if (!defined($filename));
  5390. if (!$valid_types{$type}) {
  5391. print STDERR "Incorrect type $type in _element_direction call\n";
  5392. return undef;
  5393. }
  5394. if ($self->{'global_target_elements'}->{$direction}) {
  5395. $element_target = $self->{'global_target_elements'}->{$direction};
  5396. } elsif ($element and $element->{'extra'}
  5397. and $element->{'extra'}->{'directions'}
  5398. and $element->{'extra'}->{'directions'}->{$direction}) {
  5399. $element_target
  5400. = $element->{'extra'}->{'directions'}->{$direction};
  5401. }
  5402. if ($element_target) {
  5403. ######## debug
  5404. if (!$element_target->{'type'}) {
  5405. die "No type for element_target $direction $element_target: "
  5406. . Texinfo::Common::_print_current_keys($element_target)
  5407. . "directions :". Texinfo::Structuring::_print_directions($element);
  5408. }
  5409. ########
  5410. if ($element_target->{'type'} eq 'external_node'
  5411. or $element_target->{'type'} eq 'top_node_up') {
  5412. my $external_node = $element_target->{'extra'};
  5413. if ($type eq 'href') {
  5414. return $self->command_href($external_node, $filename);
  5415. } elsif ($type eq 'text' or $type eq 'node') {
  5416. return $self->command_text($external_node);
  5417. } elsif ($type eq 'string') {
  5418. return $self->command_text($external_node, $type);
  5419. }
  5420. } elsif ($type eq 'node') {
  5421. $command = $element_target->{'extra'}->{'node'};
  5422. $target = $self->{'targets'}->{$command} if ($command);
  5423. $type = 'text';
  5424. } else {
  5425. if ($element_target->{'extra'}->{'special_element'}) {
  5426. $command = $element_target;
  5427. } else {
  5428. $command = $element_target->{'extra'}->{'element_command'};
  5429. }
  5430. if ($type eq 'href') {
  5431. if (defined($command)) {
  5432. return $self->command_href($command, $filename);
  5433. } else {
  5434. return '';
  5435. }
  5436. }
  5437. $target = $self->{'targets'}->{$command} if ($command);
  5438. }
  5439. } elsif ($self->special_element($direction)) {
  5440. $element_target = $self->special_element($direction);
  5441. $command = $element_target;
  5442. if ($type eq 'href') {
  5443. return $self->command_href($element_target, $filename);
  5444. }
  5445. $target = $self->{'targets'}->{$element_target};
  5446. } else {
  5447. return undef;
  5448. }
  5449. if (exists($target->{$type})) {
  5450. return $target->{$type};
  5451. } elsif ($type eq 'target') {
  5452. return undef;
  5453. } elsif ($command) {
  5454. return $self->command_text($command, $type);
  5455. }
  5456. }
  5457. sub _default_contents($$;$$)
  5458. {
  5459. my $self = shift;
  5460. my $cmdname = shift;
  5461. my $command = shift;
  5462. my $filename = shift;
  5463. $filename = $self->{'current_filename'} if (!defined($filename));
  5464. return ''
  5465. if (!$self->{'structuring'} or !$self->{'structuring'}->{'sectioning_root'});
  5466. my $section_root = $self->{'structuring'}->{'sectioning_root'};
  5467. my $contents;
  5468. $contents = 1 if ($cmdname eq 'contents');
  5469. my $min_root_level = $section_root->{'section_childs'}->[0]->{'level'};
  5470. my $max_root_level = $section_root->{'section_childs'}->[0]->{'level'};
  5471. foreach my $top_section(@{$section_root->{'section_childs'}}) {
  5472. $min_root_level = $top_section->{'level'}
  5473. if ($top_section->{'level'} < $min_root_level);
  5474. $max_root_level = $top_section->{'level'}
  5475. if ($top_section->{'level'} > $max_root_level);
  5476. }
  5477. # chapter level elements are considered top-level here.
  5478. $max_root_level = 1 if ($max_root_level < 1);
  5479. #print STDERR "ROOT_LEVEL Max: $max_root_level, Min: $min_root_level\n";
  5480. my $ul_class = '';
  5481. $ul_class = $NO_BULLET_LIST_CLASS if ($self->get_conf('NUMBER_SECTIONS'));
  5482. my $result = '';
  5483. if ($contents and !defined($self->get_conf('BEFORE_TOC_LINES'))
  5484. or (!$contents and !defined($self->get_conf('BEFORE_OVERVIEW')))) {
  5485. $result .= $self->_attribute_class('div', $cmdname).">\n";
  5486. } elsif($contents) {
  5487. $result .= $self->get_conf('BEFORE_TOC_LINES');
  5488. } else {
  5489. $result .= $self->get_conf('BEFORE_OVERVIEW');
  5490. }
  5491. my $toplevel_contents;
  5492. if (@{$section_root->{'section_childs'}} > 1) {
  5493. # or $section_root->{'section_childs'}->[0]->{'cmdname'} ne 'top') {
  5494. $result .= $self->_attribute_class('ul', $ul_class) .">\n";
  5495. $toplevel_contents = 1;
  5496. }
  5497. foreach my $top_section (@{$section_root->{'section_childs'}}) {
  5498. my $section = $top_section;
  5499. SECTION:
  5500. while ($section) {
  5501. if ($section->{'cmdname'} ne 'top') {
  5502. my $text = $self->command_text($section);
  5503. my $href;
  5504. if (!$contents and $self->get_conf('OVERVIEW_LINK_TO_TOC')) {
  5505. $href = $self->command_contents_href($section, 'contents', $filename);
  5506. } else {
  5507. $href = $self->command_href($section, $filename);
  5508. }
  5509. my $toc_id = $self->command_contents_target($section, $cmdname);
  5510. if ($text ne '') {
  5511. # no indenting for shortcontents
  5512. $result .= (' ' x (2*($section->{'level'} - $min_root_level)))
  5513. if ($contents);
  5514. if ($toc_id ne '' or $href ne '') {
  5515. my $toc_name_attribute = '';
  5516. if ($toc_id ne '') {
  5517. $toc_name_attribute = "name=\"$toc_id\" ";
  5518. }
  5519. my $href_attribute = '';
  5520. if ($href ne '') {
  5521. $href_attribute = "href=\"$href\"";
  5522. }
  5523. $result .= "<li><a ${toc_name_attribute}${href_attribute}>$text</a>";
  5524. } else {
  5525. $result .= "<li>$text";
  5526. }
  5527. }
  5528. } elsif ($section->{'section_childs'} and @{$section->{'section_childs'}}
  5529. and $toplevel_contents) {
  5530. $result .= "<li>";
  5531. }
  5532. # for shortcontents don't do child if child is not toplevel
  5533. if ($section->{'section_childs'}
  5534. and ($contents or $section->{'level'} < $max_root_level)) {
  5535. # no indenting for shortcontents
  5536. $result .= "\n". ' ' x (2*($section->{'level'} - $min_root_level))
  5537. if ($contents);
  5538. $result .= $self->_attribute_class('ul', $ul_class) .">\n";
  5539. $section = $section->{'section_childs'}->[0];
  5540. } elsif ($section->{'section_next'} and $section->{'cmdname'} ne 'top') {
  5541. $result .= "</li>\n";
  5542. last if ($section eq $top_section);
  5543. $section = $section->{'section_next'};
  5544. } else {
  5545. #last if ($section eq $top_section);
  5546. if ($section eq $top_section) {
  5547. $result .= "</li>\n" unless ($section->{'cmdname'} eq 'top');
  5548. last;
  5549. }
  5550. while ($section->{'section_up'}) {
  5551. $section = $section->{'section_up'};
  5552. $result .= "</li>\n". ' ' x (2*($section->{'level'} - $min_root_level))
  5553. . "</ul>";
  5554. if ($section eq $top_section) {
  5555. $result .= "</li>\n" if ($toplevel_contents);
  5556. last SECTION;
  5557. }
  5558. if ($section->{'section_next'}) {
  5559. $result .= "</li>\n";
  5560. $section = $section->{'section_next'};
  5561. last;
  5562. }
  5563. }
  5564. }
  5565. }
  5566. }
  5567. if (@{$section_root->{'section_childs'}} > 1) {
  5568. # or $section_root->{'section_childs'}->[0]->{'cmdname'} ne 'top') {
  5569. $result .= "\n</ul>";
  5570. }
  5571. if ($contents and !defined($self->get_conf('AFTER_TOC_LINES'))
  5572. or (!$contents and !defined($self->get_conf('AFTER_OVERVIEW')))) {
  5573. $result .= "\n</div>\n";
  5574. } elsif($contents) {
  5575. $result .= $self->get_conf('AFTER_TOC_LINES');
  5576. } else {
  5577. $result .= $self->get_conf('AFTER_OVERVIEW');
  5578. }
  5579. return $result;
  5580. }
  5581. sub _default_program_string($)
  5582. {
  5583. my $self = shift;
  5584. if (defined($self->get_conf('PROGRAM'))
  5585. and $self->get_conf('PROGRAM') ne ''
  5586. and defined($self->get_conf('PACKAGE_URL'))) {
  5587. return $self->convert_tree(
  5588. $self->gdt('This document was generated on @emph{@today{}} using @uref{{program_homepage}, @emph{{program}}}.',
  5589. { 'program_homepage' => $self->get_conf('PACKAGE_URL'),
  5590. 'program' => $self->get_conf('PROGRAM') }));
  5591. } else {
  5592. return $self->convert_tree(
  5593. $self->gdt('This document was generated on @emph{@today{}}.'));
  5594. }
  5595. }
  5596. sub _default_end_file($)
  5597. {
  5598. my $self = shift;
  5599. my $program_text = '';
  5600. if ($self->get_conf('PROGRAM_NAME_IN_FOOTER')) {
  5601. my $program_string = &{$self->{'format_program_string'}}($self);
  5602. $program_text = "<p><font size=\"-1\">
  5603. $program_string
  5604. </font></p>";
  5605. }
  5606. my $pre_body_close = $self->get_conf('PRE_BODY_CLOSE');
  5607. $pre_body_close = '' if (!defined($pre_body_close));
  5608. return "$program_text
  5609. $pre_body_close
  5610. </body>
  5611. </html>
  5612. ";
  5613. }
  5614. # This is used for normal output files and other files, like renamed
  5615. # nodes file headers, or redirection file headers.
  5616. sub _file_header_informations($$)
  5617. {
  5618. my $self = shift;
  5619. my $command = shift;
  5620. my $title;
  5621. if ($command) {
  5622. my $command_string =
  5623. $self->command_text($command, 'string');
  5624. if (defined($command_string)
  5625. and $command_string ne $self->{'title_string'}) {
  5626. print STDERR "DO <title>\n"
  5627. if ($self->get_conf('DEBUG'));
  5628. my $title_tree = $self->gdt('{element_text} ({title})',
  5629. { 'title' => $self->{'title_tree'},
  5630. 'element_text' => $self->command_text($command, 'tree')});
  5631. $title = $self->convert_tree_new_formatting_context(
  5632. {'type' => '_string', 'contents' => [$title_tree]},
  5633. $command->{'cmdname'}, 'element_title');
  5634. }
  5635. }
  5636. $title = $self->{'title_string'} if (!defined($title));
  5637. my $description;
  5638. if ($self->{'documentdescription_string'}) {
  5639. $description = $self->{'documentdescription_string'};
  5640. } else {
  5641. $description = $title;
  5642. }
  5643. $description = "<meta name=\"description\" content=\"$description\">"
  5644. if ($description ne '');
  5645. my $encoding = '';
  5646. $encoding
  5647. = "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=".
  5648. $self->get_conf('OUTPUT_ENCODING_NAME')."\">"
  5649. if (defined($self->get_conf('OUTPUT_ENCODING_NAME'))
  5650. and ($self->get_conf('OUTPUT_ENCODING_NAME') ne ''));
  5651. my $date = '';
  5652. if ($self->get_conf('DATE_IN_HEADER')) {
  5653. my $today = $self->convert_tree_new_formatting_context(
  5654. {'cmdname' => 'today'}, 'DATE_IN_HEADER');
  5655. $date = "\n<meta name=\"date\" content=\"$today\">";
  5656. }
  5657. my $css_lines;
  5658. if (defined($self->get_conf('CSS_LINES'))) {
  5659. $css_lines = $self->get_conf('CSS_LINES');
  5660. } else {
  5661. $css_lines = '';
  5662. }
  5663. my $doctype = $self->get_conf('DOCTYPE');
  5664. my $bodytext = $self->get_conf('BODYTEXT');
  5665. my $copying_comment = '';
  5666. $copying_comment = $self->{'copying_comment'}
  5667. if (defined($self->{'copying_comment'}));
  5668. my $after_body_open = '';
  5669. $after_body_open = $self->get_conf('AFTER_BODY_OPEN')
  5670. if (defined($self->get_conf('AFTER_BODY_OPEN')));
  5671. my $extra_head = '';
  5672. $extra_head = $self->get_conf('EXTRA_HEAD')
  5673. if (defined($self->get_conf('EXTRA_HEAD')));
  5674. my $program_and_version = $self->get_conf('PACKAGE_AND_VERSION');
  5675. my $program_homepage = $self->get_conf('PACKAGE_URL');
  5676. my $program = $self->get_conf('PROGRAM');
  5677. my $generator = '';
  5678. if (defined($program) and $program ne '') {
  5679. $generator = "\n<meta name=\"Generator\" content=\"$program\">";
  5680. }
  5681. return ($title, $description, $encoding, $date, $css_lines,
  5682. $doctype, $bodytext, $copying_comment, $after_body_open,
  5683. $extra_head, $program_and_version, $program_homepage,
  5684. $program, $generator);
  5685. }
  5686. sub _get_links ($$$)
  5687. {
  5688. my $self = shift;
  5689. my $filename = shift;
  5690. my $element = shift;
  5691. my $links = '';
  5692. if ($self->get_conf('USE_LINKS')) {
  5693. my $link_buttons = $self->get_conf('LINKS_BUTTONS');
  5694. foreach my $link (@$link_buttons) {
  5695. my $link_href = $self->_element_direction($element,
  5696. $link, 'href', $filename);
  5697. #print STDERR "$title: $link -> $link_href \n";
  5698. if ($link_href and $link_href ne '') {
  5699. my $link_string = $self->_element_direction($element,
  5700. $link, 'string');
  5701. my $link_title = '';
  5702. $link_title = " title=\"$link_string\"" if (defined($link_string));
  5703. my $rel = '';
  5704. $rel = " rel=\"".$self->get_conf('BUTTONS_REL')->{$link}.'"'
  5705. if (defined($self->get_conf('BUTTONS_REL')->{$link}));
  5706. $links .= "<link href=\"$link_href\"${rel}${link_title}>\n";
  5707. }
  5708. }
  5709. }
  5710. return $links;
  5711. }
  5712. sub _default_begin_file($$$)
  5713. {
  5714. my $self = shift;
  5715. my $filename = shift;
  5716. my $element = shift;
  5717. my $command;
  5718. if ($element and $self->get_conf('SPLIT')) {
  5719. $command = $self->element_command($element);
  5720. }
  5721. my ($title, $description, $encoding, $date, $css_lines,
  5722. $doctype, $bodytext, $copying_comment, $after_body_open,
  5723. $extra_head, $program_and_version, $program_homepage,
  5724. $program, $generator) = $self->_file_header_informations($command);
  5725. my $links = $self->_get_links ($filename, $element);
  5726. my $result = "$doctype
  5727. <html>
  5728. $copying_comment<!-- Created by $program_and_version, $program_homepage -->
  5729. <head>
  5730. <title>$title</title>
  5731. $description
  5732. <meta name=\"keywords\" content=\"$title\">
  5733. <meta name=\"resource-type\" content=\"document\">
  5734. <meta name=\"distribution\" content=\"global\">${generator}$date
  5735. $encoding
  5736. ${links}$css_lines
  5737. $extra_head
  5738. </head>
  5739. <body $bodytext>
  5740. $after_body_open";
  5741. return $result;
  5742. }
  5743. sub _default_node_redirection_page($$)
  5744. {
  5745. my $self = shift;
  5746. my $command = shift;
  5747. my ($title, $description, $encoding, $date, $css_lines,
  5748. $doctype, $bodytext, $copying_comment, $after_body_open,
  5749. $extra_head, $program_and_version, $program_homepage,
  5750. $program, $generator) = $self->_file_header_informations($command);
  5751. my $name = $self->command_text($command);
  5752. my $href = $self->command_href($command);
  5753. my $direction = "<a href=\"$href\">$name</a>";
  5754. my $string = $self->convert_tree (
  5755. $self->gdt('The node you are looking for is at {href}.',
  5756. { 'href' => {'type' => '_converted', 'text' => $direction }}));
  5757. my $result = "$doctype
  5758. <html>
  5759. $copying_comment<!-- Created by $program_and_version, $program_homepage -->
  5760. <!-- This file redirects to the location of a node or anchor -->
  5761. <head>
  5762. <title>$title</title>
  5763. $description
  5764. <meta name=\"keywords\" content=\"$title\">
  5765. <meta name=\"resource-type\" content=\"document\">
  5766. <meta name=\"distribution\" content=\"global\">${generator}$date
  5767. $encoding
  5768. $css_lines
  5769. <meta http-equiv=\"Refresh\" content=\"0; url=$href\">
  5770. $extra_head
  5771. </head>
  5772. <body $bodytext>
  5773. $after_body_open
  5774. <p>$string</p>
  5775. </body>
  5776. ";
  5777. return $result;
  5778. }
  5779. sub _default_footnotes_text($)
  5780. {
  5781. my $self = shift;
  5782. return '' if (!$foot_lines);
  5783. my $result = $self->_attribute_class('div', 'footnote').">\n";
  5784. $result .= $self->get_conf('DEFAULT_RULE') . "\n"
  5785. if (defined($self->get_conf('DEFAULT_RULE'))
  5786. and $self->get_conf('DEFAULT_RULE') ne '');
  5787. my $footnote_heading
  5788. = $self->convert_tree ($self->get_conf('SPECIAL_ELEMENTS_NAME')->{'Footnotes'});
  5789. my $class = $self->get_conf('SPECIAL_ELEMENTS_CLASS')->{'Footnotes'};
  5790. my $level = $self->get_conf('FOOTNOTE_END_HEADER_LEVEL');
  5791. $result .= &{$self->{'format_heading_text'}}($self, $class.'-heading',
  5792. $footnote_heading, $level)."\n";
  5793. $result .= &{$self->{'format_special_element_body'}}($self, 'Footnotes',
  5794. $self->{'current_element'});
  5795. $result .= "</div>\n";
  5796. return $result;
  5797. }
  5798. sub _default_special_element_body($$$)
  5799. {
  5800. my $self = shift;
  5801. my $special_type = shift;
  5802. my $element = shift;
  5803. if ($special_type eq 'About') {
  5804. my $about = "<p>\n";
  5805. my $PRE_ABOUT = $self->get_conf('PRE_ABOUT');
  5806. if (defined($PRE_ABOUT)) {
  5807. if (ref($PRE_ABOUT) eq 'CODE') {
  5808. $about .= &$PRE_ABOUT($self, $element);
  5809. } else {
  5810. $about .= $PRE_ABOUT;
  5811. }
  5812. } else {
  5813. $about .= ' '.&{$self->{'format_program_string'}}($self) ."\n";
  5814. }
  5815. $about .= <<EOT;
  5816. </p>
  5817. <p>
  5818. EOT
  5819. $about .= $self->convert_tree($self->gdt(' The buttons in the navigation panels have the following meaning:')) . "\n";
  5820. $about .= <<EOT;
  5821. </p>
  5822. <table border="1">
  5823. <tr>
  5824. EOT
  5825. $about .= ' <th> ' . $self->convert_tree($self->gdt('Button')) . " </th>\n" .
  5826. ' <th> ' . $self->convert_tree($self->gdt('Name')) . " </th>\n" .
  5827. ' <th> ' . $self->convert_tree($self->gdt('Go to')) . " </th>\n" .
  5828. ' <th> ' . $self->convert_tree($self->gdt('From 1.2.3 go to')) . "</th>\n" . " </tr>\n";
  5829. foreach my $button (@{$self->get_conf('SECTION_BUTTONS')}) {
  5830. next if ($button eq ' ' or ref($button) eq 'CODE' or ref($button) eq 'SCALAR'
  5831. or ref($button) eq 'ARRAY');
  5832. my $button_name = $self->get_conf('BUTTONS_NAME')->{$button};
  5833. $about .= " <tr>\n <td align=\"center\">";
  5834. $about .=
  5835. ($self->get_conf('ICONS') && $self->get_conf('ACTIVE_ICONS')->{$button} ?
  5836. &{$self->{'format_button_icon_img'}}($self, $button_name,
  5837. $self->get_conf('ACTIVE_ICONS')->{$button}) :
  5838. ' [' . $self->get_conf('BUTTONS_TEXT')->{$button} . '] ');
  5839. $about .= "</td>\n";
  5840. $about .=
  5841. " <td align=\"center\">".$button_name."</td>
  5842. <td>".$self->get_conf('BUTTONS_GOTO')->{$button}."</td>
  5843. <td>".$self->get_conf('BUTTONS_EXAMPLE')->{$button}."</td>
  5844. </tr>
  5845. ";
  5846. }
  5847. $about .= <<EOT;
  5848. </table>
  5849. <p>
  5850. EOT
  5851. $about .= $self->convert_tree($self->gdt(' where the @strong{ Example } assumes that the current position is at @strong{ Subsubsection One-Two-Three } of a document of the following structure:')) . "\n";
  5852. # where the <strong> Example </strong> assumes that the current position
  5853. # is at <strong> Subsubsection One-Two-Three </strong> of a document of
  5854. # the following structure:
  5855. $about .= <<EOT;
  5856. </p>
  5857. <ul>
  5858. EOT
  5859. $about .= ' <li> 1. ' . $self->convert_tree($self->gdt('Section One')) . "\n" .
  5860. " <ul>\n" .
  5861. ' <li>1.1 ' . $self->convert_tree($self->gdt('Subsection One-One')) . "\n";
  5862. $about .= <<EOT;
  5863. <ul>
  5864. <li>...</li>
  5865. </ul>
  5866. </li>
  5867. EOT
  5868. $about .= ' <li>1.2 ' . $self->convert_tree($self->gdt('Subsection One-Two')) . "\n" .
  5869. " <ul>\n" .
  5870. ' <li>1.2.1 ' . $self->convert_tree($self->gdt('Subsubsection One-Two-One')) . "</li>\n" .
  5871. ' <li>1.2.2 ' . $self->convert_tree($self->gdt('Subsubsection One-Two-Two')) . "</li>\n" .
  5872. ' <li>1.2.3 ' . $self->convert_tree($self->gdt('Subsubsection One-Two-Three')) . " &nbsp; &nbsp;\n"
  5873. .
  5874. ' <strong>&lt;== ' . $self->convert_tree($self->gdt('Current Position')) . " </strong></li>\n" .
  5875. ' <li>1.2.4 ' . $self->convert_tree($self->gdt('Subsubsection One-Two-Four')) . "</li>\n" .
  5876. " </ul>\n" .
  5877. " </li>\n" .
  5878. ' <li>1.3 ' . $self->convert_tree($self->gdt('Subsection One-Three')) . "\n";
  5879. $about .= <<EOT;
  5880. <ul>
  5881. <li>...</li>
  5882. </ul>
  5883. </li>
  5884. EOT
  5885. $about .= ' <li>1.4 ' . $self->convert_tree($self->gdt('Subsection One-Four')) . "</li>\n";
  5886. my $AFTER_ABOUT = '';
  5887. if (defined($self->get_conf('AFTER_ABOUT'))) {
  5888. $AFTER_ABOUT = $self->get_conf('AFTER_ABOUT');
  5889. }
  5890. $about .= <<EOT;
  5891. </ul>
  5892. </li>
  5893. </ul>
  5894. $AFTER_ABOUT
  5895. EOT
  5896. return $about;
  5897. } elsif ($special_type eq 'Contents') {
  5898. return &{$self->{'format_contents'}}($self, 'contents', undef);
  5899. } elsif ($special_type eq 'Overview') {
  5900. return &{$self->{'format_contents'}}($self, 'shortcontents', undef);
  5901. } elsif ($special_type eq 'Footnotes') {
  5902. my $result = $foot_lines;
  5903. $foot_lines = '';
  5904. return $result;
  5905. }
  5906. }
  5907. sub _default_frame_files($)
  5908. {
  5909. my $self = shift;
  5910. my $frame_file = $self->{'frame_pages_filenames'}->{'Frame'};
  5911. my $frame_outfile;
  5912. if (defined($self->{'destination_directory'})
  5913. and $self->{'destination_directory'} ne '') {
  5914. $frame_outfile = File::Spec->catfile($self->{'destination_directory'},
  5915. $frame_file);
  5916. } else {
  5917. $frame_outfile = $frame_file;
  5918. }
  5919. my $toc_frame_file = $self->{'frame_pages_filenames'}->{'Toc_Frame'};
  5920. my $toc_frame_outfile;
  5921. if (defined($self->{'destination_directory'})
  5922. and $self->{'destination_directory'} ne '') {
  5923. $toc_frame_outfile = File::Spec->catfile($self->{'destination_directory'},
  5924. $toc_frame_file);
  5925. } else {
  5926. $toc_frame_outfile = $toc_frame_file;
  5927. }
  5928. my $frame_fh = $self->Texinfo::Common::open_out($frame_outfile);
  5929. if (defined($frame_fh)) {
  5930. my $doctype = $self->get_conf('FRAMESET_DOCTYPE');
  5931. my $top_file = '';
  5932. if ($self->global_element('Top')) {
  5933. my $top_element = $self->global_element('Top');
  5934. $top_file = $top_element->{'filename'};
  5935. }
  5936. my $title = $self->{'title_string'};
  5937. print $frame_fh <<EOT;
  5938. $doctype
  5939. <html>
  5940. <head><title>$title</title></head>
  5941. <frameset cols="140,*">
  5942. <frame name="toc" src="$toc_frame_file">
  5943. <frame name="main" src="$top_file">
  5944. </frameset>
  5945. </html>
  5946. EOT
  5947. $self->register_close_file($frame_outfile);
  5948. if (!close ($frame_fh)) {
  5949. $self->document_error(sprintf($self->__("error on closing frame file %s: %s"),
  5950. $frame_outfile, $!));
  5951. return 0;
  5952. }
  5953. } else {
  5954. $self->document_error(sprintf($self->__("could not open %s for writing: %s"),
  5955. $frame_outfile, $!));
  5956. return 0;
  5957. }
  5958. my $toc_frame_fh = $self->Texinfo::Common::open_out($toc_frame_outfile);
  5959. if (defined($toc_frame_fh)) {
  5960. my $header = &{$self->{'format_begin_file'}}($self, $toc_frame_file, undef);
  5961. print $toc_frame_fh $header;
  5962. print $toc_frame_fh '<h2>Content</h2>'."\n";
  5963. my $shortcontents =
  5964. &{$self->{'format_contents'}}($self, 'shortcontents', undef);
  5965. $shortcontents =~ s/\bhref=/target="main" href=/g;
  5966. print $toc_frame_fh $shortcontents;
  5967. print $toc_frame_fh "</body></html>\n";
  5968. $self->register_close_file($toc_frame_outfile);
  5969. if (!close ($toc_frame_fh)) {
  5970. $self->document_error(sprintf($self->__("error on closing TOC frame file %s: %s"),
  5971. $toc_frame_outfile, $!));
  5972. return 0;
  5973. }
  5974. } else {
  5975. $self->document_error(sprintf($self->__("could not open %s for writing: %s"),
  5976. $toc_frame_outfile, $!));
  5977. return 0;
  5978. }
  5979. return 1;
  5980. }
  5981. sub convert($$)
  5982. {
  5983. my $self = shift;
  5984. my $root = shift;
  5985. my $result = '';
  5986. # This should return undef if called on a tree without node or sections.
  5987. my ($elements, $special_elements)
  5988. = $self->_prepare_elements($root);
  5989. $self->_prepare_index_entries();
  5990. $self->_prepare_footnotes();
  5991. if (!defined($elements)) {
  5992. $result = $self->_convert($root);
  5993. } else {
  5994. foreach my $element (@$elements) {
  5995. my $element_text = $self->_convert($element);
  5996. $result .= $element_text;
  5997. }
  5998. }
  5999. return $result;
  6000. }
  6001. # This is called from the main program on the converter.
  6002. sub output_internal_links($)
  6003. {
  6004. my $self = shift;
  6005. my $out_string = '';
  6006. if ($self->{'elements'}) {
  6007. foreach my $element (@{$self->{'elements'}}) {
  6008. my $text;
  6009. my $href;
  6010. my $command = $self->element_command($element);
  6011. if (defined($command)) {
  6012. # Use '' for filename, to force a filename in href.
  6013. $href = $self->command_href($command, '');
  6014. my $tree = $self->command_text($command, 'tree');
  6015. if ($tree) {
  6016. $text = Texinfo::Convert::Text::convert($tree,
  6017. {Texinfo::Common::_convert_text_options($self)});
  6018. }
  6019. }
  6020. if (defined($href) or defined($text)) {
  6021. $out_string .= $href if (defined($href));
  6022. $out_string .= "\ttoc\t";
  6023. $out_string .= $text if (defined($text));
  6024. $out_string .= "\n";
  6025. }
  6026. }
  6027. }
  6028. if ($self->{'parser'}) {
  6029. foreach my $index_name (sort(keys (%{$self->{'index_entries_by_letter'}}))) {
  6030. foreach my $letter_entry (@{$self->{'index_entries_by_letter'}->{$index_name}}) {
  6031. foreach my $index_entry (@{$letter_entry->{'entries'}}) {
  6032. my $href;
  6033. my $key;
  6034. $href = $self->command_href($index_entry->{'command'}, '');
  6035. $key = $index_entry->{'key'};
  6036. if (defined($key) and $key =~ /\S/) {
  6037. $out_string .= $href if (defined($href));
  6038. $out_string .= "\t$index_name\t";
  6039. $out_string .= $key;
  6040. $out_string .= "\n";
  6041. }
  6042. }
  6043. }
  6044. }
  6045. }
  6046. if ($out_string ne '') {
  6047. return $out_string;
  6048. } else {
  6049. return undef;
  6050. }
  6051. }
  6052. my @possible_stages = ('setup', 'structure', 'init', 'finish');
  6053. my %possible_stages;
  6054. foreach my $stage (@possible_stages) {
  6055. $possible_stages{$stage} = 1;
  6056. }
  6057. sub run_stage_handlers($$)
  6058. {
  6059. my $converter = shift;
  6060. my $stage = shift;
  6061. die if (!$possible_stages{$stage});
  6062. return 1 if (!defined($Texinfo::Config::texinfo_default_stage_handlers{$stage}));
  6063. my @sorted_priorities = sort keys(%{$Texinfo::Config::texinfo_default_stage_handlers{$stage}});
  6064. foreach my $priority (@sorted_priorities) {
  6065. foreach my $handler (@{$Texinfo::Config::texinfo_default_stage_handlers{$stage}->{$priority}}) {
  6066. if ($converter->get_conf('DEBUG')) {
  6067. print STDERR "HANDLER($stage) , priority $priority: $handler\n";
  6068. }
  6069. my $status = &{$handler}($converter, $stage);
  6070. if (!$status) {
  6071. #if ($converter->get_conf('VERBOSE')) {
  6072. # print STDERR "Handler $handler of $stage($priority) failed\n";
  6073. #}
  6074. $converter->document_error(sprintf($converter->__(
  6075. "handler %s of stage %s priority %s failed"),
  6076. $handler, $stage, $priority));
  6077. return $status;
  6078. }
  6079. }
  6080. }
  6081. return 1;
  6082. }
  6083. my $default_priority = 'default';
  6084. {
  6085. package Texinfo::Config;
  6086. use vars qw(%texinfo_default_stage_handlers %texinfo_formatting_references
  6087. %texinfo_commands_conversion %texinfo_types_conversion);
  6088. sub texinfo_register_handler($$;$)
  6089. {
  6090. my $stage = shift;
  6091. my $handler = shift;
  6092. my $priority = shift;
  6093. if (!$possible_stages{$stage}) {
  6094. carp ("Unknown stage $stage\n");
  6095. return 0;
  6096. }
  6097. $priority = $default_priority if (!defined($priority));
  6098. push @{$texinfo_default_stage_handlers{$stage}->{$priority}}, $handler;
  6099. return 1;
  6100. }
  6101. sub texinfo_register_formatting_function($$)
  6102. {
  6103. my $thing = shift;
  6104. my $handler = shift;
  6105. if (!$default_formatting_references{$thing}) {
  6106. carp ("Unknown formatting type $thing\n");
  6107. return 0;
  6108. }
  6109. $texinfo_formatting_references{$thing} = $handler;
  6110. }
  6111. sub texinfo_register_command_formatting($$)
  6112. {
  6113. my $command = shift;
  6114. my $reference = shift;
  6115. $texinfo_commands_conversion{$command} = $reference;
  6116. }
  6117. sub texinfo_register_type_formatting($$)
  6118. {
  6119. my $command = shift;
  6120. my $reference = shift;
  6121. $texinfo_types_conversion{$command} = $reference;
  6122. }
  6123. }
  6124. # Main function for outputting a manual in HTML.
  6125. # $SELF is the output converter object of class Texinfo::Convert::HTML (this
  6126. # module), and $ROOT is the Texinfo tree from the parser.
  6127. sub output($$)
  6128. {
  6129. my $self = shift;
  6130. my $root = shift;
  6131. # no splitting when writing to the null device or to stdout or returning
  6132. # a string
  6133. if (defined($self->get_conf('OUTFILE'))
  6134. and ($Texinfo::Common::null_device_file{$self->get_conf('OUTFILE')}
  6135. or $self->get_conf('OUTFILE') eq '-'
  6136. or $self->get_conf('OUTFILE') eq '')) {
  6137. $self->force_conf('SPLIT', 0);
  6138. $self->force_conf('MONOLITHIC', 1);
  6139. $self->force_conf('FRAMES', 0);
  6140. }
  6141. if ($self->get_conf('SPLIT')) {
  6142. $self->set_conf('NODE_FILES', 1);
  6143. }
  6144. if ($self->get_conf('NODE_FILES') or $self->get_conf('SPLIT') eq 'node') {
  6145. $self->set_conf('NODE_FILENAMES', 1);
  6146. }
  6147. if ($self->get_conf('FRAMES')) {
  6148. $self->set_conf('shortcontents', 1);
  6149. }
  6150. $self->set_conf('EXTERNAL_CROSSREF_SPLIT', $self->get_conf('SPLIT'));
  6151. my $setup_status = $self->run_stage_handlers('setup');
  6152. return undef unless($setup_status);
  6153. $self->_prepare_css();
  6154. # this sets OUTFILE, to be used if not split, but also
  6155. # 'destination_directory' and 'output_filename' that are useful when split.
  6156. $self->_set_outfile();
  6157. return undef unless $self->_create_destination_directory();
  6158. # collect renamed nodes
  6159. ($self->{'renamed_nodes'}, $self->{'renamed_nodes_lines'},
  6160. $self->{'renamed_nodes_file'})
  6161. = Texinfo::Common::collect_renamed_nodes($self, $self->{'input_basename_name'},
  6162. $self->{'renamed_nodes'});
  6163. # Get the list of "elements" to be processed, i.e. nodes or sections.
  6164. # This should return undef if called on a tree without node or sections.
  6165. my ($elements, $special_elements) = $self->_prepare_elements($root);
  6166. Texinfo::Structuring::split_pages($elements, $self->get_conf('SPLIT'));
  6167. # determine file names associated with the different pages, and setup
  6168. # the counters for special element pages.
  6169. if ($self->{'output_file'} ne '') {
  6170. $self->_set_pages_files($elements, $special_elements);
  6171. }
  6172. $self->_prepare_contents_elements();
  6173. # do element directions.
  6174. Texinfo::Structuring::elements_directions($self, $elements);
  6175. # do element directions related to files.
  6176. # FIXME do it here or before? Here it means that
  6177. # PrevFile and NextFile can be set.
  6178. Texinfo::Structuring::elements_file_directions($self, $elements);
  6179. # Associate the special elements that have no page with the main page.
  6180. # This may only happen if not split.
  6181. if ($special_elements
  6182. and $elements and $elements->[0]
  6183. and defined($elements->[0]->{'filename'})) {
  6184. foreach my $special_element (@$special_elements) {
  6185. if (!defined($special_element->{'filename'})) {
  6186. $special_element->{'filename'} = $elements->[0]->{'filename'};
  6187. $special_element->{'out_filename'} = $elements->[0]->{'out_filename'};
  6188. $self->{'file_counters'}->{$special_element->{'filename'}}++;
  6189. print STDERR "Special page $special_element: $special_element->{'filename'}($self->{'file_counters'}->{$special_element->{'filename'}})\n"
  6190. if ($self->get_conf('DEBUG'));
  6191. }
  6192. }
  6193. }
  6194. $self->_prepare_index_entries();
  6195. $self->_prepare_footnotes();
  6196. my $structure_status = $self->run_stage_handlers('structure');
  6197. return undef unless($structure_status);
  6198. &{$self->{'format_css_lines'}}($self);
  6199. $self->set_conf('BODYTEXT',
  6200. 'lang="' . $self->get_conf('documentlanguage') . '"');
  6201. # prepare title. fulltitle uses more possibility than simpletitle for
  6202. # title, including @-commands found in @titlepage only. Therefore
  6203. # simpletitle is more in line with what makeinfo in C does.
  6204. my $fulltitle;
  6205. foreach my $fulltitle_command('settitle', 'title',
  6206. 'shorttitlepage', 'top') {
  6207. if ($self->{'extra'}->{$fulltitle_command}) {
  6208. my $command = $self->{'extra'}->{$fulltitle_command};
  6209. next if (!$command->{'extra'}
  6210. or (!$command->{'extra'}->{'misc_content'}
  6211. or $command->{'extra'}->{'missing_argument'}));
  6212. print STDERR "Using $fulltitle_command as title\n"
  6213. if ($self->get_conf('DEBUG'));
  6214. $fulltitle = {'contents' => $command->{'extra'}->{'misc_content'}};
  6215. last;
  6216. }
  6217. }
  6218. if (!$fulltitle and $self->{'extra'}->{'titlefont'}
  6219. and $self->{'extra'}->{'titlefont'}->[0]->{'extra'}
  6220. and $self->{'extra'}->{'titlefont'}->[0]->{'extra'}->{'brace_command_contents'}
  6221. and defined($self->{'extra'}->{'titlefont'}->[0]->{'extra'}->{'brace_command_contents'}->[0])) {
  6222. $fulltitle = $self->{'extra'}->{'titlefont'}->[0];
  6223. }
  6224. # prepare simpletitle
  6225. foreach my $simpletitle_command('settitle', 'shorttitlepage') {
  6226. if ($self->{'extra'}->{$simpletitle_command}) {
  6227. my $command = $self->{'extra'}->{$simpletitle_command};
  6228. next if ($command->{'extra'}
  6229. and $command->{'extra'}->{'missing_argument'});
  6230. $self->{'simpletitle_tree'} =
  6231. {'contents' => $command->{'extra'}->{'misc_content'}};
  6232. last;
  6233. }
  6234. }
  6235. my $html_title_string;
  6236. if ($fulltitle) {
  6237. $self->{'title_tree'} = $fulltitle;
  6238. print STDERR "DO fulltitle_string\n" if ($self->get_conf('DEBUG'));
  6239. $html_title_string = $self->convert_tree_new_formatting_context(
  6240. {'type' => '_string', 'contents' => [$self->{'title_tree'}]},
  6241. 'title_string');
  6242. }
  6243. if (!defined($html_title_string) or $html_title_string !~ /\S/) {
  6244. my $default_title = $self->gdt('Untitled Document');
  6245. $self->{'title_tree'} = $default_title;
  6246. $self->{'title_string'} = $self->convert_tree_new_formatting_context(
  6247. {'type' => '_string', 'contents' => [$self->{'title_tree'}]},
  6248. 'title_string');
  6249. $self->file_line_warn($self->__(
  6250. "must specify a title with a title command or \@top"),
  6251. $self->{'info'}->{'input_file_name'});
  6252. } else {
  6253. $self->{'title_string'} = $html_title_string;
  6254. }
  6255. # copying comment
  6256. if ($self->{'extra'}->{'copying'}) {
  6257. print STDERR "DO copying_comment\n" if ($self->get_conf('DEBUG'));
  6258. my $copying_comment = Texinfo::Convert::Text::convert(
  6259. {'contents' => $self->{'extra'}->{'copying'}->{'contents'}},
  6260. {Texinfo::Common::_convert_text_options($self)});
  6261. if ($copying_comment ne '') {
  6262. $self->{'copying_comment'} = &{$self->{'format_comment'}}($self, $copying_comment);
  6263. }
  6264. }
  6265. # documentdescription
  6266. if (defined($self->get_conf('documentdescription'))) {
  6267. $self->{'documentdescription_string'}
  6268. = $self->get_conf('documentdescription');
  6269. } elsif ($self->{'extra'}->{'documentdescription'}) {
  6270. print STDERR "DO documentdescription\n" if ($self->get_conf('DEBUG'));
  6271. $self->{'documentdescription_string'}
  6272. = $self->convert_tree_new_formatting_context(
  6273. {'type' => '_string',
  6274. 'contents' => $self->{'extra'}->{'documentdescription'}->{'contents'}},
  6275. 'documentdescription');
  6276. chomp($self->{'documentdescription_string'});
  6277. }
  6278. my $init_status = $self->run_stage_handlers('init');
  6279. return undef unless($init_status);
  6280. if ($self->get_conf('FRAMES')) {
  6281. my $status = &{$self->{'format_frame_files'}}($self);
  6282. return undef if (!$status);
  6283. }
  6284. # FIXME here call _unset_global_multiple_commands? Problem is
  6285. # that some conversion, for instance for page header requires
  6286. # that the correct language is set, for instance. The @-command
  6287. # will necessarily appear later on -- even if it appears a the
  6288. # beginning of the file.
  6289. my $fh;
  6290. my $output = '';
  6291. if (!$elements or !defined($elements->[0]->{'filename'})) {
  6292. # no page
  6293. my $outfile;
  6294. if ($self->{'output_file'} ne '') {
  6295. if ($self->get_conf('SPLIT')) {
  6296. $outfile = $self->_top_node_filename();
  6297. if (defined($self->{'destination_directory'})
  6298. and $self->{'destination_directory'} ne '') {
  6299. $outfile = File::Spec->catfile($self->{'destination_directory'},
  6300. $outfile);
  6301. }
  6302. } else {
  6303. $outfile = $self->{'output_file'};
  6304. }
  6305. print STDERR "DO No pages, output in $outfile\n"
  6306. if ($self->get_conf('DEBUG'));
  6307. $fh = $self->Texinfo::Common::open_out($outfile);
  6308. if (!$fh) {
  6309. $self->document_error(sprintf($self->__("could not open %s for writing: %s"),
  6310. $outfile, $!));
  6311. return undef;
  6312. }
  6313. } else {
  6314. print STDERR "DO No pages, string output\n"
  6315. if ($self->get_conf('DEBUG'));
  6316. }
  6317. $self->{'current_filename'} = $self->{'output_filename'};
  6318. my $header = &{$self->{'format_begin_file'}}($self,
  6319. $self->{'output_filename'}, undef);
  6320. $output .= $self->_output_text($header, $fh);
  6321. if ($elements and @$elements) {
  6322. foreach my $element (@$elements) {
  6323. my $element_text = $self->_convert($element);
  6324. $output .= $self->_output_text($element_text, $fh);
  6325. }
  6326. } else {
  6327. $output .= $self->_output_text($self->_print_title(), $fh);
  6328. $output .= $self->_output_text($self->_convert($root), $fh);
  6329. }
  6330. $output .= $self->_output_text(&{$self->{'format_end_file'}}($self), $fh);
  6331. # NOTE do not close STDOUT now to avoid a perl warning.
  6332. if ($fh and $outfile ne '-') {
  6333. $self->register_close_file($outfile);
  6334. if (!close($fh)) {
  6335. $self->document_error(sprintf($self->__("error on closing %s: %s"),
  6336. $outfile, $!));
  6337. }
  6338. }
  6339. return $output if ($self->{'output_file'} eq '');
  6340. } else {
  6341. # output with pages
  6342. print STDERR "DO Elements with filenames\n"
  6343. if ($self->get_conf('DEBUG'));
  6344. my %files;
  6345. # Now do the output, converting each member in @$elements in turn.
  6346. $special_elements = [] if (!defined($special_elements));
  6347. foreach my $element (@$elements, @$special_elements) {
  6348. my $file_fh;
  6349. $self->{'current_filename'} = $element->{'filename'};
  6350. $self->{'counter_in_file'}->{$element->{'filename'}}++;
  6351. #print STDERR "TTTTTTT($element) $element->{'filename'}: $self->{'file_counters'}->{$element->{'filename'}} (out_filename $element->{'out_filename'})\n";
  6352. # First do the special pages, to avoid outputting these if they are
  6353. # empty.
  6354. my $special_element_content;
  6355. if ($element->{'extra'} and $element->{'extra'}->{'special_element'}) {
  6356. $special_element_content .= $self->_convert($element);
  6357. #print STDERR "Special element converter: $element->{'extra'}->{'special_element'}\n";
  6358. if ($special_element_content eq '') {
  6359. $self->{'file_counters'}->{$element->{'filename'}}--;
  6360. next ;
  6361. }
  6362. }
  6363. # Then open the file and output the elements or the special_page_content
  6364. if (!$files{$element->{'filename'}}->{'fh'}) {
  6365. $file_fh = $self->Texinfo::Common::open_out($element->{'out_filename'});
  6366. if (!$file_fh) {
  6367. $self->document_error(sprintf($self->__("could not open %s for writing: %s"),
  6368. $element->{'out_filename'}, $!));
  6369. return undef;
  6370. }
  6371. print $file_fh "".&{$self->{'format_begin_file'}}($self,
  6372. $element->{'filename'},
  6373. $element);
  6374. $files{$element->{'filename'}}->{'fh'} = $file_fh;
  6375. } else {
  6376. $file_fh = $files{$element->{'filename'}}->{'fh'};
  6377. }
  6378. if (defined($special_element_content)) {
  6379. print $file_fh $special_element_content;
  6380. } else {
  6381. my $element_text = $self->_convert($element);
  6382. print $file_fh $element_text;
  6383. }
  6384. $self->{'file_counters'}->{$element->{'filename'}}--;
  6385. if ($self->{'file_counters'}->{$element->{'filename'}} == 0) {
  6386. # end file
  6387. print $file_fh "". &{$self->{'format_end_file'}}($self);
  6388. # NOTE do not close STDOUT here to avoid a perl warning
  6389. if ($element->{'out_filename'} ne '-') {
  6390. $self->register_close_file($element->{'out_filename'});
  6391. if (!close($file_fh)) {
  6392. $self->document_error(sprintf($self->__("error on closing %s: %s"),
  6393. $element->{'out_filename'}, $!));
  6394. return undef;
  6395. }
  6396. }
  6397. }
  6398. }
  6399. }
  6400. my $finish_status = $self->run_stage_handlers('finish');
  6401. return undef unless($finish_status);
  6402. # do node redirection pages
  6403. $self->{'current_filename'} = undef;
  6404. if ($self->get_conf('NODE_FILES')
  6405. and $self->{'labels'} and $self->{'output_file'} ne '') {
  6406. foreach my $label (sort(keys (%{$self->{'labels'}}))) {
  6407. my $node = $self->{'labels'}->{$label};
  6408. my $target = $self->_get_target($node);
  6409. # filename may not be defined in case of an @anchor or similar in
  6410. # @titlepage, and @titlepage is not used.
  6411. my $filename = $self->command_filename($node);
  6412. my $node_filename;
  6413. # NOTE 'node_filename' is not used for Top, so the other manual
  6414. # must use the same convention to get it right. We avoid doing
  6415. # also 'node_filename' to avoid unneeded redirection files.
  6416. if ($node->{'extra'} and $node->{'extra'}->{'normalized'}
  6417. and $node->{'extra'}->{'normalized'} eq 'Top'
  6418. and defined($self->get_conf('TOP_NODE_FILE_TARGET'))) {
  6419. my $extension = '';
  6420. $extension = "." . $self->get_conf('NODE_FILE_EXTENSION')
  6421. if (defined($self->get_conf('NODE_FILE_EXTENSION'))
  6422. and $self->get_conf('NODE_FILE_EXTENSION') ne '');
  6423. $node_filename = $self->get_conf('TOP_NODE_FILE_TARGET')
  6424. .$extension;
  6425. } else {
  6426. $node_filename = $target->{'node_filename'};
  6427. }
  6428. if (defined($filename) and $node_filename ne $filename) {
  6429. my $redirection_page
  6430. = &{$self->{'format_node_redirection_page'}}($self, $node);
  6431. my $out_filename;
  6432. if (defined($self->{'destination_directory'})
  6433. and $self->{'destination_directory'} ne '') {
  6434. $out_filename = File::Spec->catfile($self->{'destination_directory'},
  6435. $node_filename);
  6436. } else {
  6437. $out_filename = $node_filename;
  6438. }
  6439. my $file_fh = $self->Texinfo::Common::open_out($out_filename);
  6440. if (!$file_fh) {
  6441. $self->document_error(sprintf($self->__(
  6442. "could not open %s for writing: %s"),
  6443. $out_filename, $!));
  6444. } else {
  6445. print $file_fh $redirection_page;
  6446. $self->register_close_file($out_filename);
  6447. if (!close ($file_fh)) {
  6448. $self->document_error(sprintf($self->__(
  6449. "error on closing redirection node file %s: %s"),
  6450. $out_filename, $!));
  6451. return undef;
  6452. }
  6453. }
  6454. }
  6455. }
  6456. }
  6457. if ($self->{'renamed_nodes'}
  6458. and $self->{'labels'} and $self->{'output_file'} ne '') {
  6459. # do a fresh parser, to avoid, for example adding new labels if renamed
  6460. # nodes incorrectly define anchors...
  6461. my $parser_for_renamed_nodes;
  6462. if ($self->{'parser'}) {
  6463. $parser_for_renamed_nodes = $self->{'parser'}->parser();
  6464. }
  6465. my %warned_new_node;
  6466. foreach my $old_node_name (sort(keys(%{$self->{'renamed_nodes'}}))) {
  6467. my $parsed_old_node = $self->_parse_node_and_warn_external(
  6468. $old_node_name, $parser_for_renamed_nodes,
  6469. $self->{'renamed_nodes_lines'}->{$old_node_name},
  6470. $self->{'renamed_nodes_file'});
  6471. if ($parsed_old_node) {
  6472. if ($self->label_command($parsed_old_node->{'normalized'})) {
  6473. $self->file_line_error(sprintf($self->__(
  6474. "old name for `%s' is a node of the document"), $old_node_name),
  6475. $self->{'renamed_nodes_file'},
  6476. $self->{'renamed_nodes_lines'}->{$old_node_name});
  6477. $parsed_old_node = undef;
  6478. } elsif ($parsed_old_node->{'normalized'} !~ /[^-]/) {
  6479. $self->file_line_error(sprintf($self->__(
  6480. "file empty for renamed node `%s'"), $old_node_name),
  6481. $self->{'renamed_nodes_file'},
  6482. $self->{'renamed_nodes_lines'}->{$old_node_name});
  6483. $parsed_old_node = undef;
  6484. }
  6485. }
  6486. my $new_node_name = $self->{'renamed_nodes'}->{$old_node_name};
  6487. my $parsed_new_node = $self->_parse_node_and_warn_external(
  6488. $new_node_name, $parser_for_renamed_nodes,
  6489. $self->{'renamed_nodes_lines'}->{$new_node_name},
  6490. $self->{'renamed_nodes_file'});
  6491. if (!$self->label_command($parsed_new_node->{'normalized'})) {
  6492. if (!$warned_new_node{$new_node_name}) {
  6493. $self->file_line_warn(sprintf($self->__(
  6494. "target node (new name for `%s') not in document: %s"),
  6495. $old_node_name, $new_node_name), $self->{'renamed_nodes_file'},
  6496. $self->{'renamed_nodes_lines'}->{$new_node_name});
  6497. $warned_new_node{$new_node_name} = 1;
  6498. }
  6499. $parsed_new_node = undef;
  6500. }
  6501. if ($parsed_new_node and $parsed_old_node) {
  6502. my ($filename, $target) = $self->_node_id_file($parsed_old_node);
  6503. $filename .= '.'.$self->get_conf('NODE_FILE_EXTENSION')
  6504. if (defined($self->get_conf('NODE_FILE_EXTENSION'))
  6505. and $self->get_conf('NODE_FILE_EXTENSION') ne '');
  6506. my $redirection_page
  6507. = &{$self->{'format_node_redirection_page'}}($self,
  6508. $self->label_command($parsed_new_node->{'normalized'}));
  6509. my $out_filename;
  6510. if (defined($self->{'destination_directory'})
  6511. and $self->{'destination_directory'} ne '') {
  6512. $out_filename = File::Spec->catfile($self->{'destination_directory'},
  6513. $filename);
  6514. } else {
  6515. $out_filename = $filename;
  6516. }
  6517. my $file_fh = $self->Texinfo::Common::open_out($out_filename);
  6518. if (!$file_fh) {
  6519. $self->document_error(sprintf($self->__("could not open %s for writing: %s"),
  6520. $out_filename, $!));
  6521. } else {
  6522. print $file_fh $redirection_page;
  6523. $self->register_close_file($out_filename);
  6524. if (!close ($file_fh)) {
  6525. $self->document_error(sprintf($self->__(
  6526. "error on closing renamed node redirection file %s: %s"),
  6527. $out_filename, $!));
  6528. return undef;
  6529. }
  6530. }
  6531. }
  6532. }
  6533. }
  6534. }
  6535. sub _parse_node_and_warn_external($$$$$)
  6536. {
  6537. my $self = shift;
  6538. my $node_texi = shift;
  6539. my $parser = shift;
  6540. my $line_number = shift;
  6541. my $file = shift;
  6542. # NOTE nothing to check that there is an invalid nesting. Indeed, there
  6543. # is no information given to the parser stating that we are in a label
  6544. # command.
  6545. # A possibility would be to consider
  6546. # 'root_line' type as a $simple_text_command, or, to avoid spurious
  6547. # messages, $full_text_command. This would imply really using
  6548. # the gdt 4th argument to pass 'translated_paragraph' when in a
  6549. # less constrained environment, for instance @center in @quotation for
  6550. # @author
  6551. #
  6552. # it is unlikely, however that invalid nesting does much harm, since
  6553. # the tree is mostly used to be normalized and this converter should
  6554. # be rather foolproof.
  6555. my $node_tree = Texinfo::Parser::parse_texi_line($parser,
  6556. $node_texi, $line_number, $file);
  6557. if ($node_tree) {
  6558. my $node_normalized_result = Texinfo::Parser::_parse_node_manual(
  6559. $node_tree);
  6560. my $line_nr = {'line_nr' => $line_number, 'file_name' => $file };
  6561. if (!$node_normalized_result) {
  6562. $self->line_warn($self->__('empty node name'), $line_nr);
  6563. } elsif ($node_normalized_result->{'manual_content'}) {
  6564. $self->line_error(sprintf($self->__("syntax for an external node used for `%s'"),
  6565. $node_texi), $line_nr);
  6566. } else {
  6567. if ($node_normalized_result->{'node_content'}) {
  6568. $node_normalized_result->{'normalized'} =
  6569. Texinfo::Convert::NodeNameNormalization::normalize_node(
  6570. {'contents' => $node_normalized_result->{'node_content'}});
  6571. }
  6572. return $node_normalized_result;
  6573. }
  6574. }
  6575. return undef;
  6576. }
  6577. # Convert the 'contents' of a tree element.
  6578. sub _convert_contents($$$)
  6579. {
  6580. my $self = shift;
  6581. my $root = shift;
  6582. my $command_type = shift;
  6583. my $content_formatted = '';
  6584. if (ref($root->{'contents'}) ne 'ARRAY') {
  6585. cluck "for $root contents not an array: $root->{'contents'}";
  6586. print STDERR Texinfo::Common::_print_current($root);
  6587. }
  6588. my $content_idx = 0;
  6589. foreach my $content (@{$root->{'contents'}}) {
  6590. my $new_content = $self->_convert($content, "$command_type [$content_idx]");
  6591. if (!defined($new_content)) {
  6592. cluck "content not defined for $command_type [$content_idx]\n";
  6593. print STDERR "root is: ".Texinfo::Common::_print_current ($root);
  6594. print STDERR "content is: ".Texinfo::Common::_print_current ($content);
  6595. } else {
  6596. $content_formatted .= $new_content;
  6597. }
  6598. $content_idx++;
  6599. }
  6600. return $content_formatted;
  6601. }
  6602. sub _attribute_class($$$)
  6603. {
  6604. my $self = shift;
  6605. my $element = shift;
  6606. my $class = shift;
  6607. if (!defined($class) or $class eq '' or $self->get_conf('NO_CSS')) {
  6608. if ($element eq 'span') {
  6609. return '';
  6610. } else {
  6611. return "<$element";
  6612. }
  6613. }
  6614. my $style = '';
  6615. if ($self->get_conf('INLINE_CSS_STYLE')
  6616. and defined($self->{'css_map'}->{"$element.$class"})) {
  6617. $style = ' style="'.$self->{'css_map'}->{"$element.$class"}.'"';
  6618. }
  6619. return "<$element class=\"$class\"$style";
  6620. }
  6621. sub _protect_space($$)
  6622. {
  6623. my $self = shift;
  6624. my $text = shift;
  6625. return $text if ($self->in_preformatted());
  6626. if ($self->in_space_protected()) {
  6627. my $open = $self->_attribute_class('span', 'nolinebreak');
  6628. if ($open ne '') {
  6629. $open .= '>';
  6630. # Protect spaces in the html leading attribute in case we are in 'w'
  6631. $open =~ s/ /\x{1F}/g;
  6632. # Special span to avoid breaking at _-
  6633. $text =~ s/(\S*[_-]\S*)/${open}$1<\/span>/g;
  6634. }
  6635. $text .= '&nbsp;' if (chomp($text));
  6636. # Protect spaces within text
  6637. $text =~ s/ /&nbsp;/g;
  6638. # Revert protected spaces in leading html attribute
  6639. $text =~ s/\x{1F}/ /g;
  6640. }
  6641. return $text;
  6642. }
  6643. # Convert tree element $ROOT, and return HTML text for the output files.
  6644. sub _convert($$;$);
  6645. sub _convert($$;$)
  6646. {
  6647. my $self = shift;
  6648. my $root = shift;
  6649. # only used for debug
  6650. my $explanation = shift;
  6651. # to help debug and trace
  6652. my $command_type = '';
  6653. if ($root->{'cmdname'}) {
  6654. $command_type = "\@$root->{'cmdname'} ";
  6655. }
  6656. if (defined($root->{'type'})) {
  6657. $command_type .= $root->{'type'};
  6658. }
  6659. if ($self->get_conf('DEBUG')) {
  6660. $explanation = 'NO EXPLANATION' if (!defined($explanation));
  6661. print STDERR "ROOT($explanation):$root (".join('|',@{$self->{'document_context'}->[-1]->{'formatting_context'}})."), ->";
  6662. print STDERR " cmd: $root->{'cmdname'}," if ($root->{'cmdname'});
  6663. print STDERR " type: $root->{'type'}" if ($root->{'type'});
  6664. my $text = $root->{'text'};
  6665. if (defined($text)) {
  6666. $text =~ s/\n/\\n/;
  6667. print STDERR " text: $text";
  6668. }
  6669. print STDERR "\n";
  6670. }
  6671. if (ref($root) ne 'HASH') {
  6672. cluck "_convert: root not a HASH\n";
  6673. return '';
  6674. }
  6675. if (($root->{'type'}
  6676. and exists ($self->{'types_conversion'}->{$root->{'type'}})
  6677. and !defined($self->{'types_conversion'}->{$root->{'type'}}))
  6678. or ($root->{'cmdname'}
  6679. and exists($self->{'commands_conversion'}->{$root->{'cmdname'}})
  6680. and !defined($self->{'commands_conversion'}->{$root->{'cmdname'}}))) {
  6681. if ($self->get_conf('DEBUG')) {
  6682. my $string = 'IGNORED';
  6683. $string .= " \@$root->{'cmdname'}" if ($root->{'cmdname'});
  6684. $string .= " $root->{'type'}" if ($root->{'type'});
  6685. print STDERR "$string\n";
  6686. }
  6687. return '';
  6688. }
  6689. # Process text
  6690. if (defined($root->{'text'})) {
  6691. # already converted to html, keep it as is
  6692. if ($root->{'type'} and $root->{'type'} eq '_converted') {
  6693. return $root->{'text'};
  6694. }
  6695. if ($root->{'type'} and $root->{'type'} eq 'untranslated') {
  6696. my $translated = $self->gdt($root->{'text'});
  6697. my $result = $self->_convert($translated);
  6698. return $result;
  6699. }
  6700. my $result = &{$self->{'types_conversion'}->{'text'}} ($self,
  6701. $root->{'type'},
  6702. $root,
  6703. $root->{'text'});
  6704. print STDERR "DO TEXT => `$result'\n" if ($self->get_conf('DEBUG'));
  6705. return $result;
  6706. }
  6707. if ($root->{'extra'}) {
  6708. #if ($root->{'extra'}->{'invalid_nesting'}) {
  6709. # print STDERR "INVALID_NESTING\n" if ($self->get_conf('DEBUG'));
  6710. # return '';
  6711. #} elsif ($root->{'extra'}->{'missing_argument'}
  6712. if ($root->{'extra'}->{'missing_argument'}
  6713. and (!$root->{'contents'} or !@{$root->{'contents'}})) {
  6714. print STDERR "MISSING_ARGUMENT\n" if ($self->get_conf('DEBUG'));
  6715. return '';
  6716. }
  6717. }
  6718. # commands like @deffnx have both a cmdname and a def_line type. It is
  6719. # better to consider them as a def_line type, as the whole point of the
  6720. # def_line type is to handle the same the def*x and def* line formatting.
  6721. if ($root->{'cmdname'}
  6722. and !($root->{'type'} and $root->{'type'} eq 'def_line'
  6723. or $root->{'type'} and $root->{'type'} eq 'definfoenclose_command')) {
  6724. my $command_name = $root->{'cmdname'};
  6725. # use the same command name for all the index entry commands
  6726. if ($root->{'extra'} and $root->{'extra'}->{'index_entry'}
  6727. and $root->{'cmdname'} and $root->{'cmdname'} =~ /index$/) {
  6728. $command_name = 'cindex';
  6729. }
  6730. if ($root_commands{$command_name}) {
  6731. $self->{'current_root_command'} = $root;
  6732. }
  6733. if (exists($self->{'commands_conversion'}->{$command_name})) {
  6734. if (exists($context_brace_commands{$command_name})) {
  6735. $self->_new_document_context($command_name);
  6736. }
  6737. push @{$self->{'document_context'}->[-1]->{'commands'}},
  6738. $root->{'cmdname'};
  6739. if (exists($format_context_commands{$command_name})) {
  6740. push @{$self->{'document_context'}->[-1]->{'formatting_context'}},
  6741. {'cmdname' => $command_name};
  6742. }
  6743. if (exists($block_commands{$command_name})) {
  6744. push @{$self->{'document_context'}->[-1]->{'formats'}}, $command_name;
  6745. }
  6746. if (exists ($composition_context_commands{$command_name})) {
  6747. push @{$self->{'document_context'}->[-1]->{'composition_context'}}, $command_name;
  6748. }
  6749. if ($pre_class_commands{$command_name}) {
  6750. push @{$self->{'document_context'}->[-1]->{'preformatted_classes'}},
  6751. $pre_class_commands{$command_name};
  6752. }
  6753. if ($format_raw_commands{$command_name}) {
  6754. $self->{'document_context'}->[-1]->{'raw'}++;
  6755. } elsif ($command_name eq 'verb' or $command_name eq 'verbatim') {
  6756. $self->{'document_context'}->[-1]->{'verbatim'}++;
  6757. }
  6758. if ($code_style_commands{$command_name} or
  6759. $preformatted_code_commands{$command_name}) {
  6760. push @{$self->{'document_context'}->[-1]->{'monospace'}}, 1;
  6761. } elsif ($regular_font_style_commands{$command_name}) {
  6762. push @{$self->{'document_context'}->[-1]->{'monospace'}}, 0;
  6763. } elsif ($upper_case_commands{$command_name}) {
  6764. $self->{'document_context'}->[-1]->{'formatting_context'}->[-1]->{'upper_case'}++;
  6765. } elsif ($command_name eq 'math') {
  6766. $self->{'document_context'}->[-1]->{'math'}++;
  6767. } elsif ($command_name eq 'w') {
  6768. $self->{'document_context'}->[-1]->{'formatting_context'}->[-1]->{'space_protected'}++;
  6769. }
  6770. my $content_formatted;
  6771. if ($root->{'contents'}) {
  6772. $content_formatted = $self->_convert_contents($root, $command_type);
  6773. }
  6774. my $args_formatted;
  6775. if ($brace_commands{$command_name}
  6776. or ($misc_commands{$command_name}
  6777. and $misc_commands{$command_name} eq 'line')
  6778. or (($command_name eq 'item' or $command_name eq 'itemx')
  6779. and ($root->{'parent'}->{'type'}
  6780. and $root->{'parent'}->{'type'} eq 'table_term'))
  6781. or ($command_name eq 'quotation'
  6782. or $command_name eq 'smallquotation')
  6783. or ($command_name eq 'float')) {
  6784. $args_formatted = [];
  6785. if ($root->{'args'}) {
  6786. my @args_specification;
  6787. @args_specification = @{$self->{'commands_args'}->{$command_name}}
  6788. if (defined($self->{'commands_args'}->{$command_name}));
  6789. my $arg_idx = 0;
  6790. foreach my $arg (@{$root->{'args'}}) {
  6791. my $arg_spec = shift @args_specification;
  6792. $arg_spec = ['normal'] if (!defined($arg_spec));
  6793. my $arg_formatted = {'tree' => $arg};
  6794. foreach my $arg_type (@$arg_spec) {
  6795. my $explanation = "$command_type \[$arg_idx\]$arg_type";
  6796. if ($arg_type eq 'normal') {
  6797. $arg_formatted->{'normal'} = $self->_convert($arg, $explanation);
  6798. } elsif ($arg_type eq 'monospace') {
  6799. push @{$self->{'document_context'}->[-1]->{'monospace'}}, 1;
  6800. #$self->{'document_context'}->[-1]->{'code'}++;
  6801. $arg_formatted->{$arg_type} = $self->_convert($arg, $explanation);
  6802. #$self->{'document_context'}->[-1]->{'code'}--;
  6803. pop @{$self->{'document_context'}->[-1]->{'monospace'}};
  6804. } elsif ($arg_type eq 'string') {
  6805. $self->_new_document_context($command_type);
  6806. $self->{'document_context'}->[-1]->{'string'}++;
  6807. $arg_formatted->{$arg_type} = $self->_convert($arg, $explanation);
  6808. pop @{$self->{'document_context'}};
  6809. } elsif ($arg_type eq 'monospacestring') {
  6810. $self->_new_document_context($command_type);
  6811. $self->{'document_context'}->[-1]->{'monospace'}->[-1] = 1;
  6812. $self->{'document_context'}->[-1]->{'string'}++;
  6813. $arg_formatted->{$arg_type} = $self->_convert($arg, $explanation);
  6814. pop @{$self->{'document_context'}};
  6815. } elsif ($arg_type eq 'monospacetext') {
  6816. $arg_formatted->{$arg_type}
  6817. = Texinfo::Convert::Text::convert($arg, {'code' => 1,
  6818. Texinfo::Common::_convert_text_options($self)});
  6819. } elsif ($arg_type eq 'raw') {
  6820. $self->{'document_context'}->[-1]->{'raw'}++;
  6821. $arg_formatted->{$arg_type} = $self->_convert($arg, $explanation);
  6822. $self->{'document_context'}->[-1]->{'raw'}--;
  6823. }
  6824. }
  6825. push @$args_formatted, $arg_formatted;
  6826. $arg_idx++;
  6827. }
  6828. }
  6829. }
  6830. if (exists ($composition_context_commands{$command_name})) {
  6831. pop @{$self->{'document_context'}->[-1]->{'composition_context'}};
  6832. }
  6833. if ($pre_class_commands{$command_name}) {
  6834. pop @{$self->{'document_context'}->[-1]->{'preformatted_classes'}};
  6835. }
  6836. if ($code_style_commands{$command_name}
  6837. or $preformatted_code_commands{$command_name}
  6838. or $regular_font_style_commands{$command_name}) {
  6839. #$self->{'document_context'}->[-1]->{'code'}--;
  6840. pop @{$self->{'document_context'}->[-1]->{'monospace'}};
  6841. } elsif ($upper_case_commands{$command_name}) {
  6842. $self->{'document_context'}->[-1]->{'formatting_context'}->[-1]->{'upper_case'}--;
  6843. } elsif ($command_name eq 'math') {
  6844. $self->{'document_context'}->[-1]->{'math'}--;
  6845. } elsif ($command_name eq 'w') {
  6846. $self->{'document_context'}->[-1]->{'formatting_context'}->[-1]->{'space_protected'}--;
  6847. }
  6848. if ($format_raw_commands{$command_name}) {
  6849. $self->{'document_context'}->[-1]->{'raw'}--;
  6850. } elsif ($command_name eq 'verb' or $command_name eq 'verbatim') {
  6851. $self->{'document_context'}->[-1]->{'verbatim'}--;
  6852. }
  6853. if (exists($block_commands{$command_name})) {
  6854. pop @{$self->{'document_context'}->[-1]->{'formats'}};
  6855. }
  6856. if (exists($format_context_commands{$command_name})) {
  6857. pop @{$self->{'document_context'}->[-1]->{'formatting_context'}};
  6858. }
  6859. pop @{$self->{'document_context'}->[-1]->{'commands'}};
  6860. if (exists($context_brace_commands{$command_name})) {
  6861. pop @{$self->{'document_context'}};
  6862. }
  6863. if ($root->{'cmdname'} eq 'node') {
  6864. $self->{'current_node'} = $root;
  6865. }
  6866. # args are formatted, now format the command itself
  6867. my $result;
  6868. if ($args_formatted) {
  6869. if (!defined($self->{'commands_conversion'}->{$command_name})) {
  6870. print STDERR "No command_conversion for $command_name\n";
  6871. $result = '';
  6872. } else {
  6873. $result = &{$self->{'commands_conversion'}->{$command_name}}($self,
  6874. $command_name, $root, $args_formatted, $content_formatted);
  6875. }
  6876. } else {
  6877. $result = &{$self->{'commands_conversion'}->{$command_name}}($self,
  6878. $command_name, $root, $content_formatted);
  6879. }
  6880. return $result;
  6881. } else {
  6882. print STDERR "Unknown command `$command_name'\n"
  6883. if ($self->get_conf('VERBOSE') or $self->get_conf('DEBUG'));
  6884. return '';
  6885. }
  6886. if ($root_commands{$command_name}) {
  6887. delete $self->{'current_root_command'};
  6888. }
  6889. } elsif ($root->{'type'}) {
  6890. push @{$self->{'document_context'}->[-1]->{'commands'}},
  6891. $root->{'cmdname'}
  6892. if ($root->{'cmdname'});
  6893. if ($root->{'type'} eq 'paragraph') {
  6894. $self->{'document_context'}->[-1]->{'formatting_context'}->[-1]->{'paragraph_number'}++;
  6895. } elsif ($root->{'type'} eq 'preformatted'
  6896. or $root->{'type'} eq 'rawpreformatted') {
  6897. $self->{'document_context'}->[-1]->{'formatting_context'}->[-1]->{'preformatted_number'}++;
  6898. } elsif ($root->{'type'} eq 'element') {
  6899. $self->{'current_element'} = $root;
  6900. $self->{'current_filename'} = $root->{'filename'};
  6901. } elsif ($pre_class_types{$root->{'type'}}) {
  6902. push @{$self->{'document_context'}->[-1]->{'preformatted_classes'}},
  6903. $pre_class_types{$root->{'type'}};
  6904. push @{$self->{'document_context'}->[-1]->{'composition_context'}},
  6905. $root->{'type'};
  6906. }
  6907. if ($self->{'code_types'}->{$root->{'type'}}) {
  6908. #$self->{'document_context'}->[-1]->{'code'}++;
  6909. push @{$self->{'document_context'}->[-1]->{'monospace'}}, 1;
  6910. }
  6911. if ($root->{'type'} eq '_string') {
  6912. $self->{'document_context'}->[-1]->{'string'}++;
  6913. }
  6914. my $content_formatted;
  6915. if ($root->{'type'} eq 'definfoenclose_command') {
  6916. if ($root->{'args'}) {
  6917. $content_formatted = $self->_convert($root->{'args'}->[0]);
  6918. }
  6919. } elsif ($root->{'contents'}) {
  6920. $content_formatted = $self->_convert_contents($root, $command_type);
  6921. }
  6922. my $result = '';
  6923. if (exists($self->{'types_conversion'}->{$root->{'type'}})) {
  6924. $result = &{$self->{'types_conversion'}->{$root->{'type'}}} ($self,
  6925. $root->{'type'},
  6926. $root,
  6927. $content_formatted);
  6928. #print STDERR "Converting type $root->{'type'} -> $result\n";
  6929. } elsif (defined($content_formatted)) {
  6930. $result = $content_formatted;
  6931. }
  6932. if ($self->{'code_types'}->{$root->{'type'}}) {
  6933. #$self->{'document_context'}->[-1]->{'code'}--;
  6934. pop @{$self->{'document_context'}->[-1]->{'monospace'}};
  6935. }
  6936. if ($root->{'type'} eq '_string') {
  6937. $self->{'document_context'}->[-1]->{'string'}--;
  6938. }
  6939. if ($root->{'type'} eq 'element') {
  6940. delete $self->{'current_element'};
  6941. delete $self->{'current_filename'};
  6942. } elsif ($pre_class_types{$root->{'type'}}) {
  6943. pop @{$self->{'document_context'}->[-1]->{'preformatted_classes'}};
  6944. pop @{$self->{'document_context'}->[-1]->{'composition_context'}};
  6945. }
  6946. print STDERR "DO type ($root->{'type'}) => `$result'\n"
  6947. if ($self->get_conf('DEBUG'));
  6948. pop @{$self->{'document_context'}->[-1]->{'commands'}}
  6949. if ($root->{'cmdname'});
  6950. return $result;
  6951. # no type, no cmdname, but contents.
  6952. } elsif ($root->{'contents'}) {
  6953. # this happens inside accents, for section/node names, for @images.
  6954. my $content_formatted = '';
  6955. my $i = 0;
  6956. foreach my $content (@{$root->{'contents'}}) {
  6957. $content_formatted .= $self->_convert($content, "$command_type [$i]");
  6958. $i++;
  6959. }
  6960. print STDERR "UNNAMED HOLDER => `$content_formatted'\n"
  6961. if ($self->get_conf('DEBUG'));
  6962. return $content_formatted;
  6963. } else {
  6964. print STDERR "UNNAMED empty\n" if ($self->get_conf('DEBUG'));
  6965. if ($self->{'types_conversion'}->{''}) {
  6966. return &{$self->{'types_conversion'}->{''}} ($self, $root);
  6967. } else {
  6968. return '';
  6969. }
  6970. }
  6971. print STDERR "DEBUG: HERE!($root)\n";
  6972. }
  6973. sub _set_variables_texi2html()
  6974. {
  6975. my @texi2html_options = (
  6976. ['NO_USE_SETFILENAME', 1],
  6977. ['USE_SETFILENAME_EXTENSION', 0],
  6978. ['footnotestyle', 'separate'],
  6979. ['INLINE_CONTENTS', 0],
  6980. ['FORCE', 1],
  6981. ['AVOID_MENU_REDUNDANCY', 1],
  6982. ['TOP_FILE', ''],
  6983. ['USE_ACCESSKEY', 0],
  6984. ['NODE_NAME_IN_MENU', 0],
  6985. ['OVERVIEW_LINK_TO_TOC', 0],
  6986. ['USE_UP_NODE_FOR_ELEMENT_UP', 1],
  6987. ['USE_REL_REV', 0],
  6988. ['USE_LINKS', 0],
  6989. ['USE_NODES', 0],
  6990. ['NODE_FILENAMES', 0],
  6991. ['USE_NUMERIC_ENTITY', 1],
  6992. ['SPLIT', ''],
  6993. ['SPLIT_INDEX', 100],
  6994. ['PROGRAM_NAME_IN_FOOTER', 1],
  6995. ['HEADER_IN_TABLE', 1],
  6996. ['USE_TITLEPAGE_FOR_TITLE', 1],
  6997. ['MENU_ENTRY_COLON', ''],
  6998. ['INDEX_ENTRY_COLON', ''],
  6999. ['ENABLE_ENCODING_USE_ENTITY', 1],
  7000. ['DO_ABOUT', undef],
  7001. ['NODE_NAME_IN_INDEX', 0],
  7002. ['CHAPTER_HEADER_LEVEL', 1],
  7003. ['BIG_RULE', '<hr size="6">'],
  7004. ['FOOTNOTE_END_HEADER_LEVEL', 3],
  7005. ['FOOTNOTE_SEPARATE_HEADER_LEVEL', 1],
  7006. ['KEEP_TOP_EXTERNAL_REF', 1],
  7007. ['SECTION_BUTTONS', ['FastBack', 'Back', 'Up', 'Forward', 'FastForward',
  7008. ' ', ' ', ' ', ' ',
  7009. 'Top', 'Contents', 'Index', 'About' ]],
  7010. ['TOP_BUTTONS', ['Back', 'Forward', ' ',
  7011. 'Contents', 'Index', 'About']],
  7012. ['MISC_BUTTONS', [ 'Top', 'Contents', 'Index', 'About' ]],
  7013. ['CHAPTER_BUTTONS', [ 'FastBack', 'FastForward', ' ',
  7014. ' ', ' ', ' ', ' ',
  7015. 'Top', 'Contents', 'Index', 'About', ]],
  7016. ['SECTION_FOOTER_BUTTONS', [ 'FastBack', 'Back', 'Up',
  7017. 'Forward', 'FastForward' ]],
  7018. ['NODE_FOOTER_BUTTONS', [ 'FastBack', 'Back',
  7019. 'Up', 'Forward', 'FastForward',
  7020. ' ', ' ', ' ', ' ',
  7021. 'Top', 'Contents', 'Index', 'About' ]],
  7022. );
  7023. foreach my $option (@texi2html_options) {
  7024. #no warnings 'once';
  7025. $defaults{$option->[0]} = $option->[1];
  7026. }
  7027. }
  7028. 1;
  7029. __END__
  7030. # $Id$
  7031. # Automatically generated from maintain/template.pod
  7032. =head1 NAME
  7033. Texinfo::Convert::HTML - Convert Texinfo tree to HTML
  7034. =head1 SYNOPSIS
  7035. my $converter
  7036. = Texinfo::Convert::HTML->converter({'parser' => $parser});
  7037. $converter->output($tree);
  7038. $converter->convert($tree);
  7039. $converter->convert_tree($tree);
  7040. $converter->output_internal_links(); # HTML only
  7041. =head1 DESCRIPTION
  7042. Texinfo::Convert::HTML converts a Texinfo tree to HTML.
  7043. =head1 METHODS
  7044. =over
  7045. =item $converter = Texinfo::Convert::HTML->converter($options)
  7046. Initialize converter from Texinfo to HTML.
  7047. The I<$options> hash reference holds options for the converter. In
  7048. this option hash reference a parser object may be associated with the
  7049. I<parser> key. The other options should be configuration options
  7050. described in the Texinfo manual. Those options, when appropriate,
  7051. override the document content.
  7052. See L<Texinfo::Convert::Converter> for more informations.
  7053. =item $converter->output($tree)
  7054. Convert a Texinfo tree I<$tree> and output the result in files as
  7055. described in the Texinfo manual.
  7056. =item $result = $converter->convert($tree)
  7057. Convert a Texinfo tree I<$tree> or tree portion and return
  7058. the resulting output.
  7059. =item $result = $converter->convert_tree($tree)
  7060. Convert a Texinfo tree portion I<$tree> and return the resulting
  7061. output. This function does not try to output a full document but only
  7062. portions. For a full document use C<convert>.
  7063. =item $result = $converter->output_internal_links()
  7064. Returns text representing the links in the document. The format should
  7065. follow the C<--internal-links> option of the texi2any/makeinfo
  7066. specification. This is only supported in (and relevant for) HTML.
  7067. =back
  7068. =head1 AUTHOR
  7069. Patrice Dumas, E<lt>pertusus@free.frE<gt>
  7070. =head1 COPYRIGHT AND LICENSE
  7071. Copyright 2015 Free Software Foundation, Inc.
  7072. This library is free software; you can redistribute it and/or modify
  7073. it under the terms of the GNU General Public License as published by
  7074. the Free Software Foundation; either version 3 of the License, or (at
  7075. your option) any later version.
  7076. =cut