12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395 |
- #! @PERL@ --
- # perl
- 'di ';
- 'ig 00 ';
- #+##############################################################################
- #
- # texi2html: Parse and transform Texinfo documents
- #
- # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
- # 2009, 2010, 2011 Free Software Foundation, Inc.
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 3 of the License,
- # or (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
- #
- #
- # Some error messages come from texinfo (makeinfo), so copyright holder
- # is the FSF or the individual who wrote them. All come from before the
- # switch of texinfo to GPLv3+.
- #
- # Originally written by Lionel Cons.
- #
- #-##############################################################################
- # The man page for this program is included at the end of this file and can be
- # viewed using the command 'nroff -man texi2html'.
- # for POSIX::setlocale and File::Spec
- require 5.00405;
- # Perl pragma to restrict unsafe constructs
- use strict;
- # used in case of tests, to revert to "C" locale.
- use POSIX qw(setlocale LC_ALL LC_CTYPE);
- # used to obtain the name of the current working directory
- use Cwd;
- # Used to find the parent directory of this script.
- use File::Basename;
- # used to find a relative path back to the current working directory
- use File::Spec;
- # to determine the path separator and null file
- use Config;
- #use encoding::warnings;
- # for translations
- #use encoding 'utf8';
- #use utf8;
- #
- # According to
- # larry.jones@sdrc.com (Larry Jones)
- # this pragma is not present in perl5.004_02:
- #
- # Perl pragma to control optional warnings
- # use warnings;
- # determine the path separators
- my $path_separator = $Config{'path_sep'};
- $path_separator = ':' if (!defined($path_separator));
- my $quoted_path_separator = quotemeta($path_separator);
- #++##########################################################################
- #
- # NOTE FOR DEBUGGING THIS SCRIPT:
- # You can run 'perl -x texi2html.pl' directly, provided you have the script
- # in the same directory with, or the environment variable T2H_HOME set to
- # the directory containing, the texi2html.pm, T2h_i18n.pm, translations.pl,
- # l2h.init, & T2h_l2h.pm files. Ditto makeinfo.pl, if you make it a
- # symlink to texi2html.pl.
- #
- #--##########################################################################
- my $T2H_HOME = defined $ENV{T2H_HOME} ? $ENV{T2H_HOME} : dirname $0;
- if ($0 =~ /\.pl$/)
- {
- # Issue a warning in debugging mode if $T2H_HOME is set but isn't
- # accessible.
- if (!-e $T2H_HOME)
- { warn "T2H_HOME ($T2H_HOME) does not exist."; }
- elsif (!-d $T2H_HOME)
- { warn "T2H_HOME ($T2H_HOME) is not a directory."; }
- elsif (!-x $T2H_HOME)
- { warn "T2H_HOME ($T2H_HOME) is not accessible."; }
- }
- # CVS version:
- # $Id$
- # Homepage:
- my $T2H_HOMEPAGE = "http://www.gnu.org/software/texinfo/";
- # Version: set in configure.in
- my $THISVERSION = '@PACKAGE_VERSION@';
- my $THISPROG = '@PACKAGE_NAME@';
- my $THISPROG_THISVERSION = "$THISPROG $THISVERSION"; # program name and version
- #+++########################################################################
- # #
- # Paths and file names #
- # #
- #---########################################################################
- # set by configure, prefix for the sysconfdir and so on
- my $prefix = '@prefix@';
- my $datarootdir;# = '@datarootdir@';
- my $sysconfdir;
- my $pkgdatadir;
- my $datadir;
- # We need to eval as $prefix has to be expanded. However when we haven't
- # run configure @sysconfdir will be expanded as an array, thus we verify
- # whether configure was run or not
- if ('@sysconfdir@' ne '@' . 'sysconfdir@')
- {
- $sysconfdir = eval '"@sysconfdir@"';
- }
- else
- {
- $sysconfdir = "/usr/local/etc";
- }
- if ('@datarootdir@' ne '@' . 'datarootdir@')
- {
- $datarootdir = eval '"@datarootdir@"';
- }
- else
- {
- $datarootdir = "/usr/local/share";
- }
- if ('@datadir@' ne '@' . 'datadir@')
- {
- $pkgdatadir = eval '"@datadir@/@PACKAGE@"';
- $datadir = eval '"@datadir@"';
- }
- else
- {
- $pkgdatadir = "/usr/local/share/texi2html";
- $datadir = "/usr/local/share";
- }
- my $target_prefix = "t_h";
- #+++########################################################################
- # #
- # Constants #
- # #
- #---########################################################################
- my $DEBUG_MENU = 1;
- my $DEBUG_INDEX = 2;
- my $DEBUG_TEXI = 4;
- my $DEBUG_MACROS = 8;
- my $DEBUG_FORMATS = 16;
- my $DEBUG_ELEMENTS = 32;
- my $DEBUG_USER = 64;
- my $DEBUG_L2H = 128;
- my $VARRE = '[\w\-]+'; # RE for a variable name
- my $MAX_LEVEL = 4;
- my $MIN_LEVEL = 1;
- # all settable variables that are reset between every pass
- # FIXME is it really right?
- # Yes, for documentlanguage, clickstyle, allowcodebreaks.
- # Maybe not for frenchspacing?
- my @document_settable_at_commands =
- ('everyheading', 'everyfooting', 'evenheading',
- 'evenfooting', 'oddheading', 'oddfooting', 'headings',
- 'allowcodebreaks', 'frenchspacing', 'exampleindent',
- 'firstparagraphindent', 'paragraphindent', 'clickstyle',
- 'documentlanguage');
- # those are not reset such that they are available between passes.
- my @document_global_at_commands = ('contents', 'shortcontents',
- 'setcontentsaftertitlepage', 'setshortcontentsaftertitlepage',
- 'footnotestyle', 'novalidate', 'kbdinputstyle', 'documentencoding',
- 'setfilename', 'today', 'documentdescription',
- # the following are not set to anything in the default
- # case, and currently not used anywhere
- 'everyheadingmarks','everyfootingmarks',
- 'evenheadingmarks','oddheadingmarks','evenfootingmarks','oddfootingmarks',
- 'fonttextsize', 'pagesizes', 'setchapternewpage'
- );
- my @command_line_settables = ('FILLCOLUMN', 'SPLIT', 'SPLIT_SIZE',
- 'HEADERS',
- 'MACRO_EXPAND', 'NUMBER_SECTIONS',
- 'NUMBER_FOOTNOTES', 'NODE_FILES',
- 'NO_WARN', 'VERBOSE',
- 'TRANSLITERATE_FILE_NAMES', 'ERROR_LIMIT', 'ENABLE_ENCODING',
- 'FORCE', 'INTERNAL_LINKS', 'OUTFILE', 'SUBDIR', 'OUT',
- 'BATCH', 'SILENT'
- );
- # FIXME TOP_HEADING_AT_BEGINNING seems to be a no-op
- my @variable_settables = (
- 'DEBUG', 'FRAMES', 'FRAMESET_DOCTYPE', 'DOCTYPE', 'TEST', 'DUMP_TEXI',
- 'TOP_FILE', 'TOC_FILE', 'SHOW_MENU', 'USE_NODES', 'TOC_LINKS', 'SHORTEXTN',
- 'PREFIX', 'SHORT_REF', 'IDX_SUMMARY', 'DEF_TABLE', 'L2H', 'MONOLITHIC',
- 'L2H_L2H', 'L2H_SKIP', 'L2H_TMP', 'L2H_FILE', 'L2H_CLEAN',
- 'L2H_HTML_VERSION', 'IGNORE_PREAMBLE_TEXT', 'EXTERNAL_DIR', 'USE_ISO',
- 'SPLIT_INDEX', 'IN_ENCODING', 'USE_NLS',
- 'VERTICAL_HEAD_NAVIGATION', 'INLINE_CONTENTS', 'NODE_FILE_EXTENSION',
- 'NO_CSS', 'INLINE_CSS_STYLE', 'USE_SECTIONS', 'USE_TITLEPAGE_FOR_TITLE',
- 'SIMPLE_MENU', 'EXTENSION', 'INLINE_INSERTCOPYING', 'USE_NUMERIC_ENTITY',
- 'I18N_PERL_HASH', 'ENABLE_ENCODING_USE_ENTITY', 'ICONS', 'USE_UNICODE',
- 'USE_UNIDECODE', 'DATE_IN_HEADER', 'OPEN_QUOTE_SYMBOL',
- 'CLOSE_QUOTE_SYMBOL', 'TOP_NODE_UP', 'TOP_NODE_FILE',
- 'TOP_NODE_FILE_TARGET', 'SHOW_TITLE', 'WORDS_IN_PAGE',
- 'HEADER_IN_TABLE', 'USE_ACCESSKEY', 'USE_REL_REV', 'USE_LINKS',
- 'OVERVIEW_LINK_TO_TOC', 'AVOID_MENU_REDUNDANCY', 'NODE_NAME_IN_MENU',
- 'NODE_NAME_IN_INDEX', 'USE_SETFILENAME', 'USE_SETFILENAME_EXTENSION',
- 'COMPLEX_FORMAT_IN_TABLE',
- 'USE_UP_FOR_ADJACENT_NODES', 'TOP_HEADING_AT_BEGINNING',
- 'SEPARATE_DESCRIPTION', 'IGNORE_BEFORE_SETFILENAME',
- 'COMPLETE_IMAGE_PATHS', 'USE_NODE_TARGET', 'NEW_CROSSREF_STYLE',
- 'PROGRAM_NAME_IN_FOOTER', 'NODE_FILENAMES', 'DEFAULT_ENCODING',
- 'OUT_ENCODING', 'ENCODING_NAME', 'EXTERNAL_CROSSREF_SPLIT', 'BODYTEXT',
- 'CSS_LINES', 'RENAMED_NODES_REDIRECTIONS', 'RENAMED_NODES_FILE',
- 'TEXI2DVI', 'DO_ABOUT');
- foreach my $var (@document_settable_at_commands, @command_line_settables,
- @document_global_at_commands, @variable_settables)
- {
- $Texi2HTML::GLOBAL{'variable_levels'}->{$var} = 10;
- }
- #+++########################################################################
- # #
- # Command name and default format #
- # #
- #---########################################################################
- my $real_command_name = $0;
- $real_command_name =~ s/.*\///;
- $real_command_name =~ s/\.pl$//;
- my %command_format = (
- 'texi2html' => 'html',
- 'makeinfo' => 'info',
- 'texi2any' => 'raw-text',
- );
- # Config files
- my $i18n_dir = 'i18n'; # name of the directory containing the per language files
- my $conf_file_name = 'Config' ;
- my $texinfo_htmlxref = 'htmlxref.cnf';
- # directories for texinfo configuration files
- my @language_config_dirs = ('./.texinfo');
- push @language_config_dirs, "$ENV{'HOME'}/.texinfo" if (defined($ENV{'HOME'}));
- push @language_config_dirs, "$sysconfdir/texinfo" if (defined($sysconfdir));
- push @language_config_dirs, "$datadir/texinfo" if (defined($datadir));
- my @texinfo_config_dirs = ('.', @language_config_dirs);
- my @program_config_dirs;
- my @program_init_dirs;
- # program name dependent initializations: config directories and default
- # format.
- sub set_config_init_dirs_output($)
- {
- my $program_name = shift;
- if (!defined($command_format{$program_name}))
- {
- # user can make any link to set $0, or use --program with an unknown name.
- # In that case the default is to use texi2any
- $program_name = 'texi2any';
- }
- my $default_output_format = $command_format{$program_name};
- # directories for config files
- @program_config_dirs = ('.', "./.$program_name");
- push @program_config_dirs, "$ENV{'HOME'}/.$program_name" if (defined($ENV{'HOME'}));
- push @program_config_dirs, "$sysconfdir/$program_name" if (defined($sysconfdir));
- push @program_config_dirs, "$datadir/$program_name" if (defined($datadir));
- # directories for init files
- @program_init_dirs = @program_config_dirs;
- # common directories for all command names
- foreach my $texinfo_config_dir (@language_config_dirs)
- {
- push @program_init_dirs, "${texinfo_config_dir}/init";
- }
- $Texi2HTML::Config::DEFAULT_OUTPUT_FORMAT = $default_output_format;
- $Texi2HTML::Config::COMMAND_NAME = $program_name;
- Texi2HTML::Config::t2h_default_load_format($default_output_format, 0);
- }
- #+++###########################################################################
- # #
- # Initialization #
- # Some declarations, some functions that are GPL and therefore cannot be in #
- # texi2html.pm, some functions that are not to be customized. #
- # Pasted content of File $(srcdir)/texi2html.pm: Default initializations #
- # #
- #---###########################################################################
- {
- package Texi2HTML::Config;
- use Config;
- # customization options variables
- use vars qw(
- @EXPAND
- @INCLUDE_DIRS
- @PREPEND_DIRS
- @CONF_DIRS
- @CSS_FILES
- @CSS_REFS
- $DEFAULT_OUTPUT_FORMAT
- $OUTPUT_FORMAT
- $COMMAND_NAME
- @COMMANDS
- );
- # customization variables
- use vars qw(
- $CAPTION_STYLE
- $MENU_PRE_STYLE
- $MENU_PRE_COMPLEX_FORMAT
- $EXAMPLE_INDENT_CELL
- $SMALL_EXAMPLE_INDENT_CELL
- $SMALL_FONT_SIZE
- $SMALL_RULE
- $DEFAULT_RULE
- $MIDDLE_RULE
- $BIG_RULE
- $TOP_HEADING
- $INDEX_CHAPTER
- $AFTER_BODY_OPEN
- $PRE_BODY_CLOSE
- $EXTRA_HEAD
- $UNNUMBERED_SYMBOL_IN_MENU
- $MENU_SYMBOL
- $MENU_ENTRY_COLON
- $INDEX_ENTRY_COLON
- $NO_NUMBER_FOOTNOTE_SYMBOL
- $NO_BULLET_LIST_STYLE
- $NO_BULLET_LIST_ATTRIBUTE
- $NO_BULLET_LIST_CLASS
- $STDIN_DOCU_NAME
- $STDOUT_DOCU_NAME
- $BEFORE_OVERVIEW
- $AFTER_OVERVIEW
- $BEFORE_TOC_LINES
- $AFTER_TOC_LINES
- %ACTIVE_ICONS
- %NAVIGATION_TEXT
- %PASSIVE_ICONS
- %BUTTONS_NAME
- %BUTTONS_GOTO
- %BUTTONS_EXAMPLE
- %BUTTONS_ACCESSKEY
- %BUTTONS_REL
- %BUTTONS_TEXT
- @T2H_FORMAT_EXPAND
- @CHAPTER_BUTTONS
- @MISC_BUTTONS
- @SECTION_BUTTONS
- @SECTION_FOOTER_BUTTONS
- @NODE_FOOTER_BUTTONS
- @TOP_BUTTONS
- @LINKS_BUTTONS
- @IMAGE_EXTENSIONS
- @INPUT_FILE_SUFFIXES
- @TEXI2DVI_ARGUMENTS
- );
- # I18n
- use vars qw(
- $I
- $LANGUAGES
- );
- # customizable subroutines references
- use vars qw(
- $print_section
- $one_section
- $end_section
- $print_Top_header
- $print_Top_footer
- $print_Top
- $print_Toc
- $print_Overview
- $print_Footnotes
- $print_About
- $print_misc_header
- $print_misc_footer
- $print_misc
- $print_section_header
- $print_section_footer
- $print_chapter_header
- $print_chapter_footer
- $print_element_header
- $print_page_head
- $print_page_foot
- $print_head_navigation
- $print_foot_navigation
- $print_title
- $button_icon_img
- $button_formatting
- $print_navigation
- $about_body
- $print_frame
- $print_toc_frame
- $toc_body
- $contents
- $internal_links
- $shortcontents
- $titlepage
- $insertcopying
- $css_lines
- $print_redirection_page
- $translate_names
- $init_out
- $finish_out
- $node_file_name
- $element_file_name
- $node_target_name
- $element_target_name
- $placed_target_file_name
- $inline_contents
- $program_string
- $preserve_misc_command
- $misc_command_line
- $misc_command_line_texi
- $protect_text
- $anchor
- $anchor_label
- $element_label
- $misc_element_label
- $def_item
- $def
- $menu
- $menu_command
- $menu_link
- $menu_description
- $menu_comment
- $simple_menu_link
- $ref_beginning
- $info_ref
- $book_ref
- $external_href
- $external_ref
- $internal_ref
- $table_item
- $table_line
- $row
- $cell
- $list_item
- $comment
- $def_line
- $def_line_no_texi
- $heading_no_texi
- $raw
- $raw_no_texi
- $heading
- $element_heading
- $heading_text
- $heading_text_preformatted
- $paragraph
- $preformatted
- $empty_preformatted
- $foot_line_and_ref
- $foot_section
- $image
- $image_files
- $index_entry_label
- $index_entry
- $index_entry_command
- $index_letter
- $print_index
- $printindex
- $index_summary
- $summary_letter
- $complex_format
- $cartouche
- $sp
- $definition_category
- $definition_index_entry
- $table_list
- $copying_comment
- $documentdescription
- $index_summary_file_entry
- $index_summary_file_end
- $index_summary_file_begin
- $style
- $line_command
- $format
- $normal_text
- $empty_line
- $unknown
- $unknown_style
- $float
- $caption_shortcaption
- $caption_shortcaption_command
- $listoffloats
- $listoffloats_entry
- $listoffloats_caption
- $listoffloats_float_style
- $listoffloats_style
- $acronym_like
- $quotation
- $quotation_prepend_text
- $paragraph_style_command
- $heading_texi
- $index_element_heading_texi
- $format_list_item_texi
- $begin_format_texi
- $begin_style_texi
- $begin_paragraph_texi
- $tab_item_texi
- $footnote_texi
- $colon_command
- $simple_command
- $thing_command
- $begin_special_region
- $end_special_region
- $PRE_ABOUT
- $AFTER_ABOUT
- );
- # hash which entries might be redefined by the user
- use vars qw(
- $complex_format_map
- %complex_format_map
- %accent_map
- %def_map
- %format_map
- %simple_map
- %simple_map_pre
- %simple_map_texi
- %simple_map_math
- %style_map
- %style_map_pre
- %style_map_math
- %style_map_texi
- %simple_format_simple_map_texi
- %simple_format_style_map_texi
- %simple_format_texi_map
- %line_command_map
- %command_type
- %paragraph_style
- %stop_paragraph_command
- %format_code_style
- %region_formats_kept
- %texi_formats_map
- %things_map
- %pre_map
- %math_map
- %texi_map
- %sorting_things_map
- %unicode_map
- %unicode_diacritical
- %transliterate_map
- %transliterate_accent_map
- %no_transliterate_map
- %ascii_character_map
- %default_simple_map
- %default_things_map
- %default_texi_map
- %default_style_map
- %default_style_map_pre
- %default_style_map_texi
- %default_simple_format_style_map_texi
- %numeric_entity_map
- %perl_charset_to_html
- %misc_pages_targets
- %misc_command
- %no_paragraph_commands
- %css_map
- %format_in_paragraph
- %special_list_commands
- %accent_letters
- %unicode_accents
- %special_accents
- %inter_item_commands
- $def_always_delimiters
- $def_in_type_delimiters
- $def_argument_separator_delimiters
- $warn_var_character_quoted
- %colon_command_punctuation_characters
- $punctuation_characters
- $after_punctuation_characters
- @command_handler_setup
- @command_handler_init
- @command_handler_names
- @command_handler_process
- @command_handler_output
- @command_handler_finish
- %command_handler
- %special_style
- %null_device_file
- %language_codes
- %region_codes
- %deprecated_commands
- %output_format_names
- %canonical_texinfo_encodings
- @text_substitutions_normal
- @text_substitutions_texi
- @text_substitutions_simple_format
- @text_substitutions_pre
- %htmlxref_entries
- %renamed_nodes
- %texi2dvi_formats
- );
- # deprecated
- use vars qw(
- $address
- %iso_symbols
- %simple_map_pre_math
- %simple_map_texi_math
- );
- # subject to change
- use vars qw(
- %makeinfo_encoding_to_map
- %makeinfo_unicode_to_eight_bit
- %eight_bit_to_unicode
- %t2h_encoding_aliases
- );
- # FIXME i18n ?
- %output_format_names = (
- 'info' => 'Info',
- 'html' => 'HTML',
- 'docbook' => 'Docbook XML',
- 'xml' => 'Texinfo XML',
- 'plaintext' => 'plain text',
- 'raw-text' => 'raw text',
- 'dvi' => 'DVI',
- 'pdf' => 'Pdf',
- 'ps' => 'Postscript'
- );
- sub load($)
- {
- my $file = shift;
- # If required like other init files, the functions would be redefined
- # and the format dependent stuff wouldn't be loaded. Having the
- # formats loaded could be worked around, for example there could be
- # a variable that, and if the variable is defined a function reference
- # should be called right after the require. There is no real
- # workaround for having the function redefined, though.
- foreach my $output_format (keys(%output_format_names))
- {
- if ($file =~ /\/$output_format\.pm$/)
- {
- t2h_default_load_format($output_format, 1);
- return 1;
- }
- }
- eval { require($file) ;};
- if ($@ ne '')
- {
- print STDERR "error loading $file: $@\n";
- return 0;
- }
- return 1;
- }
- # var: variable name
- # value: value to set. May be undef.
- # level: priority level. If undef, it means reusing the current level
- # not_global: if set the change should only concern the current document
- sub set_variable($$$;$)
- {
- my $var = shift;
- my $value = shift;
- my $level = shift;
- my $not_global = shift;
- $not_global = 0 if (!$not_global);
- my $ref_level = $Texi2HTML::GLOBAL{'variable_levels'}->{$var};
- if (!defined($ref_level))
- {
- # issue with Locale::Messages::dpgettext not already defined
- #main::msg_warn(sprintf('Unknown variable %s', $var));
- warn (sprintf('Unknown variable %s', $var));
- return 0;
- }
- #print STDERR "$var(".(main::var_to_str($level))."): ".main::var_to_str($value)." not_global $not_global\n";
- if (!defined($level) or $level <= $ref_level)
- {
- $Texi2HTML::THISDOC{'variable_levels'}->{$var} = $level if (defined($level));
- if ($not_global)
- {
- $Texi2HTML::THISDOC{'variables'}->{$var} = $value;
- }
- else
- {
- $Texi2HTML::GLOBAL{'variables'}->{$var} = $value;
- $Texi2HTML::GLOBAL{'variable_levels'}->{$var} = $level if (defined($level));
- }
- return 1;
- }
- return 0;
- }
- # var: variable name
- # level: priority level. If undef, it means reusing the current level
- # not_global: only for the current document
- sub unset_variable($$;$)
- {
- my $var = shift;
- my $level = shift;
- my $not_global = shift;
- $not_global = 0 if (!$not_global);
- my $ref_level = $Texi2HTML::GLOBAL{'variable_levels'}->{$var};
- if (!defined($ref_level))
- {
- # issue with Locale::Messages::dpgettext not already defined
- #main::msg_warn(sprintf('Unknown variable %s', $var));
- warn (sprintf('Unknown variable %s', $var));
- return 0;
- }
- #print STDERR "$var(".(main::var_to_str($level))."): ".main::var_to_str($value)." not_global $not_global\n";
- if (!defined($level) or $level <= $ref_level)
- {
- $Texi2HTML::THISDOC{'variable_levels'}->{$var} = $level if (defined($level));
- if ($not_global)
- {
- delete($Texi2HTML::THISDOC{'variables'}->{$var});
- }
- else
- {
- delete($Texi2HTML::GLOBAL{'variables'}->{$var});
- $Texi2HTML::GLOBAL{'variable_levels'}->{$var} = $level if (defined($level));
- }
- return 1;
- }
- return 0;
- }
- sub set_from_init_file ($$)
- {
- my $var = shift;
- my $value = shift;
- my $level = 3;
- return set_variable($var, $value, $level);
- }
- sub set_default ($$)
- {
- my $var = shift;
- my $value = shift;
- my $level = 7;
- return set_variable($var, $value, $level);
- }
- sub set_from_document($$)
- {
- my $var = shift;
- my $value = shift;
- my $level = 5;
- return set_variable($var, $value, $level, 1);
- }
- sub get_conf($)
- {
- my $name = shift;
- if (defined($Texi2HTML::GLOBAL{'variable_levels'}->{$name}))
- { # notice the exists, and not defined. Such that undef is a
- # value like any other possible value.
- if (exists($Texi2HTML::THISDOC{'variables'}->{$name}))
- {
- return $Texi2HTML::THISDOC{'variables'}->{$name};
- }
- else
- { # may be undef
- return $Texi2HTML::GLOBAL{'variables'}->{$name};
- }
- }
- else
- { # no i18n since it may not be set up already (?)
- warn (sprintf('get_conf: Unknown variable %s', $name));
- return undef;
- }
- }
- # manage expanded sections
- sub set_expansion($$)
- {
- my $region = shift;
- my $set = shift;
- $set = 1 if (!defined($set));
- if ($set)
- {
- push (@EXPAND, $region) unless (grep {$_ eq $region} @EXPAND);
- }
- else
- {
- @EXPAND = grep {$_ ne $region} @EXPAND;
- @T2H_FORMAT_EXPAND = grep {$_ ne $region} @T2H_FORMAT_EXPAND;
- }
- }
- # needed in this namespace for translations
- $I = \&Texi2HTML::I18n::get_string;
- sub gdt($;$$)
- {
- return &main::gdt(@_);
- }
- sub __($)
- {
- return &main::__(@_);
- }
- sub __p($$)
- {
- return &main::__p(@_);
- }
- sub N__($)
- {
- return $_[0];
- }
- #
- # Function refs covered by the GPL as part of the texi2html.pl original
- # code. As such they cannot appear in texi2html.pm which is public
- # domain (at least the things coded by me, and, if I'm not wrong also the
- # things coded by Olaf -- Pat).
- #
- sub HTML_DEFAULT_shortcontents($$)
- {
- my $elements_list = shift;
- my $stoc_file = shift;
- return unless (get_conf('shortcontents') or get_conf('FRAMES'));
- my $ul_class = '';
- $ul_class = $NO_BULLET_LIST_CLASS if (get_conf('NUMBER_SECTIONS'));
- my @result = ();
- foreach my $element (@$elements_list)
- {
- next if ($element->{'tag'} eq 'top' or $element->{'toc_level'} != 1);
- my $dest_for_stoc = $element->{'file'};
- my $dest_target_for_stoc = $element->{'target'};
- if (get_conf('OVERVIEW_LINK_TO_TOC'))
- {
- $dest_for_stoc = $Texi2HTML::THISDOC{'toc_file'};
- $dest_target_for_stoc = $element->{'tocid'};
- }
- $dest_for_stoc = '' if ($dest_for_stoc eq $stoc_file);
- my $text = $element->{'text'};
- my $stoc_entry = "<li>" . &$anchor ($element->{'stocid'}, "$dest_for_stoc#$dest_target_for_stoc",$text);
- push(@result, $stoc_entry. "</li>\n");
- }
- if (@result)
- {
- unshift @result, html_default_attribute_class('ul', $ul_class) .">\n";
- push @result, "</ul>\n";
- unshift @result, $BEFORE_OVERVIEW;
- push @result, $AFTER_OVERVIEW;
- }
- return \@result;
- }
- sub HTML_DEFAULT_contents($$)
- {
- my $elements_list = shift;
- my $toc_file = shift;
- return unless (get_conf('contents'));
- my $current_level = 0;
- my $ul_class = '';
- $ul_class = $NO_BULLET_LIST_CLASS if (get_conf('NUMBER_SECTIONS'));
- my @result = ();
- foreach my $element (@$elements_list)
- {
- next if ($element->{'tag'} eq 'top');
- my $ind = ' ' x $current_level;
- my $level = $element->{'toc_level'};
- print STDERR "Bug no toc_level for ($element) $element->{'texi'}\n" if (!defined ($level));
- if ($level > $current_level)
- {
- while ($level > $current_level)
- {
- $current_level++;
- my $ln = "\n$ind".html_default_attribute_class('ul', $ul_class).">\n";
- $ind = ' ' x $current_level;
- push(@result, $ln);
- }
- }
- elsif ($level < $current_level)
- {
- while ($level < $current_level)
- {
- $current_level--;
- $ind = ' ' x $current_level;
- my $line = "</li>\n$ind</ul>";
- $line .= "</li>" if ($level == $current_level);
- push(@result, "$line\n");
- }
- }
- else
- {
- push(@result, "</li>\n");
- }
- my $dest_for_toc = $element->{'file'};
- my $dest_for_stoc = $element->{'file'};
- my $dest_target_for_stoc = $element->{'target'};
- $dest_for_toc = '' if ($dest_for_toc eq $toc_file);
- my $text = $element->{'text'};
- my $toc_entry = "<li>" . &$anchor ($element->{'tocid'}, "$dest_for_toc#$element->{'target'}",$text);
- push (@result, $ind . $toc_entry);
- }
- while (0 < $current_level)
- {
- $current_level--;
- my $ind = ' ' x $current_level;
- push(@result, "</li>\n$ind</ul>\n");
- }
- if (@result)
- {
- unshift @result, $BEFORE_TOC_LINES;
- push @result, $AFTER_TOC_LINES;
- }
- return \@result;
- }
- #$toc_body = \&T2H_GPL_toc_body;
- #$style = \&T2H_GPL_style;
- #$format = \&T2H_GPL_format;
- #$printindex = \&t2h_GPL_default_printindex;
- #$summary_letter = \&t2h_default_summary_letter;
- sub T2H_GPL_style($$$$$$$$$$)
- { # known style
- my $style = shift;
- my $command = shift;
- my $text = shift;
- my $args = shift;
- my $no_close = shift;
- my $no_open = shift;
- my $line_nr = shift;
- my $state = shift;
- my $style_stack = shift;
- my $kept_line_nrs = shift;
- my $do_quotes = 0;
- my $use_attribute = 0;
- my $use_begin_end = 0;
- my $inline_attribute = 0;
- if (ref($style) eq 'HASH')
- {
- #print STDERR "GPL_STYLE $command ($style)\n";
- #print STDERR " @$args\n";
- if (ref($style->{'args'}) ne 'ARRAY')
- {
- print STDERR "BUG: args not an array for command `$command'\n";
- }
- $do_quotes = $style->{'quote'};
- if (defined($style->{'function'}))
- {
- $text = &{$style->{'function'}}($command, $args, $style_stack, $state, $line_nr, $kept_line_nrs);
- }
- elsif (@{$style->{'args'}} == 1)
- {
- if (defined($style->{'inline_attribute'}))
- {
- $style = $style->{'inline_attribute'};
- $use_attribute = 1;
- $inline_attribute = 1;
- }
- elsif (defined($style->{'attribute'}))
- {
- $style = $style->{'attribute'};
- $use_attribute = 1;
- }
- #$text = $args->[0];
- }
- }
- else
- {
- if ($style =~ s/^\"//)
- { # add quotes
- $do_quotes = 1;
- }
- if ($style =~ s/^\&//)
- { # custom
- $style = 'Texi2HTML::Config::' . $style;
- eval "\$text = &$style(\$text, \$command, \$style_stack)";
- }
- elsif ($style ne '')
- {
- $use_attribute = 1;
- }
- else
- { # no style
- }
- }
- if ($use_attribute)
- {
- my ($attribute_text, $class);
- ($style, $class, $attribute_text) = html_default_parse_attribute ($style);
- $text = html_default_attribute_class($style, $class) . "$attribute_text>" . "$text" if (!$no_open or $inline_attribute);
- $text .= "</$style>" if (!$no_close or $inline_attribute);
- if ($do_quotes)
- {
- $text = get_conf('OPEN_QUOTE_SYMBOL') . "$text" if (!$no_open);
- $text .= get_conf('CLOSE_QUOTE_SYMBOL') if (!$no_close);
- }
- }
- if (ref($style) eq 'HASH')
- {
- if (defined($style->{'begin'}) and !$no_open)
- {
- $text = $style->{'begin'} . $text;
- }
- if (defined($style->{'end'}) and !$no_close)
- {
- $text = $text . $style->{'end'};
- }
- if (defined($style->{'inline_begin'}))
- {
- $text = $style->{'inline_begin'} . $text;
- }
- if (defined($style->{'inline_end'}))
- {
- $text = $text . $style->{'inline_end'};
- }
- }
- if ($do_quotes and !$use_attribute)
- {
- $text = get_conf('OPEN_QUOTE_SYMBOL') . "$text" if (!$no_open);
- $text .= get_conf('CLOSE_QUOTE_SYMBOL') if (!$no_close);
- }
- return $text;
- }
- sub T2H_GPL_format($$$)
- {
- my $tag = shift;
- my $element = shift;
- my $text = shift;
- return '' if (!defined($element) or ($text !~ /\S/));
- return $text if ($element eq '');
- my $attribute_text = '';
- if ($element =~ /^(\w+)(\s+.*)/)
- {
- $element = $1;
- $attribute_text = $2;
- }
- return "<${element}$attribute_text>\n" . $text. "</$element>\n";
- }
- # for each index holds the letters split as determined by SPLIT_INDEX.
- my %t2h_default_index_letters_array;
- # equivalent of doc_nr, but with files (and hence numbers) added when
- # a split index leads to an additional element and a file is created.
- my $t2h_default_file_number;
- # this is an increasing number to construct the id for each newly
- # created index element.
- my $t2h_default_index_id_nr;
- # this holds the file name associated with an element file, such
- # as to follow the splitting coming from the main program, and also use
- # the newly generated files.
- my %t2h_default_seen_files;
- # holds the elements and indices that are split to easily set the
- # directions after they are done in the main program.
- my $t2h_default_element_split_printindices;
- # construct a hash of index names holding the letter grouped how they will
- # be split.
- sub t2h_default_init_split_indices()
- {
- push @command_handler_process, \&t2h_default_index_rearrange_directions;
- %t2h_default_index_letters_array = ();
- %t2h_default_seen_files = ();
- $t2h_default_element_split_printindices = undef;
- $t2h_default_index_id_nr = 0;
- $t2h_default_file_number = 0;
- foreach my $index_name(keys %{$Texi2HTML::THISDOC{'index_letters_array'}})
- {
- my $entries_count = 0;
- my @letters = ();
- foreach my $letter_entry (@{$Texi2HTML::THISDOC{'index_letters_array'}->{$index_name}})
- {
- push @letters, $letter_entry;
- $entries_count += scalar(@{$letter_entry->{'entries'}});
- # Don't split if document is not split
- if (get_conf('SPLIT') and get_conf('SPLIT_INDEX') and $entries_count >= get_conf('SPLIT_INDEX'))
- {
- push @{$t2h_default_index_letters_array{$index_name}}, [ @letters ];
- @letters = ();
- $entries_count = 0;
- }
- }
- push @{$t2h_default_index_letters_array{$index_name}}, [ @letters ] if (scalar(@letters));
- }
- }
- sub t2h_default_associate_index_element($$$$)
- {
- my $element = shift;
- my $is_top = shift;
- my $docu_name = shift;
- my $use_node_file = shift;
- my $default_element_file = $element->{'file'};
- # redo the file naming -- the doc_nr part -- in case new elements were
- # inserted upon index split. But respect the default splitting to keep
- # the elements that are associated with the same file in the same file,
- # or the added file.
- if (!$use_node_file or $t2h_default_seen_files{$default_element_file})
- {
- my $file;
- if ($t2h_default_seen_files{$default_element_file})
- {
- $file = $t2h_default_seen_files{$default_element_file};
- }
- else
- {
- if ($is_top eq 'top')
- { # this is the element_top, so we keep docu_top as associated file.
- # this, in fact, is not necessary since the element_top is never
- # associated with another element, but who knows.
- $t2h_default_seen_files{$default_element_file} = $default_element_file;
- }
- else
- {
- $file = "${docu_name}_$t2h_default_file_number";
- $file .= '.' . get_conf('EXTENSION') if
- (defined(get_conf('EXTENSION')));
- $t2h_default_seen_files{$default_element_file} = $file;
- }
- $t2h_default_file_number++;
- }
- $element->{'file'} = $file if (defined($file));
- }
-
- my $level = $element->{'level'};
- # Even if, without USE_SECTION, output can be split at chapter or
- # section we don't split indices accordingly. We don't want to add
- # more cases where users want split indices, this was a very difficult
- # to maintain feature from the beginning.
- #$level = $element->{'with_section'}->{'level'} if (!defined($level) and
- # defined($element->{'with_section'}));
- # if the element is not the level of splitting, then we don't split.
- # also if 'top' is set we don't split since the formatting is different
- # in that case and the result would be quite unpredictable.
- return if ($element->{'top'} or ((get_conf('SPLIT') ne 'node')
- and (!defined($level) or $level > $Texi2HTML::THISDOC{'split_level'})));
- #print STDERR "Doing printindices for $element $element->{'texi'}, file $element->{'file'} (@{$element->{'place'}})\n";
- # iterate over the @places of the element, which includes associated nodes,
- # associated elements, anchors, footnotes, floats, index entries,
- # printindices (including the element command itself, be it a @node or
- # a sectioning @-command).
- # during the iteration, split printindices that needs it, and reassociate
- # other placed elements with files and elements.
- my $current_element = $element;
- my @places = @{$element->{'place'}};
- @{$element->{'place'}} = ();
- foreach my $place (@places)
- {
- my ($printindex, $printindex_to_split, $index_name);
- # determines if the placed thing is a printindex to be split
- if ($place->{'command'} and $place->{'command'} eq 'printindex')
- {
- $printindex = $place;
- $index_name = $printindex->{'name'};
- # ! empty index
- if (exists($t2h_default_index_letters_array{$index_name}) and
- # split index
- scalar(@{$t2h_default_index_letters_array{$index_name}} > 1)
- # the condition defined($printindex->{'associated_element'} implies
- # that we don't split printindex before first element, otherwise
- # there will be a need to begin document without a first element
- # which would be annoying.
- and defined($printindex->{'associated_element'}))
- {
- $printindex_to_split = 1;
- }
- }
-
- # this is a non split printindex or any other placed thing.
- if (!$printindex_to_split)
- {
- push @{$current_element->{'place'}}, $place;
- # don't remodify the original element file, it was set right at the
- # beginning of the function.
- $place->{'file'} = $current_element->{'file'} if ($place ne $element);
- # the 'element_ref' has to be reset. Otherwise, $place->{'element_ref'}
- # will appear as a new element and trigger closing the file and
- # opening a new one.
- $place->{'element_ref'} = $current_element if ($place->{'element_ref'} and $current_element ne $element);
- # this resets the element associated with a printindex.
- if ($place->{'associated_element'} and $current_element ne $element)
- {
- $place->{'associated_element'} = $current_element;
- }
- next;
- }
- # now split the index
- my @letter_groups = ();
- my @letters_split = @{$t2h_default_index_letters_array{$index_name}};
- foreach my $letters_split (@letters_split)
- {
- push @letter_groups, {'letters' => [@$letters_split]};
- }
- $letter_groups[0]->{'element'} = $current_element;
- # besides preparing the new elements corresponding with split indices,
- # they are recorded for later directions rearrangements in
- # t2h_default_index_rearrange_directions.
- # this weird construct is there because the element used as a key is
- # converted to a string by perl, losing its meaning as a reference,
- # the reference must be recorded explicitly
- $t2h_default_element_split_printindices->{$element}->{'element'} = $element;
- push @{$t2h_default_element_split_printindices->{$element}->{'printindices'}}, $printindex;
- #print STDERR "Setting $element, $element->{'texi'}, $printindex $printindex->{'name'} as a split element\n";
- foreach my $split_group (@letter_groups)
- {
- my $first_letter = $split_group->{'letters'}->[0]->{'letter'};
- my $last_letter = $split_group->{'letters'}->[-1]->{'letter'};
- if (!$split_group->{'element'})
- { # this is not the first letters group, which is already associated
- # with an element, a new element is done.
- # construct new element name
- my $letters_heading;
- if ($last_letter ne $first_letter)
- {
- $letters_heading = &$normal_text("$first_letter -- $last_letter");
- }
- else
- {
- $letters_heading = &$normal_text("$first_letter");
- }
- my ($name, $simple);
- my $texi = "ADDED ELEMENT $element->{'texi'}: $letters_heading";
- if (!defined($element->{'text'}))
- {
- my $element_heading_texi = &$heading_texi($element->{'tag'}, $element->{'texi'}, $element->{'number'});
- my $index_heading_texi = &$index_element_heading_texi(
- $element_heading_texi,
- $element->{'tag'},
- $element->{'texi'},
- $element->{'number'},
- $first_letter, $last_letter);
- $name = main::substitute_line($index_heading_texi, sprintf(__p("\@sectioning_command index page","\@%s index page"), $element->{'tag'}));
- $simple = main::simple_format(undef,undef,"simple_format \@$element->{'tag'} index page", $index_heading_texi);
- }
- else
- { # should never happen, at this point 'text' is always undefined.
- $name = "$element->{'text'}: $letters_heading";
- $simple = "$element->{'simple_format'}: $letters_heading";
- }
- #file and id
- my $relative_file = $Texi2HTML::THISDOC{'file_base_name'} . '_' . $t2h_default_file_number;
- $t2h_default_file_number++;
- $relative_file .= '.' . get_conf('EXTENSION') if
- (defined(get_conf('EXTENSION')));
- my $id = "index_split-$t2h_default_index_id_nr";
- $t2h_default_index_id_nr++;
- my $new_element = { 'file' => $relative_file, 'id' => $id, 'target' => $id, 'text' => $name, 'texi' => $texi, 'seen' => 1, 'simple_format' => $simple };
- # to avoid crashing when there is a filename collision.
- main::add_file($new_element->{'file'});
- $split_group->{'element'} = $new_element;
- $current_element = $new_element;
- #print STDERR "Added file $new_element->{'file'} ($new_element, $new_element->{'id'}) for $new_element->{'texi'} ($first_letter:$last_letter)\n";
- }
- else
- { # this is the first index split, it is still associated with the element
- #print STDERR "No file added for ($first_letter:$last_letter)\n";
- }
- }
- $t2h_default_seen_files{$default_element_file} = $current_element->{'file'};
- $printindex->{'split_groups'} = \@letter_groups;
- #print STDERR "$index_name processed for $element, $element->{'texi'} (@{$printindex->{'split_groups'}})\n";
- }
- }
- # set directions for added elements now that they are done in the
- # main program for all the other elements.
- sub t2h_default_index_rearrange_directions()
- {
- return if (!defined($t2h_default_element_split_printindices));
- foreach my $element_string (keys(%$t2h_default_element_split_printindices))
- {
- my $element = $t2h_default_element_split_printindices->{$element_string}->{'element'};
- my $current_element = $element;
- #print STDERR " E Processing $element_string,$current_element $current_element->{'texi'}\n";
- foreach my $printindex (@{$t2h_default_element_split_printindices->{$element_string}->{'printindices'}})
- {
- #print STDERR " I Processing $printindex $printindex->{'name'} (@{$printindex->{'split_groups'}})\n";
- foreach my $split_group (@{$printindex->{'split_groups'}})
- {
- my $first_letter = $split_group->{'letters'}->[0]->{'letter'};
- my $last_letter = $split_group->{'letters'}->[-1]->{'letter'};
- my $new_element = $split_group->{'element'};
- next if ($current_element eq $new_element);
- #print STDERR " G Processing ($first_letter:$last_letter) in $element->{'texi'}, index $printindex->{'name'}: $new_element->{'texi'}\n";
- $new_element->{'This'} = $new_element;
- if ($current_element->{'Forward'})
- {
- $current_element->{'Forward'}->{'Back'} = $new_element;
- $new_element->{'Forward'} = $current_element->{'Forward'};
- }
- $current_element->{'Forward'} = $new_element;
- $new_element->{'Back'} = $current_element;
- if ($current_element->{'NodeForward'})
- {
- #print STDERR "F: C($current_element): $current_element->{'texi'}, N($new_element): $new_element->{'texi'} -- C->F: $current_element->{'NodeForward'}->{'texi'}\n";
- $new_element->{'NodeForward'} = $current_element->{'NodeForward'};
- $current_element->{'NodeForward'} = $new_element;
- $new_element->{'NodeBack'} = $current_element;
- }
- foreach my $key ('FastForward', 'FastBack', 'Up', 'tag_level', 'tag',
- 'level', 'node')
- {
- $new_element->{$key} = $element->{$key} if (defined($element->{$key}));
- }
- $new_element->{'this'} = $new_element;
- $new_element->{'element_ref'} = $new_element;
- $current_element = $new_element;
- }
- }
- }
- }
- # not needed to initialize it for a document, since it is reset
- # in index_summary
- my $t2h_symbol_indices = 0;
- # format a letter appearing in a summary for an index. The letter links to
- # the place where the index elements beginning with this letter are (called
- # a letter entry).
- #
- # arguments:
- # letter
- # file where the target letter entry is
- # identifier for the target letter entry
- sub html_default_summary_letter($$$$$$$)
- {
- my $letter = shift;
- my $file = shift;
- my $default_identifier = shift;
- my $index_element_id = shift;
- my $number = shift;
- my $index_element = shift;
- my $index_name = shift;
- return '' if ($letter =~ /^\s*$/);
- my $is_symbol = $letter !~ /^[A-Za-z]/;
- my $identifier = $default_identifier;
- if (get_conf('NEW_CROSSREF_STYLE'))
- {
- if ($is_symbol)
- {
- $t2h_symbol_indices++;
- $identifier = $index_element_id . "_${index_name}_symbol-$t2h_symbol_indices";
- }
- else
- {
- $identifier = $index_element_id . "_${index_name}_letter-${letter}";
- }
- }
- my $result = &$anchor('', $file . '#' . $identifier, '<b>' . &$protect_text($letter) . '</b>', 'class="summary-letter"');
- return $result unless (get_conf('NEW_CROSSREF_STYLE'));
- return ($result, $identifier, $is_symbol);
- }
- # this replaces do_index_page
- # args should be:
- # index_name
- # printindex
- sub t2h_GPL_default_printindex($$)
- {
- my $index_name = shift;
- my $printindex = shift;
- # could be cross verified with argument
- my $identifier_index_nr = 0;
- my @split_letters;
-
- if (defined($printindex->{'split_groups'}) and scalar(@{$printindex->{'split_groups'}}))
- {
- @split_letters = @{$printindex->{'split_groups'}};
- }
- elsif (defined($Texi2HTML::THISDOC{'index_letters_array'}->{$index_name}) and scalar(@{$Texi2HTML::THISDOC{'index_letters_array'}->{$index_name}}))
- {
- my $element = $printindex->{'associated_element'};
- # this happens for printindex before the first element.
- if (!defined($element))
- {
- $element = {'file' => '', 'id' => "$printindex->{'region'}_printindex"};
- }
- elsif (defined($element->{'element_ref'}))
- {
- $element = $element->{'element_ref'};
- }
- @split_letters = ({ 'letters' => $Texi2HTML::THISDOC{'index_letters_array'}->{$index_name}, 'element' => $element});
- }
- else
- {
- return '';
- }
- foreach my $split_group (@split_letters)
- {
- #do summmary
- my @non_alpha = ();
- my @alpha = ();
- #print STDERR "$index_name @{$split_group->{'letters'}}\n";
- # letter_id could be done once for all instead of for each split_group
- # and outside of t2h_default_summary_letter (or t2h_default_summary_letter
- # could be simplified and inlined
- my %letter_id;
- foreach my $summary_split_group (@split_letters)
- {
- foreach my $letter_entry (@{$summary_split_group->{'letters'}})
- {
- my $letter = $letter_entry->{'letter'};
- my $dest_file = '';
-
- ####################################### debug
- if (!defined($summary_split_group->{'element'}))
- {
- main::msg_debug ("index $index_name, letter $letter, element for summary_split_group $summary_split_group not defined");
- }
- elsif (!defined($summary_split_group->{'element'}->{'id'}))
- {
- main::msg_debug ("index $index_name, letter $letter, element $summary_split_group->{'element'} `$summary_split_group->{'element'}->{'texi'}', id undef");
- }
- ####################################### end debug
- $dest_file = $summary_split_group->{'element'}->{'file'}
- if ($summary_split_group ne $split_group);
- my $index_element_id = $summary_split_group->{'element'}->{'id'};
- my $default_identifier = $index_element_id . "_$identifier_index_nr";
- #print STDERR "$split_group $summary_split_group $summary_split_group->{'element'} $summary_split_group->{'element'}->{'id'} $identifier_index_nr $index_element_id $default_identifier\n";
- $identifier_index_nr++;
- my ($result, $identifier, $is_symbol) =
- &$summary_letter($letter, $dest_file, $default_identifier, $index_element_id, '', '', $index_name);
- $identifier = $default_identifier if (!defined($identifier));
- $letter_id{$letter} = $identifier;
- $is_symbol = $letter !~ /^[A-Za-z]/ if (!defined($is_symbol));
- if ($result ne '')
- {
- if ($is_symbol)
- {
- push @non_alpha, $result;
- }
- else
- {
- push @alpha, $result;
- }
- }
- }
- }
- my $summary = &$index_summary(\@alpha, \@non_alpha);
- # reset symbols numbering
- $t2h_symbol_indices = 0;
- my $letters_text = '';
- foreach my $letter_entry (@{$split_group->{'letters'}})
- {
- my $letter = $letter_entry->{'letter'};
- my $entries_text = '';
- foreach my $index_entry_ref (@{$letter_entry->{'entries'}})
- {
- my ($text_href, $entry_file, $element_file, $entry_target,
- $entry_element_target, $formatted_entry, $element_href,
- $entry_element_text, $in_region_not_in_output)
- = main::get_index_entry_infos($index_entry_ref, $split_group->{'element'});
- $entries_text .= &$index_entry ($text_href, $formatted_entry, $element_href, $entry_element_text, $entry_file, $element_file, $entry_target, $entry_element_target, $in_region_not_in_output, $index_entry_ref);
- }
- $letters_text .= &$index_letter ($letter, $letter_id{$letter}, $entries_text)
- }
- my $index_text = &$print_index($letters_text, $index_name);
- $split_group->{'text'} = $summary . $index_text . $summary;
- # print STDERR " ---> $index_name @{$split_group->{'letters'}}
- # * elt: $split_group->{'element'}->{'id'}, $split_group->{'element'}->{'file'}, $split_group->{'element'}->{'name'}
- # * directions: B: $split_group->{'element'}->{'Back'}->{'name'}, F: $split_group->{'element'}->{'Forward'}->{'name'}, FB: $split_group->{'element'}->{'FastBack'}->{'name'}, FF: $split_group->{'element'}->{'FastForward'}->{'name'}
- # * text
- #
- #$split_group->{'text'}
- #
- #";
- }
- my $current_page = shift @split_letters;
- if (!scalar(@split_letters))
- {
- return $current_page->{'text'};
- }
- while (1)
- {
- # print the index letters
- push @{$Texi2HTML::THIS_SECTION}, $current_page->{'text'};
- $current_page = shift @split_letters;
- last if (!defined($current_page));
- # there is no need to begin first element if not already done, since
- # the index is not split if not already in an element.
- # end the previous element
- main::finish_element ($Texi2HTML::THISDOC{'FH'}, $Texi2HTML::THIS_ELEMENT, $Texi2HTML::THIS_ELEMENT->{'Forward'}, 0);
- # do the new element beginning
- $Texi2HTML::THIS_ELEMENT = $current_page->{'element'};
- my $new_element = $Texi2HTML::THIS_ELEMENT;
- main::unref_file($new_element->{'file'});
- main::do_element_directions($new_element);
- my $do_page_head = main::open_out_file($new_element->{'file'});
- if ($do_page_head)
- {
- &$print_page_head($Texi2HTML::THISDOC{'FH'});
- &$print_chapter_header($Texi2HTML::THISDOC{'FH'}, $new_element) if get_conf('SPLIT') eq 'chapter';
- &$print_section_header($Texi2HTML::THISDOC{'FH'}, $new_element) if get_conf('SPLIT') eq 'section';
- }
- # almost nothing of this is used in the default html output
- @{$Texi2HTML::THIS_SECTION} = &$element_heading($new_element, $new_element->{'tag'}, $new_element->{'texi'},
- $new_element->{'text'}, 0, 0, $new_element->{'this'}, 1, 0, 0, "\@$new_element->{'tag'} $new_element->{'texi'}",
- $new_element->{'id'}, $new_element);
- }
- return '';
- }
- # leave this within comments, and keep the require statement
- # This way, you can directly run texi2html.pl,
- # if $T2H_HOME/documentlanguages.pl exists.
- #
- # @T2H_DOCUMENT_LANGUAGES@
- require "$T2H_HOME/documentlanguages.pl"
- if ($0 =~ /\.pl$/ &&
- -e "$T2H_HOME/documentlanguages.pl" && -r "$T2H_HOME/documentlanguages.pl");
- # leave this within comments, and keep the require statement
- # This way, you can directly run texi2html.pl, if
- # $T2H_HOME/texi2html.pm exists.
- # @INIT@
- require "$T2H_HOME/texi2html.pm"
- if ($0 =~ /\.pl$/ &&
- -e "$T2H_HOME/texi2html.pm" && -r "$T2H_HOME/texi2html.pm");
- # @INIT_HTML@
- require "$T2H_HOME/formats/html.pm"
- if ($0 =~ /\.pl$/ &&
- -e "$T2H_HOME/formats/html.pm" && -r "$T2H_HOME/formats/html.pm");
- # @INIT_INFO@
- require "$T2H_HOME/formats/info.pm"
- if ($0 =~ /\.pl$/ &&
- -e "$T2H_HOME/formats/info.pm" && -r "$T2H_HOME/formats/info.pm");
- # @INIT_DOCBOOK@
- require "$T2H_HOME/formats/docbook.pm"
- if ($0 =~ /\.pl$/ &&
- -e "$T2H_HOME/formats/docbook.pm" && -r "$T2H_HOME/formats/docbook.pm");
- # @INIT_XML@
- require "$T2H_HOME/formats/xml.pm"
- if ($0 =~ /\.pl$/ &&
- -e "$T2H_HOME/formats/xml.pm" && -r "$T2H_HOME/formats/xml.pm");
- # @INIT_PLAINTEXT@
- require "$T2H_HOME/formats/plaintext.pm"
- if ($0 =~ /\.pl$/ &&
- -e "$T2H_HOME/formats/plaintext.pm" && -r "$T2H_HOME/formats/plaintext.pm");
- my $translation_file = 'translations.pl'; # file containing all the translations
- my $T2H_OBSOLETE_STRINGS;
- # leave this within comments, and keep the require statement
- # This way, you can directly run texi2html.pl,
- # if $T2H_HOME/translations.pl exists.
- #
- # @T2H_TRANSLATIONS_FILE@
- require "$T2H_HOME/$translation_file"
- if ($0 =~ /\.pl$/ &&
- -e "$T2H_HOME/$translation_file" && -r "$T2H_HOME/$translation_file");
- # these are unlikely to be used by users, as they are essentially
- # used to follow the html external refs specification in texinfo
- sub t2h_cross_manual_normal_text($$$$$$$;$)
- {
- my $text = shift;
- my $in_raw_text = shift;
- my $in_preformatted = shift;
- my $in_code =shift;
- my $in_math = shift;
- my $in_simple =shift;
- my $style_stack = shift;
- my $state = shift;
- $text = uc($text) if (in_small_caps($style_stack));
- return $text if (get_conf('USE_UNICODE'));
- return t2h_no_unicode_cross_manual_normal_text($text, 0);
- }
- sub t2h_cross_manual_normal_text_transliterate($$$$$$$;$)
- {
- my $text = shift;
- my $in_raw_text = shift;
- my $in_preformatted = shift;
- my $in_code =shift;
- my $in_math = shift;
- my $in_simple =shift;
- my $style_stack = shift;
- my $state = shift;
- $text = uc($text) if (in_small_caps($style_stack));
- return $text if (get_conf('USE_UNICODE'));
- return t2h_no_unicode_cross_manual_normal_text($text, 1);
- }
- sub t2h_no_unicode_cross_manual_normal_text($$)
- {
- # if there is no unicode support, we do all the transformations here
- my $text = shift;
- my $transliterate = shift;
- my $result = '';
-
- my $encoding = get_conf('documentencoding');
- if (defined($encoding) and exists($t2h_encoding_aliases{$encoding}))
- {
- $encoding = $t2h_encoding_aliases{$encoding};
- }
-
- while ($text ne '')
- {
- if ($text =~ s/^([A-Za-z0-9]+)//o)
- {
- $result .= $1;
- }
- elsif ($text =~ s/^ //o)
- {
- $result .= '-';
- }
- elsif ($text =~ s/^(.)//o)
- {
- if (exists($ascii_character_map{$1}))
- {
- $result .= '_' . lc($ascii_character_map{$1});
- }
- else
- {
- my $character = $1;
- my $charcode = uc(sprintf("%02x",ord($1)));
- my $done = 0;
- if (defined($encoding) and exists($eight_bit_to_unicode{$encoding})
- and exists($eight_bit_to_unicode{$encoding}->{$charcode}))
- {
- $done = 1;
- my $unicode_point = $eight_bit_to_unicode{$encoding}->{$charcode};
- if (!$transliterate)
- {
- $result .= '_' . lc($unicode_point);
- }
- elsif (exists($transliterate_map{$unicode_point}))
- {
- $result .= $transliterate_map{$unicode_point};
- }
- elsif (exists($unicode_diacritical{$unicode_point}))
- {
- $result .= '';
- }
- else
- {
- $done = 0;
- }
- }
- if (!$done)
- { # wild guess that work for latin1, and thus, should fail
- $result .= '_' . '00' . lc($charcode);
- }
- }
- }
- else
- {
- msg_debug("Bug: unknown character in cross ref (likely in infinite loop)");
- msg_debug("Text: !!$text!!");
- sleep 1;
- }
- }
-
- return $result;
- }
- sub t2h_nounicode_cross_manual_accent($$$)
- {
- my $accent = shift;
- my $args = shift;
- my $style_stack = shift;
-
- my $text = $args->[0];
- if ($accent eq 'dotless')
- {
- if (($text eq 'i') and (!defined($style_stack->[-1]) or (!defined($unicode_accents{$style_stack->[-1]})) or ($style_stack->[-1] eq 'tieaccent')))
- {
- return "_0131";
- }
- #return "\x{}" if ($text eq 'j'); # not found !
- return $text;
- }
- return '_' . lc($unicode_accents{$accent}->{$text})
- if (defined($unicode_accents{$accent}->{$text}));
- return ($text . '_' . lc($unicode_diacritical{$accent}))
- if (defined($unicode_diacritical{$accent}));
- return ascii_accents($text, $accent);
- }
- sub t2h_transliterate_cross_manual_accent($$)
- {
- my $accent = shift;
- my $args = shift;
-
- my $text = $args->[0];
- if (exists($unicode_accents{$accent}->{$text}) and
- exists ($transliterate_map{$unicode_accents{$accent}->{$text}}))
- {
- return $transliterate_map{$unicode_accents{$accent}->{$text}};
- }
- return $text;
- }
- } # end package Texi2HTML::Config
- # set the defaults based on real command name
- set_config_init_dirs_output($real_command_name);
- use vars qw(
- %value
- %alias
- );
- # variables which might be redefined by the user but aren't likely to be
- # they seem to be in the main namespace
- use vars qw(
- %index_names
- %index_prefix_to_name
- %predefined_index
- %valid_index
- %reference_sec2level
- %code_style_map
- %forbidden_index_name
- );
- # Some global variables are set in the script, and used in the subroutines
- # they are in the Texi2HTML namespace, thus prefixed with Texi2HTML::.
- # see texi2html.pm for details.
- #+++############################################################################
- # #
- # Pasted content of File $(srcdir)/MySimple.pm: Command-line processing #
- # #
- #---############################################################################
- # leave this within comments, and keep the require statement
- # This way, you can directly run texi2html.pl, if $T2H_HOME/MySimple.pm
- # exists.
- # @MYSIMPLE@
- require "$T2H_HOME/MySimple.pm"
- if ($0 =~ /\.pl$/ &&
- -e "$T2H_HOME/MySimple.pm" && -r "$T2H_HOME/MySimple.pm");
- #+++########################################################################
- # #
- # Pasted content of File $(srcdir)/T2h_i18n.pm: Internationalisation #
- # #
- #---########################################################################
- # leave this within comments, and keep the require statement
- # This way, you can directly run texi2html.pl, if $T2H_HOME/T2h_i18n.pm
- # exists.
- {
- # @T2H_I18N@
- require "$T2H_HOME/T2h_i18n.pm"
- if ($0 =~ /\.pl$/ &&
- -e "$T2H_HOME/T2h_i18n.pm" && -r "$T2H_HOME/T2h_i18n.pm");
- }
- #########################################################################
- #
- # latex2html code
- #
- #---######################################################################
- {
- # leave this within comments, and keep the require statement
- # This way, you can directly run texi2html.pl, if $ENV{T2H_HOME}/T2h_l2h.pm
- # exists.
- # @T2H_L2H@
- require "$T2H_HOME/T2h_l2h.pm"
- if ($0 =~ /\.pl$/ &&
- -e "$T2H_HOME/T2h_l2h.pm" && -r "$T2H_HOME/T2h_l2h.pm");
- }
- {
- package Texi2HTML::LaTeX2HTML::Config;
- # latex2html variables
- # These variables are not used. They are here for information only, and
- # an example of config file for latex2html file is included.
- my $ADDRESS;
- my $ANTI_ALIAS;
- my $ANTI_ALIAS_TEXT;
- my $ASCII_MODE;
- my $AUTO_LINK;
- my $AUTO_PREFIX;
- my $CHILDLINE;
- my $DEBUG;
- my $DESTDIR;
- my $DVIPS = 'dvips';
- my $ERROR;
- my $EXTERNAL_FILE;
- my $EXTERNAL_IMAGES;
- my $EXTERNAL_UP_LINK;
- my $EXTERNAL_UP_TITLE;
- my $FIGURE_SCALE_FACTOR;
- my $HTML_VERSION;
- my $IMAGES_ONLY;
- my $INFO;
- my $LINE_WIDTH;
- my $LOCAL_ICONS;
- my $LONG_TITLES;
- my $MATH_SCALE_FACTOR;
- my $MAX_LINK_DEPTH;
- my $MAX_SPLIT_DEPTH;
- my $NETSCAPE_HTML;
- my $NOLATEX;
- my $NO_FOOTNODE;
- my $NO_IMAGES;
- my $NO_NAVIGATION;
- my $NO_SIMPLE_MATH;
- my $NO_SUBDIR;
- my $PAPERSIZE;
- my $PREFIX;
- my $PS_IMAGES;
- my $REUSE;
- my $SCALABLE_FONTS;
- my $SHORTEXTN;
- my $SHORT_INDEX;
- my $SHOW_SECTION_NUMBERS;
- my $SPLIT;
- my $TEXDEFS;
- my $TITLE;
- my $TITLES_LANGUAGE;
- my $TMP;
- my $VERBOSE;
- my $WORDS_IN_NAVIGATION_PANEL_TITLES;
- my $WORDS_IN_PAGE;
- # @T2H_L2H_INIT@
- }
- package main;
- # functions related with configuration variables.
- sub get_conf($)
- {
- my $var = shift;
- return Texi2HTML::Config::get_conf($var);
- }
- sub set_from_cmdline($$)
- {
- my $var = shift;
- my $value = shift;
- my $level = 1;
- return Texi2HTML::Config::set_variable($var, $value, $level);
- }
- sub global_override($$)
- {
- my $var = shift;
- my $value = shift;
- return Texi2HTML::Config::set_variable($var, $value, undef);
- }
- sub document_override($$)
- {
- my $var = shift;
- my $value = shift;
- return Texi2HTML::Config::set_variable($var, $value, undef, 1);
- }
- sub set_from_document($$)
- {
- my $var = shift;
- my $value = shift;
- my $level = 5;
- return Texi2HTML::Config::set_variable($var, $value, $level, 1);
- }
- sub unset_from_document($)
- {
- my $var = shift;
- my $level = 5;
- return Texi2HTML::Config::unset_variable($var, $level, 1);
- }
- # prepare the gettext-like framework. To be noted that Locales::TextDomain
- # canot be used, since it cannot be used dynamically through a reuires.
- # Fortunately, Locales::TextDomain is a thin layer above Locales::Messages.
- Texi2HTML::Config::set_default('USE_NLS', ('@USE_NLS@' eq 'yes' or $0 =~ /\.pl$/));
- my $strings_textdomain = '@PACKAGE@' . '_document';
- $strings_textdomain = 'texi2html_document' if ($strings_textdomain eq '@'.'PACKAGE@' . '_document');
- my $messages_textdomain = '@PACKAGE@';
- $messages_textdomain = 'texi2html' if ($messages_textdomain eq '@'.'PACKAGE@');
- #my $messages_textdomain = 'texinfo';
- if (get_conf('USE_NLS'))
- {
- if ($0 =~ /\.pl$/)
- { # use in-source libintl when testing
- unshift @INC, "$T2H_HOME/lib/libintl-perl/lib";
- }
- elsif ($ENV{T2H_SOURCE_LIBINTL})
- {
- unshift @INC, $ENV{T2H_SOURCE_LIBINTL};
- }
- elsif ('@USE_EXTERNAL_LIBINTL@' ne 'yes')
- {
- unshift @INC, "$pkgdatadir/lib/libintl-perl/lib";
- }
- else
- {
- eval {
- require Locale::Messages;
- };
- if ($@)
- {
- unshift @INC, "$pkgdatadir/lib/libintl-perl/lib";
- }
- }
- # gettext-like translations
- #require Locale::TextDomain;
- require Locale::Messages;
- # we want a reliable way to switch locale, so we don't use the system
- # gettext.
- Locale::Messages->select_package ('gettext_pp');
- if ($0 =~ /\.pl$/)
- {
- # in case of out of source build, the locales directory should
- # be two levels below. $T2H_HOME is in srcdir.
- foreach my $locales_dir ("$T2H_HOME/locales", "../../locales")
- {
- if (-d $locales_dir)
- {
- Locale::Messages::bindtextdomain ($strings_textdomain, $locales_dir);
- last;
- }
- }
- }
- else
- { # match where gettext installs
- Locale::Messages::bindtextdomain ($strings_textdomain, "$datadir/locale");
- }
- # simply bind error messages to the installation directory.
- # Messages should be untranslated for tests.
- Locale::Messages::bindtextdomain ($messages_textdomain, "$datadir/locale");
- }
- sub __($)
- {
- my $msgid = shift;
- return Locale::Messages::dgettext($messages_textdomain, $msgid);
- }
- sub __p($$)
- {
- my $context = shift;
- my $msgid = shift;
- return Locale::Messages::dpgettext($messages_textdomain, $context, $msgid);
- }
- sub N__($)
- {
- return $_[0];
- }
- #
- # flush stdout and stderr after every write
- #
- select(STDERR);
- $| = 1;
- select(STDOUT);
- $| = 1;
- my $I = \&Texi2HTML::I18n::get_string;
- ########################################################################
- #
- # Global variable initialization
- #
- ########################################################################
- #
- # pre-defined indices
- #
- %index_prefix_to_name = ();
- %index_names =
- (
- 'cp' => {'cp' => 0,'c' => 0},
- 'fn' => {'fn' => 1, 'f' => 1},
- 'vr' => {'vr' => 1, 'v' => 1},
- 'ky' => {'ky' => 1, 'k' => 1},
- 'pg' => {'pg' => 1, 'p' => 1},
- 'tp' => {'tp' => 1, 't' => 1}
- );
- foreach my $name(keys(%index_names))
- {
- foreach my $prefix (keys %{$index_names{$name}})
- {
- $forbidden_index_name{$prefix} = 1;
- $index_prefix_to_name{$prefix} = $name;
- }
- }
- foreach my $other_forbidden_index_name ('info','ps','pdf','htm',
- 'log','aux','dvi','texi','txi','texinfo','tex','bib')
- {
- $forbidden_index_name{$other_forbidden_index_name} = 1;
- }
- # commands with ---, -- '' and `` preserved
- # usefull with the old interface
- %code_style_map = (
- 'code' => 1,
- 'command' => 1,
- 'env' => 1,
- 'file' => 1,
- 'kbd' => 1,
- 'option' => 1,
- 'samp' => 1,
- 'verb' => 1,
- );
- my @element_directions = ('Up', 'Forward', 'Back', 'Next', 'Prev',
- 'SectionNext', 'SectionPrev', 'SectionUp', 'FastForward', 'FastBack',
- 'This', 'NodeUp', 'NodePrev', 'NodeNext', 'NodeForward', 'NodeBack',
- 'NextFile', 'PrevFile', 'ToplevelNext', 'ToplevelPrev');
- $::simple_map_ref = \%Texi2HTML::Config::simple_map;
- $::simple_map_math_ref = \%Texi2HTML::Config::simple_map_math;
- #$::simple_map_pre_ref = \%Texi2HTML::Config::simple_map_pre;
- $::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi;
- $::style_map_ref = \%Texi2HTML::Config::style_map;
- $::style_map_pre_ref = \%Texi2HTML::Config::style_map_pre;
- $::style_map_math_ref = \%Texi2HTML::Config::style_map_math;
- $::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi;
- $::things_map_ref = \%Texi2HTML::Config::things_map;
- $::pre_map_ref = \%Texi2HTML::Config::pre_map;
- $::texi_map_ref = \%Texi2HTML::Config::texi_map;
- #print STDERR "MAPS: $::simple_map_ref $::simple_map_pre_ref $::simple_map_texi_ref $::style_map_ref $::style_map_pre_ref $::style_map_texi_ref $::things_map_ref $::pre_map_ref $::texi_map_ref\n";
- # delete from hash if we are using the new interface
- foreach my $code (keys(%code_style_map))
- {
- delete ($code_style_map{$code})
- if (ref($::style_map_ref->{$code}) eq 'HASH');
- }
- # no paragraph in these commands
- my %no_paragraph_macro = (
- 'xref' => 1,
- 'ref' => 1,
- 'pxref' => 1,
- 'inforef' => 1,
- 'anchor' => 1,
- );
- #
- # texinfo section names to level
- #
- my %reference_sec2level = (
- 'top', 0,
- 'chapter', 1,
- 'unnumbered', 1,
- 'chapheading', 1,
- 'appendix', 1,
- 'section', 2,
- 'unnumberedsec', 2,
- 'heading', 2,
- 'appendixsec', 2,
- 'subsection', 3,
- 'unnumberedsubsec', 3,
- 'subheading', 3,
- 'appendixsubsec', 3,
- 'subsubsection', 4,
- 'unnumberedsubsubsec', 4,
- 'subsubheading', 4,
- 'appendixsubsubsec', 4,
- );
- # the reverse mapping. There is an entry for each sectioning command.
- # The value is a ref on an array containing at each index the corresponding
- # sectioning command name.
- my %level2sec;
- {
- my $sections = [ ];
- my $appendices = [ ];
- my $unnumbered = [ ];
- my $headings = [ ];
- foreach my $command (keys (%reference_sec2level))
- {
- if ($command =~ /^appendix/)
- {
- $level2sec{$command} = $appendices;
- }
- elsif ($command =~ /^unnumbered/ or $command eq 'top')
- {
- $level2sec{$command} = $unnumbered;
- }
- elsif ($command =~ /section$/ or $command eq 'chapter')
- {
- $level2sec{$command} = $sections;
- }
- else
- {
- $level2sec{$command} = $headings;
- }
- $level2sec{$command}->[$reference_sec2level{$command}] = $command;
- }
- }
- # out of the main hierarchy
- $reference_sec2level{'part'} = 0;
- # this are synonyms
- $reference_sec2level{'appendixsection'} = 2;
- # sec2level{'majorheading'} is also 1 and not 0
- $reference_sec2level{'majorheading'} = 1;
- $reference_sec2level{'chapheading'} = 1;
- $reference_sec2level{'centerchap'} = 1;
- sub stop_paragraph_command($)
- {
- my $command = shift;
- return 1 if ($Texi2HTML::Config::stop_paragraph_command{$command} or defined($reference_sec2level{$command}));
- }
- sub set_no_line_macro($$)
- {
- my $macro = shift;
- my $value = shift;
- $Texi2HTML::Config::no_paragraph_commands{$macro} = $value
- unless defined($Texi2HTML::Config::no_paragraph_commands{$macro});
- }
- # those macros aren't considered as beginning a paragraph
- foreach my $no_line_macro ('alias', 'macro', 'unmacro', 'rmacro',
- 'titlefont', 'include', 'copying', 'end copying', 'tab', 'item',
- 'itemx', '*', 'float', 'end float', 'caption', 'shortcaption', 'cindex',
- 'image')
- {
- set_no_line_macro($no_line_macro, 1);
- }
- # holds all the @-commands that should be at the beginning of a line
- my %begin_line_command = ();
- foreach my $command ('node', 'end')
- {
- $begin_line_command{$command} = $command;
- }
- foreach my $key (keys(%Texi2HTML::Config::misc_command), keys(%reference_sec2level))
- {
- set_no_line_macro($key, 1);
- $begin_line_command{$key} = $key;
- }
- foreach my $misc_not_begin_line('comment', 'c', 'sp', 'refill', 'noindent', 'indent')
- {
- delete $begin_line_command{$misc_not_begin_line};
- }
- # a hash associating a format @thing / @end thing with the type of the format
- # 'complex_format' 'simple_format' 'deff' 'list' 'menu' 'paragraph_format'
- my %format_type = ();
- foreach my $simple_format (keys(%Texi2HTML::Config::format_map))
- {
- $format_type{$simple_format} = 'simple_format';
- }
- foreach my $paragraph_style (keys(%Texi2HTML::Config::paragraph_style))
- {
- $format_type{$paragraph_style} = 'paragraph_format';
- }
- # FIXME $complex_format_map obsoleted in nov 2009
- foreach my $complex_format (keys(%$Texi2HTML::Config::complex_format_map),
- keys(%Texi2HTML::Config::complex_format_map))
- {
- $format_type{$complex_format} = 'complex_format';
- }
- foreach my $table (('table', 'ftable', 'vtable'))
- {
- $format_type{$table} = 'table';
- }
- $format_type{'multitable'} = 'multitable';
- foreach my $def_format (keys(%Texi2HTML::Config::def_map))
- {
- $format_type{$def_format} = 'deff';
- }
- $format_type{'itemize'} = 'list';
- $format_type{'enumerate'} = 'list';
- $format_type{'menu'} = 'menu';
- $format_type{'detailmenu'} = 'menu';
- $format_type{'direntry'} = 'menu';
- $format_type{'cartouche'} = 'cartouche';
- $format_type{'float'} = 'float';
- $format_type{'quotation'} = 'quotation';
- $format_type{'smallquotation'} = 'quotation';
- $format_type{'group'} = 'group';
- my @special_regions = ('titlepage', 'copying', 'documentdescription');
- foreach my $region (@special_regions)
- {
- $format_type{$region} = 'region';
- }
- foreach my $key (keys(%format_type))
- {
- set_no_line_macro($key, 1);
- set_no_line_macro("end $key", 1);
- }
- foreach my $macro (keys(%Texi2HTML::Config::format_in_paragraph))
- {
- set_no_line_macro($macro, 1);
- set_no_line_macro("end $macro", 1);
- }
- foreach my $format (keys(%format_type))
- {
- $begin_line_command{$format} = $format_type{$format};
- }
- # fake format at the bottom of the stack
- $format_type{'noformat'} = '';
- # fake formats are formats used internally within other formats
- # we associate them with a real format, for the error messages
- my %fake_format = (
- 'line' => 'table',
- 'term' => 'table',
- 'item' => 'list or table',
- 'row' => 'multitable row',
- 'cell' => 'multitable cell',
- 'deff_item' => 'definition command',
- 'menu_comment' => 'menu',
- 'menu_description' => 'menu',
- );
- foreach my $key (keys(%fake_format))
- {
- $format_type{$key} = 'fake';
- }
- # raw formats which are expanded especially
- my @raw_regions = ('html', 'tex', 'xml', 'docbook');
- foreach my $format (keys(%Texi2HTML::Config::texi_formats_map), @raw_regions)
- {
- $begin_line_command{$format} = $format;
- }
- foreach my $format (keys(%Texi2HTML::Config::texi_formats_map))
- {
- push @raw_regions, $format if ($Texi2HTML::Config::texi_formats_map{$format} eq 'raw');
- }
- # The css formats are associated with complex format commands, and associated
- # with the 'pre_style' key
- # FIXME $complex_format_map obsoleted in nov 2009
- foreach my $complex_format (keys(%$Texi2HTML::Config::complex_format_map))
- {
- next if (defined($Texi2HTML::Config::complex_format_map->{$complex_format}->{'pre_style'}));
- $Texi2HTML::Config::complex_format_map->{$complex_format}->{'pre_style'} = '';
- $Texi2HTML::Config::complex_format_map->{$complex_format}->{'pre_style'} = $Texi2HTML::Config::css_map{"pre.$complex_format"} if (exists($Texi2HTML::Config::css_map{"pre.$complex_format"}));
- }
- # The css formats are associated with complex format commands, and associated
- # with the 'pre_style' key
- foreach my $complex_format (keys(%Texi2HTML::Config::complex_format_map))
- {
- next if (defined($Texi2HTML::Config::complex_format_map{$complex_format}->{'pre_style'}));
- $Texi2HTML::Config::complex_format_map{$complex_format}->{'pre_style'} = '';
- $Texi2HTML::Config::complex_format_map{$complex_format}->{'pre_style'} = $Texi2HTML::Config::css_map{"pre.$complex_format"} if (exists($Texi2HTML::Config::css_map{"pre.$complex_format"}));
- }
- #+++############################################################################
- # #
- # Argument parsing, initialisation #
- # #
- #---############################################################################
- # shorthand for get_conf('VERBOSE')
- my $T2H_VERBOSE;
- my $T2H_DEBUG;
- #
- # %value hold texinfo variables, see also -D, -U, @set and @clear.
- # we predefine html (the output format) and texi2html (the translator)
- # it is initialized with %value_initial at the beginning of the
- # document parsing and filled and emptied as @set and @clear are
- # encountered
- # FIXME remove html
- my %value_initial =
- (
- # 'html' => 1,
- 'texi2html' => $THISVERSION,
- );
- sub line_warn($$);
- sub document_warn($);
- sub file_line_warn($$;$);
- sub cmdline_warn ($);
- my $T2H_FAILURE_TEXT = sprintf(__("Try `%s --help' for more information.\n"), $real_command_name);
- #print STDERR "" . gdt('test i18n: \' , \a \\ %% %{unknown}a %known % %{known} \\', { 'known' => 'a known string', 'no' => 'nope'}); exit 0;
- sub add_to_texi2dvi_args($;$)
- {
- my $option = shift;
- my $value = shift;
- #print STDERR "$option $value\n";
- push @Texi2HTML::Config::TEXI2DVI_ARGUMENTS, $option;
- push @Texi2HTML::Config::TEXI2DVI_ARGUMENTS, $value if (defined($value));
- }
- # file: file name to locate. It can be a file path.
- # directories: a reference on a array containing a list of directories to
- # search the file in.
- # all_files: if true collect all the files with that name, otherwise stop
- # at first match.
- sub locate_init_file($$$)
- {
- my $file = shift;
- my $directories = shift;
- my $all_files = shift;
- if ($file =~ /^\//)
- {
- return $file if (-e $file and -r $file);
- }
- else
- {
- my @files;
- foreach my $dir (@$directories)
- {
- next unless (-d "$dir");
- if ($all_files)
- {
- push (@files, "$dir/$file") if (-e "$dir/$file" and -r "$dir/$file");
- }
- else
- {
- return "$dir/$file" if (-e "$dir/$file" and -r "$dir/$file");
- }
- }
- return @files if ($all_files);
- }
- return undef;
- }
- # called on -init-file
- sub load_init_file
- {
- # First argument is option
- shift;
- # second argument is value of options
- my $init_file = shift;
- my $file = locate_init_file($init_file, [ @Texi2HTML::Config::CONF_DIRS, @program_init_dirs ], 0);
- if ($file)
- {
- print STDERR "# reading initialization file from $file\n"
- if ($T2H_VERBOSE);
- # require the file in the Texi2HTML::Config namespace
- return (Texi2HTML::Config::load($file));
- }
- else
- {
- document_error ("Can't read init file $init_file");
- return 0;
- }
- }
- sub set_date($)
- {
- my $language = shift;
- if (!get_conf('TEST'))
- {
- print STDERR "# Setting date in $language\n" if ($T2H_DEBUG);
- set_from_document('today', Texi2HTML::I18n::pretty_date($language)); # like "20 September 1993";
- }
- else
- {
- set_from_document('today', 'a sunny day');
- }
- $::things_map_ref->{'today'} = get_conf('today');
- $::pre_map_ref->{'today'} = get_conf('today');
- $::texi_map_ref->{'today'} = get_conf('today');
- }
- sub warn_unknown_language($;$)
- {
- my $lang = shift;
- my $line_nr = shift;
- my $lang_code = $lang;
- my $region_code;
- if ($lang =~ /^([a-z]+)_([A-Z]+)/)
- {
- $lang_code = $1;
- $region_code = $2;
- }
- if (! $Texi2HTML::Config::language_codes{$lang_code})
- {
- msg_warn(sprintf(__("%s is not a valid language code"), $lang_code), $line_nr);
- }
- if (defined($region_code) and ! $Texi2HTML::Config::region_codes{$region_code})
- {
- msg_warn(sprintf(__("%s is not a valid region code"), $region_code), $line_nr);
- }
- }
- # Called on --document-language, at the beginning of each pass and
- # when a @documentlanguage appears
- sub set_document_language ($;$)
- {
- my $lang = shift;
- my $line_nr = shift;
- # Always succeed if using a gettext-like environment
- if (!get_conf('I18N_PERL_HASH'))
- {
- set_date($lang);
- return 1;
- }
- # old framework code
- my @langs = ($lang);
- my $main_lang;
- if ($lang =~ /^([a-z]+)_([A-Z]+)/)
- {
- $main_lang = $1;
- push @langs, $main_lang;
- }
- my @files = locate_init_file("$i18n_dir/$lang.thl", \@program_config_dirs, 1);
- if (! scalar(@files) and defined($main_lang))
- {
- @files = locate_init_file("$i18n_dir/$main_lang.thl", \@program_config_dirs, 1);
- }
- foreach my $file (@files)
- {
- Texi2HTML::Config::load($file);
- }
- foreach my $language (@langs)
- {
- if (Texi2HTML::I18n::set_language($language))
- {
- print STDERR "# using '$language' as document language\n" if ($T2H_VERBOSE);
- set_date($language);
- return 1;
- }
- }
- return 0;
- }
- # manage footnote style
- sub set_footnote_style($$;$)
- {
- my $value = shift;
- my $from_command_line = shift;
- my $line_nr = shift;
- my $command = 'footnotestyle';
- if ($value eq 'end' or $value eq 'separate')
- {
- if ($from_command_line)
- {
- set_from_cmdline($command, $value);
- }
- else
- {
- set_from_document($command, $value);
- }
- }
- elsif ($from_command_line)
- {
- die sprintf(__("%s: --footnote-style arg must be `separate' or `end', not `%s'.\n"), $real_command_name, $value);
- # the T2H_FAILURE_TEXT is output by getOption, seems to catch die
- }
- else
- {
- line_error (sprintf(__("\@%s arg must be `separate' or `end', not `%s'"), $command, $value), $line_nr);
- }
- }
- sub set_output($;$)
- {
- my $output = shift;
- my $from_command_line = shift;
- my $var = 'OUTFILE';
- if ($output =~ m:/$: or -d $output)
- {
- $var = 'SUBDIR';
- }
- if ($from_command_line)
- {
- set_from_cmdline($var, $output);
- set_from_cmdline('OUT', $output);
- add_to_texi2dvi_args('-o', $output);
- }
- else
- {
- set_default($var, $output);
- if (set_default('OUT', $output))
- {
- add_to_texi2dvi_args('-o', $output);
- }
- }
- }
- # used both for command line and @-command argument checking
- sub set_paragraphindent($$;$$)
- {
- my $value = shift;
- my $from_command_line = shift;
- my $line_nr = shift;
- my $pass = shift;
- my $command = 'paragraphindent';
- if ($value =~ /^([0-9]+)$/ or $value eq 'none' or $value eq 'asis')
- {
- if ($from_command_line)
- {
- set_from_cmdline($command, $value)
- }
- else
- {
- set_from_document($command, $value)
- }
- }
- elsif ($from_command_line)
- {
- die sprintf(__("%s: --paragraph-indent arg must be numeric/`none'/`asis', not `%s'.\n"), $real_command_name, $value);
- }
- elsif ($pass == 1)
- {
- line_error (sprintf(__("\@paragraphindent arg must be numeric/`none'/`asis', not `%s'"), $value), $line_nr);
- }
- }
- # find the encoding alias.
- # with encoding support (USE_UNICODE), may return undef if no alias was found.
- # The $line_nr argument should only be set when called from misc_command_texi
- # for @documentencoding, and so the error message should only be echoed at
- # that time.
- sub encoding_alias($;$$)
- {
- my $encoding = shift;
- my $line_nr = shift;
- my $context_string = shift;
- return undef if (!defined($encoding) or $encoding eq '');
- if (get_conf('USE_UNICODE'))
- {
- my $result_encoding = Encode::resolve_alias($encoding);
- if (! $result_encoding)
- {
- line_warn(sprintf(__("unrecognized encoding name `%s'"), $encoding), $line_nr);
- return undef;
- }
- if (defined($Texi2HTML::Config::t2h_encoding_aliases{$result_encoding}))
- {
- $result_encoding = $Texi2HTML::Config::t2h_encoding_aliases{$result_encoding};
- }
- print STDERR "# Using encoding $result_encoding\n" if ($T2H_VERBOSE);
- return $result_encoding;
- }
- else
- {
- if (exists($Texi2HTML::Config::t2h_encoding_aliases{$encoding}))
- {
- $encoding = $Texi2HTML::Config::t2h_encoding_aliases{$encoding};
- return $encoding;
- }
- line_warn(sprintf(__("Encoding %s certainly poorly supported"), $encoding), $line_nr);
- return $encoding;
- }
- }
- # libintl converts between encodings but doesn't decode them into the
- # perl internal format.
- sub encode_i18n_string($$)
- {
- my $string = shift;
- my $encoding = shift;
- if ($encoding ne 'us-ascii' and get_conf('USE_UNICODE')
- and Encode::resolve_alias($encoding))
- {
- return Encode::decode($encoding, $string);
- }
- return $string;
- }
- sub gdt($;$$)
- {
- my $message = shift;
- my $context = shift;
- my $state = shift;
- # FIXME this should be done only once, for @documentencoding
- my $encoding;
- my $input_encoding = get_conf('documentencoding');
- if (defined($input_encoding))
- {
- $encoding = lc($input_encoding);
- }
- if (defined($encoding) and $encoding ne '' and exists($Texi2HTML::Config::t2h_encoding_aliases{$encoding}))
- {
- $encoding = $Texi2HTML::Config::t2h_encoding_aliases{$encoding};
- }
- $encoding = 'us-ascii' if (!defined($encoding) or $encoding eq '');
- return &$I($message, $context, $state) if (get_conf('I18N_PERL_HASH'));
- # if set, use substitute_text instead of substitute_line
- my $allow_paragraph = $state->{'allow_paragraph'};
- # if duplicate is passed, it means that we are in the text and so should
- # use the main state
- if (defined($state) and $state->{'duplicate'} and defined($Texi2HTML::THISDOC{'state'}))
- {
- $state = main::duplicate_formatting_state($Texi2HTML::THISDOC{'state'});
- }
- my $result;
- # taken from libintl perl, copyright Guido. sub __expand. Overall not
- # enough code taken form Guido right now to be copyrightable.
- my $re = join '|', map { quotemeta $_ } keys %$context if (defined($context) and ref($context));
- if (get_conf('USE_NLS'))
- {
- my $saved_LANGUAGE = $ENV{'LANGUAGE'};
- Locale::Messages::textdomain($strings_textdomain);
-
- Locale::Messages::bind_textdomain_codeset($strings_textdomain, $encoding) if ($encoding ne 'us-ascii');
- Locale::Messages::bind_textdomain_filter($strings_textdomain, \&encode_i18n_string, $encoding);
- my $lang = get_conf('documentlanguage');
- my @langs = ($lang);
- if ($lang =~ /^([a-z]+)_([A-Z]+)/)
- {
- my $main_lang = $1;
- my $region_code = $2;
- push @langs, $main_lang;
- }
-
- my $locales = '';
- foreach my $language (@langs)
- {
- $locales .= "$language.$encoding:";
- #$locales .= "$language:";
- # always try us-ascii, the charset should always be a subset of
- # all charset, and should resort to @-commands if needed for non
- # ascii characters
- if ($encoding ne 'us-ascii')
- {
- $locales .= "$language.us-ascii:";
- }
- }
- $locales =~ s/:$//;
- #print STDERR "$locales\n";
- Locale::Messages::nl_putenv("LANGUAGE=$locales");
-
- if (!defined($context) or ref($context))
- {
- $result = Locale::Messages::gettext($message);
- }
- else
- {
- $result = Locale::Messages::pgettext($context, $message);
- }
- Locale::Messages::textdomain($messages_textdomain);
- # old perl complains 'Use of uninitialized value in scalar assignment'
- if (!defined($saved_LANGUAGE))
- {
- delete ($ENV{'LANGUAGE'});
- }
- else
- {
- $ENV{'LANGUAGE'} = $saved_LANGUAGE;
- }
- }
- # now perform the argument substitutions
- if ($state->{'keep_texi'})
- {
- # next line taken from libintl perl, copyright Guido. sub __expand
- $result =~ s/\{($re)\}/defined $context->{$1} ? $context->{$1} : "{$1}"/ge if (defined($re));
- return $result;
- }
- if (defined($re))
- {
- # next line taken from libintl perl, copyright Guido. sub __expand
- $result =~ s/\{($re)\}/\@internal_translation_open_brace\{\}$1\@internal_translation_close_brace\{\}/g;
- foreach my $map (\%Texi2HTML::Config::things_map, \%Texi2HTML::Config::pre_map, \%Texi2HTML::Config::texi_map, \%Texi2HTML::Config::simple_format_texi_map)
- {
- $map->{'internal_translation_open_brace'} = '{';
- $map->{'internal_translation_close_brace'} = '}';
- }
- }
- if ($allow_paragraph)
- {
- delete $state->{'allow_paragraph'};
- $result = substitute_text ($state, undef, __("translation"), ($result));
- }
- else
- {
- $result = substitute_line ($result, __("translation"), $state);
- }
- if (defined($re))
- {
- $result =~ s/\{($re)\}/defined $context->{$1} ? $context->{$1} : "{$1}"/ge;
- foreach my $map (\%Texi2HTML::Config::things_map, \%Texi2HTML::Config::pre_map, \%Texi2HTML::Config::texi_map, \%Texi2HTML::Config::simple_format_texi_map)
- {
- delete $map->{'internal_translation_open_brace'};
- delete $map->{'internal_translation_close_brace'};
- }
- }
- return $result;
- }
- sub unicode_to_protected($)
- {
- my $text = shift;
- my $result = '';
- while ($text ne '')
- {
- if ($text =~ s/^([A-Za-z0-9]+)//o)
- {
- $result .= $1;
- }
- elsif ($text =~ s/^ //o)
- {
- $result .= '-';
- }
- elsif ($text =~ s/^(.)//o)
- {
- my $char = $1;
- if (exists($Texi2HTML::Config::ascii_character_map{$char}))
- {
- $result .= '_' . lc($Texi2HTML::Config::ascii_character_map{$char});
- }
- else
- {
- if (ord($char) <= hex(0xFFFF))
- {
- $result .= '_' . lc(sprintf("%04x",ord($char)));
- }
- else
- {
- $result .= '__' . lc(sprintf("%06x",ord($char)));
- }
- }
- }
- else
- {
- print STDERR "Bug: unknown character in a cross ref (likely in infinite loop)\n";
- print STDERR "Text: !!$text!!\n";
- sleep 1;
- }
- }
- return $result;
- }
- sub unicode_to_transliterate($)
- {
- my $text = shift;
- if (chomp($text))
- {
- print STDERR "Strange: end of line to transliterate: $text\n";
- }
- my $result = '';
- while ($text ne '')
- {
- if ($text =~ s/^([A-Za-z0-9 ]+)//o)
- {
- $result .= $1;
- }
- elsif ($text =~ s/^(.)//o)
- {
- my $char = $1;
- if (exists($Texi2HTML::Config::ascii_character_map{$char}))
- {
- $result .= $char;
- }
- elsif (ord($char) <= hex(0xFFFF) and exists($Texi2HTML::Config::transliterate_map{uc(sprintf("%04x",ord($char)))}))
- {
- $result .= $Texi2HTML::Config::transliterate_map{uc(sprintf("%04x",ord($char)))};
- }
- elsif (ord($char) <= hex(0xFFFF) and exists($Texi2HTML::Config::unicode_diacritical{uc(sprintf("%04x",ord($char)))}))
- {
- $result .= '';
- }
- # in this case, we want to avoid calling unidecode, as we are sure
- # that there is no useful transliteration of the unicode character
- # instead we want to keep it as is.
- # This is the case, for example, for @exclamdown, is corresponds
- # with x00a1, but unidecode transliterates it to a !, we want
- # to avoid that and keep x00a1.
- elsif (ord($char) <= hex(0xFFFF) and exists($Texi2HTML::Config::no_transliterate_map{uc(sprintf("%04x",ord($char)))}))
- {
- $result .= $char;
- }
- else
- {
- if (get_conf('USE_UNIDECODE'))
- {
- $result .= unidecode($char);
- }
- else
- {
- $result .= $char;
- }
- }
- }
- else
- {
- print STDERR "Bug: unknown character in cross ref transliteration (likely in infinite loop)\n";
- print STDERR "Text: !!$text!!\n";
- sleep 1;
- }
- }
- return $result;
- }
- # T2H_OPTIONS is a hash whose keys are the (long) names of valid
- # command-line options and whose values are a hash with the following keys:
- # type ==> one of !|=i|:i|=s|:s (see Getopt::Long for more info)
- # linkage ==> ref to scalar, array, or subroutine (see Getopt::Long for more info)
- # verbose ==> short description of option (displayed by -h)
- # noHelp ==> if 1 -> for "not so important options": only print description on -h 1
- # 2 -> for obsolete options: only print description on -h 2
- my $T2H_OPTIONS;
- $T2H_OPTIONS -> {'macro-expand|E'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('MACRO_EXPAND', $_[1]); add_to_texi2dvi_args('-E'); },
- 'verbose' => 'output macro expanded source in <file>',
- };
- $T2H_OPTIONS -> {'ifhtml'} =
- {
- 'type' => '!',
- 'linkage' => sub { Texi2HTML::Config::set_expansion('html', $_[1]); },
- 'verbose' => "expand ifhtml and html sections",
- };
- $T2H_OPTIONS -> {'ifinfo'} =
- {
- 'type' => '!',
- 'linkage' => sub { Texi2HTML::Config::set_expansion('info', $_[1]); },
- 'verbose' => "expand ifinfo",
- };
- $T2H_OPTIONS -> {'ifxml'} =
- {
- 'type' => '!',
- 'linkage' => sub { Texi2HTML::Config::set_expansion('xml', $_[1]); },
- 'verbose' => "expand ifxml and xml sections",
- };
- $T2H_OPTIONS -> {'ifdocbook'} =
- {
- 'type' => '!',
- 'linkage' => sub { Texi2HTML::Config::set_expansion('docbook', $_[1]); },
- 'verbose' => "expand ifdocbook and docbook sections",
- };
- $T2H_OPTIONS -> {'iftex'} =
- {
- 'type' => '!',
- 'linkage' => sub { Texi2HTML::Config::set_expansion('tex', $_[1]); },
- 'verbose' => "expand iftex and tex sections",
- };
- $T2H_OPTIONS -> {'ifplaintext'} =
- {
- 'type' => '!',
- 'linkage' => sub { Texi2HTML::Config::set_expansion('plaintext', $_[1]); },
- 'verbose' => "expand ifplaintext sections",
- };
- $T2H_OPTIONS -> {'I'} =
- {
- 'type' => '=s',
- 'linkage' => sub { add_to_texi2dvi_args('-'.$_[0], $_[1]); push @Texi2HTML::Config::INCLUDE_DIRS, $_[1] },
- 'verbose' => 'append $s to the @include search path',
- };
- $T2H_OPTIONS -> {'conf-dir'} =
- {
- 'type' => '=s',
- 'linkage' => \@Texi2HTML::Config::CONF_DIRS,
- 'verbose' => 'append $s to the init file directories',
- };
- $T2H_OPTIONS -> {'P'} =
- {
- 'type' => '=s',
- 'linkage' => sub {unshift (@Texi2HTML::Config::PREPEND_DIRS, $_[1]);},
- 'verbose' => 'prepend $s to the @include search path',
- };
- $T2H_OPTIONS -> {'number-sections'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('NUMBER_SECTIONS', $_[1]);},
- 'verbose' => 'output chapter and sectioning numbers.',
- };
- $T2H_OPTIONS -> {'number-footnotes'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('NUMBER_FOOTNOTES', $_[1]);},
- 'verbose' => 'output footnote numbers.',
- };
- $T2H_OPTIONS -> {'node-files'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('NODE_FILES', $_[1]);},
- 'verbose' => 'produce one file per node for cross references'
- };
- $T2H_OPTIONS -> {'footnote-style|s'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_footnote_style ($_[1], 1);},
- 'verbose' => 'output footnotes separate|end',
- };
- $T2H_OPTIONS -> {'split'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('SPLIT', $_[1])},
- 'verbose' => 'split document on section|chapter|node else no splitting',
- };
- $T2H_OPTIONS -> {'no-split'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('SPLIT', ''); set_from_cmdline('SPLIT_SIZE', undef);},
- 'verbose' => 'no splitting of document',
- 'noHelp' => 1,
- };
- $T2H_OPTIONS -> {'headers'} =
- {
- 'type' => '!',
- 'linkage' => sub {
- set_from_cmdline('HEADERS', $_[1]);
- set_from_cmdline('SHOW_MENU', $_[1]);
- Texi2HTML::Config::t2h_default_load_format('plaintext', 1)
- if (!$_[1] and defined($Texi2HTML::Config::OUTPUT_FORMAT) and $Texi2HTML::Config::OUTPUT_FORMAT eq 'info');
- },
- 'verbose' => 'output navigation headers for each section',
- };
- $T2H_OPTIONS -> {'output|out|o'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_output($_[1], 1);},
- 'verbose' => 'output goes to $s (directory if split)',
- };
- $T2H_OPTIONS -> {'no-validate|no-pointer-validate'} =
- {
- 'type' => '',
- 'linkage' => sub {set_from_cmdline('novalidate',$_[1])},
- 'verbose' => 'suppress node cross-reference validation',
- };
- $T2H_OPTIONS -> {'no-warn'} =
- {
- 'type' => '',
- 'linkage' => sub {set_from_cmdline('NO_WARN', $_[1]);},
- 'verbose' => 'suppress warnings (but not errors).'
- };
- $T2H_OPTIONS -> {'verbose'} = 0;
- $T2H_OPTIONS -> {'verbose|v'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('VERBOSE', $_[1]); add_to_texi2dvi_args('--verbose'); },
- 'verbose' => 'print progress info to stdout',
- };
- $T2H_OPTIONS -> {'document-language'} =
- {
- 'type' => '=s',
- 'linkage' => sub {
- warn_unknown_language ($_[1]);
- set_from_cmdline('documentlanguage', $_[1])
- },
- 'verbose' => 'use $s as document language',
- };
- $T2H_OPTIONS -> {'D'} =
- {
- 'type' => '=s',
- 'linkage' => sub {$value_initial{$_[1]} = 1;},
- 'verbose' => 'equivalent to Texinfo "@set $s 1"',
- 'noHelp' => 1,
- };
- $T2H_OPTIONS -> {'U'} =
- {
- 'type' => '=s',
- 'linkage' => sub {delete $value_initial{$_[1]};},
- 'verbose' => 'equivalent to Texinfo "@clear $s"',
- 'noHelp' => 1,
- };
- $T2H_OPTIONS -> {'init-file'} =
- {
- 'type' => '=s',
- 'linkage' => \&load_init_file,
- 'verbose' => 'load init file $s'
- };
- $T2H_OPTIONS -> {'set-init-variable'} =
- {
- 'type' => '=s',
- 'linkage' => sub { my $var_val = $_[1];
- if ($var_val =~ s/^(\w+)\s*=?\s*//)
- {
- my $var = $1;
- my $value = $var_val;
- if ($value =~ /^undef$/i)
- {
- $value = undef;
- }
- set_from_cmdline ($var, $value);
- }
- },
- 'verbose' => 'set an init file variable to a value'
- };
- $T2H_OPTIONS -> {'css-include'} =
- {
- 'type' => '=s',
- 'linkage' => \@Texi2HTML::Config::CSS_FILES,
- 'verbose' => 'use css file $s'
- };
- $T2H_OPTIONS -> {'css-ref'} =
- {
- 'type' => '=s',
- 'linkage' => \@Texi2HTML::Config::CSS_REFS,
- 'verbose' => 'generate reference to the CSS URL $s'
- };
- $T2H_OPTIONS -> {'transliterate-file-names'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('TRANSLITERATE_FILE_NAMES', $_[1]);},
- 'verbose' => 'produce file names in ASCII transliteration',
- };
- $T2H_OPTIONS -> {'error-limit|e'} =
- {
- 'type' => '=i',
- 'linkage' => sub {set_from_cmdline('ERROR_LIMIT', $_[1]);},
- 'verbose' => 'quit after NUM errors (default '.get_conf('ERROR_LIMIT').').',
- };
- $T2H_OPTIONS -> {'split-size'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('SPLIT_SIZE', $_[1])},
- 'verbose' => 'split Info files at size s (default '.get_conf('SPLIT_SIZE').').',
- };
- $T2H_OPTIONS -> {'paragraph-indent|p'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_paragraphindent($_[1], 1);},
- 'verbose' => "indent Info paragraphs by VAL spaces (default ".get_conf('paragraphindent').").
- If VAL is `none', do not indent; if VAL is
- `asis', preserve existing indentation.",
- };
- $T2H_OPTIONS -> {'fill-column|f'} =
- {
- 'type' => '=i',
- 'linkage' => sub {set_from_cmdline('FILLCOLUMN',$_[1]);},
- 'verbose' => "break Info lines at NUM characters (default ".get_conf('FILLCOLUMN').")",
- };
- $T2H_OPTIONS -> {'enable-encoding'} =
- {
- 'type' => '',
- 'linkage' => sub {set_from_cmdline('ENABLE_ENCODING', $_[1]);},
- 'verbose' => 'override --disable-encoding (default in Info).',
- };
- $T2H_OPTIONS -> {'disable-encoding'} =
- {
- 'type' => '',
- 'linkage' => sub {set_from_cmdline('ENABLE_ENCODING', 0);},
- 'verbose' => 'do not output accented and special characters
- in Info output based on @documentencoding.',
- };
- $T2H_OPTIONS -> {'internal-links'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('INTERNAL_LINKS', $_[1]);},
- 'verbose' => 'produce list of internal links in FILE.'
- };
- $T2H_OPTIONS -> {'force|F'} =
- { 'type' => '!',
- 'linkage' => sub {set_from_cmdline('FORCE', $_[1]);},
- 'verbose' => 'preserve output even if errors.'
- };
- $T2H_OPTIONS -> {'commands-in-node-names'} =
- {
- 'type' => '!',
- 'verbose' => 'Always set',
- 'noHelp' => 1
- };
- $T2H_OPTIONS -> {'output-indent'} =
- {
- 'type' => '=i',
- 'verbose' => 'This option used to indent XML, it is ignored',
- 'noHelp' => 1
- };
- $T2H_OPTIONS -> {'program'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_config_init_dirs_output($_[1]);},
- 'verbose' => 'Call as $s, setting corresponding defaults'
- };
- $T2H_OPTIONS -> {'reference-limit' } =
- {
- 'type' => '=i',
- 'verbose' => 'Does nothing, retained for backward compatibility',
- 'noHelp' => 2
- };
- #$T2H_OPTIONS -> {'command'} =
- #{
- # 'type' => '=s',
- # 'linkage' => \@Texi2HTML::Config::COMMANDS,
- # 'verbose' => 'insert CMD in copy of input file'
- #};
- $T2H_OPTIONS -> {'Xopt'} =
- {
- 'type' => '=s',
- 'linkage' => \@Texi2HTML::Config::TEXI2DVI_ARGUMENTS,
- 'verbose' => 'pass argument to the dvi/pdf converter.',
- };
- $T2H_OPTIONS -> {'batch'} =
- {
- 'type' => '',
- 'linkage' => sub {set_from_cmdline('BATCH', $_[1]); add_to_texi2dvi_args('--'.$_[0]);},
- 'noHelp' => 2
- };
- $T2H_OPTIONS -> {'silent|quiet'} =
- {
- 'type' => '',
- 'linkage' => sub {set_from_cmdline('SILENT', $_[1]); add_to_texi2dvi_args('--'.$_[0]);},
- 'noHelp' => 2
- };
- my $call_texi2dvi = 0;
- foreach my $output_format (keys(%Texi2HTML::Config::output_format_names))
- {
- next if (defined($Texi2HTML::Config::DEFAULT_OUTPUT_FORMAT) and $output_format eq $Texi2HTML::Config::DEFAULT_OUTPUT_FORMAT);
- my $linkage;
- if ($Texi2HTML::Config::texi2dvi_formats{$output_format})
- {
- $linkage = sub {add_to_texi2dvi_args('--'.$_[0]); $call_texi2dvi = 1;
- Texi2HTML::Config::t2h_default_load_format($_[0], 1);};
- }
- else
- {
- $linkage = sub {Texi2HTML::Config::t2h_default_load_format($_[0], 1);};
- }
- $T2H_OPTIONS -> {$output_format} =
- {
- 'type' => '',
- 'linkage' => $linkage,
- 'verbose' => "output $Texi2HTML::Config::output_format_names{$output_format} rather than $Texi2HTML::Config::output_format_names{$Texi2HTML::Config::DEFAULT_OUTPUT_FORMAT}.",
- }
- };
- $T2H_OPTIONS -> {$Texi2HTML::Config::DEFAULT_OUTPUT_FORMAT} =
- {
- 'type' => '',
- 'linkage' => sub {Texi2HTML::Config::t2h_default_load_format($_[0], 1);},
- 'verbose' => "output default format.",
- 'noHelp' => 2
- };
- $T2H_OPTIONS -> {'debug'} =
- {
- 'type' => '=i',
- 'linkage' => sub {set_from_cmdline('DEBUG', $_[1]), add_to_texi2dvi_args('--'.$_[0]); },
- 'verbose' => 'output debuging information',
- 'noHelp' => 1,
- };
- ##
- ## obsolete cmd line options
- ##
- my $T2H_OBSOLETE_OPTIONS;
- $T2H_OBSOLETE_OPTIONS -> {'subdir'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('SUBDIR', $_[1]);},
- 'verbose' => 'put files in directory $s, not $cwd',
- 'noHelp' => 1,
- };
- # actually a noop, since it is not used anywhere
- $T2H_OBSOLETE_OPTIONS -> {'invisible'} =
- {
- 'type' => '=s',
- 'verbose' => 'Not used',
- 'noHelp' => 2,
- };
- $T2H_OBSOLETE_OPTIONS -> {'toc-links'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('TOC_LINKS', $_[1]);},
- 'verbose' => 'create links from headings to toc entries',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'short-ext'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('SHORTEXTN', $_[1]);},
- 'verbose' => 'use "htm" extension for output HTML files',
- 'noHelp' => 1,
- };
- # FIXME this is not that helpful as a message, as reported by
- # Jens Schleusener one could imagine that absolute paths are
- # accepted.
- $T2H_OBSOLETE_OPTIONS -> {'prefix'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('PREFIX', $_[1]);},
- 'verbose' => 'use as prefix for output files, instead of <docname>',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'short-ref'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('SHORT_REF', $_[1]);},
- 'verbose' => 'if set, references are without section numbers',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'idx-sum'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('IDX_SUMMARY', $_[1]);},
- 'verbose' => 'if set, also output index summary',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'def-table'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('DEF_TABLE', $_[1]);},
- 'verbose' => 'if set, \@def.. are converted using tables.',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'ignore-preamble-text'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('IGNORE_PREAMBLE_TEXT', $_[1]);},
- 'verbose' => 'if set, ignore the text before @node and sectioning commands',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'html-xref-prefix'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('EXTERNAL_DIR', $_[1]);},
- 'verbose' => '$s is the base dir for external manual references',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'l2h'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('L2H', $_[1]);},
- 'verbose' => 'if set, uses latex2html for @math and @tex',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'l2h-l2h'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('L2H_L2H', $_[1]);},
- 'verbose' => 'program to use for latex2html translation',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'l2h-skip'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('L2H_SKIP', $_[1]);},
- 'verbose' => 'if set, tries to reuse previously latex2html output',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'l2h-tmp'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('L2H_TMP', $_[1]);},
- 'verbose' => 'if set, uses $s as temporary latex2html directory',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'l2h-file'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('L2H_FILE', $_[1]);},
- 'verbose' => 'if set, uses $s as latex2html init file',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'l2h-clean'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('L2H_CLEAN', $_[1]);},
- 'verbose' => 'if set, do not keep intermediate latex2html files for later reuse',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'use-nodes'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('USE_NODES', $_[1]);},
- 'verbose' => 'use nodes for sectioning',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'monolithic'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('MONOLITHIC', $_[1]);},
- 'verbose' => 'output only one file including ToC, About...',
- 'noHelp' => 1
- };
- $T2H_OBSOLETE_OPTIONS -> {'top-file'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('TOP_FILE', $_[1]);},
- 'verbose' => 'use $s as top file, instead of <docname>.html',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'toc-file'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('TOC_FILE', $_[1]);},
- 'verbose' => 'use $s as ToC file, instead of <docname>_toc.html',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'frames'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('FRAMES', $_[1])},
- 'verbose' => 'output files which use HTML 4.0 frames (experimental)',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'menu'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('SHOW_MENU', $_[1]);},
- 'verbose' => 'output Texinfo menus',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'iso'} =
- {
- 'type' => 'iso',
- 'linkage' => sub {Texi2HTML::Config::t2h_default_set_iso_symbols ($_[1], 1);},
- 'verbose' => 'if set, entities are used for special symbols (like copyright, etc...) and quotes',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'doctype'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('DOCTYPE', $_[1]);},
- 'verbose' => 'document type which is output in header of HTML files',
- 'noHelp' => 1
- };
- $T2H_OBSOLETE_OPTIONS -> {'frameset-doctype'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('FRAMESET_DOCTYPE', $_[1]);},
- 'verbose' => 'document type for HTML frameset documents',
- 'noHelp' => 1
- };
- $T2H_OBSOLETE_OPTIONS -> {'test'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('TEST', $_[1]);},
- 'verbose' => 'use predefined information to avoid differences with reference files',
- 'noHelp' => 1
- };
- $T2H_OBSOLETE_OPTIONS -> {'dump-texi'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('DUMP_TEXI', $_[1]);},
- 'verbose' => 'dump the output of first pass into a file with extension passfirst and exit',
- 'noHelp' => 1
- };
- $T2H_OBSOLETE_OPTIONS -> {'expand'} =
- {
- 'type' => '=s',
- 'linkage' => sub {Texi2HTML::Config::set_expansion($_[1], 1);},
- 'verbose' => 'Expand <s> section of texinfo source',
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'no-expand'} =
- {
- 'type' => '=s',
- 'linkage' => sub {Texi2HTML::Config::set_expansion ($_[1], 0);},
- 'verbose' => 'Don\'t expand the given section of texinfo source',
- };
- $T2H_OBSOLETE_OPTIONS -> {'noexpand'} =
- {
- 'type' => '=s',
- 'linkage' => $T2H_OBSOLETE_OPTIONS->{'no-expand'}->{'linkage'},
- 'verbose' => $T2H_OBSOLETE_OPTIONS->{'no-expand'}->{'verbose'},
- 'noHelp' => 1,
- };
- $T2H_OBSOLETE_OPTIONS -> {'out-file'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('OUTFILE', $_[1]); set_from_cmdline('SPLIT', '');},
- 'verbose' => 'if set, all HTML output goes into file $s, obsoleted by "-output" with different semantics',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {'lang'} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('documentlanguage', $_[1])},
- 'verbose' => 'obsolete, use "--document-language" instead',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {'separated-footnotes'} =
- {
- 'type' => '!',
- 'linkage' => sub {my $style = 'separate'; $style = 'end' if !$_[1]; set_footnote_style ($style, 1);},
- 'verbose' => 'obsolete, use "--footnote-style" instead',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {'Verbose'} =
- {
- 'type' => '!',
- linkage=> sub {set_from_cmdline('VERBOSE', $_[1]);},
- 'verbose' => 'obsolete, use "--verbose" instead',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {init_file} =
- {
- 'type' => '=s',
- 'linkage' => \&load_init_file,
- 'verbose' => 'obsolete, use "-init-file" instead',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {l2h_clean} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('L2H_CLEAN', $_[1]);},
- 'verbose' => 'obsolete, use "-l2h-clean" instead',
- 'noHelp' => 2,
- };
- $T2H_OBSOLETE_OPTIONS -> {l2h_l2h} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('L2H_L2H', $_[1]);},
- 'verbose' => 'obsolete, use "-l2h-l2h" instead',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {l2h_skip} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('L2H_SKIP', $_[1]);},
- 'verbose' => 'obsolete, use "-l2h-skip" instead',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {l2h_tmp} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('L2H_TMP', $_[1]);},
- 'verbose' => 'obsolete, use "-l2h-tmp" instead',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {out_file} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('OUTFILE', $_[1]); set_from_cmdline('SPLIT', '');},
- 'verbose' => 'obsolete, use "-out-file" instead',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {short_ref} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('SHORT_REF', $_[1]);},
- 'verbose' => 'obsolete, use "-short-ref" instead',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {idx_sum} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('IDX_SUMMARY', $_[1]);},
- 'verbose' => 'obsolete, use "-idx-sum" instead',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {def_table} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('DEF_TABLE', $_[1]);},
- 'verbose' => 'obsolete, use "-def-table" instead',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {short_ext} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('SHORTEXTN', $_[1]);},
- 'verbose' => 'obsolete, use "-short-ext" instead',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {sec_nav} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('HEADERS', $_[1]);},
- 'verbose' => 'obsolete, use "-headers" instead',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {'sec-nav'} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('HEADERS', $_[1]);},
- 'verbose' => 'obsolete, use "--header" instead',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {top_file} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('TOP_FILE', $_[1]);},
- 'verbose' => 'obsolete, use "-top-file" instead',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {toc_file} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('TOC_FILE', $_[1]);},
- 'verbose' => 'obsolete, use "-toc-file" instead',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {glossary} =
- {
- 'type' => '!',
- 'verbose' => "this does nothing",
- 'noHelp' => 2,
- };
- $T2H_OBSOLETE_OPTIONS -> {check} =
- {
- 'type' => '!',
- 'linkage' => sub {exit 0;},
- 'verbose' => "exit without doing anything",
- 'noHelp' => 2,
- };
- $T2H_OBSOLETE_OPTIONS -> {dump_texi} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('DUMP_TEXI', $_[1]);},
- 'verbose' => 'obsolete, use "-dump-texi" instead',
- 'noHelp' => 1
- };
- $T2H_OBSOLETE_OPTIONS -> {frameset_doctype} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('FRAMESET_DOCTYPE', $_[1]);},
- 'verbose' => 'obsolete, use "-frameset-doctype" instead',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {use_acc} =
- {
- 'type' => '!',
- 'verbose' => 'obsolete, set to true unconditionnaly',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {expandinfo} =
- {
- 'type' => '!',
- 'linkage' => sub {push @Texi2HTML::Config::EXPAND, 'info';},
- 'verbose' => 'obsolete, use "--ifinfo" instead',
- 'noHelp' => 2,
- };
- $T2H_OBSOLETE_OPTIONS -> {expandtex} =
- {
- 'type' => '!',
- 'linkage' => sub {push @Texi2HTML::Config::EXPAND, 'tex';},
- 'verbose' => 'obsolete, use "--iftex" instead',
- 'noHelp' => 2,
- };
- $T2H_OBSOLETE_OPTIONS -> {split_node} =
- {
- 'type' => '!',
- 'linkage' => sub{set_from_cmdline('SPLIT', 'section');},
- 'verbose' => 'obsolete, use "-split section" instead',
- 'noHelp' => 2,
- };
- $T2H_OBSOLETE_OPTIONS -> {split_chapter} =
- {
- 'type' => '!',
- 'linkage' => sub{set_from_cmdline('SPLIT', 'chapter');},
- 'verbose' => 'obsolete, use "-split chapter" instead',
- 'noHelp' => 2,
- };
- $T2H_OBSOLETE_OPTIONS -> {no_verbose} =
- {
- 'type' => '!',
- 'linkage' => sub{set_from_cmdline('VERBOSE', 0);},
- 'verbose' => 'obsolete, use -noverbose instead',
- 'noHelp' => 2,
- };
- $T2H_OBSOLETE_OPTIONS -> {output_file} =
- {
- 'type' => '=s',
- 'linkage' => sub {set_from_cmdline('OUTFILE', $_[1]); set_from_cmdline('SPLIT','');},
- 'verbose' => 'obsolete, use --out-file instead',
- 'noHelp' => 2
- };
- $T2H_OBSOLETE_OPTIONS -> {section_navigation} =
- {
- 'type' => '!',
- 'linkage' => sub {set_from_cmdline('HEADERS', $_[1]);},
- 'verbose' => 'obsolete, use --sec-nav instead',
- 'noHelp' => 2,
- };
- # read initialzation from $sysconfdir/texi2htmlrc or $HOME/.texi2htmlrc
- # (this is obsolete). Obsoleted in 1.68 (March 20 2004).
- my @rc_files = ();
- push @rc_files, "$sysconfdir/texi2htmlrc" if defined($sysconfdir);
- push @rc_files, "$ENV{'HOME'}/.texi2htmlrc" if (defined($ENV{'HOME'}));
- foreach my $i (@rc_files)
- {
- if (-e $i and -r $i)
- {
- print STDERR "# reading initialization file from $i\n"
- if ($T2H_VERBOSE);
- print STDERR "Reading config from $i is obsolete, use texi2html/$conf_file_name instead\n";
- Texi2HTML::Config::load($i);
- }
- }
- # read initialization files
- foreach my $file (locate_init_file($conf_file_name, [ reverse(@program_config_dirs) ], 1))
- {
- print STDERR "# reading initialization file from $file\n" if ($T2H_VERBOSE);
- Texi2HTML::Config::load($file);
- }
- #+++############################################################################
- # #
- # parse command-line options
- # #
- #---############################################################################
- # options known by makeinfo (+version, help and if*)
- #my @makeinfo_options = ('error-limit', 'document-language',
- #'force', 'help', 'no-validate', 'no-warn', 'verbose', 'docbook', 'html',
- #'xml', 'plaintext', 'macro-expand', 'headers', 'no-split',
- #'number-sections', 'output', 'disable-encoding', 'enable-encoding',
- #'fill-column', 'footnote-style', 'paragraph-indent', 'split-size',
- #'css-include', 'css-ref', 'internal-links', 'transliterate-file-names',
- #'output-indent', 'number-footnotes', 'D', 'I', 'P', 'U');
- # always used, even though they are not in makeinfo in C.
- # split is in makeinfo in C, as --no-split.
- # 'conf-dir', 'init-file' options have to be taken into account for proper
- # functionning.
- #my @basic_options = ('conf-dir', 'init-file',
- #'split', 'program', 'set-init-variable');
- # --command=CMD insert CMD in copy of input file
- my $makeinfo_help =
- sprintf(__("Usage: %s [OPTION]... TEXINFO-FILE...\n"), $real_command_name)
- ."\n".
- __("Translate Texinfo source documentation to various other formats, by default
- Info files suitable for reading online with Emacs or standalone GNU Info.\n")
- ."\n";
- $makeinfo_help .= sprintf(__("General options:
- --error-limit=NUM quit after NUM errors (default %d).
- --document-language=STR locale to use in translating Texinfo keywords
- for the output document (default C).
- --force preserve output even if errors.
- --help display this help and exit.
- --no-validate suppress node cross-reference validation.
- --no-warn suppress warnings (but not errors).
- --conf-dir=DIR search also for initialization files in DIR.
- --init-file=FILE load FILE to modify the default behaviour.
- --set-init-variable VAR=VAL set configuration variable VAR to VAL.
- -v, --verbose explain what is being done.
- --version display version information and exit.\n"), get_conf('ERROR_LIMIT'))
- ."\n";
- $makeinfo_help .= __("Output format selection (default is to produce Info):
- --docbook output Docbook XML rather than Info.
- --html output HTML rather than Info.
- --xml output Texinfo XML rather than Info.
- --plaintext output plain text rather than Info.\n")
- ."\n";
- $makeinfo_help .= __("General output options:
- -E, --macro-expand=FILE output macro-expanded source to FILE,
- ignoring any \@setfilename.
- --no-headers suppress node separators, Node: lines, and menus
- from Info output (thus producing plain text)
- or from HTML (thus producing shorter output);
- also, write to standard output by default if
- producing Info.
- --split=SPLIT split at SPLIT, where SPLIT may be chapter,
- section or node if output supports splitting.
- --no-split suppress the splitting of Info or HTML output,
- generate only one output file.
- --number-sections output chapter and sectioning numbers.
- -o, --output=FILE output to FILE (or directory if split).
- If not split and FILE is a directory, put the
- resulting files in FILE.\n")
- ."\n";
- $makeinfo_help .= sprintf(__("Options for Info and plain text:
- --disable-encoding do not output accented and special characters
- in Info output based on \@documentencoding.
- --enable-encoding override --disable-encoding (default).
- --fill-column=NUM break Info lines at NUM characters (default %d).
- --footnote-style=STYLE output footnotes in Info according to STYLE:
- `separate' to put them in their own node;
- `end' to put them at the end of the node, in
- which they are defined (this is the default).
- --paragraph-indent=VAL indent Info paragraphs by VAL spaces (default %d).
- If VAL is `none', do not indent; if VAL is
- `asis', preserve existing indentation.
- --split-size=NUM split Info files at size NUM (default %d).\n"),
- get_conf('FILLCOLUMN'), get_conf('paragraphindent'), get_conf('SPLIT_SIZE'))
- ."\n";
- $makeinfo_help .= __("Options for HTML:
- --css-include=FILE include FILE in HTML <style> output;
- read stdin if FILE is -.
- --css-ref=URL generate reference to a CSS file.
- --internal-links=FILE produce list of internal links in FILE.
- --transliterate-file-names
- produce file names in ASCII transliteration.
- --node-files produce redirection files for nodes and
- anchors. Default is set only if split.\n")
- ."\n";
- $makeinfo_help .= __("Options for XML and Docbook:
- --output-indent=VAL does nothing, retained for compatibility.\n")
- ."\n";
- # This is ignored
- #Options for XML and Docbook:
- # --output-indent=VAL indent XML elements by VAL spaces (default 2).
- # If VAL is 0, ignorable whitespace is dropped.
- # Always set and ignored
- # --commands-in-node-names allow \@ commands in node names.
- #
- $makeinfo_help .= __("Input file options:
- --commands-in-node-names does nothing, retained for compatibility.
- -D VAR define the variable VAR, as with \@set.
- -I DIR append DIR to the \@include search path.
- -P DIR prepend DIR to the \@include search path.
- -U VAR undefine the variable VAR, as with \@clear.\n")
- ."\n";
- $makeinfo_help .= __("Conditional processing in input:
- --ifdocbook process \@ifdocbook and \@docbook even if
- not generating Docbook.
- --ifhtml process \@ifhtml and \@html even if not generating HTML.
- --ifinfo process \@ifinfo even if not generating Info.
- --ifplaintext process \@ifplaintext even if not generating plain text.
- --iftex process \@iftex and \@tex; implies --no-split.
- --ifxml process \@ifxml and \@xml.
- --no-ifdocbook do not process \@ifdocbook and \@docbook text.
- --no-ifhtml do not process \@ifhtml and \@html text.
- --no-ifinfo do not process \@ifinfo text.
- --no-ifplaintext do not process \@ifplaintext text.
- --no-iftex do not process \@iftex and \@tex text.
- --no-ifxml do not process \@ifxml and \@xml text.
- Also, for the --no-ifFORMAT options, do process \@ifnotFORMAT text.\n")
- ."\n";
- $makeinfo_help .= __(" The defaults for the \@if... conditionals depend on the output format:
- if generating HTML, --ifhtml is on and the others are off;
- if generating Info, --ifinfo is on and the others are off;
- if generating plain text, --ifplaintext is on and the others are off;
- if generating XML, --ifxml is on and the others are off.\n")
- ."\n";
- $makeinfo_help .= __("Examples:
- makeinfo foo.texi write Info to foo's \@setfilename
- makeinfo --html foo.texi write HTML to \@setfilename
- makeinfo --xml foo.texi write Texinfo XML to \@setfilename
- makeinfo --docbook foo.texi write DocBook XML to \@setfilename
- makeinfo --no-headers foo.texi write plain text to standard output
- makeinfo --html --no-headers foo.texi write html without node lines, menus
- makeinfo --number-sections foo.texi write Info with numbered sections
- makeinfo --no-split foo.texi write one Info file however big\n")
- ."\n";
- $makeinfo_help .= __("Email bug reports to bug-texinfo\@gnu.org,
- general questions and discussion to help-texinfo\@gnu.org.
- Texinfo home page: http://www.gnu.org/software/texinfo/") ."\n";
- # parsing like texi2html:
- my $T2H_USAGE_TEXT = <<EOT;
- Usage: texi2html [OPTIONS] TEXINFO-FILE
- Translates Texinfo source documentation to HTML.
- EOT
- my $options = new Getopt::MySimple;
- $T2H_OPTIONS -> {'help'} = 0;
- $T2H_OPTIONS -> {'help|h'} =
- {
- type => ':i',
- default => '',
- linkage => sub {$options->helpOptions($_[1]);
- print "\nSend bugs and suggestions to <texi2html-bug\@nongnu.org>\n";
- exit (0);},
- verbose => "print help and exit"
- };
- # this avoids getOptions defining twice 'help' and 'version'.
- $T2H_OBSOLETE_OPTIONS->{'help'} = 0;
- $T2H_OBSOLETE_OPTIONS->{'version'} = 0;
- $T2H_OBSOLETE_OPTIONS->{'verbose'} = 0;
- if ($real_command_name eq 'texi2html')
- {
- # some older version of GetOpt::Long don't have
- # Getopt::Long::Configure("pass_through")
- eval {Getopt::Long::Configure("pass_through");};
- my $Configure_failed = $@ && <<EOT;
- **WARNING: Parsing of obsolete command-line options could have failed.
- Consider to use only documented command-line options (run
- 'texi2html --help 2' for a complete list) or upgrade to perl
- version 5.005 or higher.
- EOT
- if (! $options->getOptions($T2H_OPTIONS, $T2H_USAGE_TEXT, "$THISVERSION\n"))
- {
- print STDERR "$Configure_failed" if $Configure_failed;
- die $T2H_FAILURE_TEXT;
- }
- # Now that texi2html can process many files on the command line, this is
- # not a good heuristic anymore. Not a big deal.
- if (@ARGV > 1)
- {
- eval {Getopt::Long::Configure("no_pass_through");};
- if (! $options->getOptions($T2H_OBSOLETE_OPTIONS, $T2H_USAGE_TEXT, "$THISVERSION\n"))
- {
- print STDERR "$Configure_failed" if $Configure_failed;
- die $T2H_FAILURE_TEXT;
- }
- }
- }
- else
- {
- # changes how command lines are parsed, for example -init file.init
- # doesn't work anymore.
- Getopt::Long::Configure("gnu_getopt");
- my $opts;
- my @types;
- foreach my $key (keys(%$T2H_OPTIONS))
- {
- next unless ($T2H_OPTIONS->{$key});
- my $primary = $key;
- $primary =~ s/\|.*//;
- next if ($primary eq 'version' or $primary eq 'help');
- #next if ($real_command_name eq 'makeinfo' and ! grep {$primary eq $_} (@makeinfo_options, @basic_options) and $primary !~ /^if/);
- $opts->{$primary} = $T2H_OPTIONS->{$key}->{'linkage'} if defined($T2H_OPTIONS->{$key}->{'linkage'});
- push @types, "$key$T2H_OPTIONS->{$key}->{'type'}";
- }
- $opts->{'version'} = sub {
- print "$real_command_name (GNU texinfo) $THISVERSION\n\n";
- printf __("Copyright (C) %s Free Software Foundation, Inc.
- License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
- This is free software: you are free to change and redistribute it.
- There is NO WARRANTY, to the extent permitted by law.\n"), '2008';
- exit 0;
- };
- $opts->{'help'} = sub {
- print "$makeinfo_help";
- exit 0;
- };
- push @types, ('version|V', 'help|h');
- #foreach my $key (sort(keys(%$opts)))
- #{
- # #print STDERR "$key, $opts->{$key}\n";
- # print "$key\n";
- #}
- #print STDERR "@types\n";
- my $result_options = Getopt::Long::GetOptions ($opts, @types);
- }
- if (! $Texi2HTML::THISDOC{'format_from_command_line'} and defined($ENV{'TEXINFO_OUTPUT_FORMAT'}) and $ENV{'TEXINFO_OUTPUT_FORMAT'} ne '')
- {
- if ($Texi2HTML::Config::texi2dvi_formats{$ENV{'TEXINFO_OUTPUT_FORMAT'}})
- {
- add_to_texi2dvi_args("--$ENV{'TEXINFO_OUTPUT_FORMAT'}");
- $call_texi2dvi = 1;
- }
- if (! Texi2HTML::Config::t2h_default_load_format($ENV{'TEXINFO_OUTPUT_FORMAT'}, 0))
- {
- warn sprintf(__("%s: Ignoring unrecognized TEXINFO_OUTPUT_FORMAT value `%s'.\n"), $real_command_name, $ENV{'TEXINFO_OUTPUT_FORMAT'});
- }
- }
- # $T2H_DEBUG and $T2H_VERBOSE are shorthands
- $T2H_DEBUG = get_conf('DEBUG');
- $T2H_VERBOSE = get_conf('VERBOSE');
- #
- # read texi2html extensions (if any)
- # It is obsolete (obsoleted by -init-file). we keep it for backward
- # compatibility.
- my $extensions = 'texi2html.ext'; # extensions in working directory
- if (-f $extensions)
- {
- print STDERR "# reading extensions from $extensions\n" if $T2H_VERBOSE;
- require($extensions);
- }
- my $progdir;
- ($progdir = $0) =~ s/[^\/]+$//;
- if ($progdir && ($progdir ne './'))
- {
- $extensions = "${progdir}texi2html.ext"; # extensions in texi2html directory
- if (-f $extensions)
- {
- print STDERR "# reading extensions from $extensions\n" if $T2H_VERBOSE;
- require($extensions);
- }
- }
- if ($call_texi2dvi)
- {
- if (defined(get_conf('OUT')) and @ARGV > 1)
- {
- die sprintf(__('when generating %s, only one input FILE may be specified with -o'), $Texi2HTML::Config::output_format_names{$Texi2HTML::Config::DEFAULT_OUTPUT_FORMAT});
- }
- print STDERR "".join('|', (get_conf('TEXI2DVI'), @Texi2HTML::Config::TEXI2DVI_ARGUMENTS, @ARGV)) ."\n" if ($T2H_DEBUG or $T2H_VERBOSE);
- exec { get_conf('TEXI2DVI') } (@Texi2HTML::Config::TEXI2DVI_ARGUMENTS, @ARGV);
- }
- #+++############################################################################
- # #
- # evaluation of cmd line options
- # #
- #---############################################################################
- # set the default 'args' entry to normal for each style hash (and each command
- # within)
- my $name_index = -1;
- my @hash_names = ('style_map', 'style_map_pre', 'style_map_texi', 'simple_format_style_map_texi');
- foreach my $hash (\%Texi2HTML::Config::style_map, \%Texi2HTML::Config::style_map_pre, \%Texi2HTML::Config::style_map_texi, \%Texi2HTML::Config::simple_format_style_map_texi)
- {
- $name_index++;
- my $name = $hash_names[$name_index]; # name associated with hash ref
- foreach my $style (keys(%{$hash}))
- {
- next unless (ref($hash->{$style}) eq 'HASH');
- $hash->{$style}->{'args'} = ['normal'] if (!exists($hash->{$style}->{'args'}));
- die "Bug: args not defined, but existing, for $style in $name" if (!defined($hash->{$style}->{'args'}));
- #print STDERR "DEFAULT($name, $hash) add normal as arg for $style ($hash->{$style}), $hash->{$style}->{'args'}\n";
- }
- }
- # setup hashes used for html manual cross references in texinfo
- my %cross_ref_texi_map = %Texi2HTML::Config::default_texi_map;
- my %cross_transliterate_texi_map = %cross_ref_texi_map;
- my %cross_ref_simple_map_texi = %Texi2HTML::Config::default_simple_map;
- $cross_ref_simple_map_texi{"*"} = ' ';
- my %cross_ref_style_map_texi = ();
- my %cross_transliterate_style_map_texi = ();
- Texi2HTML::Config::t2h_default_copy_style_map(\%Texi2HTML::Config::default_style_map_texi, \%cross_ref_style_map_texi);
- Texi2HTML::Config::t2h_default_copy_style_map(\%Texi2HTML::Config::default_style_map_texi, \%cross_transliterate_style_map_texi);
- # Fill in the %style_type hash, a hash associating style @-comand with
- # the type, 'accent', real 'style', 'simple_style', or 'special'.
- # 'simple_style' styles don't extend accross lines.
- my %style_type = ();
- my @simple_styles = ('ctrl', 'w', 'url','uref','indicateurl','email',
- 'titlefont');
- foreach my $style (keys(%Texi2HTML::Config::style_map))
- {
- if (exists $Texi2HTML::Config::command_type{$style})
- {
- $style_type{$style} = $Texi2HTML::Config::command_type{$style};
- next;
- }
- if (ref($Texi2HTML::Config::style_map{$style} eq 'HASH'))
- {
- $style_type{$style} = $Texi2HTML::Config::style_map{$style}->{'type'}
- if (exists($Texi2HTML::Config::style_map{$style}->{'type'}));
- }
- else
- {
- $style_type{$style} = 'simple_style' if (grep {$_ eq $style} @simple_styles);
- }
- $style_type{$style} = 'style' unless (defined($style_type{$style}));
- }
- foreach my $accent (keys(%Texi2HTML::Config::unicode_accents), 'tieaccent', 'dotless')
- {
- if (exists $Texi2HTML::Config::command_type{$accent})
- {
- $style_type{$accent} = $Texi2HTML::Config::command_type{$accent};
- next;
- }
- $style_type{$accent} = 'accent';
- }
- foreach my $special ('footnote', 'ref', 'xref', 'pxref', 'inforef', 'anchor', 'image', 'hyphenation')
- {
- if (exists $Texi2HTML::Config::command_type{$special})
- {
- $style_type{$special} = $Texi2HTML::Config::command_type{$special};
- next;
- }
- $style_type{$special} = 'special';
- }
- push (@Texi2HTML::Config::EXPAND, @Texi2HTML::Config::T2H_FORMAT_EXPAND);
- # correct %Texi2HTML::Config::texi_formats_map based on command line and init
- # variables
- $Texi2HTML::Config::texi_formats_map{'menu'} = 'normal' if (get_conf('SHOW_MENU'));
- foreach my $expanded (@Texi2HTML::Config::EXPAND)
- {
- $Texi2HTML::Config::texi_formats_map{"if$expanded"} = 1 if (exists($Texi2HTML::Config::texi_formats_map{"if$expanded"}));
- next unless (exists($Texi2HTML::Config::texi_formats_map{$expanded}));
- if (grep {$_ eq $expanded} @raw_regions)
- {
- $Texi2HTML::Config::texi_formats_map{$expanded} = 'raw';
- }
- else
- {
- $Texi2HTML::Config::texi_formats_map{$expanded} = 'normal';
- }
- }
- # don't set set_no_line_macro for raw EXPAND formats
- foreach my $key (keys(%Texi2HTML::Config::texi_formats_map))
- {
- unless ($Texi2HTML::Config::texi_formats_map{$key} eq 'raw')
- {
- set_no_line_macro($key, 1);
- set_no_line_macro("end $key", 1);
- }
- }
- # the remaining (not in @EXPAND) raw formats are set as 'raw' such that
- # they are propagated to formatting functions, but
- # they don't start paragraphs or preformatted.
- foreach my $raw (@raw_regions)
- {
- if (!defined($Texi2HTML::Config::texi_formats_map{$raw}))
- {
- $Texi2HTML::Config::texi_formats_map{$raw} = 'raw';
- $Texi2HTML::Config::format_in_paragraph{$raw} = 1;
- set_no_line_macro($raw, 1);
- set_no_line_macro("end $raw", 1);
- }
- }
- # handle ifnot regions
- foreach my $region (keys (%Texi2HTML::Config::texi_formats_map))
- {
- next if ($region =~ /^ifnot/);
- if ($Texi2HTML::Config::texi_formats_map{$region} and $region =~ /^if(\w+)$/)
- {
- $Texi2HTML::Config::texi_formats_map{"ifnot$1"} = 0;
- }
- }
- if ($T2H_VERBOSE)
- {
- print STDERR "# Expanded: ";
- foreach my $text_macro (keys(%Texi2HTML::Config::texi_formats_map))
- {
- print STDERR "$text_macro " if ($Texi2HTML::Config::texi_formats_map{$text_macro});
- }
- print STDERR "\n";
- }
- # The following lines seems to be incorrect. We don't wat to set T2H_DEBUG
- # everytime DUMP_TEXI is set.
- #$T2H_DEBUG |= $DEBUG_TEXI if (get_conf('DUMP_TEXI'));
- # no user provided USE_UNICODE, use configure provided
- if (!defined(get_conf('USE_UNICODE')))
- {
- Texi2HTML::Config::set_default('USE_UNICODE', '@USE_UNICODE@');
- }
- # no user provided nor configured, run time test
- if (get_conf('USE_UNICODE') eq 'unknown' or get_conf('USE_UNICODE') eq '@' .'USE_UNICODE@')
- {
- eval {
- require Encode;
- require Unicode::Normalize;
- Encode->import('encode');
- };
- if ($@)
- {
- Texi2HTML::Config::set_default('USE_UNICODE', 0);
- }
- else
- {
- Texi2HTML::Config::set_default('USE_UNICODE', 1);
- }
- }
- if (get_conf('USE_UNICODE'))
- {
- require Encode;
- require Unicode::Normalize;
- Encode->import('encode');
- # use EastAsianWidth if USE_UNICODE is set
- if ($0 =~ /\.pl$/)
- { # use in-source EastAsianWidth when testing
- unshift @INC, "$T2H_HOME/lib/Unicode-EastAsianWidth/lib";
- }
- elsif ($ENV{T2H_SOURCE_EASTASIANWIDTH})
- {
- unshift @INC, $ENV{T2H_SOURCE_EASTASIANWIDTH};
- }
- elsif ('@USE_EXTERNAL_EASTASIANWIDTH@' ne 'yes')
- {
- unshift @INC, "$pkgdatadir/lib/Unicode-EastAsianWidth/lib";
- }
- else
- {
- eval {
- require Unicode::EastAsianWidth;
- };
- if ($@)
- {
- unshift @INC, "$pkgdatadir/lib/Unicode-EastAsianWidth/lib";
- }
- }
- # unicode east asian character width tables.
- require Unicode::EastAsianWidth;
- }
- if ($0 =~ /\.pl$/)
- {
- unshift @INC, "$T2H_HOME/lib/Text-Unidecode/lib";
- }
- elsif ('@USE_EXTERNAL_UNIDECODE@' ne 'yes')
- {
- unshift @INC, "$pkgdatadir/lib/Text-Unidecode/lib";
- }
- else
- {
- eval {
- require Text::Unidecode;
- };
- if ($@)
- {
- unshift @INC, "$pkgdatadir/lib/Text-Unidecode/lib";
- }
- }
- require Text::Unidecode;
- Text::Unidecode->import('unidecode');
- Texi2HTML::Config::set_default('USE_UNIDECODE', 1);
- print STDERR "# USE_UNICODE ".get_conf('USE_UNICODE').", USE_UNIDECODE ".get_conf('USE_UNIDECODE')." \n"
- if ($T2H_VERBOSE);
- # Construct hashes used for cross references generation
- # Do it now as the user may have changed USE_UNICODE
- foreach my $key (keys(%Texi2HTML::Config::unicode_map))
- {
- if ($Texi2HTML::Config::unicode_map{$key} ne '')
- {
- if (get_conf('USE_UNICODE'))
- {
- my $char_nr = hex($Texi2HTML::Config::unicode_map{$key});
- #$cross_ref_texi_map{$key} = chr(hex($Texi2HTML::Config::unicode_map{$key}));
- #$cross_ref_texi_map{$key} = pack("U0U*",hex($Texi2HTML::Config::unicode_map{$key}));
- if ($char_nr > 126 and $char_nr < 255)
- {
- $cross_ref_texi_map{$key} = Encode::decode("iso-8859-1", chr($char_nr));
- }
- else
- {
- $cross_ref_texi_map{$key} = chr($char_nr);
- }
- # cross_transliterate_texi_map is only used if
- # USE_UNIDECODE is unset and TRANSLITERATE_FILE_NAMES is set
- if (exists ($Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}}))
- {
- $cross_transliterate_texi_map{$key} = $Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}};
- }
- else
- {
- $cross_transliterate_texi_map{$key} = $cross_ref_texi_map{$key};
- }
- }
- else
- {
- $cross_ref_texi_map{$key} = '_' . lc($Texi2HTML::Config::unicode_map{$key});
- # cross_transliterate_texi_map is used if TRANSLITERATE_FILE_NAMES is set
- if (exists ($Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}}))
- {
- $cross_transliterate_texi_map{$key} = $Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}};
- }
- else
- {
- $cross_transliterate_texi_map{$key} = '_' . lc($Texi2HTML::Config::unicode_map{$key});
- }
- }
- }
- }
- if (get_conf('TRANSLITERATE_FILE_NAMES') and (
- (get_conf('USE_UNICODE') and ! get_conf('USE_UNIDECODE'))
- or !get_conf('USE_UNICODE')))
- {
- foreach my $key (keys (%Texi2HTML::Config::transliterate_accent_map))
- {
- $Texi2HTML::Config::transliterate_map{$key} = $Texi2HTML::Config::transliterate_accent_map{$key};
- }
- }
- foreach my $key (keys(%cross_ref_style_map_texi))
- {
- if ($style_type{$key} eq 'accent'
- and (ref($cross_ref_style_map_texi{$key}) eq 'HASH'))
- {
- if (get_conf('USE_UNICODE'))
- {
- $cross_ref_style_map_texi{$key}->{'function'} = \&Texi2HTML::Config::t2h_utf8_accent;
- }
- else
- {
- $cross_ref_style_map_texi{$key}->{'function'} = \&Texi2HTML::Config::t2h_nounicode_cross_manual_accent;
- }
- # this is only used if TRANSLITERATE_FILE_NAMES is set and USE_UNICODE
- # or USE_UNIDECODE is not set
- $cross_transliterate_style_map_texi{$key}->{'function'} = \&Texi2HTML::Config::t2h_transliterate_cross_manual_accent;
- }
- }
- if (get_conf('L2H') and defined($Texi2HTML::Config::OUTPUT_FORMAT) and $Texi2HTML::Config::OUTPUT_FORMAT eq 'html')
- {
- push @Texi2HTML::Config::command_handler_init, \&Texi2HTML::LaTeX2HTML::init;
- push @Texi2HTML::Config::command_handler_process, \&Texi2HTML::LaTeX2HTML::latex2html;
- # do it here once to have something ready for special regions
- push @Texi2HTML::Config::command_handler_process, \&Texi2HTML::LaTeX2HTML::init_from_html;
- # do it here once more in case the file was modified (see mediawiki.pm)
- push @Texi2HTML::Config::command_handler_output, \&Texi2HTML::LaTeX2HTML::init_from_html;
- push @Texi2HTML::Config::command_handler_finish, \&Texi2HTML::LaTeX2HTML::finish;
- $Texi2HTML::Config::command_handler{'math'} =
- { 'init' => \&Texi2HTML::LaTeX2HTML::to_latex,
- 'expand' => \&Texi2HTML::LaTeX2HTML::do_tex
- };
- $Texi2HTML::Config::command_handler{'tex'} =
- { 'init' => \&Texi2HTML::LaTeX2HTML::to_latex,
- 'expand' => \&Texi2HTML::LaTeX2HTML::do_tex
- };
- }
- if (get_conf('ENABLE_ENCODING'))
- {
- if (get_conf('USE_UNICODE'))
- {
- Texi2HTML::Config::t2h_enable_encoding_load();
- }
- else
- { # FIXME: only warn if ENABLE_ENCODING is set on the command line
- #warn "** --enable-encoding requires utf-8 support\n";
- }
- }
- # for all files. This won't be overriden by @documentencoding, this is not
- # what is done in general.
- #Texi2HTML::Config::set_conf('IN_ENCODING', $Texi2HTML::Config::IN_ENCODING);
- #Texi2HTML::Config::set_conf('DOCUMENT_ENCODING', $Texi2HTML::Config::DOCUMENT_ENCODING);
- # APA: There's got to be a better way:
- if (get_conf('TEST'))
- {
- # to generate files similar to reference ones to be able to check for
- # real changes we use these dummy values if -test is given
- $THISPROG = 'texi2html';
- $THISPROG_THISVERSION = 'texi2html';
- setlocale( LC_ALL, "C" );
- }
- $Texi2HTML::GLOBAL{'debug_l2h'} = 1 if ($T2H_DEBUG & $DEBUG_L2H);
- # parse texinfo cnf file for external manual specifications.
- sub prepare_htmlxref($)
- {
- my $input_directory = shift;
- my @htmlxref_dirs = @language_config_dirs;
- if (get_conf('TEST'))
- {
- @htmlxref_dirs = ('./.texinfo');
- }
- if ($input_directory ne '.' and $input_directory ne '')
- {
- unshift @htmlxref_dirs, $input_directory;
- }
- unshift @htmlxref_dirs, '.';
- my @texinfo_htmlxref_files = locate_init_file ($texinfo_htmlxref, \@htmlxref_dirs, 1);
- foreach my $file (@texinfo_htmlxref_files)
- {
- print STDERR "html refs config file: $file\n" if ($T2H_DEBUG);
- unless (open (HTMLXREF, $file))
- {
- document_warn("Cannot open html refs config file ${file}: $!");
- next;
- }
- my $line_nr = 0;
- my %variables;
- while (my $hline = <HTMLXREF>)
- {
- my $line = $hline;
- $line_nr++;
- next if $hline =~ /^\s*#/;
- #$hline =~ s/[#]\s.*//;
- $hline =~ s/^\s*//;
- next if $hline =~ /^\s*$/;
- chomp ($hline);
- if ($hline =~ s/^\s*(\w+)\s*=\s*//)
- {
- # handle variables
- my $var = $1;
- my $re = join '|', map { quotemeta $_ } keys %variables;
- $hline =~ s/\$\{($re)\}/defined $variables{$1} ? $variables{$1} : "\${$1}"/ge;
- $variables{$var} = $hline;
- next;
- }
- my @htmlxref = split /\s+/, $hline;
- my $manual = shift @htmlxref;
- my $split_or_mono = shift @htmlxref;
- #print STDERR "$split_or_mono $Texi2HTML::Config::htmlxref_entries{$split_or_mono} $line_nr\n";
- if (!defined($split_or_mono))
- {
- file_line_warn(__("Missing type"), $file, $line_nr);
- next;
- }
- elsif (!defined($Texi2HTML::Config::htmlxref_entries{$split_or_mono}))
- {
- file_line_warn(sprintf(__("Unrecognized type: %s"), $split_or_mono), $file, $line_nr);
- next;
- }
- my $href = shift @htmlxref;
- next if (exists($Texi2HTML::THISDOC{'htmlxref'}->{$manual}->{$split_or_mono}));
-
- if (defined($href))
- { # substitute 'variables'
- my $re = join '|', map { quotemeta $_ } keys %variables;
- $href =~ s/\$\{($re)\}/defined $variables{$1} ? $variables{$1} : "\${$1}"/ge;
- $href =~ s/\/*$// if ($split_or_mono ne 'mono');
- }
- $Texi2HTML::THISDOC{'htmlxref'}->{$manual}->{$split_or_mono} = $href;
- }
- close (HTMLXREF);
- }
- }
-
- if ($T2H_DEBUG)
- {
- foreach my $manual (keys(%{$Texi2HTML::GLOBAL{'htmlxref'}}))
- {
- foreach my $split (keys(%Texi2HTML::Config::htmlxref_entries))
- {
- my $href = 'NO';
- next unless (exists($Texi2HTML::GLOBAL{'htmlxref'}->{$manual}->{$split}));
- $href = $Texi2HTML::GLOBAL{'htmlxref'}->{$manual}->{$split}->{'href'} if
- exists($Texi2HTML::GLOBAL{'htmlxref'}->{$manual}->{$split}->{'href'});
- print STDERR "$manual: $split, href: $href\n";
- }
- }
- }
- # resulting files splitting
- # FIXME we should remove that code
- if (get_conf('SPLIT') =~ /section/i)
- {
- global_override('SPLIT', 'section');
- }
- elsif (get_conf('SPLIT') =~ /node/i)
- {
- global_override('SPLIT', 'node');
- }
- elsif (get_conf('SPLIT') =~ /chapter/i)
- {
- global_override('SPLIT', 'chapter');
- }
- else
- {
- global_override('SPLIT', '');
- }
- global_override('SPLIT_INDEX', 0) unless (get_conf('SPLIT'));
- Texi2HTML::Config::set_default('NODE_FILES', 1) if (!defined(get_conf('NODE_FILES')) and get_conf('SPLIT'));
- Texi2HTML::Config::set_default('NODE_FILENAMES', 1) if ((!defined(get_conf('NODE_FILENAMES')) and get_conf('SPLIT') eq 'node') or get_conf('NODE_FILES'));
- ## Something like backward compatibility. This would make sense to keep
- ## it ad-infinitum since the meaning of --out and --subdir are different.
- #if (get_conf('SPLIT') and defined($Texi2HTML::Config::SUBDIR)
- # and ($Texi2HTML::Config::SUBDIR ne '') and
- # (!defined(get_conf('OUT')) or (get_conf('OUT') eq '')))
- #{
- # set_from_cmdline('OUT', $Texi2HTML::Config::SUBDIR);
- #}
- my %not_split_formats = (
- 'xml' => 1,
- 'info' => 1,
- 'plaintext' => 1,
- 'docbook' => 1
- );
- if (defined($Texi2HTML::Config::OUTPUT_FORMAT) and get_conf('SPLIT') and $not_split_formats{$Texi2HTML::Config::OUTPUT_FORMAT})
- {
- document_warn(sprintf(__('Ignoring splitting for format %s'), $Texi2HTML::Config::OUTPUT_FORMAT));
- global_override('SPLIT', '');
- global_override('FRAMES', 0);
- }
- # FIXME: why is this only done for SUBDIR and if split? Isn't the
- # same issue possible for not split output?
- if (get_conf('SPLIT') and defined(get_conf('SUBDIR')) and (get_conf('SUBDIR') eq '.'))
- {# This is to avoid trouble with latex2html
- global_override('SUBDIR', '');
- }
- @Texi2HTML::Config::INCLUDE_DIRS = split(/$quoted_path_separator/,join($path_separator,@Texi2HTML::Config::INCLUDE_DIRS));
- @Texi2HTML::Config::PREPEND_DIRS = split(/$quoted_path_separator/,join($path_separator,@Texi2HTML::Config::PREPEND_DIRS));
- my @include_dirs_orig = @Texi2HTML::Config::INCLUDE_DIRS;
- @Texi2HTML::Config::CONF_DIRS = split(/$quoted_path_separator/,join($path_separator,@Texi2HTML::Config::CONF_DIRS));
- # extension
- #$Texi2HTML::GLOBAL{'extension'} = get_conf('EXTENSION');
- if (get_conf('SHORTEXTN'))
- {
- #$Texi2HTML::GLOBAL{'extension'} = "htm";
- global_override('EXTENSION', 'htm');
- }
- my $global_pass; # track the phases of processing for debugging output purposes
- #
- # file name business
- #
- my @created_directories = ();
- my $docu_dir; # directory of the document
- my $docu_name; # basename of the document
- my $docu_rdir; # directory for the output
- my $docu_toc; # document's table of contents
- my $docu_stoc; # document's short toc
- my $docu_foot; # document's footnotes
- my $docu_about; # about this document
- my $docu_top; # document top
- my $docu_doc; # document (or document top of split)
- my $docu_frame; # main frame file
- my $docu_toc_frame; # toc frame file
- my $path_to_working_dir; # relative path leading to the working
- # directory from the document directory
- my $docu_doc_file;
- my $docu_toc_file;
- my $docu_stoc_file;
- my $docu_foot_file;
- my $docu_about_file;
- my $docu_top_file;
- my $docu_frame_file;
- my $docu_toc_frame_file;
- sub set_docu_names($$)
- {
- my $docu_base_name = shift;
- my $file_nr = shift;
- if ($docu_base_name =~ /(.*\/)/)
- {
- $docu_dir = $1;
- chop($docu_dir);
- $docu_name = $docu_base_name;
- $docu_name =~ s/.*\///;
- }
- else
- {
- $docu_dir = '.';
- $docu_name = $docu_base_name;
- }
- # AAAA
- if (get_conf('PREFIX') and ($file_nr == 0))
- {
- $docu_name = get_conf('PREFIX');
- }
- elsif ($docu_name eq '-')
- {
- $docu_name = $Texi2HTML::Config::STDIN_DOCU_NAME;
- }
- # subdir
- $docu_rdir = '';
- my $no_file_output;
- if (defined(get_conf('OUTFILE')) and ($file_nr == 0) and ($Texi2HTML::Config::null_device_file{get_conf('OUTFILE')} or get_conf('OUTFILE') eq '-'))
- { # this overrides the setting for this file.
- if (get_conf ('SPLIT'))
- {
- document_override('SPLIT', '');
- document_warn(sprintf(__('Cannot split output %s'), get_conf('OUTFILE')));
- }
- document_override('FRAMES', 0);
- document_override('SPLIT_SIZE', undef);
- $no_file_output = 1;
- $path_to_working_dir = $docu_rdir;
- }
- if (!$no_file_output)
- {
- if (get_conf('SPLIT'))
- {
- if (defined(get_conf('OUT')) and ($file_nr == 0))
- {
- $docu_rdir = get_conf('OUT');
- }
- else
- {
- $docu_rdir = $docu_name;
- }
- if ($docu_rdir ne '')
- {
- $docu_rdir =~ s|/*$||;
- $docu_rdir .= '/';
- }
- }
- else
- {
- my $out_dir;
- # AAAA
- if (defined(get_conf('OUTFILE')) and ($file_nr == 0))
- {
- $out_dir = get_conf('OUTFILE');
- $out_dir =~ s|[^/]*$||;
- }
- # even if the out file is not set by OUT, in case it is not the first
- # file, the subdir directory is still used, if it has been determined.
- elsif (defined(get_conf('SUBDIR')) and get_conf('SUBDIR') ne '')
- {
- $out_dir = get_conf('SUBDIR');
- }
- if (defined($out_dir) and $out_dir =~ m|(.*)/|)
- {# there is a leading directories
- $docu_rdir = "$1/";
- }
- }
-
- if ($docu_rdir ne '')
- {
- unless (-d $docu_rdir)
- {
- if ( mkdir($docu_rdir, oct(755)))
- {
- print STDERR "# created directory $docu_rdir\n" if ($T2H_VERBOSE);
- push @created_directories, $docu_rdir;
- }
- else
- {
- my $original_rdir = $docu_rdir;
- # as explained in the doc, retry with the extension appended.
- # this is dubious practice, but workaround extension-less info
- # files
- if (get_conf('SPLIT') and get_conf('EXTENSION') and get_conf('EXTENSION') ne '')
- {
- $docu_rdir =~ s/\/*$//;
- $docu_rdir .= '.' . get_conf('EXTENSION') . '/';
- if (! -d $docu_rdir)
- {
- if ( mkdir($docu_rdir, oct(755)))
- {
- print STDERR "# created directory $docu_rdir\n" if ($T2H_VERBOSE);
- push @created_directories, $docu_rdir;
- }
- else
- {
- document_error (sprintf(__("Can't create directories `%s' or `%s': %s"), $original_rdir, $docu_rdir, $!), 1);
- }
- }
- }
- else
- {
- document_error (sprintf(__("Can't create directory `%s': %s"), $docu_rdir, $!), 1);
- }
- }
- }
- print STDERR "# putting result files into directory $docu_rdir\n" if ($T2H_VERBOSE);
- }
- else
- {
- print STDERR "# putting result files into current directory \n" if ($T2H_VERBOSE);
- }
- # We don't use "./" as $docu_rdir when $docu_rdir is the current directory
- # because it is problematic for latex2html. To test writability with -w,
- # however we need a real directory.
- my $result_rdir = $docu_rdir;
- $result_rdir = "." if ($docu_rdir eq '');
- unless (-w $result_rdir)
- {
- if ($docu_rdir eq '')
- {
- document_error(__('current directory not writable'), 1);
- }
- else
- {
- document_error(sprintf(__('%s not writable'), $docu_rdir), 1);
- }
- }
-
- # relative path leading to the working directory from the document directory
- $path_to_working_dir = $docu_rdir;
- if ($docu_rdir ne '')
- {
- my $cwd = cwd;
- my $docu_path = $docu_rdir;
- $docu_path = $cwd . '/' . $docu_path unless ($docu_path =~ /^\//);
- my @result = ();
- # this code simplify the paths. The cwd is absolute, while in the
- # document path there may be some .., a .. is removed with the
- # previous path element, such that something like
- # /cwd/directory/../somewhere/
- # leads to
- # /cwd/somewhere/
- # with directory/.. removed
- foreach my $element (split /\//, File::Spec->canonpath($docu_path))
- {
- if ($element eq '')
- {
- push @result, '';
- }
- elsif ($element eq '..')
- {
- if (@result and ($result[-1] eq ''))
- {
- print STDERR "Too much .. in absolute file name\n";
- }
- elsif (@result and ($result[-1] ne '..'))
- {
- pop @result;
- }
- else
- {
- push @result, $element;
- }
- }
- else
- {
- push @result, $element;
- }
- }
- $path_to_working_dir = File::Spec->abs2rel($cwd, join ('/', @result));
- # this should not be needed given what canonpath does
- $path_to_working_dir =~ s:/*$::;
- $path_to_working_dir .= '/' unless($path_to_working_dir eq '');
- }
- }
-
- my $docu_ext = get_conf('EXTENSION');
- $Texi2HTML::THISDOC{'destination_directory'} = $docu_rdir;
- $Texi2HTML::THISDOC{'file_base_name'} = $docu_name;
- $docu_doc = $docu_name . (defined($docu_ext) ? ".$docu_ext" : ""); # document's contents
- if (get_conf('SPLIT') and get_conf('NODE_FILENAMES'))
- {
- if (defined(get_conf('TOP_NODE_FILE')))
- {
- $docu_doc = get_conf('TOP_NODE_FILE');
- if (defined(get_conf('NODE_FILE_EXTENSION')) and get_conf('NODE_FILE_EXTENSION') ne '')
- {
- $docu_doc .= '.' . get_conf('NODE_FILE_EXTENSION');
- }
- }
- }
- if (get_conf('SPLIT'))
- {
- # AAAA
- if (defined(get_conf('TOP_FILE')) and (get_conf('TOP_FILE') ne '') and ($file_nr == 0))
- {
- $docu_top = get_conf('TOP_FILE');
- }
- }
- else
- {
- # AAAA
- if (defined(get_conf('OUTFILE')) and ($file_nr == 0))
- {
- my $out_file = get_conf('OUTFILE');
- if (get_conf('OUT') ne get_conf('OUTFILE'))
- {
- # FIXME output a warning?
- #document_warn(sprintf(__('Not using %s as an out file as it is a directory'), get_conf('OUT')));
- }
- $out_file =~ s|.*/|| unless ($no_file_output);
- $docu_doc = $out_file if ($out_file !~ /^\s*$/);
- }
- }
- if (defined $Texi2HTML::Config::element_file_name)
- {
- my $docu_doc_set = &$Texi2HTML::Config::element_file_name
- (undef, 'doc', $docu_name);
- $docu_doc = $docu_doc_set if (defined($docu_doc_set));
- }
- $docu_top = $docu_doc if (!defined($docu_top));
- if (get_conf('SPLIT') or !get_conf('MONOLITHIC'))
- {
- if (defined $Texi2HTML::Config::element_file_name)
- {
- $docu_toc = &$Texi2HTML::Config::element_file_name
- (undef, 'toc', $docu_name);
- $docu_stoc = &$Texi2HTML::Config::element_file_name
- (undef, 'stoc', $docu_name);
- $docu_foot = &$Texi2HTML::Config::element_file_name
- (undef, 'foot', $docu_name);
- $docu_about = &$Texi2HTML::Config::element_file_name
- (undef, 'about', $docu_name);
- # $docu_top may be overwritten later.
- }
- if (!defined($docu_toc))
- {
- my $default_toc = "${docu_name}_toc";
- $default_toc .= ".$docu_ext" if (defined($docu_ext));
- # AAAA
- if (defined(get_conf('TOC_FILE')) and (get_conf('TOC_FILE') ne '') and ($file_nr == 0))
- {
- $docu_toc = get_conf('TOC_FILE');
- }
- else
- {
- $docu_toc = $default_toc;
- }
- }
- if (!defined($docu_stoc))
- {
- $docu_stoc = "${docu_name}_ovr";
- $docu_stoc .= ".$docu_ext" if (defined($docu_ext));
- }
- if (!defined($docu_foot))
- {
- $docu_foot = "${docu_name}_fot";
- $docu_foot .= ".$docu_ext" if (defined($docu_ext));
- }
- if (!defined($docu_about))
- {
- $docu_about = "${docu_name}_abt";
- $docu_about .= ".$docu_ext" if (defined($docu_ext));
- }
- }
- else
- {
- $docu_toc = $docu_foot = $docu_stoc = $docu_about = $docu_doc;
- }
- # Note that file extension has already been added here.
- if (get_conf('FRAMES'))
- {
- if (defined $Texi2HTML::Config::element_file_name)
- {
- $docu_frame = &$Texi2HTML::Config::element_file_name
- (undef, 'frame', $docu_name);
- $docu_toc_frame = &$Texi2HTML::Config::element_file_name
- (undef, 'toc_frame', $docu_name);
- }
- }
- if (!defined($docu_frame))
- {
- $docu_frame = "${docu_name}_frame";
- $docu_frame .= ".$docu_ext" if (defined($docu_ext));
- }
- if (!defined($docu_toc_frame))
- {
- $docu_toc_frame = "${docu_name}_toc_frame";
- $docu_toc_frame .= ".$docu_ext" if (defined($docu_ext));
- }
- if ($T2H_VERBOSE)
- {
- print STDERR "# Files and directories:\n";
- print STDERR "# rdir($docu_rdir) path_to_working_dir($path_to_working_dir)\n";
- print STDERR "# doc($docu_doc) top($docu_top) toc($docu_toc) stoc($docu_stoc)\n";
- print STDERR "# foot($docu_foot) about($docu_about) frame($docu_toc) toc_frame($docu_toc_frame)\n";
- }
- $docu_doc_file = "$docu_rdir$docu_doc";
- $docu_toc_file = "$docu_rdir$docu_toc";
- $docu_stoc_file = "$docu_rdir$docu_stoc";
- $docu_foot_file = "$docu_rdir$docu_foot";
- $docu_about_file = "$docu_rdir$docu_about";
- $docu_top_file = "$docu_rdir$docu_top";
- $docu_frame_file = "$docu_rdir$docu_frame";
- $docu_toc_frame_file = "$docu_rdir$docu_toc_frame";
- # For use in init files
- $Texi2HTML::THISDOC{'filename'}->{'top'} = $docu_top;
- $Texi2HTML::THISDOC{'filename'}->{'foot'} = $docu_foot;
- $Texi2HTML::THISDOC{'filename'}->{'stoc'} = $docu_stoc;
- $Texi2HTML::THISDOC{'filename'}->{'about'} = $docu_about;
- $Texi2HTML::THISDOC{'filename'}->{'toc'} = $docu_toc;
- $Texi2HTML::THISDOC{'filename'}->{'toc_frame'} = $docu_toc_frame;
- $Texi2HTML::THISDOC{'filename'}->{'frame'} = $docu_frame;
- }
- sub var_to_str($)
- {
- return 'UNDEF' if (!defined($_[0]));
- return $_[0];
- }
- #
- # Common initializations
- #
- sub texinfo_initialization($)
- {
- my $pass = shift;
- # set the translations now. This means at the beginning of each pass.
- # Do it silently, except during the last pass.
- my $lang = get_conf('documentlanguage');
- my $silent_lang = 1 if ($pass != 2);
- if (!set_document_language($lang))
- { # may only fail if not using the default gettext framework
- document_warn ("Translations for '$lang' not found. Using 'en'.") unless ($silent_lang);
- set_document_language('en');
- }
- # All the initialization used the informations still there at the
- # end of the previous pass.
- # Now we reset everything, such that things are used when they happen.
- # also reset the @set/@clear values.
- %value = %value_initial;
- foreach my $init_mac (@document_settable_at_commands)
- {
- unset_from_document($init_mac);
- }
- }
- #+++###########################################################################
- # #
- # Pass texi: read source, handle variable, ignored text, #
- # #
- #---###########################################################################
- #my @lines = (); # whole document
- #my @lines_numbers = (); # line number, originating file associated with
- # whole document
- my $macros = undef; # macros. reference on a hash
- my %info_enclose = (); # macros defined with definfoenclose
- my @floats = (); # floats list
- my %floats = (); # floats by style
- sub initialise_state_texi($)
- {
- my $state = shift;
- $state->{'texi'} = 1; # for substitute_text and close_stack:
- # 1 if pass_texi/scan_texi is to be used
- $state->{'macro_inside'} = 0 unless(defined($state->{'macro_inside'}));
- $state->{'ifvalue_inside'} = 0 unless(defined($state->{'ifvalue_inside'}));
- $state->{'arg_expansion'} = 0 unless(defined($state->{'arg_expansion'}));
- $state->{'files_stack'} = [] unless(defined($state->{'files_stack'}));
- }
- sub pass_texi($)
- {
- my $input_file_name = shift;
- #my $texi_line_number = { 'file_name' => '', 'line_nr' => 0, 'macro' => '' };
- my @lines = (); # whole document
- my @lines_numbers = (); # line number, originating file associated with
- # whole document
- my @first_lines = ();
- my $first_lines = 1; # is it the first lines
- my $state = {};
- # holds the informations about the context
- # to pass it down to the functions
- # FIXME not used, to be used after @setfilename use is clearer
- my @command_line_lines = @Texi2HTML::Config::COMMANDS;
- initialise_state_texi($state);
- my $texi_line_number;
- ($texi_line_number, $state->{'input_spool'}) =
- open_file($input_file_name, '', $state->{'files_stack'});
- my @stack;
- my $text;
- my $cline;
- INPUT_LINE: while (1)
- {
- ($cline, $state->{'input_spool'}) = next_line($texi_line_number, $state->{'files_stack'});
- last if (!defined($cline));
- #
- # remove the lines preceding \input or an @-command
- #
- if ($first_lines)
- {
- if ($cline =~ /^\\input/)
- {
- push @first_lines, $cline;
- $first_lines = 0;
- next;
- }
- if ($cline =~ /^\s*\@/)
- {
- $first_lines = 0;
- }
- else
- {
- push @first_lines, $cline;
- next;
- }
- }
- #print STDERR "PASS_TEXI($texi_line_number->{'line_nr'})$cline";
- my $chomped_line = $cline;
- if (scan_texi ($cline, \$text, \@stack, $state, $texi_line_number) and chomp($chomped_line))
- {
- #print STDERR "==> new page (line_nr $texi_line_number->{'line_nr'},$texi_line_number->{'file_name'},$texi_line_number->{'macro'})\n";
- push (@lines_numbers, { 'file_name' => $texi_line_number->{'file_name'},
- 'line_nr' => $texi_line_number->{'line_nr'},
- 'macro' => $texi_line_number->{'macro'} });
- }
- #dump_stack (\$text, \@stack, $state);
- if ($state->{'bye'})
- {
- #dump_stack(\$text, \@stack, $state);
- # close stack after bye
- #print STDERR "close stack after bye\n";
- close_stack_texi(\$text, \@stack, $state, $texi_line_number);
- #dump_stack(\$text, \@stack, $state);
- }
- next if (@stack);
- $cline = $text;
- $text = '';
- if (!defined($cline))
- {
- msg_debug ("\$cline undefined after scan_texi", $texi_line_number);
- next unless ($state->{'bye'});
- }
- push @lines, split_lines($cline);
- last if ($state->{'bye'});
- }
- # close stack at the end of pass texi
- #print STDERR "close stack at the end of pass texi\n";
- close_stack_texi(\$text, \@stack, $state, $texi_line_number);
- my @end_lines = split_lines($text);
- #push @lines, split_lines($text);
- foreach my $line (split_lines($text))
- {
- push @lines, $line;
- $texi_line_number->{'line_nr'}++;
- push (@lines_numbers, { 'file_name' => $texi_line_number->{'file_name'},
- 'line_nr' => $texi_line_number->{'line_nr'},
- 'macro' => __(' end of file') });
- }
- print STDERR "# end of pass texi\n" if $T2H_VERBOSE;
- return (\@lines, \@first_lines, \@lines_numbers);
- }
- #+++###########################################################################
- # #
- # Pass structure: parse document structure #
- # #
- #---###########################################################################
- sub initialise_state_structure($)
- {
- my $state = shift;
- $state->{'structure'} = 1; # for substitute_text and close_stack:
- # 1 if pass_structure/scan_structure is
- # to be used
- $state->{'menu'} = 0; # number of opened menus
- $state->{'detailmenu'} = 0; # number of opened detailed menus
- $state->{'direntry'} = 0; # number of opened direntry
- $state->{'sectioning_base'} = 0; # current base sectioning level
- $state->{'table_stack'} = [ "no table" ]; # a stack of opened tables/lists
- # seems to be only debug
- if (exists($state->{'region_lines'}) and !defined($state->{'region_lines'}))
- {
- delete ($state->{'region_lines'});
- print STDERR "Bug: state->{'region_lines'} exists but undef.\n";
- }
- }
- # This is a virtual element for things appearing before @node and
- # sectioning commands
- my $element_before_anything;
- #
- # initial counters. Global variables for pass_structure.
- #
- my $document_idx_num;
- my $document_sec_num;
- my $document_head_num;
- my $document_anchor_num;
- # section to level hash taking into account raise and lower sections.
- # Reset at document beginning
- my %sec2level;
- # initial state for the special regions.
- my %region_initial_state;
- my %region_lines;
- my %region_line_nrs;
- # This is a place for index entries, anchors and so on appearing in
- # copying or documentdescription
- my $no_element_associated_place;
- my %nodes; # nodes hash. The key is the texi node name
- my %cross_reference_nodes; # normalized node names arrays
- #
- # _foo: internal variables to track @foo
- # obsolete
- foreach my $key ('_author', '_title', '_subtitle', '_shorttitlepage',
- '_settitle', '_titlefont')
- {
- $value_initial{$key} = ''; # prevent -w warnings
- }
- my @nodes_list; # nodes in document reading order
- # each member is a reference on a hash
- my @sections_list; # sections in reading order
- # each member is a reference on a hash
- my @all_elements; # sectioning elements (nodes and sections)
- # in reading order. Each member is a reference
- # on a hash which also appears in %nodes,
- # @sections_list @nodes_list, @elements_list
- my @headings_list; # headings in reading order.
- my @elements_list; # all the resulting elements in document order
- my %sections; # sections hash. The key is the section number
- my %headings; # headings hash. The key is the heading number
- my $section_top; # @top section
- my $element_top; # Top element
- my $node_top; # Top node
- my $node_first; # First node
- my $element_index; # element with first index
- my $element_chapter_index; # chapter with first index
- my $element_first; # first element
- my $element_last; # last element
- my %special_commands; # hash for the commands specially handled
- # by the user
- # element for content and shortcontent if on a separate page
- my %content_element;
- my %reference_content_element =
- (
- 'contents' => { 'id' => $Texi2HTML::Config::misc_pages_targets{'Contents'},
- 'target' => $Texi2HTML::Config::misc_pages_targets{'Contents'},
- 'contents' => 1, 'texi' => '_contents' },
- 'shortcontents' => {
- 'id' => $Texi2HTML::Config::misc_pages_targets{'Overview'},
- 'target' => $Texi2HTML::Config::misc_pages_targets{'Overview'},
- 'shortcontents' => 1, 'texi' => '_shortcontents' },
- );
- # holds content elements located with @*contents commands
- my %all_content_elements;
- # common code for headings and sections
- sub new_section_heading($$$$)
- {
- my $command = shift;
- my $name = shift;
- my $state = shift;
- my $line_nr = shift;
-
- $name = trim_comment_spaces ($name, "\@$command", $line_nr);
- $name = normalise_texi_space($name);
- $name = '' if (!defined($name));
- # no increase if in @copying and the like. Also no increase if it is top
- # since top has number 0.
- my $docid;
- my $num;
- my $section_ref = { 'texi' => $name,
- 'level' => $sec2level{$command},
- 'tag' => $command,
- };
- return $section_ref;
- }
- sub scan_line_separators($$$;$)
- {
- my $line = shift;
- my $separators = shift;
- my $context = shift;
- my $line_nr = shift;
- my @command_stack;
- my $result = '';
- while (1)
- {
- # macro_regexp
- if ($line =~ s/^([^{}\@$separators]*)\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/\\])// or $line =~ s/^([^{}\@$separators]*)\@([a-zA-Z][\w-]*)//)
- {
- $result .= $1;
- my $command = $2;
- $command = $alias{$command} if (exists($alias{$command}));
- if (defined($Texi2HTML::Config::misc_command{$command}))
- {
- if ($command ne 'c' and $command ne 'comment')
- { # misc commands other than comments are kept as-is, only
- # comments are removed.
- my ($text, $args);
- ($line, $text, $args) = &$Texi2HTML::Config::preserve_misc_command($line, $command);
- $result .= "\@$command".$text;
- next;
- }
- else
- {
- $line =~ s/.*//;
- return ($result, $line, undef);
- }
- }
- $result .= "\@$command";
- if ($line =~ s/^{//)
- {
- push @command_stack, $command;
- $result .= '{';
- }
- if ($command eq 'verb')
- {
- if ($line =~ s/^(.)//)
- {
- my $char = $1;
- my $verb_char = quotemeta($char);
- if ($line =~ s/^(.*?${verb_char}\})//)
- {
- $result .= $char.$1;
- }
- else
- {
- $line =~ s/^(.*)//;
- $result .= $char . $1;
- return ($result, $line, undef);
- }
- }
- else
- {
- return ($result, $line, undef);
- }
- pop @command_stack;
- }
- }
- elsif ($line =~ s/^([^\{\}$separators]*)([{}])//)
- {
- $result .= $1 . $2;
- my $brace = $2;
- if (@command_stack and $brace eq '}')
- {
- pop @command_stack;
- }
- }
- elsif ($separators ne '' and $line =~ s/^([^${separators}]*)([$separators])//)
- {
- $result .= $1;
- my $separator = $2;
- if (@command_stack)
- {
- $result .= $separator;
- }
- else
- {
- return ($result, $line, $separator);
- }
- }
- else
- {
- $result .= $line;
- $line = '';
- return ($result, $line, undef);
- }
- }
- }
- sub trim_comment_spaces($$;$)
- {
- my $line = shift;
- my $context = shift;
- my $line_nr = shift;
- if(!defined($line))
- {
- msg_debug("trim_comment_spaces: $context: line undef", $line_nr);
- return undef;
- }
- my ($arg, $remaining, $separator) = scan_line_separators ($line, '', $context, $line_nr);
- #msg_debug ("trim_comment_spaces: $context: arg undef. $line", $line_nr) if (!defined($arg));
- #msg_debug ("trim_comment_spaces: $context: $arg !!! $line", $line_nr);
- return $arg if (!defined($arg));
- return trim_around_spaces($arg);
- }
- # argument may be the number of arguments when the commas in the last
- # argument has no specific meaning. When it is undef it means that
- # all the arguments have to be parsed
- sub parse_line_arguments($$$;$)
- {
- my $line = shift;
- my $arg_total_nr = shift;
- my $context = shift;
- my $line_nr = shift;
- my @args;
- my $arg_nr = 0;
- my $remaining = $line;
- while (!defined($arg_total_nr) or $arg_nr < $arg_total_nr -1)
- {
- my ($arg, $separator);
- ($arg, $remaining, $separator) = scan_line_separators($remaining, ',', $context, $line_nr);
- push @args, trim_around_spaces($arg) if (defined($arg));
- return @args if (!defined($separator) or !defined($remaining) or !defined($arg));
- $arg_nr++;
- }
- if (defined($arg_total_nr))
- {
- my ($last_arg, $separator);
- ($last_arg, $remaining, $separator) = scan_line_separators($remaining, '', $context, $line_nr);
- push @args, trim_around_spaces($last_arg) if (defined($last_arg));
- }
- return @args;
- }
- sub pass_structure($$)
- {
- my $texi_lines = shift;
- my $lines_numbers = shift;
- my @doc_lines; # whole document
- my @doc_numbers; # whole document line numbers and file names
- my $state = {};
- # holds the informations about the context
- # to pass it down to the functions
- initialise_state_structure($state);
- $state->{'heading_element'} = $element_before_anything;
- $state->{'current_element'} = $element_before_anything;
- $state->{'place'} = $element_before_anything->{'place'};
- my @stack;
- my $text;
- my $line_nr;
- while (@$texi_lines or $state->{'in_deff_line'})
- {
- my $cline = shift @$texi_lines;
- my $chomped_line = $cline;
- if (@$texi_lines and !chomp($chomped_line))
- {
- $texi_lines->[0] = $cline . $texi_lines->[0];
- next;
- }
- # !defined($cline) may happen if $state->{'in_deff_line'} is true
- # but there is no more line, in case the last end of line is
- # protected
- $line_nr = shift (@$lines_numbers) unless (!defined($cline));
- if ($state->{'in_deff_line'})
- { # line stored in $state->{'in_deff_line'} was protected by @
- # and can be concatenated with the next line
- if (defined($cline))
- {
- $cline = $state->{'in_deff_line'} . $cline;
- }
- else
- {# end of line protected at the very end of the file
- # in that case there is also no line_nr anymore.
- $cline = $state->{'in_deff_line'};
- }
- delete $state->{'in_deff_line'};
- }
- #print STDERR "PASS_STRUCTURE($line_nr->{'line_nr'}. raw:".var_to_str($state->{'raw'}).", verb:".var_to_str($state->{'verb'})."): $cline";
- if (!$state->{'raw'} and !$state->{'verb'})
- {
- my $tag = '';
- if ($cline =~ /^\s*\@(\w+)\b/)
- {
- $tag = $1;
- }
- #
- # analyze the tag
- #
- if ($tag and $tag eq 'node' or (defined($sec2level{$tag}) and ($tag !~ /heading/)) or ($tag eq 'insertcopying' and get_conf('INLINE_INSERTCOPYING')))
- {
- my @added_lines = ($cline);
- my @added_numbers = ($line_nr);
- if ($tag eq 'node' or defined($sec2level{$tag}))
- {# in pass structure node shouldn't appear in formats
- close_stack_structure(\$text, \@stack, $state, $line_nr);
- if (exists($state->{'region_lines'}))
- {
- push @{$region_lines{$state->{'region_lines'}->{'format'}}}, split_lines($text);
- push @doc_lines, split_lines($text) if ($Texi2HTML::Config::region_formats_kept{$state->{'region_lines'}->{'format'}});
- $state->{'region_lines'}->{'number'} = 0;
- close_region($state);
- }
- else
- {
- push @doc_lines, split_lines($text);
- }
- $text = '';
- }
- if ($tag eq 'node')
- {
- my $node_ref;
- my $auto_directions;
- my $node_line = $cline;
- $node_line =~ s/^\@node\s*//;
- my @node_res = parse_line_arguments($node_line, undef, '@node', $line_nr);
- @node_res = normalise_node_array (\@node_res);
- # even for empty nodes, @nodes_res has one element.
- #line_error (sprintf(__("Error scanning %s"), $cline), $line_nr) if (@node_res < 1);
- $auto_directions = 1 if (scalar(@node_res) == 1);
- if (@node_res > 4)
- {
- line_warn(__("Superfluous arguments for node"), $line_nr);
- }
- my ($node, $node_next, $node_prev, $node_up) = @node_res;
- if (defined($node) and ($node ne ''))
- {
- if (exists($nodes{$node}) and defined($nodes{$node})
- and $nodes{$node}->{'seen'})
- {
- line_error (sprintf(__("Node `%s' previously defined %s"), $node, format_line_number($nodes{$node}->{'line_nr'})), $line_nr);
- next;
- }
- elsif ($node =~ /^\(.+\)/)
- {
- line_error (sprintf(__("Syntax for an external node used for `%s'"), $node), $line_nr);
- next;
- }
- else
- {
- if (exists($nodes{$node}) and defined($nodes{$node}))
- { # node appeared in a menu
- $node_ref = $nodes{$node};
- }
- else
- {
- $node_ref = {};
- $nodes{$node} = $node_ref;
- }
- $node_ref->{'node'} = 1;
- $node_ref->{'tag'} = 'node';
- $node_ref->{'tag_level'} = 'node';
- $node_ref->{'texi'} = $node;
- $node_ref->{'seen'} = 1;
- $node_ref->{'automatic_directions'} = $auto_directions;
- $node_ref->{'place'} = [];
- $node_ref->{'current_place'} = [];
- $node_ref->{'line_nr'} = $line_nr;
- merge_element_before_anything($node_ref);
- $node_ref->{'index_names'} = [];
- $state->{'place'} = $node_ref->{'current_place'};
- $state->{'heading_element'} = $node_ref;
- $state->{'current_element'} = $node_ref;
- $state->{'node_ref'} = $node_ref;
- $state->{'menu_in_node'} = 0;
- # makeinfo treats differently case variants of
- # top in nodes and anchors and in refs commands and
- # refs from nodes.
- if ($node =~ /^top$/i)
- {
- if (!defined($node_top))
- {
- $node_top = $node_ref;
- $node_top->{'texi'} = 'Top';
- delete $nodes{$node};
- $nodes{$node_top->{'texi'}} = $node_ref;
- }
- else
- { # All the refs are going to point to the first Top
- line_warn ("Top node already exists", $line_nr);
- }
- }
- unless (@nodes_list)
- {
- $node_first = $node_ref;
- }
- push (@nodes_list, $node_ref);
- push @all_elements, $node_ref;
- }
- }
- else
- {
- line_error ("Empty node", $line_nr);
- next;
- }
- if (defined($node_next) and ($node_next ne ''))
- {
- $node_ref->{'node_next'} = $node_next;
- }
- if (defined($node_prev) and ($node_prev ne ''))
- {
- $node_ref->{'node_prev'} = $node_prev;
- }
- if (defined($node_up) and ($node_up ne ''))
- {
- $node_ref->{'node_up'} = $node_up;
- }
- }
- elsif (defined($sec2level{$tag}))
- { # section
- if ($cline =~ /^\@$tag\s*(.*)$/)
- {
- my $name = $1;
- my $section_ref = new_section_heading($tag, $name, $state, $line_nr);
- $document_sec_num++ if ($tag ne 'top');
-
- $section_ref->{'sec_num'} = $document_sec_num;
- $section_ref->{'id'} = "SEC$document_sec_num";
- $section_ref->{'seen'} = 1;
- $section_ref->{'index_names'} = [];
- $section_ref->{'current_place'} = [];
- $section_ref->{'place'} = [];
- $section_ref->{'section'} = 1;
- $section_ref->{'line_nr'} = $line_nr;
- if ($tag eq 'top')
- {
- $section_ref->{'number'} = '';
- $section_ref->{'id'} = "SEC_Top";
- $section_ref->{'sec_num'} = 0;
- if (defined($section_top))
- {
- line_error ("\@top already exists", $line_nr);
- $sections{0} = $section_ref;
- }
- else
- {
- $sections{0.1} = $section_ref;
- }
- $section_top = $section_ref;
- }
- else
- {
- $sections{$section_ref->{'sec_num'}} = $section_ref;
- }
- merge_element_before_anything($section_ref);
- if ($state->{'node_ref'})
- {
- $section_ref->{'node_ref'} = $state->{'node_ref'};
- push @{$state->{'node_ref'}->{'sections'}}, $section_ref;
- }
- if ($state->{'node_ref'} and !exists($state->{'node_ref'}->{'with_section'}))
- {
- my $node_ref = $state->{'node_ref'};
- $section_ref->{'with_node'} = $node_ref;
- $section_ref->{'titlefont'} = $node_ref->{'titlefont'};
- $node_ref->{'with_section'} = $section_ref;
- }
- if (! $name and $section_ref->{'level'})
- {
- line_warn (sprintf(__("\@%s requires an argument"), $tag), $line_nr);
- }
- push @sections_list, $section_ref;
- push @all_elements, $section_ref;
- $state->{'heading_element'} = $section_ref;
- $state->{'current_element'} = $section_ref;
- $state->{'place'} = $section_ref->{'current_place'};
- ################# debug
- my $node_ref = "NO NODE";
- my $node_texi ='';
- if ($state->{'node_ref'})
- {
- $node_ref = $state->{'node_ref'};
- $node_texi = $state->{'node_ref'}->{'texi'};
- }
- print STDERR "# pass_structure node($node_ref)$node_texi, tag \@$tag($section_ref->{'level'}) ref $section_ref, num,id $section_ref->{'sec_num'},$section_ref->{'id'}\n $name\n"
- if $T2H_DEBUG & $DEBUG_ELEMENTS;
- ################# end debug
- }
- }
- elsif ($cline =~ /^\@insertcopying\s*/)
- {
- @added_lines = @{$region_lines{'copying'}};
- @added_numbers = @{$region_line_nrs{'copying'}};
- unshift (@$texi_lines, @added_lines);
- unshift (@$lines_numbers, @added_numbers);
- next;
- }
- if (exists($state->{'region_lines'}))
- {
- push @{$region_lines{$state->{'region_lines'}->{'format'}}}, @added_lines;
- if ($Texi2HTML::Config::region_formats_kept{$state->{'region_lines'}->{'format'}})
- { # the region is kept in the document in addition with
- # being put in the appropriate region_lines entry.
- push @doc_lines, @added_lines;
- push @doc_numbers, @added_numbers;
- }
- }
- else
- {
- push @doc_lines, @added_lines;
- push @doc_numbers, @added_numbers;
- }
- next;
- }
- }
- if (scan_structure ($cline, \$text, \@stack, $state, $line_nr))
- {
- if (!exists($state->{'region_lines'}) or $Texi2HTML::Config::region_formats_kept{$state->{'region_lines'}->{'format'}})
- {
- push (@doc_numbers, $line_nr);
- }
- if (exists($state->{'region_lines'}))
- {
- push @{$region_line_nrs{$state->{'region_lines'}->{'format'}}}, $line_nr unless ($state->{'region_lines'}->{'first_line'});
- }
- }
- next if (scalar(@stack) or $state->{'in_deff_line'});
- $cline = $text;
- $text = '';
- next if (!defined($cline));
- if ($state->{'region_lines'})
- {
- # the first line is like @copying, it is not put in the region
- # lines
- push @{$region_lines{$state->{'region_lines'}->{'format'}}}, split_lines($cline) unless ($state->{'region_lines'}->{'first_line'});
- delete $state->{'region_lines'}->{'first_line'};
- push @doc_lines, split_lines($cline) if ($Texi2HTML::Config::region_formats_kept{$state->{'region_lines'}->{'format'}});
- }
- else
- {
- push @doc_lines, split_lines($cline);
- }
- }
- if (@stack)
- {# close stack at the end of pass structure
- close_stack_structure(\$text, \@stack, $state, $line_nr);
- if ($text)
- {
- if (!exists($state->{'region_lines'}) or $Texi2HTML::Config::region_formats_kept{$state->{'region_lines'}->{'format'}})
- {
- push @doc_lines, split_lines($text);
- }
- if (exists($state->{'region_lines'}))
- {
- push @{$region_lines{$state->{'region_lines'}->{'format'}}},
- split_lines($text);
- }
- }
- }
- #line_warn ("Expected $state->{'region_lines'}->{'number'} \@end $state->{'region_lines'}->{'format'}", $line_nr) if (exists($state->{'region_lines'}));
- line_error (sprintf(__("Expected \@end %s"), $state->{'region_lines'}->{'format'}), $line_nr) if (exists($state->{'region_lines'}));
- print STDERR "# end of pass structure\n" if $T2H_VERBOSE;
- # To remove once they are handled
- #print STDERR "No node nor section, texi2html won't be able to place things rightly\n" if ($element_before_anything->{'place'} and @{$element_before_anything->{'place'}});
- return (\@doc_lines, \@doc_numbers);
- }
- # split line at end of line and put each resulting line in an array
- # FIXME there must be a more perlish way to do it... Not a big deal
- # as long as it work
- sub split_lines($)
- {
- my $line = shift;
- my @result = ();
- return @result if (!defined($line));
- my $i = 0;
- while ($line ne '')
- {
- $result[$i] = '';
- $line =~ s/^(.*)//;
- $result[$i] .= $1;
- $result[$i] .= "\n" if ($line =~ s/^\n//);
- #print STDERR "$i: $result[$i]";
- $i++;
- }
- return @result;
- }
- # handle @documentlanguage
- sub do_documentlanguage($$$$)
- {
- my $command = shift;
- my $line = shift;
- my $silent = shift;
- my $line_nr = shift;
- my $language_change_succes = 0;
- if ($line =~ s/\s+(\w+)\s*//)
- {
- my $lang = $1;
- my $prev_lang = get_conf('documentlanguage');
- # This won't be done if the documentlanguage was set on the command line
- if (set_from_document('documentlanguage', $lang))
- {
- warn_unknown_language ($lang, $line_nr) unless ($silent);
- $language_change_succes = set_document_language($lang, $line_nr);
- if (!$language_change_succes)
- { # reset previous documentlanguage. Cannot happen in the default
- # gettext-like framework.
- set_from_document('documentlanguage', $prev_lang);
- line_warn (sprintf(__("Translations for `%s' not found. Reverting to `%s'"),$lang, $prev_lang), $line_nr) unless ($silent);
- }
- }
- # FIXME warn about stuff remaining on the line?
- }
- return $language_change_succes;
- }
- # actions that should be done in more than one pass. In fact most are not
- # to be done in pass_texi. The $pass argument is the number of the pass,
- # 0 for pass_texi, 1 for pass_structure, 2 for pass_text
- sub common_misc_commands($$$$)
- {
- my $command = shift;
- my $line = shift;
- my $pass = shift;
- my $line_nr = shift;
- # for error messages
- my $cline = $line;
- chomp($cline);
- $cline =~ s/^\s*//;
- # track variables
- if ($command eq 'set')
- {
- if ($line =~ /^(\s+)($VARRE)(\s+)(.*)$/)
- {
- $value{$2} = $4;
- }
- else
- {
- line_error (sprintf(__("%c%s requires a name"), ord('@'), $command), $line_nr) if (!$pass);
- }
- }
- elsif ($command eq 'clear')
- {
- if ($line =~ /^(\s+)($VARRE)/)
- {
- delete $value{$2};
- }
- else
- {
- line_error (sprintf(__("%c%s requires a name"), ord('@'), $command), $line_nr) if (!$pass);
- }
- }
- elsif ($command eq 'clickstyle')
- {
- if ($line =~ s/^\s+@([^\s\{\}\@]+)({})?\s*//)
- {
- set_from_document($command, $1);
- # FIXME warn about what remains on the line?
- }
- else
- {
- line_error (sprintf(__("\@%s should only accept a \@-command as argument, not `%s'"), $command, $cline), $line_nr) if ($pass == 1);
- }
- }
- elsif ($command eq 'novalidate')
- {
- set_from_document($command, 1);
- }
- if ($pass)
- { # these commands are only taken into account here in pass_structure 1
- # and pass_text 2
- if ($command eq 'setfilename')
- {
- my $filename = trim_comment_spaces($line, "\@$command");
- $filename = substitute_line($filename, "\@$command",{'code_style' => 1, 'remove_texi' => 1});
- if ($filename ne '')
- {
- set_from_document($command, $filename);
- }
- }
- elsif ($command eq 'paragraphindent')
- {
- if ($line =~ /\s+([\w\-]+)[^\w\-]/)
- {
- set_paragraphindent ($1, 0, $line_nr, $pass);
- }
- else
- {
- set_paragraphindent ($line, 0, $line_nr, $pass);
- }
- }
- elsif ($command eq 'firstparagraphindent')
- {
- if (($line =~ /^\s+(none)[^\w\-]/) or ($line =~ /^\s+(insert)[^\w\-]/))
- {
- set_from_document($command, $1);
- }
- else
- {
- line_error (sprintf(__("\@firstparagraphindent arg must be `none' or `insert', not `%s'"), $cline), $line_nr) if ($pass == 1);
- }
- }
- elsif ($command eq 'exampleindent')
- {
- if ($line =~ /^\s+([0-9]+)/)
- {
- set_from_document($command, $1);
- }
- elsif ($line =~ /^\s+(asis)[^\w\-]/)
- {
- set_from_document($command, $1);
- }
- else
- {
- line_error (sprintf(__("\@exampleindent arg must be numeric/`asis', not `%s'"), $cline), $line_nr) if ($pass == 1);
- }
- }
- elsif ($command eq 'frenchspacing')
- {
- if (($line =~ /^\s+(on)[^\w\-]/) or ($line =~ /^\s+(off)[^\w\-]/))
- {
- set_from_document($command, $1);
- }
- else
- {
- line_error (sprintf(__("Expected \@%s on or off, not `%s'"), $command, $cline), $line_nr) if ($pass == 1);
- }
- }
- elsif ($command eq 'kbdinputstyle')
- {
- if ($line =~ /\s+([a-z]+)/ and ($1 eq 'code' or $1 eq 'example' or $1 eq 'distinct'))
- {
- set_from_document($command, $1);
- }
- else
- {
- line_error (sprintf(__("\@kbdinputstyle arg must be `code'/`example'/`distinct', not `%s'"), $cline), $line_nr) if ($pass == 1);
- }
- }
- elsif (grep {$command eq $_} ('everyheading', 'everyfooting',
- 'evenheading', 'evenfooting', 'oddheading', 'oddfooting'))
- { # FIXME have a _texi and without texi, and without texi,
- # and expand rightly @this*? And use @| to separate, and give
- # an array for user consumption? This should be done for each new
- # chapter, section, and page. What is a page is not necessarily
- # well defined in html, however...
- # @thisfile is the @include file. Should be in $line_nr.
- my $arg = $line;
- $arg =~ s/^\s+//;
- set_from_document($command, $arg);
- }
- elsif ($command eq 'allowcodebreaks')
- {
- if (($line =~ /^\s+(true)[^\w\-]/) or ($line =~ /^\s+(false)[^\w\-]/))
- {
- set_from_document($command, $1);
- }
- else
- {
- line_error (sprintf(__("\@allowcodebreaks arg must be `true' or `false', not `%s'"), $cline), $line_nr) if ($pass == 1);
- }
- }
- elsif ($command eq 'headings')
- {
- my $valid_arg = 0;
- foreach my $possible_arg (('off','on','single','double',
- 'singleafter','doubleafter'))
- {
- if ($line =~ /^\s+($possible_arg)[^\w\-]/)
- {
- $valid_arg = 1;
- set_from_document($command, $possible_arg);
- last;
- }
- }
- unless ($valid_arg)
- {
- line_error (sprintf(__("Bad argument to \@%s: %s"), $command, $cline), $line_nr) if ($pass == 1);
- }
- }
- elsif ($command eq 'documentlanguage')
- {
- if (do_documentlanguage($command, $line, $pass -1, $line_nr))
- {
- &$Texi2HTML::Config::translate_names();
- set_special_names();
- }
- }
- }
- }
- sub misc_command_texi($$$$)
- {
- my $line = shift;
- my $command = shift;
- my $state = shift;
- my $line_nr = shift;
- my $text;
- my $args;
- my $cline = $line;
-
- if (!$state->{'ignored'} and !$state->{'arg_expansion'})
- {
- if ($command eq 'documentencoding')
- { # FIXME accept more characters, like @?
- if ($cline =~ s/^(\s+)([\w\-]+)//)
- {
- my $encoding = $2;
- line_warn(sprintf(__("Encoding %s is not a canonical texinfo encoding"), $encoding), $line_nr)
- if (!$Texi2HTML::Config::canonical_texinfo_encodings{lc($encoding)});
- if (set_from_document('documentencoding', $encoding))
- {
- my $from_encoding = encoding_alias($encoding, $line_nr);
- set_from_document('IN_ENCODING', $from_encoding)
- if (defined($from_encoding));
- if (defined($from_encoding) and get_conf('USE_UNICODE'))
- {
- foreach my $file (@{$state->{'files_stack'}})
- {
- binmode($file->{'fh'}, ":encoding($from_encoding)");
- }
- }
- }
- #FIXME error if garbage remains on the line?
- }
- else
- {
- line_error(sprintf(__("\@%s arg must be an encoding"), $command), $line_nr);
- }
- }
- elsif ($command eq 'alias')
- {
- if ($line =~ /(\s+)([a-zA-Z][\w-]*)(\s*=\s*)([a-zA-Z][\w-]*)(\s*)/)
- {
- $alias{$2} = $4;
- }
- else
- {
- line_error (sprintf(__("Bad argument to \@%s"), $command), $line_nr);
- }
- }
- elsif ($command eq 'definfoenclose')
- {
- if ($cline =~ s/^\s+([a-z][\w\-]*)\s*,\s*([^\s]+)\s*,\s*([^\s]+)//)
- {
- $info_enclose{$1} = [ $2, $3 ];
- }
- else
- {
- line_error (sprintf(__("Bad argument to \@%s"), $command), $line_nr);
- } # FIXME warn about garbage remaining on the line?
- }
- else
- {
- if ($command eq 'setfilename' and get_conf('USE_SETFILENAME'))
- { # a double setfillename is removed before calling misc_command_texi
- my $filename = trim_comment_spaces($line, "\@$command");
- $filename = substitute_line($filename, "\@$command",{'code_style' => 1, 'remove_texi' => 1}, $line_nr);
- if ($filename ne '')
- {
- set_from_document($command, $filename);
- # remove extension
- $filename =~ s/\.[^\.]*$//;
- init_with_file_name ($filename) if ($filename ne '');
- }
- }
- # in reality, do only set, clear and clickstyle.
- # though we should never go there for clickstyle...
- common_misc_commands($command, $line, 0, $line_nr);
- }
- }
- ($line, $text, $args) = &$Texi2HTML::Config::preserve_misc_command($line, $command);
- return ($line, $text);
- }
- sub new_content_element($)
- {
- my $command = shift;
- $command = 'shortcontents' if ($command ne 'contents');
- my $element;
- foreach my $key (keys(%{$reference_content_element{$command}}))
- {
- $element->{$key} = $reference_content_element{$command}->{$key};
- }
- return $element;
- }
- # handle misc commands and misc command args
- sub misc_command_structure($$$$)
- {
- my $line = shift;
- my $command = shift;
- my $state = shift;
- my $line_nr = shift;
- my $text;
- my $args;
- # for error messages
- my $cline = $line;
- chomp $cline;
- $cline =~ s/^\s*//;
- if ($command eq 'lowersections')
- {
- my ($sec, $level);
- while (($sec, $level) = each %sec2level)
- {
- $sec2level{$sec} = $level + 1 if ($reference_sec2level{$sec} > 0);
- }
- $state->{'sectioning_base'}--;
- }
- elsif ($command eq 'raisesections')
- {
- my ($sec, $level);
- while (($sec, $level) = each %sec2level)
- {
- $sec2level{$sec} = $level - 1 if ($reference_sec2level{$sec} > 0);
- }
- $state->{'sectioning_base'}++;
- }
- elsif (($command eq 'contents') or ($command eq 'summarycontents') or ($command eq 'shortcontents'))
- {
- if ($command ne 'contents')
- {
- $command = 'shortcontents';
- }
- set_from_document($command, 1);
- my $new_content_element = new_content_element($command);
- push @{$state->{'place'}}, $new_content_element;
- push @{$all_content_elements{$command}}, $new_content_element;
- }
- elsif ($command eq 'dircategory')
- {
- my $arg = trim_comment_spaces ($line, "\@$command");
- $Texi2HTML::THISDOC{"${command}_texi"} = $arg;
- $Texi2HTML::THISDOC{$command} = substitute_line($arg, "\@$command");
- }
- elsif (grep {$_ eq $command} ('settitle','shorttitlepage','title'))
- {
- my $arg = trim_comment_spaces($line, "\@$command");
- $Texi2HTML::THISDOC{$command . '_texi'} = $arg;
- $Texi2HTML::THISDOC{$command . '_line_nr'} = $line_nr;
- # FIXME backward compatibility. Obsoleted in nov 2009.
- $value{"_$command"} = $arg;
- if ($command eq 'title')
- { # FIXME This was obsoleted in jun 2007
- $Texi2HTML::THISDOC{"${command}s_texi"} = [ $arg ];
- }
- }
- elsif (grep {$_ eq $command} ('author','subtitle'))
- {
- my $arg = trim_comment_spaces($line, "\@$command");
- if ($state->{'region'} and $state->{'region'} eq 'titlepage')
- {
- $Texi2HTML::THISDOC{$command . '_texi'} .= $arg . "\n";
- push @{$Texi2HTML::THISDOC{"${command}s_texi"}}, $arg;
- push @{$Texi2HTML::THISDOC{"${command}s_line_nr"}}, $line_nr;
- # FIXME backward compatibility. Obsoleted in nov 2009.
- $value{"_$command"} .= $arg . "\n";
- }
- }
- elsif ($command eq 'synindex' || $command eq 'syncodeindex')
- {
- if ($line =~ /^\s+(\w+)\s+(\w+)/)
- {
- my $index_from = $1;
- my $index_to = $2;
- line_error (sprintf(__("Unknown from index `%s' in \@%s"), $index_from, $command), $line_nr)
- unless $index_names{$index_from};
- line_error (sprintf(__("Unknown to index name `%s' in \@%s"), $index_to, $command), $line_nr)
- unless $index_names{$index_to};
- if ($index_names{$index_from} and $index_names{$index_to})
- {
- my $in_code = 0;
- $in_code = 1 if ($command eq 'syncodeindex');
- my $current_to = $index_to;
- while ($current_to ne $index_from and $Texi2HTML::THISDOC{'merged_index'}->{$current_to})
- {
- $current_to = $Texi2HTML::THISDOC{'merged_index'}->{$current_to};
- }
- if ($current_to ne $index_from)
- {
- foreach my $prefix (keys(%{$index_names{$index_from}}))
- {
- $index_names{$current_to}->{$prefix} = $in_code;
- $index_prefix_to_name{$prefix} = $current_to;
- }
- $Texi2HTML::THISDOC{'merged_index'}->{$index_from} = $current_to;
- }
- push @{$Texi2HTML::THISDOC{$command}}, [$index_from,$index_to];
- }
- }
- else
- {
- line_error (sprintf(__("Bad argument to \@%s: %s"), $command, $cline), $line_nr);
- }
- }
- elsif ($command eq 'defindex' || $command eq 'defcodeindex')
- {
- if ($line =~ /^\s+(\w+)\s*$/)
- {
- my $name = $1;
- if ($forbidden_index_name{$name})
- {
- line_error(sprintf(__("Reserved index name %s"),$name), $line_nr);
- }
- else
- {
- my $in_code = 0;
- $in_code = 1 if ($command eq 'defcodeindex');
- # FIXME this leads to spurious error message in hello_nodes
- #if (defined($index_names{$name}))
- #{
- # line_error(sprintf(__("Index `%s' already exists"),$name), $line_nr);
- #}
- $index_names{$name}->{$name} = $in_code;
- $index_prefix_to_name{$name} = $name;
- push @{$Texi2HTML::THISDOC{$command}}, $name;
- }
- }
- else
- {
- line_error (sprintf(__("Bad argument to \@%s: %s"), $command, $cline), $line_nr);
- }
- }
- elsif (grep {$_ eq $command} ('everyheadingmarks','everyfootingmarks',
- 'evenheadingmarks','oddheadingmarks','evenfootingmarks','oddfootingmarks'))
- {
- if (($line =~ /^\s+(top)[^\w\-]/) or ($line =~ /^\s+(bottom)[^\w\-]/))
- {
- set_from_document($command, $1);
- }
- else
- {
- line_error (sprintf(__("\@%s arg must be `top' or `bottom', not `%s'"), $command, $cline), $line_nr);
- }
- }
- elsif ($command eq 'fonttextsize')
- {
- if (($line =~ /^\s+(10)[^\w\-]/) or ($line =~ /^\s+(11)[^\w\-]/))
- {
- set_from_document($command, $1);
- }
- else
- {
- line_error (sprintf(__("Only \@%s 10 or 11 is supported, not `%s'"),$command, $cline), $line_nr);
- }
- }
- elsif ($command eq 'pagesizes')
- {
- if ($line =~ /^\s+(.*)\s*$/)
- {
- set_from_document($command, $1);
- }
- }
- elsif ($command eq 'footnotestyle')
- {
- if ($line =~ /^\s+([a-z]+)[^\w\-]/)
- {
- set_footnote_style ($1, 0, $line_nr);
- }
- else
- {
- set_footnote_style ($line, 0, $line_nr);
- }
- }
- elsif ($command eq 'setchapternewpage')
- {
- if (($line =~ /^\s+(on)[^\w\-]/) or ($line =~ /^\s+(off)[^\w\-]/)
- or ($line =~ /^\s+(odd)[^\w\-]/))
- {
- set_from_document($command, $1);
- }
- else
- {
- line_error (sprintf(__("\@%s arg must be `on', `off' or `odd', not `%s'"), $command, $cline), $line_nr);
- }
- }
- elsif ($command eq 'setcontentsaftertitlepage' or $command eq 'setshortcontentsaftertitlepage')
- {
- set_from_document($command, 1);
- }
- elsif ($command eq 'need')
- { # only a warning
- unless (($line =~ /^\s+([0-9]+(\.[0-9]*)?)[^\w\-]/) or
- ($line =~ /^\s+(\.[0-9]+)[^\w\-]/))
- {
- line_error (sprintf(__("Bad argument to \@%s: %s"), $command, $cline), $line_nr);
- }
- }
- else
- {
- common_misc_commands($command, $line, 1, $line_nr);
- }
- ($text, $line, $args) = &$Texi2HTML::Config::preserve_misc_command($line, $command);
- return ($text, $line);
- }
- sub set_special_names()
- {
- $Texi2HTML::NAME{'About'} = gdt('About This Document');
- $Texi2HTML::NAME{'Contents'} = gdt('Table of Contents');
- $Texi2HTML::NAME{'Overview'} = gdt('Short Table of Contents');
- $Texi2HTML::NAME{'Footnotes'} = gdt('Footnotes');
- $Texi2HTML::NO_TEXI{'About'} = gdt('About This Document', {}, {'remove_texi' => 1} );
- $Texi2HTML::NO_TEXI{'Contents'} = gdt('Table of Contents', {}, {'remove_texi' => 1} );
- $Texi2HTML::NO_TEXI{'Overview'} = gdt('Short Table of Contents', {}, {'remove_texi' => 1} );
- $Texi2HTML::NO_TEXI{'Footnotes'} = gdt('Footnotes', {}, {'remove_texi' => 1} );
- $Texi2HTML::SIMPLE_TEXT{'About'} = gdt('About This Document', {}, {'simple_format' => 1});
- $Texi2HTML::SIMPLE_TEXT{'Contents'} = gdt('Table of Contents',{}, {'simple_format' => 1});
- $Texi2HTML::SIMPLE_TEXT{'Overview'} = gdt('Short Table of Contents', {}, {'simple_format' => 1});
- $Texi2HTML::SIMPLE_TEXT{'Footnotes'} = gdt('Footnotes', {},{'simple_format' => 1});
- }
- sub enter_author_command($$$$$$)
- {
- my $command = shift;
- my $texi = shift;
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $line_nr = shift;
- $texi = trim_comment_spaces($texi, "\@$command");
- $text = substitute_line($texi, "\@$command", duplicate_formatting_state($state)) if (!defined($text));
- my $top_format = top_stack($stack, 2);
- if (defined($top_format) and $format_type{$top_format->{'format'}} eq 'quotation')
- {
- push @{$top_format->{'quote_authors'}}, {'author_texi' => $texi, 'author_text' => $text};
- }
- elsif (!$state->{'region'} or $state->{'region'} ne 'titlepage')
- {
- line_warn (sprintf(__("\@%s not meaningful outside `\@titlepage' and `\@quotation' environments"), $command), $line_nr);
- }
- }
- # return the line after removing things according to misc_command map.
- # if the skipped command has an effect it is done here
- # this is used during pass_text
- sub misc_command_text($$$$$$)
- {
- my $line = shift;
- my $command = shift;
- my $stack = shift;
- my $state = shift;
- my $text = shift;
- my $line_nr = shift;
- my ($skipped, $remaining, $args, $result);
- # The strange condition associated with 'keep_texi' is
- # there because for an argument appearing on an @itemize
- # line (we're in 'check_item'), meant to be prepended to an
- # @item we don't want to keep @c or @comment as otherwise it
- # eats the @item line. Other commands could do that too but
- # then the user deserves what he gets.
- if ($state->{'keep_texi'} and
- (!$state->{'check_item'} or ($command ne 'c' and $command ne 'comment')))
- {
- ($remaining, $skipped, $args) = &$Texi2HTML::Config::preserve_misc_command($line, $command);
- add_prev($text, $stack, "\@$command". $skipped);
- return $remaining;
- }
- ($remaining, $skipped, $args) = &$Texi2HTML::Config::preserve_misc_command($line, $command);
- if ($state->{'remove_texi'})
- {
- ($command, $line, $result) = &$Texi2HTML::Config::misc_command_line_texi($command, $line, $args, $stack, $state);
- }
- else
- {
- ($command, $line, $result) = &$Texi2HTML::Config::misc_command_line($command, $line, $args, $stack, $state);
- }
- enter_author_command ($command, $line, $result, $stack, $state, $line_nr) if ($command eq 'author');
- # for error messages
- my $cline = $line;
- $cline =~ s/^\s*//;
- chomp $cline;
- # if it is true the command args are kept so the user can modify how
- # they are skipped and handle them as unknown @-commands. Nowadays, it is
- # not that interesting since using misc_command_line above should do
- # about the same more simply.
- my $keep = $Texi2HTML::Config::misc_command{$command}->{'keep'};
- if ($command eq 'sp')
- {
- my $sp_number;
- if ($line =~ /^\s+(\d+)\s/)
- {
- $sp_number = $1;
- }
- elsif ($line =~ /(\s*)$/)
- {
- $sp_number = '';
- }
- else
- {
- line_error (sprintf(__("\@sp requires a positive numeric argument, not `%s'"), $cline), $line_nr);
- }
- $sp_number = 1 if ($sp_number eq '');
- if (!$state->{'remove_texi'})
- {
- add_prev($text, $stack, &$Texi2HTML::Config::sp($sp_number, $state->{'preformatted'}));
- }
- }
- elsif($command eq 'verbatiminclude' and !$keep)
- {
- if ($line =~ /\s+(.+)/)
- {
- my $arg = $1;
- $arg = trim_around_spaces($arg);
- my $file_name = substitute_line($arg, "\@$command", {'code_style' => 1});
- my $file = locate_include_file($file_name);
- if (defined($file))
- {
- if (!open(VERBINCLUDE, $file))
- {
- line_error (sprintf(__("Cannot read %s: %s"), $file, $!), $line_nr);
- }
- else
- {
- my $verb_text = '';
- while (my $verb_line = <VERBINCLUDE>)
- {
- $verb_text .= $verb_line;
- }
-
- if ($state->{'remove_texi'})
- {
- add_prev ($text, $stack, &$Texi2HTML::Config::raw_no_texi('verbatiminclude', $verb_text));
- }
- else
- {
- add_prev($text, $stack, &$Texi2HTML::Config::raw('verbatiminclude', $verb_text, $line_nr));
- }
- close VERBINCLUDE;
- }
- }
- else
- {
- line_error (sprintf(__("\@%s: Cannot find %s"), $command, $file_name), $line_nr);
- }
- }
- else
- {
- line_error (sprintf(__("Bad argument to \@%s: %s"), $command, $cline), $line_nr);
- }
- }
- elsif ($command eq 'indent' or $command eq 'noindent')
- {
- $state->{'paragraph_indent'} = $command;
- }
- else
- {
- common_misc_commands($command, $line, 2, $line_nr);
- }
- return ($skipped.$remaining, $result) if ($keep);
- return ($remaining, $result);
- }
- # merge the things appearing before the first @node or sectioning command
- # (held by element_before_anything) with the current element
- # do that only once.
- sub merge_element_before_anything($)
- {
- my $element = shift;
- if (exists($element_before_anything->{'place'}))
- {
- $element->{'current_place'} = $element_before_anything->{'place'};
- delete $element_before_anything->{'place'};
- foreach my $placed_thing (@{$element->{'current_place'}})
- {
- $placed_thing->{'element'} = $element if (exists($placed_thing->{'element'}));
- }
- }
- # this is certainly redundant with the above condition, but cleaner
- # that way
- if (exists($element_before_anything->{'titlefont'}))
- {
- $element->{'titlefont'} = $element_before_anything->{'titlefont'};
- delete $element_before_anything->{'titlefont'};
- }
- }
- # find menu_prev, menu_up... for a node in menu
- sub menu_entry_texi($$$)
- {
- my $node = shift;
- my $state = shift;
- my $line_nr = shift;
- return if ($state->{'direntry'});
- my $node_menu_ref = {};
- if (exists($nodes{$node}))
- {
- $node_menu_ref = $nodes{$node};
- }
- else
- {
- $nodes{$node} = $node_menu_ref;
- $node_menu_ref->{'texi'} = $node;
- $node_menu_ref->{'external_node'} = 1 if ($node =~ /^\(.+\)/);
- }
- return if ($state->{'detailmenu'});
- if ($state->{'node_ref'})
- {
- if ($node_menu_ref->{'menu_up'} and !$node_menu_ref->{'external_node'})
- {
- # This is not an error. This is used a lot in real life manuals
- #line_warn ("Double entry in menu for `$node' (also below `$node_menu_ref->{'menu_up'}->{'texi'}')", $line_nr);
- }
- $node_menu_ref->{'menu_up'} = $state->{'node_ref'};
- $node_menu_ref->{'menu_up_hash'}->{$state->{'node_ref'}->{'texi'}} = 1;
- }
- if ($state->{'prev_menu_node'})
- {
- $node_menu_ref->{'menu_prev'} = $state->{'prev_menu_node'};
- $state->{'prev_menu_node'}->{'menu_next'} = $node_menu_ref;
- }
- elsif ($state->{'node_ref'} and !$state->{'node_ref'}->{'menu_child'})
- {
- $state->{'node_ref'}->{'menu_child'} = $node_menu_ref;
- }
- $state->{'prev_menu_node'} = $node_menu_ref;
- }
- my @index_labels; # array corresponding with @?index commands
- # constructed during pass_structure, used to
- # put labels in pass_text
- my @unknown_index_index_entries; # array of index entries not associated
- # with any index
- sub sorted_line($)
- {
- my $line = shift;
- $::texi_map_ref = \%Texi2HTML::Config::sorting_things_map;
- my $result = remove_texi($line);
- $::texi_map_ref = \%Texi2HTML::Config::texi_map;
- return $result;
- }
- sub prepare_indices()
- {
- #print STDERR "Do splitting of index letters, once.\n";
- foreach my $index_name(keys %{$Texi2HTML::THISDOC{'index_entries_array'}})
- {
- #print STDERR "$Texi2HTML::THISDOC{'index_entries_array'}->{$index_name}) letters\n";
- my %letters_hash;
- foreach my $index_entry (@{$Texi2HTML::THISDOC{'index_entries_array'}->{$index_name}})
- {
- my $key = sorted_line($index_entry->{'texi'});
- $index_entry->{'key'} = $key;
- my $letter = uc(substr($key, 0, 1));
- push @{$letters_hash{$letter}}, $index_entry;
- }
- # use cmp if only letters or only symbols, otherwise symbols before
- # letters
- foreach my $letter (sort {
- ((($a =~ /^[[:alpha:]]/ and $b =~ /^[[:alpha:]]/) or
- ($a !~ /^[[:alpha:]]/ and $b !~ /^[[:alpha:]]/)) && $a cmp $b)
- || ($a =~ /^[[:alpha:]]/ && 1) || -1 } (keys %letters_hash))
- {
- # FIXME sort without uc?
- # This sorts the entries for a given letter
- my @sorted_letter_entries = (sort {uc($a->{'key'}) cmp uc($b->{'key'})} (@{$letters_hash{$letter}}));
- push @{$Texi2HTML::THISDOC{'index_letters_array'}->{$index_name}}, { 'letter' => $letter, 'entries' => \@sorted_letter_entries };
- }
- }
- # generate the keys for index sorting also for the entries not
- # associated with an index.
- foreach my $index_entry_without_index (@unknown_index_index_entries)
- {
- my $key = sorted_line($index_entry_without_index->{'texi'});
- $index_entry_without_index->{'key'} = $key;
- }
- Texi2HTML::Config::t2h_default_init_split_indices();
- }
- # This function is used to construct link names from node names as
- # specified for texinfo
- sub cross_manual_links()
- {
- my @all_index_entries;
- foreach my $index_name (sort(keys(%{$Texi2HTML::THISDOC{'index_entries_array'}})))
- {
- push @all_index_entries, @{$Texi2HTML::THISDOC{'index_entries_array'}->{$index_name}};
- }
- print STDERR "# Doing ".scalar(keys(%nodes))." cross manual links ".
- scalar(@all_index_entries). " index entries\n"
- if ($T2H_DEBUG);
- $::simple_map_texi_ref = \%cross_ref_simple_map_texi;
- $::style_map_texi_ref = \%cross_ref_style_map_texi;
- $::texi_map_ref = \%cross_ref_texi_map;
- my $normal_text_kept = $Texi2HTML::Config::normal_text;
- $Texi2HTML::Config::normal_text = \&Texi2HTML::Config::t2h_cross_manual_normal_text;
- my $style_kept = $Texi2HTML::Config::style;
- $Texi2HTML::Config::style = \&Texi2HTML::Config::T2H_GPL_style;
- foreach my $key (sort(keys(%nodes)))
- {
- my $node = $nodes{$key};
- #print STDERR "CROSS_MANUAL:$key,$node\n";
- if (!defined($node->{'texi'}))
- {
- ###################### debug section
- foreach my $key (keys(%$node))
- {
- #print STDERR "$key:$node->{$key}!!!\n";
- }
- ###################### end debug section
- }
- else
- {
- $node->{'cross_manual_target'} = remove_texi($node->{'texi'});
- if ($node->{'cross_manual_target'} !~ /\S/)
- {
- line_error (sprintf(__("Empty node name after expansion `%s'"), $node->{'texi'}), $node->{'line_nr'});
- $node->{'cross_manual_target'} = 't_0';
- $node->{'cross_manual_file'} = 't_0';
- }
- elsif (get_conf('USE_UNICODE'))
- {
- $node->{'cross_manual_target'} = Unicode::Normalize::NFC($node->{'cross_manual_target'});
- if (get_conf('TRANSLITERATE_FILE_NAMES') and get_conf('USE_UNIDECODE'))
- {
- $node->{'cross_manual_file'} =
- unicode_to_protected(unicode_to_transliterate($node->{'cross_manual_target'}));
- }
- $node->{'cross_manual_target'} =
- unicode_to_protected($node->{'cross_manual_target'});
- }
- #print STDERR "CROSS_MANUAL_TARGET $node->{'cross_manual_target'}\n";
- unless ($node->{'external_node'})
- {
- if (exists($cross_reference_nodes{$node->{'cross_manual_target'}}))
- {
- my $other_node_array = $cross_reference_nodes{$node->{'cross_manual_target'}};
- my $node_seen;
- foreach my $other_node (@{$other_node_array})
- { # find the first node seen for the error message
- $node_seen = $other_node;
- last if ($nodes{$other_node}->{'seen'})
- }
- my $other_node_line_nr = $nodes{$node_seen}->{'line_nr'};
- if (defined($other_node_line_nr))
- {
- msg_error ("Node equivalent with `$node->{'texi'}' already used `$node_seen' ".format_line_number($other_node_line_nr), $node->{'line_nr'});
- }
- else
- {
- msg_error ("Node equivalent with `$node->{'texi'}' already used `$node_seen'", $node->{'line_nr'});
- }
- push @{$other_node_array}, $node->{'texi'};
- }
- else
- {
- push @{$cross_reference_nodes{$node->{'cross_manual_target'}}}, $node->{'texi'};
- }
- }
- }
- }
-
- if (get_conf('TRANSLITERATE_FILE_NAMES') and
- (!get_conf('USE_UNICODE') or !get_conf('USE_UNIDECODE')))
- {
- $::style_map_texi_ref = \%cross_transliterate_style_map_texi;
- $::texi_map_ref = \%cross_transliterate_texi_map;
- $Texi2HTML::Config::normal_text = \&Texi2HTML::Config::t2h_cross_manual_normal_text_transliterate if (!get_conf('USE_UNICODE'));
- foreach my $key (keys(%nodes))
- {
- my $node = $nodes{$key};
- #print STDERR "TRANSLITERATE:$key,$node\n";
- if (defined($node->{'texi'}))
- {
- $node->{'cross_manual_file'} = remove_texi($node->{'texi'});
- if ($node->{'cross_manual_file'} !~ /\S/)
- {
- $node->{'cross_manual_file'} = 't_0';
- }
- elsif (get_conf('USE_UNICODE'))
- {
- $node->{'cross_manual_file'} = unicode_to_protected(unicode_to_transliterate($node->{'cross_manual_file'}));
- }
- }
- }
- foreach my $entry (@all_index_entries, values(%sections), values(%headings))
- {
- #print STDERR "TRANSLITERATE($entry) $entry->{'texi'}\n";
- $entry->{'cross'} = remove_texi($entry->{'texi'});
- $entry->{'cross'} = unicode_to_protected(unicode_to_transliterate($entry->{'cross'})) if (get_conf('USE_UNICODE'));
- }
- }
- else
- {
- foreach my $entry (@all_index_entries, values(%sections), values(%headings))
- {
- $entry->{'cross'} = remove_texi($entry->{'texi'});
- if (get_conf('USE_UNICODE'))
- {
- $entry->{'cross'} = Unicode::Normalize::NFC($entry->{'cross'});
- if (get_conf('TRANSLITERATE_FILE_NAMES') and get_conf('USE_UNIDECODE')) # USE_UNIDECODE is redundant
- {
- $entry->{'cross'} =
- unicode_to_protected(unicode_to_transliterate($entry->{'cross'}));
- }
- else
- {
- $entry->{'cross'} =
- unicode_to_protected($entry->{'cross'});
- }
- }
- }
- }
- $Texi2HTML::Config::normal_text = $normal_text_kept;
- $Texi2HTML::Config::style = $style_kept;
- $::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi;
- $::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi;
- $::texi_map_ref = \%Texi2HTML::Config::texi_map;
- }
- # This function is used to construct a link name from a node name as
- # specified for texinfo
- sub cross_manual_line($;$)
- {
- my $text = shift;
- my $transliterate = shift;
- #print STDERR "cross_manual_line $text\n";
- #print STDERR "remove_texi text ". remove_texi($text)."\n\n\n";
- if ($text !~ /\S/)
- {
- # special case for empty node/ref
- return ('t_0', 't_0');
- }
- $::simple_map_texi_ref = \%cross_ref_simple_map_texi;
- $::style_map_texi_ref = \%cross_ref_style_map_texi;
- $::texi_map_ref = \%cross_ref_texi_map;
- my $normal_text_kept = $Texi2HTML::Config::normal_text;
- $Texi2HTML::Config::normal_text = \&Texi2HTML::Config::t2h_cross_manual_normal_text;
- my $style_kept = $Texi2HTML::Config::style;
- $Texi2HTML::Config::style = \&Texi2HTML::Config::T2H_GPL_style;
-
- my ($cross_ref_target, $cross_ref_file);
- if (get_conf('USE_UNICODE'))
- {
- $cross_ref_target = Unicode::Normalize::NFC(remove_texi($text));
- if ($transliterate and get_conf('USE_UNIDECODE'))
- {
- $cross_ref_file =
- unicode_to_protected(unicode_to_transliterate($cross_ref_target));
- }
- $cross_ref_target = unicode_to_protected($cross_ref_target);
- }
- else
- {
- $cross_ref_target = remove_texi($text);
- }
-
- if ($transliterate and
- (!get_conf('USE_UNICODE') or !get_conf('USE_UNIDECODE')))
- {
- $::style_map_texi_ref = \%cross_transliterate_style_map_texi;
- $::texi_map_ref = \%cross_transliterate_texi_map;
- $Texi2HTML::Config::normal_text = \&Texi2HTML::Config::t2h_cross_manual_normal_text_transliterate if (!get_conf('USE_UNICODE'));
- $cross_ref_file = remove_texi($text);
- $cross_ref_file = unicode_to_protected(unicode_to_transliterate($cross_ref_file))
- if (get_conf('USE_UNICODE'));
- }
- $Texi2HTML::Config::normal_text = $normal_text_kept;
- $Texi2HTML::Config::style = $style_kept;
- $::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi;
- $::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi;
- $::texi_map_ref = \%Texi2HTML::Config::texi_map;
- #print STDERR "\n\ncross_ref $cross_ref\n";
- unless ($transliterate)
- {
- return $cross_ref_target;
- }
- # print STDERR "$text|$cross_ref_target|$cross_ref_file\n";
- return ($cross_ref_target, $cross_ref_file);
- }
- sub equivalent_nodes($)
- {
- my $name = shift;
- #print STDERR "equivalent_nodes $name\n";
- my $node = normalise_node($name);
- $name = cross_manual_line($node);
- #print STDERR "equivalent_nodes `$node' `$name'\n";
- my @equivalent_nodes = ();
- if (exists($cross_reference_nodes{$name}))
- {
- @equivalent_nodes = grep {$_ ne $node} @{$cross_reference_nodes{$name}};
- }
- return @equivalent_nodes;
- }
- sub find_equivalent_node($)
- {
- my $name = shift;
- my @equivalent_nodes = equivalent_nodes($name);
- my $node_seen;
- foreach my $equivalent_node (@equivalent_nodes)
- {
- if ($nodes{$equivalent_node}->{'seen'})
- {
- $node_seen = $equivalent_node;
- last;
- }
- }
- return $node_seen;
- }
- sub do_place_target_file($$$)
- {
- my $place = shift;
- my $element = shift;
- my $context = shift;
- $place->{'file'} = $element->{'file'} unless defined($place->{'file'});
- $place->{'target'} = $element->{'target'} unless defined($place->{'target'});
- if (defined($Texi2HTML::Config::placed_target_file_name))
- {
- my ($target, $id, $file) = &$Texi2HTML::Config::placed_target_file_name($place, $element, $place->{'target'}, $place->{'id'}, $place->{'file'}, $context);
- $place->{'target'} = $target if (defined($target));
- $place->{'file'} = $file if (defined($file));
- $place->{'id'} = $id if (defined($id));
- }
- }
- sub do_node_target_file($$)
- {
- my $node = shift;
- my $type_of_node = shift;
- my $node_file = &$Texi2HTML::Config::node_file_name($node,$type_of_node);
- $node->{'node_file'} = $node_file if (defined($node_file));
- if (defined($Texi2HTML::Config::node_target_name))
- {
- my ($target,$id) = &$Texi2HTML::Config::node_target_name($node, $node->{'target'}, $node->{'id'}, $type_of_node);
- $node->{'target'} = $target if (defined($target));
- $node->{'id'} = $id if (defined($id));
- }
- }
- sub do_element_targets($;$)
- {
- my $element = shift;
- my $use_node_file = shift;
- my $is_top = '';
- $is_top = 'top' if (defined($element_top) and ($element eq $element_top or (defined($element->{'with_node'}) and $element->{'with_node'} eq $element_top)));
- if (get_conf('SPLIT_INDEX') and get_conf('SPLIT'))
- {
- Texi2HTML::Config::t2h_default_associate_index_element($element, $is_top, $docu_name, $use_node_file);
- }
- if (defined($Texi2HTML::Config::element_file_name))
- {
- my $previous_file_name = $element->{'file'};
- my $filename =
- &$Texi2HTML::Config::element_file_name ($element, $is_top, $docu_name);
- if (defined($filename))
- {
- foreach my $place (@{$element->{'place'}})
- {
- $place->{'file'} = $filename if (defined($place->{'file'}) and ($place->{'file'} eq $previous_file_name));
- }
- $element->{'file'} = $filename;
- if ($is_top)
- { # reset these variables, although they aren't used much, they may be
- # used in file name comparisons
- $docu_top = $filename;
- $docu_top_file = "$docu_rdir$docu_top";
- }
- }
- }
- print STDERR "file !defined for element $element->{'texi'}\n" if (!defined($element->{'file'}));
- if (defined($Texi2HTML::Config::element_target_name))
- {
- my ($target,$id) = &$Texi2HTML::Config::element_target_name($element, $element->{'target'}, $element->{'id'});
- $element->{'target'} = $target if (defined($target));
- $element->{'id'} = $id if (defined($id));
- }
- foreach my $place(@{$element->{'place'}})
- {
- do_place_target_file($place, $element, '');
- }
- }
- sub add_t2h_element($$$)
- {
- my $element = shift;
- my $elements_list = shift;
- my $prev_element = shift;
- push @$elements_list, $element;
- $element->{'element_ref'} = $element;
- $element->{'this'} = $element;
- if (defined($prev_element))
- {
- $element->{'back'} = $prev_element;
- $prev_element->{'forward'} = $element;
- }
- push @{$element->{'place'}}, $element;
- push @{$element->{'place'}}, @{$element->{'current_place'}};
- return $element;
- }
- sub add_t2h_dependent_element ($$)
- {
- my $element = shift;
- my $element_ref = shift;
- $element->{'element_ref'} = $element_ref;
- $element_index = $element_ref if ($element_index and ($element_index eq $element));
- push @{$element_ref->{'place'}}, $element;
- push @{$element_ref->{'place'}}, @{$element->{'current_place'}};
- }
- my %files = (); # keys are files. This is used to avoid reusing an already
- # used file name
- my @opened_files = (); # all the files opened by the program to remove
- # them if FORCE is not set and an error occured
- my %printed_indices = (); # value is true for an index name not empty and
- # printed
- # This is a virtual element used to have the right hrefs for index entries
- # and anchors in footnotes.
- my $footnote_element;
- # find next, prev, up, back, forward, fastback, fastforward
- # find element id and file
- # split index pages
- # associate placed items (items which have links to them) with the right
- # file and id
- # associate nodes with sections
- sub rearrange_elements()
- {
- print STDERR "# find sections levels and toplevel\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
-
- my $toplevel = 4;
- # correct level if raisesections or lowersections overflowed
- # and find toplevel level
- # use %sections and %headings to modify also the headings
- foreach my $section (values(%sections), values(%headings))
- {
- my $level = $section->{'level'};
- if ($level > $MAX_LEVEL)
- {
- $section->{'level'} = $MAX_LEVEL;
- }
- # second condition is for @top and @part
- elsif ($level < $MIN_LEVEL and ($reference_sec2level{$section->{'tag'}} >= $MIN_LEVEL))
- {
- $section->{'level'} = $MIN_LEVEL;
- }
- else
- {
- $section->{'level'} = $level;
- }
- $section->{'toc_level'} = $section->{'level'};
- # This is for top
- $section->{'toc_level'} = $MIN_LEVEL if ($section->{'level'} < $MIN_LEVEL);
- # find the new tag corresponding with the level of the section
- if ($section->{'tag'} !~ /heading/ and ($level ne $reference_sec2level{$section->{'tag'}}))
- {
- $section->{'tag_level'} = $level2sec{$section->{'tag'}}->[$section->{'level'}];
- }
- else
- {
- $section->{'tag_level'} = $section->{'tag'};
- }
- $toplevel = $section->{'level'} if (($section->{'level'} < $toplevel) and ($section->{'level'} > 0 and ($section->{'tag'} !~ /heading/)));
- print STDERR "# section level $level: $section->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- }
-
- print STDERR "# find sections structure, construct section numbers (toplevel=$toplevel)\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- my $in_appendix = 0;
- # these arrays have an element per sectioning level.
- my @previous_numbers = (); # holds the number of the previous sections
- # at the same and upper levels
- my @previous_sections = (); # holds the ref of the previous sections
- my $previous_toplevel;
- my @pending_parts; # parts yet to be associated with the
- # following element
-
- foreach my $section (@sections_list)
- {
- ########################### debug
- print STDERR "BUG: node or section_ref defined for section $section->{'texi'}\n"
- if (exists($section->{'node'}) or exists($section->{'section_ref'}));
- print STDERR "Bug level undef for ($section) $section->{'texi'}\n" if (!defined($section->{'level'}));
- ########################### end debug
- # associate with first node if it is a section appearing before
- # the first node
- $section->{'node_ref'} = $nodes_list[0] if ($nodes_list[0] and !$section->{'node_ref'});
- # a part doesn't really make up an element, it is associated with the
- # next sectioning element instead.
- if ($section->{'tag'} eq 'part')
- {
- push @pending_parts, $section;
- }
- elsif (@pending_parts)
- {
- if ($section->{'tag'} ne 'top')
- {
- foreach my $part (@pending_parts)
- {
- $part->{'part_section_ref'} = $section;
- if (!$section->{'with_part'})
- {
- $section->{'with_part'} = $part;
- $part->{'part_with_section'} = $section;
- }
- # if a node is associated with the part, reassociate it with
- # the chapter
- if ($part->{'with_node'} and !$section->{'with_node'})
- {
- $section->{'with_node'} = $part->{'with_node'};
- delete $part->{'with_node'};
- $section->{'with_node'}->{'with_section'} = $section;
- }
- }
- }
- @pending_parts = ();
- }
- # we track the toplevel next and previous because there is no
- # strict child parent relationship between chapters and top. Indeed
- # a chapter may appear before @top, it may be better to consider them
- # on the same toplevel.
- if ($section->{'level'} <= $toplevel)
- {
- $section->{'toplevel'} = 1;
- if (defined($previous_toplevel))
- {
- $previous_toplevel->{'toplevelnext'} = $section;
- $section->{'toplevelprev'} = $previous_toplevel;
- }
- # part is not used as previous_toplevel since toplevel directions
- # are used to move between chapters (and top)
- $previous_toplevel = $section if ($section->{'tag'} ne 'part');
- # In fact this is only useful for toplevel elements appearing
- # before @top, the other have their sectionup reset up below
- # based on the sectioning commands hierarchy.
- if (defined($section_top) and $section ne $section_top)
- {
- $section->{'sectionup'} = $section_top;
- }
- }
- # undef things under that section level
- my $section_level = $section->{'level'};
- for (my $level = $section_level + 1; $level < $MAX_LEVEL + 1 ; $level++)
- {
- $previous_numbers[$level] = undef unless ($section->{'tag'} =~ /unnumbered/ or $section->{'tag'} eq 'centerchap');
- $previous_sections[$level] = undef;
- }
- my $number_set;
- # find number at the current level
- if ($section->{'tag'} =~ /appendix/ and !$in_appendix)
- {
- $previous_numbers[$toplevel] = 'A';
- $in_appendix = 1;
- $number_set = 1 if ($section->{'level'} <= $toplevel);
- $section->{'appendix_beginning'} = 1;
- }
- if (!defined($previous_numbers[$section->{'level'}]) and !$number_set)
- {
- if ($section->{'tag'} =~ /unnumbered/ or $section->{'tag'} eq 'centerchap')
- {
- $previous_numbers[$section->{'level'}] = undef;
- }
- else
- {
- $previous_numbers[$section->{'level'}] = 1;
- }
- }
- elsif ($section->{'tag'} !~ /unnumbered/ and $section->{'tag'} ne 'centerchap' and !$number_set)
- {
- $previous_numbers[$section->{'level'}]++;
- }
- # construct the section number
- $section->{'number'} = '';
- unless ($section->{'tag'} =~ /unnumbered/ or $section->{'tag'} eq 'centerchap' or $section->{'tag'} eq 'top' or $section->{'tag'} eq 'part')
- {
- my $level = $section->{'level'};
- while ($level > $toplevel)
- {
- my $number = $previous_numbers[$level];
- $number = 0 if (!defined($number));
- if ($section->{'number'})
- {
- $section->{'number'} = "$number.$section->{'number'}";
- }
- else
- {
- $section->{'number'} = $number;
- }
- $level--;
- }
- my $toplevel_number = $previous_numbers[$toplevel];
- $toplevel_number = 0 if (!defined($toplevel_number));
-
- if ($section->{'number'})
- { # not toplevel
- $section->{'number'} = "$toplevel_number.$section->{'number'}";
- }
- else
- { # toplevel
- $section->{'number'} = $toplevel_number;
- if ($section->{'tag'} =~ /appendix/)
- {# i18n
- $section->{'plain_number'} = $section->{'number'};
- $section->{'number'} = "Appendix $section->{'number'}";
- }
- }
- }
- $section->{'plain_number'} = $section->{'number'} if (!defined($section->{'plain_number'}));
- # find the previous section
- if (defined($previous_sections[$section->{'level'}]))
- {
- my $prev_section = $previous_sections[$section->{'level'}];
- $section->{'sectionprev'} = $prev_section;
- $prev_section->{'sectionnext'} = $section;
- }
- # find the up section
- my $level = $section->{'level'} - 1;
- while (!defined($previous_sections[$level]) and ($level >= 0))
- {
- $level--;
- }
- # The second conditions ensures that a @part is stopped by
- # the first @appendix command.
- if (defined($previous_sections[$level])
- and !($section->{'appendix_beginning'} and $previous_sections[$level]->{'tag'} eq 'part' and $previous_sections[$level]->{'part_section_ref'} ne $section))
- {
- # toplevel elements have already their up set to the top element,
- # it is overwriten here for most cases -- this leads to a different
- # sectionup if there are parts, for instance.
- # as a side note, it is not touched upon if the element appears
- # before @top.
- $section->{'sectionup'} = $previous_sections[$level];
- # 'child' is the first child.
- if (!$section->{'sectionup'}->{'child'})
- {
- $section->{'sectionup'}->{'child'} = $section;
- }
- else
- {
- # 'childnext' is the next child of a an element. it may
- # be different from 'sectionnext' when the elemnt are not
- # at the same level, for example
- # @chapter chapter
- # @subsection subsection (certainly wrong)
- # @section section (not next of subsection, but childnext)
- $section->{'sectionup'}->{'section_childs'}->[-1]->{'childnext'} = $section if (defined($section->{'sectionup'}->{'section_childs'}));
- }
- push @{$section->{'sectionup'}->{'section_childs'}}, $section;
- }
- $previous_sections[$section->{'level'}] = $section;
- # This is what is used in the init file.
- $section->{'up'} = $section->{'sectionup'};
- # Not used but documented.
- $section->{'next'} = $section->{'sectionnext'};
- $section->{'prev'} = $section->{'sectionprev'};
- ############################# debug
- my $up = "NO_UP";
- $up = $section->{'sectionup'} if (defined($section->{'sectionup'}));
- print STDERR "# numbering section ($section->{'level'}): $section->{'number'}: (up: $up) $section->{'texi'}\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- ############################# end debug
- }
- # at that point there are still some node structures that are not
- # in %nodes, (the external nodes, and unknown nodes in case
- # novalidate is true) so we cannot find the id. The consequence is that
- # some node equivalent with another node may not be catched during
- # that pass. We mark the nodes that have directions for unreferenced
- # nodes and make a second pass for these nodes afterwards.
- my @nodes_with_unknown_directions = ();
- my %node_directions = (
- 'node_prev' => 'nodeprev',
- 'node_next' => 'nodenext',
- 'node_up' => 'nodeup');
- # handle nodes
- # the node_prev... are texinfo strings, find the associated node references
- print STDERR "# Resolve nodes directions\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- foreach my $node (@nodes_list)
- {
- foreach my $direction (sort(keys(%node_directions)))
- {
- if (defined($node->{$direction}))
- {
- if ($nodes{$node->{$direction}} and $nodes{$node->{$direction}}->{'seen'})
- {
- $node->{$node_directions{$direction}} = $nodes{$node->{$direction}};
- }
- elsif (($node->{$direction} =~ /^\(.*\)/) or Texi2HTML::Config::get_conf('novalidate'))
- { # ref to an external node
- if (exists($nodes{$node->{$direction}}))
- {
- $node->{$node_directions{$direction}} = $nodes{$node->{$direction}};
- }
- else
- {
- my $node_ref = { 'texi' => $node->{$direction} };
- $node_ref->{'external_node'} = 1 if ($node->{$direction} =~ /^\(.*\)/);
- $nodes{$node->{$direction}} = $node_ref;
- $node->{$node_directions{$direction}} = $node_ref;
- }
- }
- else
- {
- push @nodes_with_unknown_directions, $node;
- }
- }
- }
- }
- # Find cross manual links as explained on the texinfo mailing list
- # The specification is such that cross manual links formatting should
- # be insensitive to the manual split
- cross_manual_links();
- my %direction_texts = (
- 'node_prev' => 'Prev',,
- 'node_next' => 'Next',
- 'node_up' => 'Up'
- );
- # Now it is possible to find the unknown directions that are equivalent
- # (have same node id) than an existing node
- foreach my $node (@nodes_with_unknown_directions)
- {
- foreach my $direction (sort(keys(%node_directions)))
- {
- if (defined($node->{$direction}) and !$node->{$node_directions{$direction}})
- {
- line_error (sprintf(__("%s reference to nonexistent `%s'"),$direction_texts{$direction}, $node->{$direction}), $node->{'line_nr'}); # for `$node->{'texi'}'"
- my $node_seen = find_equivalent_node($node->{$direction});
- if (defined($node_seen))
- {
- document_warn ("---> but equivalent node `$node_seen' found");
- $node->{$node_directions{$direction}} = $nodes{$node_seen};
- }
- }
- }
- }
- # nodes are attached to the section preceding them if not already
- # associated with a section.
- # a @part should never have nodes associated, if it is associated
- # with a chapter, instead the chapter pointed on by part_section_ref is
- # used.
- my $current_section = $sections_list[0];
- $current_section = $current_section->{'part_section_ref'} if ($current_section and $current_section->{'part_section_ref'});
- foreach my $element (@all_elements)
- {
- if ($element->{'node'})
- {
- if ($element->{'with_section'})
- { # the node is associated with a section
- $element->{'section_ref'} = $element->{'with_section'};
- }
- elsif (defined($current_section))
- {# node appearing after a section, but not before another section,
- # or appearing before any section
- $element->{'section_ref'} = $current_section;
- push @{$current_section->{'node_childs'}}, $element;
- }
- }
- else
- {
- $current_section = $element;
- $current_section = $element->{'part_section_ref'} if ($element->{'part_section_ref'});
- }
- }
- print STDERR "# Complete nodes next prev and up based on menus and sections\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- # set the default id based on the node number
- my $node_nr = 1;
- # find the node* directions
- # find the directions corresponding with sections
- # and set 'up' for the node
- foreach my $node (@nodes_list)
- {
- # first a warning if the node and the equivalent nodes don't
- # appear in menus.
- # Don't warn for the top node, and the first node if there is no
- # top node.
- if ((($node_top and $node ne $node_top) or (!$node_top and $node ne $node_first)) and !$node->{'menu_up'} and get_conf('SHOW_MENU'))
- {
- my @equivalent_nodes = equivalent_nodes($node->{'texi'});
- my $found = 0;
- foreach my $equivalent_node (@equivalent_nodes)
- {
- if (($nodes{$equivalent_node} eq $node_first) or $nodes{$equivalent_node}->{'menu_up'})
- {
- $found = 1;
- last;
- }
- }
- unless ($found)
- { # makeinfo has also
- # "`%s' has no Up field (perhaps incorrect sectioning?)"
- # but it is not useful since the up will always be set if
- # the node appears in a menu so the following error message
- # is enough
- line_warn (sprintf(__("unreferenced node `%s'"), $node->{'texi'}), $node->{'line_nr'});
- }
- }
- # use values deduced from menus to complete missing up, next, prev
- # or from sectioning commands if automatic sectioning
- if (!$node->{'nodeup'})
- {
- if (defined($node_top) and ($node eq $node_top) and $node->{'automatic_directions'})
- { # Top node has a special up, which is (dir) by default
- my $top_nodeup = get_conf('TOP_NODE_UP');
- if (exists($nodes{$top_nodeup}))
- {
- $node->{'nodeup'} = $nodes{$top_nodeup};
- }
- else
- {
- my $node_ref = { 'texi' => $top_nodeup };
- $node_ref->{'external_node'} = 1;
- $nodes{$top_nodeup} = $node_ref;
- $node->{'nodeup'} = $node_ref;
- }
- }
- elsif ($node->{'automatic_directions'})
- {
- if ($node->{'with_section'})
- {
- # ignore the up if it is a @part. If the sectioning is
- # correct, the element is toplevel and will be handled
- # by the next condition.
- if ($node->{'with_section'}->{'sectionup'} and !$node->{'with_section'}->{'sectionup'}->{'part_section_ref'})
- {
- $node->{'nodeup'} = get_node($node->{'with_section'}->{'sectionup'});
- }
- elsif ($node->{'with_section'}->{'toplevel'} and defined($section_top) and ($node->{'with_section'} ne $section_top))
- {
- $node->{'nodeup'} = get_node($section_top);
- }
- print STDERR "# Deducing from section node_up $node->{'nodeup'}->{'texi'} for $node->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS and defined($node->{'nodeup'}));
- }
- elsif ($node->{'menu_up'})
- {
- $node->{'nodeup'} = $node->{'menu_up'};
- print STDERR "# Deducing from menu node_up $node->{'menu_up'}->{'texi'} for $node->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- }
- }
- }
- if ($node->{'nodeup'} and !$node->{'nodeup'}->{'external_node'})
- {
- # We detect when the up node has no menu entry for that node, as
- # there may be infinite loops when finding following node (see below)
- unless (defined($node->{'menu_up_hash'}) and ($node->{'menu_up_hash'}->{$node->{'nodeup'}->{'texi'}}))
- {
- line_error(sprintf(__("Node `%s' lacks menu item for `%s' despite being its Up target"), $node->{'nodeup'}->{'texi'}, $node->{'texi'}), $node->{'nodeup'}->{'line_nr'}) if (get_conf('SHOW_MENU'));
- }
- }
- # check that the up is in one of the menus
- if (get_conf('SHOW_MENU') and $node->{'nodeup'} and $node->{'menu_up'})
- {
- my @equivalent_nodes = equivalent_nodes($node->{'nodeup'}->{'texi'});
- my $found = 0;
- foreach my $equivalent_node ($node->{'nodeup'}->{'texi'}, @equivalent_nodes)
- {
- if ($node->{'menu_up_hash'}->{$equivalent_node})
- {
- $found = 1;
- last;
- }
- }
- unless ($found)
- {
- line_warn (sprintf(__("For `%s', up in menu `%s' and up `%s' don't match"), $node->{'texi'}, $node->{'menu_up'}->{'texi'}, $node->{'nodeup'}->{'texi'}), $node->{'line_nr'});
- }
- }
- # Find next node if not already found
- if ($node->{'nodenext'})
- {
- # doing the following would be wrong:
- #$node->{'nodenext'}->{'nodeprev'} = $node if (!defined($node->{'nodenext'}->{'nodeprev'}));
- }
- elsif ($node->{'texi'} eq 'Top' and $node->{'automatic_directions'})
- { # special case as said in the texinfo manual
- if ($node->{'menu_child'})
- {
- $node->{'nodenext'} = $node->{'menu_child'};
- $node->{'menu_child'}->{'nodeprev'} = $node;
- }
- }
- elsif ($node->{'automatic_directions'})
- {
- if (defined($node->{'with_section'}))
- {
- my $next;
- my $warn_for_next_not_in_menu = 1;
- my $section = $node->{'with_section'};
- if ($section->{'sectionnext'})
- {
- $next = get_node($section->{'sectionnext'});
- }
- # we use toplevelnext, mostly for chapters associated with
- # @part. But we don't want to have the @top as prev for
- # a @chapter or the like
- elsif ($section->{'toplevelnext'} and $section->{'toplevelnext'} ne $section_top)
- {
- $next = get_node($section->{'toplevelnext'});
- }
- elsif (get_conf('USE_UP_FOR_ADJACENT_NODES'))
- { # makeinfo don't do that. So this is conditionnal.
- # Also no warning, because it is expected that the
- # next found out with the up is not the next in menu.
- $warn_for_next_not_in_menu = 0;
- while (defined($section->{'sectionup'}) and !defined($section->{'sectionnext'}))
- {
- $section = $section->{'sectionup'};
- }
- if (defined($section->{'sectionnext'}))
- {
- $next = get_node($section->{'sectionnext'});
- }
- }
- if (defined($next) and get_conf('SHOW_MENU') and $warn_for_next_not_in_menu)
- {
- line_warn (sprintf(__("No node following `%s' in menu, but `%s' follows in sectioning"), $node->{'texi'}, $next->{'texi'}), $node->{'line_nr'}) if (!defined($node->{'menu_next'}));
- line_warn (sprintf(__("Node following `%s' in menu `%s' and in sectioning `%s' differ"), $node->{'texi'}, $node->{'menu_next'}->{'texi'}, $next->{'texi'}), $node->{'line_nr'})
- if (defined($node->{'menu_next'}) and $next ne $node->{'menu_next'});
- }
- $node->{'nodenext'} = $next;
- }
- elsif ($node->{'menu_next'})
- {
- $node->{'nodenext'} = $node->{'menu_next'};
- }
- }
- # Find prev node
- if ($node->{'nodeprev'})
- {
- # doing the following would be wrong:
- #$node->{'nodeprev'}->{'nodenext'} = $node if (!defined($node->{'nodeprev'}->{'nodenext'}));
- }
- elsif ($node->{'automatic_directions'})
- {
- if (defined($node->{'with_section'}))
- {
- my $section = $node->{'with_section'};
- if ($section->{'sectionprev'})
- {
- $node->{'nodeprev'} = get_node($section->{'sectionprev'});
- }
- # we use toplevelprev, mostly for chapters associated with
- # @part. But we don't want to have the @top as prev for
- # a @chapter or the like
- elsif ($section->{'toplevelprev'} and $section->{'toplevelprev'} ne $section_top)
- {
- $node->{'nodeprev'} = get_node($section->{'toplevelprev'});
- }
- elsif (get_conf('USE_UP_FOR_ADJACENT_NODES') and defined($section->{'sectionup'}))
- { # makeinfo don't do that
- $node->{'nodeprev'} = get_node($section->{'sectionup'});
- }
- }
- elsif ($node->{'menu_prev'})
- {
- $node->{'nodeprev'} = $node->{'menu_prev'};
- }
- # the prev node is the parent node
- elsif ($node->{'menu_up'} and ($node->{'menu_up'}->{'menu_child'} eq $node) and get_conf('USE_UP_FOR_ADJACENT_NODES'))
- {
- $node->{'nodeprev'} = $node->{'menu_up'};
- }
- }
-
- # the nodeforward node is the node following in node reading order
- # it is thus first the child, else the next, else the next following
- # the up
- if ($node->{'menu_child'})
- {
- $node->{'nodeforward'} = $node->{'menu_child'};
- }
- elsif ($node->{'automatic_directions'} and defined($node->{'with_section'}) and defined($node->{'with_section'}->{'child'}))
- {
- $node->{'nodeforward'} = get_node($node->{'with_section'}->{'child'});
- }
- elsif (defined($node->{'nodenext'}))
- {
- $node->{'nodeforward'} = $node->{'nodenext'};
- }
- else
- {
- my $up = $node->{'nodeup'};
- my @up_list = ($node);
- # the condition with the up_list avoids infinite loops
- # the last condition stops when the Top node is reached.
- while (defined($up) and not (grep {$up eq $_} @up_list or (($node_top) and ($up eq $node_top))))
- {
- if (defined($up->{'nodenext'}))
- {
- $node->{'nodeforward'} = $up->{'nodenext'};
- last;
- }
- push @up_list, $up;
- $up = $up->{'nodeup'};
- }
- }
- $node->{'nodeforward'}->{'nodeback'} = $node
- if ($node->{'nodeforward'} and not $node->{'nodeforward'}->{'nodeback'});
- # copy the direction of the associated section.
- if (defined($node->{'with_section'}))
- {
- my $section = $node->{'with_section'};
- foreach my $direction ('sectionnext', 'sectionprev', 'sectionup')
- {
- $node->{$direction} = $section->{$direction}
- if (defined($section->{$direction}));
- }
- }
- # 'up' is used in init files. It is almost sectionup, but not
- # exactly, it allows to have something relevant whether elements
- # are nodes or sections -- just like Back and Forward. So it
- # should certainly be kept.
- if (defined($node->{'sectionup'}))
- {
- $node->{'up'} = $node->{'sectionup'};
- }
- elsif (defined($node->{'nodeup'}) and
- (!$node_top or ($node ne $node_top)))
- {
- $node->{'up'} = $node->{'nodeup'};
- }
- # 'next' not used but documented.
- if (defined($node->{'sectionnext'}))
- {
- $node->{'next'} = $node->{'sectionnext'};
- }
- if (defined($node->{'sectionprev'}))
- {
- $node->{'prev'} = $node->{'sectionprev'};
- }
- # default id for nodes. Should be overriden later.
- $node->{'id'} = 'NOD' . $node_nr;
- $node_nr++;
- }
-
- # do node directions for sections.
- foreach my $section (@sections_list)
- {
- # If the element is not a node, then all the node directions are copied
- # if there is an associated node
- if (defined($section->{'with_node'}))
- {
- $section->{'nodenext'} = $section->{'with_node'}->{'nodenext'};
- $section->{'nodeprev'} = $section->{'with_node'}->{'nodeprev'};
- $section->{'menu_next'} = $section->{'with_node'}->{'menu_next'};
- $section->{'menu_prev'} = $section->{'with_node'}->{'menu_prev'};
- $section->{'menu_child'} = $section->{'with_node'}->{'menu_child'};
- $section->{'menu_up'} = $section->{'with_node'}->{'menu_up'};
- $section->{'nodeup'} = $section->{'with_node'}->{'nodeup'};
- $section->{'nodeforward'} = $section->{'with_node'}->{'nodeforward'};
- $section->{'nodeback'} = $section->{'with_node'}->{'nodeback'};
- }
- }
- my $only_nodes = 0;
- my $only_sections = 0;
- # for legibility
- my $use_nodes = get_conf('USE_NODES');
- my $use_sections = get_conf('USE_SECTIONS');
- $only_nodes = 1 if (
- (!scalar(@sections_list) and
- ($use_nodes or (!$use_sections and !defined($use_nodes))))
- or ($use_nodes and !$use_sections)
- );
- $only_sections = 1 if (!$only_nodes and !$use_nodes and ($use_sections or !defined($use_sections)));
- #print STDERR "USE_NODES $use_nodes, USE_SECTIONS $use_sections. only_nodes: $only_nodes, only_sections $only_sections\n";
- my $prev_element;
- print STDERR "# Build the elements list only_nodes: $only_nodes, only_sections $only_sections\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- foreach my $element (@all_elements)
- {
- if ($element->{'node'})
- {
- if ($element->{'section_ref'} and ($only_sections or (!$only_nodes and $element->{'with_section'})))
- {
- add_t2h_dependent_element ($element, $element->{'section_ref'});
- }
- elsif (!$only_sections)
- {
- $prev_element = add_t2h_element($element, \@elements_list, $prev_element);
- }
- else # $only_section and !$section_ref. This should only
- # happen when there are no sections
- {
- #print STDERR "node $element->{'texi'} not associated with an element\n";
- }
- }
- else
- {
- my $part_element = $element->{'part_section_ref'};
- if (($element->{'node_ref'} or ($part_element and $part_element->{'node_ref'})) and $only_nodes)
- {
- my $element_with_node = $element;
- $element_with_node = $part_element if ($part_element);
- add_t2h_dependent_element ($element, $element_with_node->{'node_ref'});
- }
- elsif (!$only_nodes)
- {
- if ($part_element)
- {
- add_t2h_dependent_element ($element, $part_element);
- }
- else
- {
- $prev_element = add_t2h_element($element, \@elements_list, $prev_element);
- }
- }
- else
- { # no node, and $only_nodes
- #print STDERR "$element->{'tag'} $element->{'texi'} not associated with an element\n";
- }
- }
- }
- # find texi2html specific directions and elements that are not texinfo
- # language features.
- #
- # Maybe Config hooks should be used at that point (up to index
- # preparation)
- #
- # find first, last and top elements
- if (@elements_list)
- {
- $element_first = $elements_list[0];
- print STDERR "# element first: $element_first->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- # It is the last element before indices split, which may add new
- # elements
- $element_last = $elements_list[-1];
- }
- else
- {
- print STDERR "# \@elements_list is empty\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- }
- print STDERR "# top node: $node_top->{'texi'}\n" if (defined($node_top) and
- ($T2H_DEBUG & $DEBUG_ELEMENTS));
- # Remark: there are many subtle distinctions among the elements that
- # have a flavor of being at top. First there are the texinfo top
- # elements (if present), namely $section_top for the @top element
- # and $node_top for the @node Top element (and both may be associated).
- # Then there is $element_top, set up just below. In addition to
- # $section_top and $node_top, the section associated with $node_top
- # and the first element may be used. $element_top is used to determine
- # file splitting and file names, since it is always associated with
- # $docu_top file.
- # The $element_top may have 'top' set, in case it is a node or @top.
- # In that case, special formatting is done, like using print_Top and
- # similar.
- # Similarly with element_top, some other nodes than $node_top may
- # get associated with the top node filename without being considered
- # as top otherwise (this is done below).
- if (defined($section_top) and $section_top->{'this'})
- {
- # element top is the element with @top.
- $element_top = $section_top;
- }
- elsif (defined($node_top) and $node_top->{'this'})
- {
- # otherwise top node may be the element_top
- $element_top = $node_top;
- }
- elsif (defined($node_top) and defined($node_top->{'with_section'}) and $node_top->{'with_section'}->{'this'})
- {
- # next, the element associated with the @node Top may be
- # the $element_top. In that case $element_top->{'top'} won't be set
- $element_top = $node_top->{'with_section'};
- }
- elsif (defined($element_first))
- {
- # If there is no @top section no top node associated with an element,
- # first element is used
- $element_top = $element_first;
- }
- # Rather arbitrarily, 'top' is set for nodes as top elements
- # and @top. This triggers specific formatting, like calling
- # print_Top and similar things.
- if (defined($element_top))
- {
- $element_top->{'top'} = 1 if ($element_top->{'node'} or $element_top->{'tag'} eq 'top');
- if ($T2H_DEBUG & $DEBUG_ELEMENTS)
- {
- my $element_top_is_node = 'not a node';
- $element_top_is_node = 'node' if ($element_top->{'node'});
- print STDERR "# element top($element_top_is_node): $element_top->{'texi'}\n";
- }
- }
-
- print STDERR "# find fastback and fastforward\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- foreach my $element (@elements_list)
- { # nodes are ignored here, although their associated sectioning
- # command may be taken into account.
- my $up = get_top($element);
- next unless (defined($up));
- # take the opportunity to set the first chapter with index
- $element_chapter_index = $up if ($element_index and ($element_index eq $element));
- # fastforward is the next element on same level than the upper parent
- # element.
- if (exists ($up->{'toplevelnext'}))
- {
- $element->{'fastforward'} = $up->{'toplevelnext'}
- }
- # if the element isn't at the highest level, fastback is the
- # highest parent element
- if ($up and ($up ne $element))
- {
- $element->{'fastback'} = $up;
- }
- elsif ($element->{'toplevel'})
- {
- # the element is a top level element, we adjust the next
- # toplevel element fastback
- $element->{'fastforward'}->{'fastback'} = $element if ($element->{'fastforward'});
- }
- }
- # set 'reference_element' which is used each time there is a cross ref
- # to that node (xref and menu entry), to do the href, and also the
- # element heading text.
- # It is the section associated with the node if there are only sections.
- # Since in the default case the target is the node target, even for
- # sections, this, in fact shouldn't lead to a different target, unless
- # the node and the section don't have the same file associated, which could
- # only happen with indices split. The heading text will be different, though.
- # The node name should also always be passed to the formatting functions
- # such that it is always possible for the formatting to chose the node
- # heading over the element heading selected using 'reference_element'.
- if ($only_sections)
- {
- foreach my $node(@nodes_list)
- {
- if ($node->{'with_section'})
- {
- $node->{'reference_element'} = $node->{'with_section'};
- }
- }
- }
- # the symmetric is not done for sections, since there is no crossref
- # to sections in texinfo (only to anchors and nodes), so that when
- # there is a link to an element (in Toc, for instance),
- # there is no reason to want to have the node (though, once again,
- # the href is almost surely the same than what would be with the node,
- # the heading would be different).
- # end texi2html added directions
- # do human readable id
- print STDERR "# find float id\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- foreach my $float (@floats)
- {
- $float->{'style_id'} = cross_manual_line($float->{'style_texi'});
- my $float_style = { };
- if (exists($floats{$float->{'style_id'}}))
- {
- $float_style = $floats{$float->{'style_id'}};
- }
- else
- {
- $floats{$float->{'style_id'}} = $float_style;
- }
- push @{$float_style->{'floats'}}, $float;
- $float->{'absolute_nr'} = scalar(@{$float_style->{'floats'}});
- my $up = get_top($float->{'element'});
- if (defined($up) and (!defined($float_style->{'current_chapter'}) or ($up->{'texi'} ne $float_style->{'current_chapter'})))
- {
- $float_style->{'current_chapter'} = $up->{'texi'};
- $float_style->{'nr_in_chapter'} = 1;
- }
- else
- {
- $float_style->{'nr_in_chapter'}++;
- }
- if (defined($up) and $up->{'toplevel'} and $up->{'number'} ne '')
- {
- $float->{'chapter_nr'} = $up->{'plain_number'};
- $float->{'nr'} = $float->{'chapter_nr'} . "." . $float_style->{'nr_in_chapter'};
- }
- else
- {
- $float->{'nr'} = $float->{'absolute_nr'};
- }
- }
- print STDERR "# do human-readable index entries id\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- if (get_conf('NEW_CROSSREF_STYLE'))
- {
- foreach my $entry_region (sort(keys(%{$Texi2HTML::THISDOC{'index_entries_region_array'}})))
- {
- foreach my $index_entry (@{$Texi2HTML::THISDOC{'index_entries_region_array'}->{$entry_region}})
- {
- my $region = '';
- $region = "$index_entry->{'region'}-" if (defined($index_entry->{'region'}) and $index_entry->{'region'} ne '');
- my $index_id = "index-" . $region .$index_entry->{'cross'};
- my $index = 1;
- # $index > 0 should prevent integer overflow, hopefully
- while (exists($cross_reference_nodes{$index_id}) and $index > 0)
- {
- $index_id = "index-" . $region . $index_entry->{'cross'} . "-" .$index;
- $index++;
- }
- $index_entry->{'id'} = $index_id;
- $index_entry->{'target'} = $index_id;
- my $texi_entry = "index-".$region.$index_entry->{'texi'};
- $texi_entry .= "-".$index if ($index > 1);
- push @{$cross_reference_nodes{$index_id}}, $texi_entry;
- }
- }
- }
- if (get_conf('NEW_CROSSREF_STYLE'))
- {
- foreach my $key (keys(%nodes))
- {
- my $node = $nodes{$key};
- next if ($node->{'external_node'});
- $node->{'id'} = node_to_id($node->{'cross_manual_target'});
- # FIXME if NEW_CROSSREF_STYLE false is it done for anchors?
- $node->{'target'} = $node->{'id'};
- }
- }
- # use %sections and %headings to modify also the headings
- foreach my $section (@sections_list, @headings_list)
- {
- if (get_conf('NEW_CROSSREF_STYLE') and ($section->{'cross'} =~ /\S/))
- {
- my $section_cross = $section->{'cross'};
- if (defined($section->{'region'}))
- { # for headings appearing in special regions like @copying...
- $section_cross = "${target_prefix}-$section->{'region'}_$section_cross";
- }
- $section->{'cross_manual_target'} = $section_cross;
- my $index = 1;
- # $index > 0 should prevent integer overflow, hopefully
- while (exists($cross_reference_nodes{$section->{'cross_manual_target'}}) and $index > 0)
- {
- $section->{'cross_manual_target'} = $section_cross . "-" .$index;
- $index++;
- }
- my $texi_entry = $section->{'texi'};
- $texi_entry .= "-".$index if ($index > 1);
- push @{$cross_reference_nodes{$section->{'cross_manual_target'}}}, $texi_entry;
- $section->{'id'} = node_to_id($section->{'cross_manual_target'});
- }
- }
- # use the associated @part as target if there is an associated part.
- # do it separately to be sure that all the parts have an id.
- foreach my $section (values(%sections), values(%headings))
- {
- my $target = $section;
- $target = $section->{'with_part'} if ($section->{'with_part'});
- if (get_conf('USE_NODE_TARGET') and $target->{'with_node'})
- {
- $section->{'target'} = $target->{'with_node'}->{'target'};
- }
- else
- {
- $section->{'target'} = $target->{'id'};
- }
- }
- # construct human readable tocid
- foreach my $section (values(%sections))
- {
- if (get_conf('NEW_CROSSREF_STYLE') and ($section->{'cross'} =~ /\S/))
- {
- foreach my $toc_id (['tocid','toc'], ['stocid', 'stoc'])
- {
- my $id_string = $toc_id->[0];
- my $prefix_string = $toc_id->[1];
- my $cross_string = '-' . $section->{'cross_manual_target'};
- $section->{$id_string} = $prefix_string . $cross_string;
- my $index = 1;
- # $index > 0 should prevent integer overflow, hopefully
- while (exists($cross_reference_nodes{$section->{$id_string}}) and $index > 0)
- {
- $section->{$id_string} = $prefix_string . "-" .$index .$cross_string;
- $index++;
- }
- my $texi_entry = $prefix_string.'-'.$section->{'texi'};
- $texi_entry = $prefix_string .'-'.$index.'-'.$section->{'texi'} if ($index > 1);
- push @{$cross_reference_nodes{$section->{$id_string}}}, $texi_entry;
- }
- }
- }
- if (!get_conf('NEW_CROSSREF_STYLE'))
- {
- my $tocnr = 1;
- foreach my $element (@elements_list)
- {
- $element->{'tocid'} = 'TOC' . $tocnr;
- $tocnr++;
- }
- }
- # Set file names
- # Find node file names and file names for nodes considered as elements
- my $node_as_top;
- if ($node_top)
- {
- $node_as_top = $node_top;
- }
- # following possibilities lead to some node being considered
- # as top for the purpose of setting the file node, but not as node_top
- elsif ($element_top->{'with_node'})
- {
- $node_as_top = $element_top->{'with_node'};
- }
- else
- {
- $node_as_top = $node_first;
- }
- if ($node_as_top)
- {
- do_node_target_file($node_as_top, 'top');
- }
- foreach my $key (keys(%nodes))
- {
- my $node = $nodes{$key};
- next if (defined($node_as_top) and ($node eq $node_as_top));
- do_node_target_file($node,'');
- }
-
- print STDERR "# split(".get_conf('SPLIT').") and set files\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- # find document nr and document file for sections and nodes.
- # Split according to Texi2HTML::Config::SPLIT.
- # find file and id for placed elements (anchors, index entries, headings)
- if (get_conf('SPLIT'))
- {
- $Texi2HTML::THISDOC{'split_level'} = $toplevel;
- my $doc_nr = -1;
- if (get_conf('SPLIT') eq 'section')
- {
- $Texi2HTML::THISDOC{'split_level'} = 2 if ($toplevel <= 2);
- }
- my $previous_file;
- my $previous_is_top = 0;
- foreach my $element (@elements_list)
- {
- print STDERR "# Splitting (".get_conf('SPLIT').":$Texi2HTML::THISDOC{'split_level'}) $element->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- my $new_file = 0;
- if (
- (!defined($previous_file)) or
- (get_conf('SPLIT') eq 'node') or
- (
- defined($element->{'level'}) and ($element->{'level'} <= $Texi2HTML::THISDOC{'split_level'})
- ) or
- (
- !defined($element->{'level'}) and defined($element->{'with_section'}) and ($element->{'with_section'}->{'level'} <= $Texi2HTML::THISDOC{'split_level'})
- ) or
- ( # top file after another file
- (defined($previous_file) and ($element eq $element_top)
- and ($previous_file ne $docu_top))
- ) # element following top element is always considered to be
- # in a different file.
- or ($previous_is_top)
- )
- {
- $new_file = 1;
- $doc_nr++;
- }
- $previous_is_top = 0 if ($previous_is_top);
- $element->{'doc_nr'} = $doc_nr;
- $element->{'file'} = "${docu_name}_$doc_nr"
- . (defined(get_conf('EXTENSION')) ? '.'.get_conf('EXTENSION') : '');
- my $use_node_file = 0;
- if ($element eq $element_top)
- { # the top element
- $element->{'file'} = $docu_top;
- $previous_is_top = 1;
- }
- elsif (get_conf('NODE_FILENAMES'))
- {
- $use_node_file = 1;
- if ($new_file)
- {
- my $node = get_node($element);
- if ($node and defined($node->{'node_file'}))
- {
- $element->{'file'} = $node->{'node_file'};
- }
- elsif ($element->{'cross'} =~ /\S/)
- { # use the canonicalized/transliterated section file name.
- $element->{'file'} = $element->{'cross'}
- . (defined(get_conf('EXTENSION')) ? '.'.get_conf('EXTENSION') : '');
- }
- # The remaining case is for sectioning elements with empty
- # headings and no node associated. They will have a name
- # with numbers, like "${docu_name}_$doc_nr", they may
- # collide with split indices names
- }
- else
- {
- $element->{'file'} = $previous_file;
- }
- }
- $previous_file = $element->{'file'};
- do_element_targets($element, $use_node_file);
- print STDERR "# [$doc_nr] add_file($use_node_file,$new_file,".var_to_str($previous_file).") $element->{'file'} for $element->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- add_file($element->{'file'});
- }
- }
- else
- { # not split
- add_file($docu_doc);
- foreach my $element(@elements_list)
- {
- $element->{'file'} = $docu_doc;
- $element->{'doc_nr'} = 0;
- do_element_targets($element);
- }
- }
- # 'pathological' cases. No texinfo sectioning element at all or no
- # texi2html sectioning elements
- if (!@elements_list)
- {
- if (@all_elements)
- {
- # in fact this happens only if there is no top element, but still
- # sections, so only if USE_SECTIONS = 0 and there is no node.
- #document_warn ("No elements available for splitting") if (get_conf('SPLIT'));
- foreach my $element (@all_elements)
- {
- #print STDERR "# no \@elements_list. Processing $element->{'texi'}\n";
- $element->{'file'} = $docu_doc;
- $element->{'doc_nr'} = 0;
- push @{$element->{'place'}}, @{$element->{'current_place'}};
- do_element_targets($element, get_conf('NODE_FILENAMES'));
- print STDERR "# no \@elements_list, setting $element->{'file'} for $element->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- }
- add_file($docu_doc);
- }
- else
- {
- #document_warn ("No elements at all") if (get_conf('SPLIT'));
- $element_before_anything->{'file'} = $docu_doc;
- $element_before_anything->{'doc_nr'} = 0;
- do_element_targets($element_before_anything,get_conf('NODE_FILENAMES'));
- print STDERR "# no element at all, setting $element_before_anything->{'file'} for $element_before_anything->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- }
- }
- # correct the id and file for the things placed in footnotes
- foreach my $place(@{$footnote_element->{'place'}})
- {
- do_place_target_file ($place, $footnote_element, 'footnotes');
- }
- # if setcontentsaftertitlepage is set, the contents should be associated
- # with the titlepage. That's what is done there.
- push @$no_element_associated_place, $content_element{'contents'}
- if (get_conf('contents') and get_conf('setcontentsaftertitlepage'));
- push @$no_element_associated_place, $content_element{'shortcontents'}
- if (get_conf('shortcontents') and get_conf('setshortcontentsaftertitlepage'));
- # correct the id and file for the things placed in regions (copying...)
- foreach my $place(@$no_element_associated_place)
- {
- #print STDERR "entry $place->{'entry'} texi $place->{'texi'}\n";
- $place->{'element'} = $element_top if (exists($place->{'element'}));
- do_place_target_file ($place, $element_top, 'no_associated_element');
- }
-
- # determine contents element and files
- foreach my $content_type(keys(%content_element))
- {
- # with set*aftertitlepage, there will always be a href to Contents
- # or Overview pointing to the top element, even if there is no
- # titlepage outputed.
- if (!scalar(@{$all_content_elements{$content_type}}))
- {
- if (get_conf('INLINE_CONTENTS'))
- {
- print STDERR "# No content $content_type\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- $content_element{$content_type} = undef;
- }
- }
- elsif (get_conf('INLINE_CONTENTS') and !get_conf('set' . $content_type .'aftertitlepage'))
- { # use the last element for references in case there is more than one
- $content_element{$content_type} = $all_content_elements{$content_type}->[-1];
- }
- }
- my ($toc_file, $stoc_file);
- $toc_file = $docu_toc;
- $stoc_file = $docu_stoc;
- if (get_conf('INLINE_CONTENTS'))
- {
- $toc_file = $content_element{'contents'}->{'file'} if (defined($content_element{'contents'}));
- $stoc_file = $content_element{'shortcontents'}->{'file'} if (defined($content_element{'shortcontents'}));
- }
- $Texi2HTML::THISDOC{'toc_file'} = $toc_file;
- $Texi2HTML::THISDOC{'stoc_file'} = $stoc_file;
-
- print STDERR "# find NextFile and PrevFile\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- foreach my $element (@elements_list)
- {
- my $current_element = $element;
- my $file = $current_element->{'file'};
- my $previous_file;
- while ($current_element->{'back'})
- {
- #print STDERR "Back $current_element->{'texi'}\n";
- $current_element = $current_element->{'back'};
- if ($current_element->{'file'} ne $file)
- {
- $previous_file = $current_element->{'file'};
- last;
- }
- }
- if (defined($previous_file))
- {
- while ($current_element->{'back'})
- {
- if ($current_element->{'back'}->{'file'} ne $previous_file)
- {
- last;
- }
- $current_element = $current_element->{'back'};
- }
- $element->{'prevfile'} = $current_element;
- }
- $current_element = $element;
- while ($current_element->{'forward'})
- {
- #print STDERR "Fwd $current_element->{'texi'}\n";
- $current_element = $current_element->{'forward'};
- if ($current_element->{'file'} ne $file)
- {
- $element->{'nextfile'} = $current_element;
- last;
- }
- }
- }
- # convert directions in direction with first letter in all caps, to be
- # consistent with the convention used in the init file.
- foreach my $element (@elements_list)
- {
- foreach my $direction (@element_directions)
- {
- my $direction_no_caps = $direction;
- $direction_no_caps =~ tr/A-Z/a-z/;
- $element->{$direction} = $element->{$direction_no_caps};
- }
- }
- ########################### debug prints
- foreach my $file (keys(%files))
- {
- last unless ($T2H_DEBUG & $DEBUG_ELEMENTS);
- print STDERR "$file: counter $files{$file}->{'counter'}\n";
- }
- my $output_elements = \@elements_list;
- if (!scalar(@elements_list) and ($T2H_DEBUG & $DEBUG_ELEMENTS))
- {
- print STDERR "No elements_list, no texi2html elements\n";
- $output_elements = \@all_elements;
- }
- foreach my $element ((@$output_elements, $footnote_element))
- {
- last unless ($T2H_DEBUG & $DEBUG_ELEMENTS);
- my $is_toplevel = 'not toplevel';
- $is_toplevel = 'toplevel' if ($element->{'toplevel'});
- print STDERR "$element ";
- if ($element->{'node'})
- {
- print STDERR "node($element->{'id'}, $is_toplevel, doc_nr $element->{'doc_nr'}($element->{'file'})) $element->{'texi'}:\n";
- print STDERR " section_ref: $element->{'section_ref'}->{'texi'}\n" if (defined($element->{'section_ref'}));
- print STDERR " with_section: $element->{'with_section'}->{'texi'}\n" if (defined($element->{'with_section'}));
- }
- elsif ($element->{'footnote'})
- {
- print STDERR "footnotes($element->{'id'}, file $element->{'file'})\n";
- }
- else
- {
- my $number = "UNNUMBERED";
- $number = $element->{'number'} if ($element->{'number'});
- print STDERR "$number ($element->{'id'}, $is_toplevel, level $element->{'level'}-$element->{'toc_level'}, doc_nr $element->{'doc_nr'}($element->{'file'})) $element->{'texi'}:\n";
- print STDERR " with_node: $element->{'with_node'}->{'texi'}\n" if (defined($element->{'with_node'}));
- print STDERR " node_ref: $element->{'node_ref'}->{'texi'}\n" if (defined($element->{'node_ref'}));
- }
- if (!$element->{'footnote'})
- {
- if (!defined($files{$element->{'file'}}))
- {
- die "Bug: files{\$element->{'file'}} undef element $element->{'texi'}, file $element->{'file'}.";
- }
- print STDERR " file: $element->{'file'} $files{$element->{'file'}}, counter $files{$element->{'file'}}->{'counter'}\n";
- }
- print STDERR " level: $element->{'level'}\n" if (defined($element->{'level'}));
- print STDERR " TOP($toplevel) " if ($element->{'top'});
- print STDERR " u: $element->{'up'}->{'texi'}\n" if (defined($element->{'up'}));
- print STDERR " ch: $element->{'child'}->{'texi'}\n" if (defined($element->{'child'}));
- print STDERR " fb: $element->{'fastback'}->{'texi'}\n" if (defined($element->{'fastback'}));
- print STDERR " b: $element->{'back'}->{'texi'}\n" if (defined($element->{'back'}));
- print STDERR " p: $element->{'prev'}->{'texi'}\n" if (defined($element->{'prev'}));
- print STDERR " u: $element->{'sectionup'}->{'texi'}\n" if (defined($element->{'sectionup'}));
- print STDERR " n: $element->{'sectionnext'}->{'texi'}\n" if (defined($element->{'sectionnext'}));
- print STDERR " t_n: $element->{'toplevelnext'}->{'texi'}\n" if (defined($element->{'toplevelnext'}));
- print STDERR " t_p: $element->{'toplevelprev'}->{'texi'}\n" if (defined($element->{'toplevelprev'}));
- print STDERR " n_u: $element->{'nodeup'}->{'texi'}\n" if (defined($element->{'nodeup'}));
- print STDERR " f: $element->{'forward'}->{'texi'}\n" if (defined($element->{'forward'}));
- print STDERR " n_f: $element->{'nodeforward'}->{'texi'}\n" if (defined($element->{'nodeforward'}));
- print STDERR " n_b: $element->{'nodeback'}->{'texi'}\n" if (defined($element->{'nodeback'}));
- print STDERR " m_p: $element->{'menu_prev'}->{'texi'}\n" if (defined($element->{'menu_prev'}));
- print STDERR " m_n: $element->{'menu_next'}->{'texi'}\n" if (defined($element->{'menu_next'}));
- print STDERR " m_u: $element->{'menu_up'}->{'texi'}\n" if (defined($element->{'menu_up'}));
- print STDERR " m_ch: $element->{'menu_child'}->{'texi'}\n" if (defined($element->{'menu_child'}));
- print STDERR " ff: $element->{'fastforward'}->{'texi'}\n" if (defined($element->{'fastforward'}));
- print STDERR " n_f: $element->{'nextfile'}->{'texi'}\n" if (defined($element->{'nextfile'}));
- print STDERR " p_f: $element->{'prevfile'}->{'texi'}\n" if (defined($element->{'prevfile'}));
- my $section_childs = '';
- if (defined($element->{'section_childs'}))
- {
- foreach my $child (@{$element->{'section_childs'}})
- {
- $section_childs .= "$child->{'texi'}|";
- }
- }
- print STDERR " s_chs: $section_childs\n" if ($section_childs ne '');
- my $node_childs = '';
- if (defined($element->{'node_childs'}))
- {
- foreach my $child (@{$element->{'node_childs'}})
- {
- $node_childs .= "$child->{'texi'}|";
- }
- }
- print STDERR " n_chs: $node_childs\n" if ($node_childs ne '');
- if (defined($element->{'menu_up_hash'}))
- {
- print STDERR " parent nodes:\n";
- foreach my $menu_up (keys%{$element->{'menu_up_hash'}})
- {
- print STDERR " $menu_up ($element->{'menu_up_hash'}->{$menu_up})\n";
- }
- }
- print STDERR " places: $element->{'place'}\n";
- foreach my $place(@{$element->{'place'}})
- {
- if (!$place->{'entry'} and !$place->{'float'} and !$place->{'texi'} and !$place->{'contents'} and !$place->{'shortcontents'} and (!defined($place->{'command'} or $place->{'command'} ne 'printindex')))
- {
- print STDERR "BUG: unknown placed stuff ========\n";
- foreach my $key (keys(%$place))
- {
- print STDERR "$key: $place->{$key}\n";
- }
- print STDERR "==================================\n";
- }
- elsif ($place->{'entry'})
- {
- print STDERR " index($place): $place->{'entry'} ($place->{'id'}, $place->{'file'})\n";
- }
- elsif ($place->{'anchor'})
- {
- print STDERR " anchor: $place->{'texi'} ($place->{'id'}, $place->{'file'})\n";
- }
- elsif ($place->{'float'})
- {
- if (defined($place->{'texi'}))
- {
- print STDERR " float($place): $place->{'texi'} ($place->{'id'}, $place->{'file'})\n";
- }
- else
- {
- print STDERR " float($place): NO LABEL ($place->{'id'}, $place->{'file'})\n";
- }
- }
- elsif ($place->{'contents'})
- {
- print STDERR " contents\n";
- }
- elsif ($place->{'shortcontents'})
- {
- print STDERR " shortcontents\n";
- }
- elsif (defined($place->{'command'}) and $place->{'command'} eq 'printindex')
- {
- print STDERR " printindex $place->{'name'}\n";
- }
- else
- {
- print STDERR " heading: $place->{'texi'} ($place->{'id'}, $place->{'file'})\n";
- }
- }
- }
- ########################### end debug prints
- }
- sub add_file($)
- {
- my $file = shift;
- if ($files{$file})
- {
- $files{$file}->{'counter'}++;
- }
- else
- {
- $files{$file} = {
- 'counter' => 1,
- 'relative_foot_num' => 0,
- 'foot_lines' => []
- };
- }
- }
- # find parent element which is a toplevel element
- sub get_top($)
- {
- my $element = shift;
- if ($element->{'node'})
- {
- if (defined($element->{'section_ref'}))
- {
- $element = $element->{'section_ref'};
- }
- else
- {
- return undef;
- }
- }
- return undef if ($element eq $element_before_anything);
- my $up = $element;
- while (!$up->{'toplevel'} and $up->{'tag'} ne 'top')
- {
- if (!defined($up->{'sectionup'}))
- {
- # If there is no section, it is normal not to have toplevel element,
- # and it is also the case if there is a low level element before
- # a top level element
- return undef;
- }
- $up = $up->{'sectionup'};
- }
- return $up;
- }
- sub get_node($)
- {
- my $element = shift;
- return undef if (!defined($element));
- return $element if ($element->{'node'});
- return $element->{'with_node'} if ($element->{'with_node'});
- }
- sub do_section_names($$)
- {
- my $number = shift;
- my $section = shift;
- my $texi = &$Texi2HTML::Config::heading_texi($section->{'tag'}, $section->{'texi'}, $section->{'number'});
- $section->{'text'} = substitute_line($texi, "\@$section->{'tag'}", undef, $section->{'line_nr'});
- # no need for translation since there is no line number it should never
- # appear in error messages.
- $section->{'text_nonumber'} = substitute_line($section->{'texi'}, "\@$section->{'tag'} no number");
- # backward compatibility
- # Removed from doc in nov 2009
- $section->{'name'} = $section->{'text_nonumber'};
- $section->{'no_texi'} = remove_texi($texi);
- $section->{'simple_format'} = simple_format(undef,undef,"\@$section->{'tag'} simple_format", $texi);
- $section->{'heading_texi'} = $texi;
- }
- # get the html names from the texi for all elements
- sub do_names()
- {
- print STDERR "# Doing ". scalar(keys(%nodes)) . " nodes, ".
- scalar(keys(%sections)) . " sections, " .
- scalar(keys(%headings)) . " headings in ". $#elements_list .
- " elements\n" if ($T2H_DEBUG);
- # for nodes and anchors we haven't any state defined
- # This seems right, however, as we don't want @refs or @footnotes
- # or @anchors within nodes, section commands or anchors.
- $global_pass = '2 node names';
- foreach my $node (sort(keys(%nodes)))
- {
- my $texi = &$Texi2HTML::Config::heading_texi($nodes{$node}->{'tag'},
- $nodes{$node}->{'texi'}, undef);
- my $command = 'node';
- $command = $nodes{$node}->{'tag'} if ($nodes{$node}->{'tag'});
- $nodes{$node}->{'text'} = substitute_line ($texi, "\@$command", {'code_style' => 1}, $nodes{$node}->{'line_nr'});
- $nodes{$node}->{'text_nonumber'} = $nodes{$node}->{'text'};
- # backward compatibility -> maybe used to have the name without code_style ?
- # Removed from doc in nov 2009
- $nodes{$node}->{'name'} = substitute_line($texi, "\@$command name");
- $nodes{$node}->{'no_texi'} = remove_texi($texi);
- $nodes{$node}->{'simple_format'} = simple_format(undef, undef, "\@$command simple_format", $texi);
- $nodes{$node}->{'heading_texi'} = $texi;
-
- ################# debug
- # if $nodes{$node}->{'external_node'} and $nodes{$node}->{'seen'}
- # this is a bug, since there are checks that the node hasn't an
- # external node syntax.
- msg_debug ("$nodes{$node}->{'texi'} is external and was seen", $nodes{$node}->{'line_nr'}) if ($nodes{$node}->{'seen'} and $nodes{$node}->{'external_node'});
- ################# end debug
- }
- $global_pass = '2 section names';
- foreach my $number (keys(%sections))
- {
- do_section_names($number, $sections{$number});
- }
- $global_pass = '2 heading names';
- foreach my $number (keys(%headings))
- {
- do_section_names($number, $headings{$number});
- }
- print STDERR "# Names done\n" if ($T2H_DEBUG);
- }
- #+++############################################################################
- # #
- # Stuff related to Index generation #
- # #
- #---############################################################################
- # called during pass_structure
- sub enter_index_entry($$$$$)
- {
- my $prefix = shift;
- my $line_nr = shift;
- my $entry = shift;
- my $command = shift;
- my $state = shift;
- my $heading_element = $state->{'heading_element'};
- my $current_element = $state->{'current_element'};
- my $place = $state->{'place'};
- my $region = $state->{'region'};
- my $index_name = $index_prefix_to_name{$prefix};
- if (!defined($index_name))
- {
- line_error (sprintf(__("Unknown index `%s'"), $prefix), $line_nr);
- }
- if ($current_element eq $element_before_anything)
- {
- #line_warn ("Index entry before document: \@${prefix}index $entry", $line_nr);
- line_error (sprintf(__("Entry for index `%s' outside of any node"), $index_name), $line_nr);
- }
- $entry = trim_comment_spaces ($entry, "index entry in \@$command", $line_nr);
- # beware that the texinfo could be non empty, but the no_texi be empty.
- # So the $no_texi should be used to determine whether the entry is
- # empty or not.
- my $no_texi = remove_texi($entry);
- my $id;
- # don't add a specific index target if the index entry is in a special
- # region like @copying or the like or the index is not defined
- if (!defined($region))
- {
- $region = 'document';
- # No id if the index is unknown.
- $id = 'IDX' . ++$document_idx_num if (defined($index_name));
- }
- my $target = $id;
- # entry will later be in @code for code-like index entry. texi stays
- # the same.
- my $index_entry = {
- 'entry' => $entry,
- 'texi' => $entry,
- 'in_code' => 0,
- 'element' => $heading_element,
- 'real_element' => $current_element,
- 'prefix' => $prefix,
- 'id' => $id,
- 'target' => $target,
- 'command' => $command,
- 'region' => $state->{'region'},
- 'line_nr' => $line_nr,
- 'index_name' => $index_name
- };
-
- my $id_text = $id;
- $id_text = 'NO ID' if (!defined($id));
- print STDERR "# in $region enter \@$command ${prefix}index($no_texi) [$entry] with id $id_text ($index_entry)\n"
- if ($T2H_DEBUG & $DEBUG_INDEX);
-
- $index_entry->{'in_code'} = 1
- if (defined($index_name) and
- defined($index_names{$index_name}) and
- $index_names{$index_name}->{$prefix}
- and $no_texi =~ /\S/);
- $index_entry->{'entry'} = '@code{'.$index_entry->{'entry'}.'}'
- if ($index_entry->{'in_code'});
- push @$place, $index_entry;
- #msg_debug("enter_index_entry: region $region, index_entry $index_entry, \@$command, texi `$entry'", $line_nr);
- # don't add the index entry to the list of index entries used for index
- # entry formatting, if the index entry appears in a region like copying
- # currently this is only used for debugging purposes, since the
- # index entries lists are broken by region now.
- push @index_labels, $index_entry unless (defined($state->{'region'}));
- # these lists are used to retrieve index entries in pass 3
- push @{$Texi2HTML::THISDOC{'index_entries'}->{$region}->{$entry}->{'entries'}}, $index_entry;
- if (defined($index_name))
- {
- # this is used for @printindex
- push @{$Texi2HTML::THISDOC{'index_entries_array'}->{$index_name}}, $index_entry;
- # this is used for targets
- push @{$Texi2HTML::THISDOC{'index_entries_region_array'}->{$region}}, $index_entry;
- }
- else
- {
- push @unknown_index_index_entries, $index_entry;
- }
- }
- # these variables are global, so great care should be taken with
- # state->{'multiple_state'}, ->{'region'}, ->{'region_pass'} and
- # {'outside_document'}.
- my $global_head_num = 0; # heading index. it is global for the main doc,
- # and taken from the state if in multiple_pass.
- my $global_foot_num = 0;
- my $global_relative_foot_num = 0;
- my @foot_lines = (); # footnotes
- my $copying_comment = ''; # comment constructed from text between
- # @copying and @end copying with licence
- my %acronyms_like = (); # acronyms or similar commands associated texts
- # the key are the commands, the values are
- # hash references associating shorthands to
- # texts.
- # detailmenu number of opened detailed menus
- sub fill_state($)
- {
- my $state = shift;
- foreach my $key ('preformatted', 'code_style', 'math_style', 'keep_texi',
- 'keep_nr', 'detailmenu', 'direntry', 'sec_num', 'menu', 'multiple_pass')
- {
- $state->{$key} = 0 unless exists($state->{$key});
- }
-
- $state->{'paragraph_style'} = [ '' ] unless exists($state->{'paragraph_style'});
- $state->{'preformatted_stack'} = [ '' ] unless exists($state->{'preformatted_stack'});
- $state->{'command_stack'} = [] unless exists($state->{'command_stack'});
- $state->{'quotation_stack'} = [] unless exists($state->{'quotation_stack'});
- # if there is no $state->{'element'} the first element is used
- if ((!$state->{'element'} or $state->{'element'}->{'before_anything'}) and (@elements_list))
- {
- $state->{'element'} = $elements_list[0];
- }
- # this is consistent with what is done in rearrange_elements
- $state->{'element'} = {'file' => $docu_doc, 'texi' => 'VIRTUAL ELEMENT'} if (!$state->{'element'});
- }
- sub do_element_directions ($)
- {
- my $this_element = shift;
- #print STDERR "Doing hrefs for $this_element->{'texi'} First ";
- $Texi2HTML::HREF{'First'} = href($element_first, $this_element->{'file'});
- #print STDERR "Last ";
- $Texi2HTML::HREF{'Last'} = href($element_last, $this_element->{'file'});
- #print STDERR "Index ";
- $Texi2HTML::HREF{'Index'} = href($element_chapter_index, $this_element->{'file'}) if (defined($element_chapter_index));
- #print STDERR "Top ";
- $Texi2HTML::HREF{'Top'} = href($element_top, $this_element->{'file'});
- if (get_conf('INLINE_CONTENTS'))
- {
- $Texi2HTML::HREF{'Contents'} = href($content_element{'contents'}, $this_element->{'file'});
- $Texi2HTML::HREF{'Overview'} = href($content_element{'shortcontents'}, $this_element->{'file'});
- }
- else
- {
- $Texi2HTML::HREF{'Contents'} = file_target_href($Texi2HTML::THISDOC{'toc_file'}, $this_element->{'file'}, $content_element{'contents'}->{'target'}) if (@{$Texi2HTML::TOC_LINES} and defined($content_element{'contents'}));
- $Texi2HTML::HREF{'Overview'} = file_target_href($Texi2HTML::THISDOC{'stoc_file'}, $this_element->{'file'}, $content_element{'shortcontents'}->{'target'}) if (@{$Texi2HTML::OVERVIEW} and defined($content_element{'shortcontents'}));
- }
- if ($Texi2HTML::THISDOC{'do_about'})
- {
- $Texi2HTML::HREF{'About'} = file_target_href($docu_about, $this_element->{'file'}, $Texi2HTML::Config::misc_pages_targets{'About'});
- }
- $Texi2HTML::HREF{'Footnotes'} = file_target_href($docu_foot, $this_element->{'file'}, $Texi2HTML::Config::misc_pages_targets{'Footnotes'});
- foreach my $direction (@element_directions)
- {
- my $elem = $this_element->{$direction};
- $Texi2HTML::NODE{$direction} = undef;
- $Texi2HTML::HREF{$direction} = undef;
- $Texi2HTML::NAME{$direction} = undef;
- #print STDERR "$direction \n";
- next unless (defined($elem));
- if ($elem->{'node'} or $elem->{'external_node'} or !$elem->{'seen'})
- {
- $Texi2HTML::NODE{$direction} = $elem->{'text'};
- }
- elsif ($elem->{'with_node'})
- {
- $Texi2HTML::NODE{$direction} = $elem->{'with_node'}->{'text'};
- }
- if (!$elem->{'seen'})
- {
- $Texi2HTML::HREF{$direction} = do_external_href($elem->{'texi'});
- }
- else
- {
- $Texi2HTML::HREF{$direction} = href($elem, $this_element->{'file'});
- }
- $Texi2HTML::NAME{$direction} = $elem->{'text'};
- $Texi2HTML::NO_TEXI{$direction} = $elem->{'no_texi'};
- $Texi2HTML::SIMPLE_TEXT{$direction} = $elem->{'simple_format'};
- #print STDERR "$direction ($this_element->{'texi'}): \n NO_TEXI: $Texi2HTML::NO_TEXI{$direction}\n NAME $Texi2HTML::NAME{$direction}\n NODE $Texi2HTML::NODE{$direction}\n HREF $Texi2HTML::HREF{$direction}\n\n";
- }
- #print STDERR "\nDone hrefs for $this_element->{'texi'}\n";
- }
- sub open_out_file($)
- {
- my $new_file = shift;
- my $do_page_head = 0;
- # if the filehandle is closed, with fileno undef, open_out
- # is called with the second argument true, which leads to opening
- # the file in append mode, to avoid overwriting the previous
- # file.
- if ($files{$new_file}->{'filehandle'} and defined(fileno($files{$new_file}->{'filehandle'})))
- {
- $Texi2HTML::THISDOC{'FH'} = $files{$new_file}->{'filehandle'};
- }
- else
- {
- my $known_file = 0;
- if ($files{$new_file}->{'filehandle'})
- {
- $known_file = 1;
- document_warn ("The file $new_file was already closed and is reopened");
- }
- $Texi2HTML::THISDOC{'FH'} = open_out("$docu_rdir$new_file", $known_file);
- #print STDERR "OPEN $docu_rdir$file, $Texi2HTML::THISDOC{'FH'}". scalar($Texi2HTML::THISDOC{'FH'})."\n";
- $files{$new_file}->{'filehandle'} = $Texi2HTML::THISDOC{'FH'};
- $do_page_head = !$known_file;
- }
- return $do_page_head;
- }
- sub set_line_nr_in_stack($$$)
- {
- my $state = shift;
- my $stack = shift;
- my $line_nr = shift;
- if ($state->{'keep_texi'} and defined($line_nr))
- {
- my $stack_index = $#$stack;
- while ($stack_index >= 0 and defined($stack->[$stack_index]->{'keep_line_nr'}))
- {
- push @{$stack->[$stack_index]->{'keep_line_nr'}}, $line_nr;
- $stack_index --;
- }
- }
- }
- sub unref_file($)
- {
- my $file = shift;
- $files{$file}->{'counter'}--;
- print STDERR "# Unref file $file, remaining counter $files{$file}->{'counter'}\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- }
- sub pass_text($$)
- {
- my $doc_lines = shift;
- my $doc_numbers = shift;
- my %state;
- fill_state(\%state);
- my @stack;
- my $text = '';
- my $doc_nr;
- my $in_doc = 0;
- my @text =();
- my $one_section = 1 if (@elements_list <= 1);
- push_state(\%state);
- $global_pass = '3 prepare names';
- set_special_names();
- $footnote_element->{'text'} = $Texi2HTML::NAME{'Footnotes'};
- # We set titlefont only if the titlefont appeared in the top element
- if (defined($element_top->{'titlefont'}))
- {
- $Texi2HTML::THISDOC{'titlefont_texi'} = $element_top->{'titlefont'};
- # backward compatibility obsoleted in nov 2009
- $value{'_titlefont'} = $element_top->{'titlefont'};
- }
-
- # prepare %Texi2HTML::THISDOC
- $Texi2HTML::THISDOC{'command_stack'} = $state{'command_stack'};
- $Texi2HTML::THISDOC{'top_texi'} = $section_top->{'texi'} if (defined($section_top));
- $Texi2HTML::THISDOC{'fulltitle_texi'} = '';
- foreach my $possible_fulltitle('settitle', 'title', 'shorttitlepage', 'top', 'titlefont')
- {
- if (defined($Texi2HTML::THISDOC{$possible_fulltitle . '_texi'}) and $Texi2HTML::THISDOC{$possible_fulltitle . '_texi'} =~ /\S/)
- {
- $Texi2HTML::THISDOC{'fulltitle_texi'} = $Texi2HTML::THISDOC{$possible_fulltitle . '_texi'};
- last;
- }
- }
- $Texi2HTML::THISDOC{'simpletitle_texi'} = '';
- foreach my $possible_simpletitle('settitle', 'shorttitlepage')
- {
- if (defined($Texi2HTML::THISDOC{$possible_simpletitle . '_texi'}) and $Texi2HTML::THISDOC{$possible_simpletitle . '_texi'} =~ /\S/)
- {
- $Texi2HTML::THISDOC{'simpletitle_texi'} = $Texi2HTML::THISDOC{$possible_simpletitle . '_texi'};
- last;
- }
- }
- foreach my $doc_thing (('shorttitlepage', 'settitle', 'author',
- 'titlefont', 'subtitle', 'title', 'fulltitle', 'simpletitle'))
- {
- my $thing_texi = $Texi2HTML::THISDOC{$doc_thing . '_texi'};
- $Texi2HTML::THISDOC{$doc_thing} = substitute_line($thing_texi, "\@$doc_thing", undef, $Texi2HTML::THISDOC{$doc_thing . '_line_nr'});
- $Texi2HTML::THISDOC{$doc_thing . '_no_texi'} =
- remove_texi($thing_texi);
- $Texi2HTML::THISDOC{$doc_thing . '_simple_format'} =
- simple_format(undef, undef, "simple_format \@$doc_thing", $thing_texi);
- }
- # find the triplet (Top name, Top with texi removed, Top simply formatted)
- # the corresponding href is used a lot but these are only used because
- # they are used in LINKS_BUTTONS...
- my $element_top_Top = [undef,undef,undef];
- my $node_top_Top = [undef,undef,undef];
- # Preferred Top name is the element_top name if it is not the @node Top
- # the @node Top may also be used, but before fulltitle is tried
- if (defined($element_top))
- {
- if ($element_top->{'node'} and $element_top->{'texi'} =~ /^Top$/i)
- {
- $node_top_Top = [ $element_top->{'text'}, $element_top->{'no_texi'}, $element_top->{'simple_format'} ];
- }
- else
- {
- $element_top_Top = [ $element_top->{'text'}, $element_top->{'no_texi'}, $element_top->{'simple_format'} ];
- }
- }
- # FIXME remove fulltitle?
- foreach my $possible_top (
- [substitute_line($Texi2HTML::Config::TOP_HEADING, '$TOP_HEADING'),
- remove_texi($Texi2HTML::Config::TOP_HEADING),
- simple_format(undef, undef, 'simple_format $TOP_HEADING', $Texi2HTML::Config::TOP_HEADING)],
- $element_top_Top,
- [$Texi2HTML::THISDOC{'fulltitle'},
- $Texi2HTML::THISDOC{'fulltitle_no_texi'},
- $Texi2HTML::THISDOC{'fulltitle_simple_format'}],
- $node_top_Top
- )
- {
- if (defined($possible_top->[0]) and $possible_top->[0] =~ /\S/)
- {
- ($Texi2HTML::NAME{'Top'}, $Texi2HTML::NO_TEXI{'Top'}, $Texi2HTML::SIMPLE_TEXT{'Top'}) = @$possible_top;
- print STDERR "RESULTING TOP: ".join('|', @$possible_top)."\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- last;
- }
- }
-
- $Texi2HTML::THISDOC{'program'} = $THISPROG;
- $Texi2HTML::THISDOC{'program_and_version'} = $THISPROG_THISVERSION;
- $Texi2HTML::THISDOC{'program_homepage'} = $T2H_HOMEPAGE;
- # titles is for backard compatibility
- foreach my $command (('authors', 'subtitles', 'titles'))
- {
- $Texi2HTML::THISDOC{$command} = [];
- my $i;
- for ($i = 0; $i < $#{$Texi2HTML::THISDOC{$command .'_texi'}} + 1; $i++)
- {
- my $texi_line = $Texi2HTML::THISDOC{$command .'_texi'}->[$i];
- my $command_line_nr = $Texi2HTML::THISDOC{$command .'_line_nr'}->[$i];
- chomp ($texi_line);
- $Texi2HTML::THISDOC{$command}->[$i] = substitute_line($texi_line, "\@$command", undef, $command_line_nr);
- #print STDERR "$command:$i: $Texi2HTML::THISDOC{$command}->[$i]\n";
- }
- }
- $Texi2HTML::THISDOC{'do_about'} = 1 unless (!get_conf('DO_ABOUT') or $one_section or (not get_conf('SPLIT') and not get_conf('HEADERS')));
-
- $Texi2HTML::NAME{'First'} = $element_first->{'text'};
- $Texi2HTML::NAME{'Last'} = $element_last->{'text'};
- $Texi2HTML::NAME{'Index'} = $element_chapter_index->{'text'} if (defined($element_chapter_index));
- $Texi2HTML::NAME{'Index'} = $Texi2HTML::Config::INDEX_CHAPTER if ($Texi2HTML::Config::INDEX_CHAPTER ne '');
- $Texi2HTML::NO_TEXI{'First'} = $element_first->{'no_texi'};
- $Texi2HTML::NO_TEXI{'Last'} = $element_last->{'no_texi'};
- $Texi2HTML::NO_TEXI{'Index'} = $element_chapter_index->{'no_texi'} if (defined($element_chapter_index));
- $Texi2HTML::SIMPLE_TEXT{'First'} = $element_first->{'simple_format'};
- $Texi2HTML::SIMPLE_TEXT{'Last'} = $element_last->{'simple_format'};
- $Texi2HTML::SIMPLE_TEXT{'Index'} = $element_chapter_index->{'simple_format'} if (defined($element_chapter_index));
- # We do the regions formatting here, even if they never appear.
- # so we should be very carefull to take into accout 'outside_document' to
- # avoid messing with information that has to be set in the main document.
- # FIXME also the error messages will appear even though the corresponding
- # texinfo is never used. Since no state is passed to the do_special_region_lines
- # 'outside_document' will be true. Also 'multiple_pass' is equal to -1
- # for this case.
- $global_pass = '3 prepare regions';
- my ($region_text, $region_no_texi, $region_simple_format);
- ($region_text, $region_no_texi, $region_simple_format) = do_special_region_lines('documentdescription');
- &$Texi2HTML::Config::documentdescription($region_lines{'documentdescription'}, $region_text, $region_no_texi, $region_simple_format);
-
- # do copyright notice inserted in comment at the beginning of the files
- ($region_text, $region_no_texi, $region_simple_format) = do_special_region_lines('copying');
- $copying_comment = &$Texi2HTML::Config::copying_comment($region_lines{'copying'}, $region_text, $region_no_texi, $region_simple_format);
- $Texi2HTML::THISDOC{'copying_comment'} = $copying_comment;
- # must be after toc_body, but before titlepage
- foreach my $command ('contents', 'shortcontents')
- {
- next if (!defined($content_element{$command}));
- my $toc_lines = &$Texi2HTML::Config::inline_contents(undef, $command, $content_element{$command}, \@sections_list);
- @{$Texi2HTML::THISDOC{'inline_contents'}->{$command}} = @$toc_lines if (defined($toc_lines));
- }
-
- ($region_text, $region_no_texi, $region_simple_format) = do_special_region_lines('titlepage');
- &$Texi2HTML::Config::titlepage($region_lines{'titlepage'}, $region_text, $region_no_texi, $region_simple_format);
- $global_pass = '3';
- &$Texi2HTML::Config::init_out();
- # FIXME It is not clear whether it should be here or before
- # command_handler_output calls. After, it means that
- # command_handler_output may modify the initializations. Before
- # it allows to look at the values from the preceding pass.
- texinfo_initialization(2);
- foreach my $handler(@Texi2HTML::Config::command_handler_output)
- {
- &$handler;
- }
- ############################################################################
- # print frame and frame toc file
- #
- if (get_conf('FRAMES'))
- {
- my $FH = open_out($docu_frame_file);
- print STDERR "# Creating frame in $docu_frame_file ...\n" if $T2H_VERBOSE;
- &$Texi2HTML::Config::print_frame($FH, $docu_toc_frame_file, $docu_top_file);
- close_out($FH, $docu_frame_file);
- $FH = open_out($docu_toc_frame_file);
- print STDERR "# Creating toc frame in $docu_frame_file ...\n" if $T2H_VERBOSE;
- &$Texi2HTML::Config::print_toc_frame($FH, $Texi2HTML::OVERVIEW);
- close_out($FH, $docu_toc_frame_file);
- }
- ############################################################################
- # Start processing the document
- #
- #my $FH;
- my $line_nr;
- my $current_file;
- my $first_section = 0; # 1 if it is the first section of a page
- my $previous_is_top = 0; # 1 if it is the element following the top element
- my $cline;
- # this is true for the state that goes through the document
- $state{'inside_document'} = 1;
- while (@$doc_lines)
- {
- $cline = shift @$doc_lines;
- my $chomped_line = $cline;
- if (!chomp($chomped_line) and @$doc_lines)
- { # if the line has no end of line it is concatenated with the next
- # this shouldn't happen anymore. And will certainly mess up
- # line counting. Let it be a bug.
- msg_debug ("no end of line line passed in doc_line",$line_nr);
- $doc_lines->[0] = $cline . $doc_lines->[0];
- next;
- }
- $line_nr = shift (@$doc_numbers);
- $Texi2HTML::THISDOC{'line_nr'} = $line_nr;
- print STDERR "BUG: line_nr not defined in pass_text. cline: $cline" if (!defined($line_nr));
- #dump_stack(\$text, \@stack, \%state);
- # make sure the current state from here is $Texi2HTML::THIS_ELEMENT
- # in case it was set by the user.
- $state{'element'} = $Texi2HTML::THIS_ELEMENT if (defined($Texi2HTML::THIS_ELEMENT));
- #print STDERR "PASS_TEXT($line_nr->{'line_nr'})$cline";
- if (!$state{'raw'} and !$state{'verb'})
- {
- my $tag = '';
- $tag = $1 if ($cline =~ /^\@(\w+)/);
- if ($tag eq 'setfilename' and get_conf('IGNORE_BEFORE_SETFILENAME'))
- {
- if (defined($Texi2HTML::THIS_ELEMENT))
- {
- line_warn (sprintf(__("\@%s after the first element"), $tag), $line_nr);
- }
- else
- {
- @{$Texi2HTML::THIS_SECTION} = ();
- }
- }
- if (($tag eq 'node') or (defined($sec2level{$tag}) and ($tag !~ /heading/)))
- {
- # in pass text node and section shouldn't appear in formats
- #print STDERR "close_stack before \@$tag\n";
- #print STDERR "text!$text%" if (! @stack);
- close_stack(\$text, \@stack, \%state, $line_nr);
- msg_debug ("text undef", $line_nr) if (!defined($text));
- push @{$Texi2HTML::THIS_SECTION}, $text if ($text ne '');
- $text = '';
- $state{'sec_num'}++ if ($sec2level{$tag} and ($tag ne 'top'));
- my $new_element;
- my $current_element;
- # handle node and structuring elements
- $current_element = shift (@all_elements);
- ########################## begin debug section
- if (!defined($current_element))
- {
- msg_debug ("No element left for $cline", $line_nr);
- }
- if ($current_element->{'node'})
- {
- print STDERR 'NODE ' . "$current_element->{'texi'}($current_element->{'file'})" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- print STDERR "($current_element->{'section_ref'}->{'texi'})" if ($current_element->{'section_ref'} and ($T2H_DEBUG & $DEBUG_ELEMENTS));
- }
- else
- {
- print STDERR 'SECTION ' . $current_element->{'texi'} if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- }
- print STDERR ": $cline" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- ########################## end debug section
- # The element begins a new section if there is no previous
- # or the reference element is not the same
- if (defined($current_element->{'element_ref'}) and (!$Texi2HTML::THIS_ELEMENT or ($current_element->{'element_ref'} ne $Texi2HTML::THIS_ELEMENT)))
- {
- $new_element = $current_element->{'element_ref'};
- ########################### debug
- my $old = 'NO_OLD';
- $old = $Texi2HTML::THIS_ELEMENT->{'texi'} if (defined($Texi2HTML::THIS_ELEMENT));
- print STDERR "NEW: $new_element->{'texi'}, OLD: $old\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- ########################### end debug
- # print the element that just finished
- if ($Texi2HTML::THIS_ELEMENT)
- {
- finish_element($Texi2HTML::THISDOC{'FH'}, $Texi2HTML::THIS_ELEMENT, $new_element, $first_section);
- $first_section = 0;
- $previous_is_top = 0 if (!$Texi2HTML::THIS_ELEMENT->{'top'});
- @{$Texi2HTML::THIS_SECTION} = ();
- }
- else
- {
- print STDERR "# Writing elements:" if ($T2H_VERBOSE);
- if (get_conf('IGNORE_PREAMBLE_TEXT'))
- {
- @{$Texi2HTML::THIS_SECTION} = ();
- }
- # remove empty for the first document lines
- shift @{$Texi2HTML::THIS_SECTION} while (@{$Texi2HTML::THIS_SECTION} and ($Texi2HTML::THIS_SECTION->[0] =~ /^\s*$/));
- my $title = &$Texi2HTML::Config::print_title();
- unshift @{$Texi2HTML::THIS_SECTION}, $title if (defined($title) and $title ne '');
- }
- # begin new element
- $Texi2HTML::THIS_ELEMENT = $new_element;
- $state{'element'} = $Texi2HTML::THIS_ELEMENT;
- do_element_directions($Texi2HTML::THIS_ELEMENT);
- unref_file ($Texi2HTML::THIS_ELEMENT->{'file'});
- #if (!defined($previous_file) or ($Texi2HTML::THIS_ELEMENT->{'file'} ne $previous_file))
- if (!defined($current_file) or ($Texi2HTML::THIS_ELEMENT->{'file'} ne $current_file))
- {
- $current_file = $Texi2HTML::THIS_ELEMENT->{'file'};
- print STDERR "\n" if ($T2H_VERBOSE and !$T2H_DEBUG);
- print STDERR "# Writing to $docu_rdir$current_file " if $T2H_VERBOSE;
- my $do_page_head = open_out_file($current_file);
- if ($Texi2HTML::THIS_ELEMENT->{'top'})
- {
- &$Texi2HTML::Config::print_Top_header($Texi2HTML::THISDOC{'FH'}, $do_page_head);
- $previous_is_top = 1;
- }
- else
- {
- &$Texi2HTML::Config::print_page_head($Texi2HTML::THISDOC{'FH'}) if ($do_page_head);
- &$Texi2HTML::Config::print_chapter_header($Texi2HTML::THISDOC{'FH'}, $Texi2HTML::THIS_ELEMENT) if get_conf('SPLIT') eq 'chapter';
- &$Texi2HTML::Config::print_section_header($Texi2HTML::THISDOC{'FH'}, $Texi2HTML::THIS_ELEMENT) if get_conf('SPLIT') eq 'section';
- }
- $first_section = 1;
- }
- print STDERR "." if ($T2H_VERBOSE);
- print STDERR "\n" if ($T2H_DEBUG);
- }
-
- my $cmd_line = $cline;
- $cmd_line =~ s/\@$tag\s*//;
- ######################## begin debug
- msg_debug ("Element $current_element current_element->{'tag_level'} not defined", $line_nr)
- if (!defined($current_element->{'tag_level'}));
- msg_debug ("Element $current_element $tag ne ".var_to_str($current_element->{'tag'}), $line_nr)
- if ($tag ne 'node' and (!defined($current_element->{'tag'}) or $tag ne $current_element->{'tag'}));
- msg_debug ("Element $current_element ".var_to_str($current_element->{'tag'})." is not a node, but tag is a node", $line_nr)
- if ($tag eq 'node' and !$current_element->{'node'});
- ######################## end debug
- my $heading_formatted = &$Texi2HTML::Config::element_heading($current_element, $tag, $cmd_line, substitute_line($cmd_line, "\@$tag"), undef, $one_section, $current_element->{'this'}, $first_section, $current_element->{'top'}, $previous_is_top, $cline, $current_element->{'id'}, $new_element);
- push @{$Texi2HTML::THIS_SECTION}, $heading_formatted if (defined($heading_formatted) and ($heading_formatted ne ''));
- next;
- }
- }
- set_line_nr_in_stack(\%state, \@stack, $line_nr);
- scan_line($cline, \$text, \@stack, \%state, $line_nr);
- #print STDERR "after scan_line: $cline";
- #dump_stack(\$text, \@stack, \%state);
- next if (@stack);
- if ($text ne '')
- {
- push @{$Texi2HTML::THIS_SECTION}, $text;
- $text = '';
- }
- }
- # close stack at the end of pass text
- close_stack(\$text, \@stack, \%state, $line_nr);
- if (defined($text))
- {
- push @{$Texi2HTML::THIS_SECTION}, $text;
- }
- print STDERR "\n" if ($T2H_VERBOSE);
-
- # if no sections, then simply print document as is
- if ($one_section)
- {
- # may happen if there are 0 sections
- if (! defined($Texi2HTML::THISDOC{'FH'}))
- {
- open_out_file($docu_doc);
- &$Texi2HTML::Config::print_page_head($Texi2HTML::THISDOC{'FH'});
- shift @{$Texi2HTML::THIS_SECTION} while (@{$Texi2HTML::THIS_SECTION} and ($Texi2HTML::THIS_SECTION->[0] =~ /^\s*$/));
- my $title = &$Texi2HTML::Config::print_title();
- unshift @{$Texi2HTML::THIS_SECTION}, $title if (defined($title) and $title ne '');
- }
- if (@foot_lines)
- {
- &$Texi2HTML::Config::foot_section (\@foot_lines);
- push @{$Texi2HTML::THIS_SECTION}, @foot_lines;
- }
- print STDERR "# Write the section $Texi2HTML::THIS_ELEMENT->{'texi'}\n" if ($T2H_VERBOSE);
- &$Texi2HTML::Config::one_section($Texi2HTML::THISDOC{'FH'}, $Texi2HTML::THIS_ELEMENT);
- close_out($Texi2HTML::THISDOC{'FH'}, $docu_doc_file);
- # no misc element is done
- return;
- }
- finish_element ($Texi2HTML::THISDOC{'FH'}, $Texi2HTML::THIS_ELEMENT, undef, $first_section);
- ############################################################################
- # Print ToC, Overview, Footnotes
- #
- foreach my $direction (@element_directions)
- {
- $Texi2HTML::HREF{$direction} = undef;
- delete $Texi2HTML::HREF{$direction};
- # it is better to undef in case the references to these hash entries
- # are used, as if deleted, the
- # references are still refering to the old, undeleted element
- # (we could do both)
- $Texi2HTML::NAME{$direction} = undef;
- $Texi2HTML::NO_TEXI{$direction} = undef;
- $Texi2HTML::SIMPLE_TEXT{$direction} = undef;
- $Texi2HTML::NODE{$direction} = undef;
- $Texi2HTML::THIS_ELEMENT = undef;
- }
- my $about_body;
- $about_body = &$Texi2HTML::Config::about_body() if (defined($Texi2HTML::Config::about_body));
- # @foot_lines is emptied in finish_element if footnotestyle separate
- my %misc_page_infos = (
- 'Footnotes' => { 'file' => $docu_foot_file,
- 'relative_file' => $docu_foot,
- 'process' => $Texi2HTML::Config::print_Footnotes,
- 'section' => \@foot_lines },
- 'Contents' => { 'file' => $docu_toc_file,
- 'relative_file' => $docu_toc,
- 'process' => $Texi2HTML::Config::print_Toc,
- 'section' => $Texi2HTML::TOC_LINES },
- 'Overview' => { 'file' => $docu_stoc_file,
- 'relative_file' => $docu_stoc,
- 'process' => $Texi2HTML::Config::print_Overview,
- 'section' => $Texi2HTML::OVERVIEW },
- 'About' => { 'file' => $docu_about_file,
- 'relative_file' => $docu_about,
- 'process' => $Texi2HTML::Config::print_About,
- 'section' => [$about_body] }
- );
- $misc_page_infos{'Footnotes'}->{'do'} = 1 if (@foot_lines);
- $misc_page_infos{'Contents'}->{'do'} = 1 if
- (@{$Texi2HTML::TOC_LINES} and !get_conf('INLINE_CONTENTS') and (!get_conf('setcontentsaftertitlepage') or !get_conf('USE_TITLEPAGE_FOR_TITLE')));
- $misc_page_infos{'Overview'}->{'do'} = 1 if
- (@{$Texi2HTML::OVERVIEW} and !get_conf('INLINE_CONTENTS') and (!get_conf('setshortcontentsaftertitlepage') or !get_conf('USE_TITLEPAGE_FOR_TITLE')));
- $misc_page_infos{'About'}->{'do'} = 1 if ($about_body and $Texi2HTML::THISDOC{'do_about'});
-
- foreach my $misc_page('Footnotes', 'Contents', 'Overview', 'About')
- {
- next unless ($misc_page_infos{$misc_page}->{'do'});
- my $file = $misc_page_infos{$misc_page}->{'file'};
- my $relative_file = $misc_page_infos{$misc_page}->{'relative_file'};
- print STDERR "# writing $misc_page in $file\n" if $T2H_VERBOSE;
- my $saved_FH;
- my $open_new = 0;
- if ($relative_file ne $docu_doc)
- {
- $saved_FH = $Texi2HTML::THISDOC{'FH'};
- # Use open_out_file not to overwrite a file that the user would have
- # created
- open_out_file ($relative_file);
- print STDERR "# Opening $file for $misc_page\n" if $T2H_VERBOSE;
- $open_new = 1;
- }
- else
- {
- print STDERR "# writing $misc_page in current file\n" if $T2H_VERBOSE;
- }
- foreach my $href_page (keys(%misc_page_infos))
- {
- $Texi2HTML::HREF{$href_page} = file_target_href(
- $misc_page_infos{$href_page}->{'relative_file'}, $relative_file,
- $Texi2HTML::Config::misc_pages_targets{$href_page})
- if ($misc_page_infos{$href_page}->{'do'});
- }
- #print STDERR "Doing hrefs for $misc_page First ";
- $Texi2HTML::HREF{'First'} = href($element_first, $relative_file);
- #print STDERR "Last ";
- $Texi2HTML::HREF{'Last'} = href($element_last, $relative_file);
- #print STDERR "Index ";
- $Texi2HTML::HREF{'Index'} = href($element_chapter_index, $relative_file) if (defined($element_chapter_index));
- #print STDERR "Top ";
- $Texi2HTML::HREF{'Top'} = href($element_top, $relative_file);
- if (get_conf('INLINE_CONTENTS'))
- {
- $Texi2HTML::HREF{'Contents'} = href($content_element{'contents'}, $relative_file);
- $Texi2HTML::HREF{'Overview'} = href($content_element{'shortcontents'}, $relative_file);
- }
- $Texi2HTML::HREF{$misc_page} = '#' . $Texi2HTML::Config::misc_pages_targets{$misc_page};
- $Texi2HTML::HREF{'This'} = $Texi2HTML::HREF{$misc_page};
- $Texi2HTML::NAME{'This'} = $Texi2HTML::NAME{$misc_page};
- $Texi2HTML::NO_TEXI{'This'} = $Texi2HTML::NO_TEXI{$misc_page};
- $Texi2HTML::SIMPLE_TEXT{'This'} = $Texi2HTML::SIMPLE_TEXT{$misc_page};
- $Texi2HTML::THIS_SECTION = $misc_page_infos{$misc_page}->{'section'}
- if defined($misc_page_infos{$misc_page}->{'section'});
- &{$misc_page_infos{$misc_page}->{'process'}}($Texi2HTML::THISDOC{'FH'}, $open_new, $misc_page);
-
- if ($open_new)
- {
- close_out($Texi2HTML::THISDOC{'FH'}, $file);
- $Texi2HTML::THISDOC{'FH'} = $saved_FH;
- }
- }
-
- unless (get_conf('SPLIT'))
- {
- &$Texi2HTML::Config::print_page_foot($Texi2HTML::THISDOC{'FH'});
- # this leaves the possibility for external code to close the file
- # without erroring out
- close_out ($Texi2HTML::THISDOC{'FH'}, $docu_doc_file) if (fileno($Texi2HTML::THISDOC{'FH'}));
- }
- pop_state();
- }
- # print section, close file if needed.
- sub finish_element($$$$)
- {
- my $FH = shift;
- my $element = shift;
- my $new_element = shift;
- my $first_section = shift;
- #print STDERR "FINISH_ELEMENT($FH)($element->{'texi'})[$element->{'file'}] counter $files{$element->{'file'}}->{'counter'}\n";
- # handle foot notes
- if (get_conf('SPLIT') and scalar(@foot_lines)
- and (get_conf('footnotestyle') eq 'end')
- and (! $new_element or
- ($element and ($new_element->{'file'} ne $element->{'file'})))
- )
- {
- if ($files{$element->{'file'}}->{'counter'})
- {# there are other elements in that page we are not on its foot
- $files{$element->{'file'}}->{'relative_foot_num'}
- = $global_relative_foot_num;
- push @{$files{$element->{'file'}}->{'foot_lines'}},
- @foot_lines;
- }
- else
- {# we output the footnotes as we are at the file end
- unshift @foot_lines, @{$files{$element->{'file'}}->{'foot_lines'}};
- &$Texi2HTML::Config::foot_section (\@foot_lines);
- push @{$Texi2HTML::THIS_SECTION}, @foot_lines;
- }
- if ($new_element)
- {
- $global_relative_foot_num =
- $files{$new_element->{'file'}}->{'relative_foot_num'};
- }
- @foot_lines = ();
- }
- if ($element->{'top'})
- {
- ############### debug
- #print STDERR "TOP $element->{'texi'}, @{$Texi2HTML::THIS_SECTION}\n";
- die "element->{'top'} $element ne element_top $element_top" if ($element ne $element_top);
- print STDERR "# Doing element top\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- print STDERR "[Top]" if ($T2H_VERBOSE);
- ############### end debug
- &$Texi2HTML::Config::print_Top($FH, $element->{'titlefont'}, $element);
- my $end_page = 0;
- if (get_conf('SPLIT'))
- {
- if ($files{$element->{'file'}}->{'counter'} == 0)
- {
- $end_page = 1;
- }
- }
- &$Texi2HTML::Config::print_Top_footer($FH, $end_page, $element);
- close_out($FH, $docu_top_file) if ($end_page);
- }
- else
- {
- print STDERR "# do element $element->{'texi'}\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- &$Texi2HTML::Config::print_section($FH, $first_section, 0, $element);
- ################# debug
- my $new_elem_file = 'NO ELEM => no file';
- $new_elem_file = $new_element->{'file'} if (defined($new_element));
- print STDERR "# FILES new: $new_elem_file old(".fileno($FH)."): $element->{'file'}\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- ################# end debug
- if (defined($new_element) and ($new_element->{'file'} ne $element->{'file'}))
- {
- print STDERR "# End of section with change in file(".fileno($FH).") $element->{'file'} -> $new_element->{'file'}\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- if (!$files{$element->{'file'}}->{'counter'})
- {
- &$Texi2HTML::Config::print_chapter_footer($FH, $element) if (get_conf('SPLIT') eq 'chapter');
- &$Texi2HTML::Config::print_section_footer($FH, $element) if (get_conf('SPLIT') eq 'section');
- print STDERR "# Close file(".fileno($FH).") after $element->{'texi'}\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- &$Texi2HTML::Config::print_page_foot($FH);
- close_out($FH, "$docu_rdir$element->{'file'}");
- }
- else
- {
- print STDERR "# Counter $files{$element->{'file'}}->{'counter'} ne 0, file(".fileno($FH).") $element->{'file'}\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- }
- }
- elsif (!defined($new_element))
- {
- print STDERR "# End of last section, file(".fileno($FH).") $element->{'file'}, counter $files{$element->{'file'}}->{'counter'}\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- if (get_conf('SPLIT'))
- { # end of last splitted section
- &$Texi2HTML::Config::print_chapter_footer($FH, $element) if (get_conf('SPLIT') eq 'chapter');
- &$Texi2HTML::Config::print_section_footer($FH, $element) if (get_conf('SPLIT') eq 'section');
- &$Texi2HTML::Config::print_page_foot($FH);
- close_out($FH, "$docu_rdir$element->{'file'}");
- }
- else
- { # end of last unsplit section
- &$Texi2HTML::Config::end_section($FH, 1, $element);
- }
- }
- elsif ($new_element->{'top'})
- {
- print STDERR "# Section followed by Top, file(".fileno($FH).") counter $files{$element->{'file'}}->{'counter'}\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- &$Texi2HTML::Config::end_section($FH, 1, $element);
- }
- else
- { # end of section followed by another one
- print STDERR "# Section followed by another one, file(".fileno($FH).") counter $files{$element->{'file'}}->{'counter'}\n"
- if ($T2H_DEBUG & $DEBUG_ELEMENTS);
- &$Texi2HTML::Config::end_section($FH, 0, $element);
- }
- }
- }
- # write to files with name the node name for cross manual references.
- sub do_node_files()
- {
- foreach my $key (sort(keys(%nodes)))
- {
- my $node = $nodes{$key};
- next unless ($node->{'node_file'});
- my $redirection_file = $docu_doc;
- $redirection_file = $node->{'file'} if (get_conf('SPLIT'));
- if (!$redirection_file)
- {
- print STDERR "Bug: file for redirection for `$node->{'texi'}' don't exist\n" unless (Texi2HTML::Config::get_conf('novalidate') or !$node->{'seen'});
- next;
- }
- next if ($redirection_file eq $node->{'node_file'});
- my $file = "${docu_rdir}$node->{'node_file'}";
- $Texi2HTML::NODE{'This'} = $node->{'text'};
- $Texi2HTML::NO_TEXI{'This'} = $node->{'no_texi'};
- $Texi2HTML::SIMPLE_TEXT{'This'} = $node->{'simple_format'};
- $Texi2HTML::NAME{'This'} = $node->{'text'};
- my $href_file = $node->{'file'};
- if (!defined($href_file))
- {
- if (Texi2HTML::Config::get_conf('novalidate'))
- {
- $href_file = '';
- }
- else
- {
- msg_debug ("Undefined file for `$node->{'texi'}' in do_node_files");
- }
- }
- $Texi2HTML::HREF{'This'} = "$href_file#$node->{'id'}";
- my $redirect = &$Texi2HTML::Config::print_redirection_page ();
- if (defined($redirect))
- {
- my $NODEFILE = open_out ($file);
- print $NODEFILE "$redirect";
- close $NODEFILE || document_error ("Can't close $file: $!", 1);
- }
- }
- }
- # do redirection files for renamed nodes
- sub do_renamed_node_files()
- {
- foreach my $old_node_name (sort(keys(%Texi2HTML::Config::renamed_nodes)))
- {
- my $new_node_name = $Texi2HTML::Config::renamed_nodes{$old_node_name};
- $old_node_name = normalise_node($old_node_name);
- $new_node_name = normalise_node($new_node_name);
- my $new_node_equivalent_name = find_equivalent_node($new_node_name);
- my ($node_id, $old_node_file);
- if (get_conf('TRANSLITERATE_FILE_NAMES'))
- {
- ($node_id, $old_node_file) = cross_manual_line($old_node_name,1);
- }
- else
- {
- $old_node_file = cross_manual_line($old_node_name);
- }
- my $file = "${docu_rdir}$old_node_file";
- $file .= '.'.get_conf('NODE_FILE_EXTENSION') if (defined(get_conf('NODE_FILE_EXTENSION')));
- if (!defined($old_node_file) or $old_node_file eq '')
- {
- document_error(sprintf(__("File empty for renamed node `%s'"), $old_node_name));
- }
- elsif (!defined($new_node_equivalent_name))
- {
- document_error(sprintf(__("Node to be renamed as, `%s' not found"), $new_node_name));
- }
- elsif (defined($nodes{$old_node_name}))
- {
- document_error(sprintf(__("Node `%s' that is to be renamed exists "), $old_node_name));
- }
- else
- {
- my $new_node = $nodes{$new_node_equivalent_name};
- $Texi2HTML::NODE{'This'} = $new_node->{'text'};
- $Texi2HTML::NO_TEXI{'This'} = $new_node->{'no_texi'};
- $Texi2HTML::SIMPLE_TEXT{'This'} = $new_node->{'simple_format'};
- $Texi2HTML::NAME{'This'} = $new_node->{'text'};
- my $href_file = $new_node->{'file'};
- if (!defined($href_file))
- {
- if (Texi2HTML::Config::get_conf('novalidate'))
- {
- $href_file = '';
- }
- else
- {
- msg_debug ("Undefined file for `$new_node->{'texi'}' in do_node_files for renamed nodes");
- }
- }
- $Texi2HTML::HREF{'This'} = "$href_file#$new_node->{'id'}";
- my $redirect = &$Texi2HTML::Config::print_redirection_page ();
- if (defined($redirect))
- {
- my $NODEFILE = open_out ($file);
- print $NODEFILE "$redirect";
- close $NODEFILE || document_error ("Can't close $file: $!", 1);
- }
- }
- }
- }
- #+++############################################################################
- # #
- # Low level functions #
- # #
- #---############################################################################
- sub locate_include_file($)
- {
- my $file = shift;
- # APA: Don't implicitely search ., to conform with the docs!
-
- # if file begins with /, ./ or ../ don't search in -I (Karl)
- if ($file =~ m,^(/|\./|\.\./),)
- {
- return "$file" if (-e "$file" && -r "$file");
- return undef;
- }
- foreach my $dir (@Texi2HTML::Config::INCLUDE_DIRS)
- {
- return "$dir/$file" if (-e "$dir/$file" && -r "$dir/$file");
- }
- return undef;
- }
- sub open_file($$$)
- {
- my $name = shift;
- # my $line_number = shift;
- my $macro = shift;
- my $files_stack = shift;
- my $line_number;
- my $input_spool;
-
- local *FH;
- if (open(*FH, "<$name"))
- {
- my $in_encoding = get_conf('IN_ENCODING');
- if (defined($in_encoding) and get_conf('USE_UNICODE'))
- {
- binmode(*FH, ":encoding($in_encoding)");
- }
- my $file = { 'fh' => *FH,
- 'input_spool' => { 'spool' => [],
- 'macro' => '' },
- 'name' => $name,
- 'line_nr' => 0 };
- unshift(@$files_stack, $file);
- $input_spool = $file->{'input_spool'};
- $line_number->{'file_name'} = $name;
- $line_number->{'line_nr'} = 1;
- $line_number->{'macro'} = $macro;
- }
- else
- {
- document_error ("Can't read file $name: $!", 1);
- }
- return ($line_number, $input_spool);
- }
- my %filehandles = ();
- sub open_out($;$)
- {
- my $file = shift;
- my $append = shift;
- local *FILE;
- if ($file eq '-')
- {
- binmode(STDOUT, ":encoding(".get_conf('OUT_ENCODING').")") if (get_conf('OUT_ENCODING') and get_conf('USE_UNICODE'));
- return \*STDOUT;
- }
- my $mode = '>';
- $mode = '>>' if ($append);
- unless (open(FILE, $mode, $file))
- {
- document_error ("could not open $file for writing: $!", 1);
- }
- push @opened_files, $file;
- if (defined(get_conf('OUT_ENCODING')) and get_conf('USE_UNICODE'))
- {
- if (get_conf('OUT_ENCODING') eq 'utf8' or get_conf('OUT_ENCODING') eq 'utf-8-strict')
- {
- binmode(FILE, ':utf8');
- }
- else
- {
- binmode(FILE, ':bytes');
- }
- # FIXME is it useful when in utf8?
- binmode(FILE, ":encoding(".get_conf('OUT_ENCODING').")");
- }
- $file =~ s/^(\.[\/]+)*//;
- $filehandles{fileno(*FILE)} = $file;
- return *FILE;
- }
- sub close_out($$)
- {
- my $FH = shift;
- my $file = shift;
- return if (defined($file) and $file eq '-');
- $file =~ s/^(\.[\/]+)*//;
- my $fileno = fileno($FH);
- #print STDERR "close_out $file $fileno\n";
- if (!defined($fileno))
- {
- msg_debug("fileno not defined for $file")
- }
- elsif (defined($filehandles{$fileno}) and $filehandles{$fileno} ne $file)
- {
- #msg_debug("filehandles{$fileno} $filehandles{$fileno} and file $file different")
- }
- close ($FH) || document_error ("Error when closing $file: $!");
- }
- sub next_line($$)
- {
- my $line_number = shift;
- my $files_stack = shift;
- my $input_spool;
- while (@$files_stack)
- {
- my $file = $files_stack->[0];
- $line_number->{'file_name'} = $file->{'name'};
- $input_spool = $file->{'input_spool'};
- if (@{$input_spool->{'spool'}})
- {
- $line_number->{'macro'} = $file->{'input_spool'}->{'macro'};
- $line_number->{'line_nr'} = $file->{'line_nr'};
- my $line = shift(@{$input_spool->{'spool'}});
- print STDERR "# unspooling $line" if ($T2H_DEBUG & $DEBUG_MACROS);
- return($line, $input_spool);
- }
- else
- {
- $file->{'input_spool'}->{'macro'} = '';
- $line_number->{'macro'} = '';
- }
- my $fh = $file->{'fh'};
- no strict "refs";
- my $line = <$fh>;
- use strict "refs";
- my $chomped_line = $line;
- $file->{'line_nr'}++ if (defined($line) and chomp($chomped_line));
- $line_number->{'line_nr'} = $file->{'line_nr'};
- # do that right now, before any other treatement
- $line =~ s/\x{7F}.*\s*// if (defined($line));
- return($line, $input_spool) if (defined($line));
- no strict "refs";
- close($fh);
- use strict "refs";
- shift(@$files_stack);
- }
- return(undef, $input_spool);
- }
- sub check_die(;$)
- {
- my $always_die = shift;
- if (!get_conf('FORCE'))
- {
- if (@opened_files == 1)
- {
- warn sprintf(__("%s: Removing output file `%s' due to errors; use --force to preserve.\n"), $real_command_name, $opened_files[0]);
- }
- elsif (@opened_files > 1)
- {
- warn sprintf(__("%s: Removing output files due to errors; use --force to preserve.\n"), $real_command_name);
- }
- foreach my $file (@opened_files)
- {
- unlink ($file);
- }
- foreach my $dir (@created_directories)
- {
- rmdir ($dir);
- }
- }
- if ($always_die or !get_conf('FORCE'))
- {
- exit (1);
- }
- }
- sub file_line_warn($$;$)
- {
- return if (get_conf('NO_WARN'));
- my $text = shift;
- chomp($text);
- my $file = shift;
- my $line_nr = shift;
- if (!defined($line_nr))
- {
- warn "$file: $text\n";
- }
- else
- {
- warn "$file:$line_nr: $text\n";
- }
- }
- sub document_warn ($)
- {
- return if (get_conf('NO_WARN'));
- my $text = shift;
- chomp ($text);
- warn sprintf(__p("warning: warning_message", "warning: %s\n"), $text);
- }
- my $error_nrs = 0;
- sub check_errors()
- {
- $error_nrs ++;
- die __("Too many errors! Gave up.\n") if ($error_nrs >= get_conf('ERROR_LIMIT'));
- }
- sub msg_debug($;$)
- {
- my $text = shift;
- chomp ($text);
- my $line_number = shift;
- if (defined($line_number))
- {
- warn "!! $text " . format_line_number($line_number) . "\n";
- }
- else
- {
- warn "!! $text\n";
- }
- }
- sub cmdline_warn ($)
- {
- my $text = shift;
- chomp ($text);
- warn sprintf(__p("command_name: warning_message", "%s: %s\n"), $real_command_name, $text);
- }
- # seems not to be used
- sub cmdline_error ($)
- {
- my $text = shift;
- #chomp ($text);
- warn sprintf(__p("command_name: error_message", "%s: %s"), $real_command_name, $text);
- }
- sub document_error($;$)
- {
- my $text = shift;
- chomp ($text);
- my $die = shift;
- warn ("$text\n");
- check_die ($die);
- check_errors();
- }
- # echo an error
- sub msg_error($;$)
- {
- my $text = shift;
- my $line_number = shift;
- if (defined($line_number))
- {
- line_error ($text, $line_number);
- }
- else
- {
- document_error ($text);
- }
- }
- # echo a warning
- sub msg_warn($;$$)
- {
- my $text = shift;
- my $line_number = shift;
- my $context_string = shift;
- if (defined($line_number))
- {
- line_warn ($text, $line_number);
- }
- elsif (defined($context_string))
- {
- document_warn ("$text (in $context_string)");
- }
- else
- {
- document_warn ($text);
- }
- }
- # echo a warning associated with a line in the document
- sub line_warn($$)
- {
- return if (get_conf('NO_WARN'));
- my $text = shift;
- chomp ($text);
- my $line_number = shift;
- return if (!defined($line_number));
- my $file = $line_number->{'file_name'};
- # otherwise out of source build fail since the file names are different
- $file =~ s/^.*\/// if (get_conf('TEST'));
- if ($line_number->{'macro'} ne '')
- {
- warn sprintf(__("%s:%d: warning: %s (possibly involving \@%s)\n"), $file, $line_number->{'line_nr'}, $text, $line_number->{'macro'});
- }
- else
- {
- warn sprintf(__("%s:%d: warning: %s\n"), $file, $line_number->{'line_nr'}, $text);
- }
- }
- sub line_error($$)
- {
- my $text = shift;
- chomp ($text);
- my $line_number = shift;
- if (defined($line_number))
- {
- my $file = $line_number->{'file_name'};
- $file =~ s/^.*\/// if (get_conf('TEST'));
- my $macro_text = '';
- $macro_text = " (possibly involving \@$line_number->{'macro'})" if ($line_number->{'macro'} ne '');
- warn "$file:$line_number->{'line_nr'}: $text$macro_text\n";
- check_die();
- }
- check_errors();
- }
- sub format_line_number(;$)
- {
- my $line_number = shift;
- $line_number = $Texi2HTML::THISDOC{'line_nr'} if (!defined($line_number));
- my $macro_text = '';
- #$line_number = undef;
- return '' unless (defined($line_number));
- my $print_filename = ($line_number->{'file_name'} ne $Texi2HTML::THISDOC{'input_file_name'});
- if ($line_number->{'macro'} ne '')
- {
- if ($print_filename)
- {
- return sprintf(__("(in %s l. %d possibly involving \@%s)"), $line_number->{'file_name'}, $line_number->{'line_nr'}, $line_number->{'macro'});
- }
- else
- {
- return sprintf(__("(l. %d possibly involving \@%s)"), $line_number->{'line_nr'}, $line_number->{'macro'});
- }
- }
- elsif ($print_filename)
- {
- return sprintf(__("(in %s l. %d)"), $line_number->{'file_name'}, $line_number->{'line_nr'});
- }
- else
- {
- return sprintf(__("(l. %d)"), $line_number->{'line_nr'});
- }
- }
- # to debug, dump the result of pass_texi and pass_structure in a file
- sub dump_texi($$;$$)
- {
- my $lines = shift;
- my $pass = shift;
- my $numbers = shift;
- my $file = shift;
- $file = "$docu_rdir$docu_name" . ".pass$pass" if (!defined($file));
- my $FH = open_out($file);
- print STDERR "# Dump texi\n" if ($T2H_VERBOSE);
- my $index = 0;
- foreach my $line (@$lines)
- {
- my $number_information = '';
- my $chomped_line = $line;
- # if defined, it means that an output of the file is asked for
- if (defined($numbers))
- {
- my $basefile = $numbers->[$index]->{'file_name'};
- $basefile = 'no file' if (!defined($basefile));
- $basefile =~ s|.*/||;
- my $macro_name = $numbers->[$index]->{'macro'};
- $macro_name = '' if (!defined($macro_name));
- my $line_number = $numbers->[$index]->{'line_nr'};
- $line_number = '' if (!defined($line_number));
- $number_information = "${basefile}($macro_name,$line_number) ";
- }
- print $FH "${number_information}$line";
- $index++ if (chomp($chomped_line));
- }
- close_out ($FH, $file);
- }
- # return next tag on the line
- sub next_tag($)
- {
- my $line = shift;
- # macro_regexp
- if ($line =~ /^\s*\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/\\])/o or $line =~ /^\s*\@([a-zA-Z][\w-]*)/)
- {
- return ($1);
- }
- return '';
- }
- sub next_end_tag($)
- {
- my $line = shift;
- if ($line =~ /^\s*\@end\s+([a-zA-Z][\w-]*)/)
- {
- return $1;
- }
- return '';
- }
- sub next_tag_or_end_tag($)
- {
- my $line = shift;
- my $next_tag = next_tag($line);
- return $next_tag if (defined($next_tag) and $next_tag ne '');
- return next_end_tag($line);
- }
- sub top_stack($;$)
- {
- my $stack = shift;
- my $ignore_para = shift;
- my $index = scalar (@$stack);
- return undef unless ($index);
- return $stack->[-1] unless ($ignore_para);
- if ($ignore_para == 1)
- {
- if (exists($stack->[-1]->{'format'}) and ($stack->[-1]->{'format'} eq 'paragraph' or $stack->[-1]->{'format'} eq 'preformatted'))
- {
- if (exists($stack->[-2]))
- {
- return $stack->[-2];
- }
- else
- {
- return undef;
- }
- }
- else
- {
- return $stack->[-1];
- }
- }
- else
- {
- while ($index and
- (
- (exists($stack->[$index-1]->{'format'})
- and ($stack->[$index-1]->{'format'} eq 'paragraph' or $stack->[$index-1]->{'format'} eq 'preformatted'))
- or (exists($stack->[$index-1]->{'style'}))
- ))
- {
- $index--;
- }
- }
- return undef unless ($index);
- return $stack->[$index-1];
- }
- # return the next element with balanced {}
- sub next_bracketed($$$;$)
- {
- my $line = shift;
- my $command = shift;
- my $line_nr = shift;
- my $report = shift;
- my $opened_braces = 0;
- my $result = '';
- my $spaces;
- #print STDERR "next_bracketed $line";
- if ($line =~ /^(\s*)$/)
- {
- return ('','',$1);
- }
- while ($line !~ /^\s*$/)
- {
- #print STDERR "next_bracketed($opened_braces): $result !!! $line";
- if (!$opened_braces)
- { # beginning of item
- $line =~ s/^(\s*)//;
- $spaces = $1;
- #if ($line =~ s/^([^\{\}\s]+)//)
- if ($line =~ s/^([^\{\}]+?)(\s+)/$2/ or $line =~ s/^([^\{\}]+?)$//)
- {
- $result = $1;
- $result = trim_around_spaces($result);
- return ($result, $line, $spaces);
- }
- elsif ($line =~ s/^([^\{\}]+?)([\{\}])/$2/)
- {
- $result = $1;
- }
- }
- elsif($line =~ s/^([^\{\}]+)//)
- {
- $result .= $1;
- }
- if ($line =~ s/^([\{\}])//)
- {
- my $brace = $1;
- $opened_braces++ if ($brace eq '{');
- $opened_braces-- if ($brace eq '}');
-
- if ($opened_braces < 0)
- {
- line_error(sprintf(__("Too much '}' in \@%s"), $command), $line_nr) if ($report);
- $opened_braces = 0;
- #next;
- }
- $result .= $brace;
- return ($result, $line, $spaces) if ($opened_braces == 0);
- }
- }
- if ($opened_braces)
- {
- line_error(sprintf(__("Missing `}' on \@%s line"), $command), $line_nr) if ($report);
- return ($result, '', $spaces);
- #return ($result . ( '}' x $opened_braces), '', $spaces);
- }
- msg_debug ("BUG: at the end of next_bracketed", $line_nr);
- return undef;
- }
- # def prams are also split at @-commands if not in brackets
- sub next_def_param($$$;$)
- {
- my $line = shift;
- my $command = shift;
- my $line_nr = shift;
- my $report = shift;
- my ($item, $spaces);
- ($item, $line, $spaces) = next_bracketed($line, $command, $line_nr, $report);
- return ($item, $line, $spaces) if (!defined($item));
- if ($item =~ /^\{/)
- {
- $item =~ s/^\{(.*)\}$/$1/;
- }
- else
- {
- my $delimeter_quoted = quotemeta($Texi2HTML::Config::def_argument_separator_delimiters);
- if ($item =~ s/^([^\@$delimeter_quoted]+)//)
- {
- $line = $item . $line;
- $item = $1;
- }
- elsif ($item =~ s/^([$delimeter_quoted])//)
- {
- $line = $item . $line;
- $item = $1;
- }
- elsif ($item =~ s/^(\@[^\@\{]+)(\@)/$2/)
- {
- $line = $item . $line;
- $item = $1;
- }
- }
- return ($item, $line, $spaces);
- }
- # do a href using file and id and taking care of ommitting file if it is
- # the same
- # element: structuring element to point to
- # file: current file
- sub href($$;$)
- {
- my $element = shift;
- my $file = shift;
- my $line_nr = shift;
- return '' unless defined($element);
- my $href = '';
- msg_debug("Bug: $element->{'texi'}, target undef", $line_nr) if (!defined($element->{'target'}));
- msg_debug("Bug: $element->{'texi'}, file undef", $line_nr) if (!defined($element->{'file'}));
- msg_debug("Bug: file undef in href", $line_nr) if (!defined($file));
- $href .= $element->{'file'} if (defined($element->{'file'}) and $file ne $element->{'file'});
- $href .= "#$element->{'target'}" if (defined($element->{'target'}));
- return $href;
- }
- sub file_target_href($$$)
- {
- my $dest_file = shift;
- my $orig_file = shift;
- my $target = shift;
- my $href = '';
- $href .= $dest_file if (defined($dest_file) and ($dest_file ne $orig_file));
- $href .= "#$target" if (defined($target));
- return $href;
- }
- sub trim_around_spaces($)
- {
- my $text = shift;
- $text =~ s/^\s*//;
- $text =~ s/(\s)\s*$/$1/;
- if ($text =~ /(\@+)\s$/)
- {
- my $arobases = $1;
- if ((length($arobases) % 2) == 0)
- {
- $text =~ s/\s$//;
- }
- }
- else
- {
- $text =~ s/\s$//;
- }
- return $text;
- }
- sub normalise_space($)
- {
- return undef unless (defined ($_[0]));
- my $text = shift;
- $text =~ s/\s+/ /go;
- $text =~ s/ $//;
- $text =~ s/^ //;
- return $text;
- }
- sub normalise_texi_space($)
- {
- return undef unless (defined ($_[0]));
- my $text = shift;
- $text = trim_around_spaces($text);
- $text =~ s/\s+/ /go;
- return $text;
- }
- sub normalise_node($)
- {
- return undef unless (defined ($_[0]));
- my $text = shift;
- $text = normalise_texi_space($text);
- $text =~ s/^top$/Top/i;
- return $text;
- }
- sub normalise_node_array($)
- {
- my $array = shift;
- my @result;
- foreach my $node (@$array)
- {
- push @result, normalise_node($node);
- }
- return @result;
- }
- sub do_anchor_label($$$$)
- {
- my $command = shift;
- #my $anchor = shift;
- my $args = shift;
- my $anchor = $args->[0];
- my $style_stack = shift;
- my $state = shift;
- my $line_nr = shift;
- #msg_debug("do_anchor_label $state->{'region'} m_p $state->{'multiple_pass'} remove $state->{'remove_texi'} `$anchor'", $line_nr);
- $anchor = normalise_node($anchor);
- if ((defined($state->{'multiple_pass'}) and $state->{'multiple_pass'} > 0) or $state->{'outside_document'})
- {
- # no warning when outside of document.
- line_warn(sprintf(__("Anchor `%s' ignored in %s expanded more than once"),$anchor, $state->{'region'}), $line_nr) unless ($state->{'outside_document'} or defined($state->{'expansion'}));
- return '';
- }
- if (!exists($nodes{$anchor}) or !defined($nodes{$anchor}->{'id'}))
- {
- msg_debug("Unknown anchor `$anchor'", $line_nr);
- }
- return &$Texi2HTML::Config::anchor_label($nodes{$anchor}->{'id'}, $anchor, $nodes{$anchor}, $state->{'expansion'});
- }
- sub get_format_command($)
- {
- my $format = shift;
- my $command = '';
- my $format_name = '';
- my $term = 0;
- my $item_nr;
- my $paragraph_number;
- my $enumerate_type;
- my $number;
-
- $command = $format->{'command'} if (defined($format->{'command'}));
- $format_name = $format->{'format'} if (defined($format->{'format'}));
- return ($format_name,$command,\$format->{'paragraph_number'},$term,
- $format->{'item_nr'}, $format->{'spec'}, $format->{'number'},
- $format->{'stack_at_beginning'});
- }
- sub do_paragraph($$;$)
- {
- my $text = shift;
- my $state = shift;
- my $stack = shift;
- if (!defined ($state->{'paragraph_context'}))
- {
- msg_debug ("paragraph_context undef", $Texi2HTML::THISDOC{'line_nr'});
- dump_stack (undef, $stack, $state);
- }
- my ($format, $paragraph_command, $paragraph_number, $term, $item_nr,
- $enumerate_type, $number, $stack_at_beginning)
- = get_format_command ($state->{'paragraph_context'});
- delete $state->{'paragraph_context'};
- my $indent_style = '';
- if (exists($state->{'paragraph_indent'}))
- {
- $indent_style = $state->{'paragraph_indent'};
- $state->{'paragraph_indent'} = undef;
- delete $state->{'paragraph_indent'};
- }
- my $paragraph_command_formatted;
- $state->{'paragraph_nr'}--;
- (print STDERR "Bug text undef in do_paragraph", return '') unless defined($text);
- my $align = '';
- $align = $state->{'paragraph_style'}->[-1] if ($state->{'paragraph_style'}->[-1]);
-
- if ($paragraph_command and !exists($Texi2HTML::Config::special_list_commands{$format}->{$paragraph_command}))
- {
- $paragraph_command_formatted = substitute_line("\@$paragraph_command\{\}", "paragraph \@$format \@$paragraph_command", duplicate_formatting_state($state));
- }
- return &$Texi2HTML::Config::paragraph($text, $align, $indent_style, $paragraph_command, $paragraph_command_formatted, $paragraph_number, $format, $item_nr, $enumerate_type, $number,$state->{'command_stack'},$stack_at_beginning);
- }
- sub do_preformatted($$;$)
- {
- my $text = shift;
- my $state = shift;
- my $stack = shift;
- if (!defined ($state->{'preformatted_context'}))
- {
- msg_debug ("preformatted_context undef", $Texi2HTML::THISDOC{'line_nr'});
- dump_stack (undef, $stack, $state);
- }
- my ($format, $leading_command, $preformatted_number, $term, $item_nr,
- $enumerate_type, $number,$stack_at_beginning)
- = get_format_command($state->{'preformatted_context'});
- delete ($state->{'preformatted_context'});
- my $leading_command_formatted;
- my $pre_style = '';
- my $class = '';
- $pre_style = $state->{'preformatted_stack'}->[-1]->{'pre_style'} if ($state->{'preformatted_stack'}->[-1]->{'pre_style'});
- $class = $state->{'preformatted_stack'}->[-1]->{'class'};
- print STDERR "BUG: !state->{'preformatted_stack'}->[-1]->{'class'}\n" unless ($class);
- if (defined($leading_command) and $leading_command ne '' and !exists($Texi2HTML::Config::special_list_commands{$format}->{$leading_command}))
- {
- $leading_command_formatted = substitute_line("\@$leading_command\{\}", "preformatted \@$format \@$leading_command", duplicate_formatting_state($state));
- }
- return &$Texi2HTML::Config::preformatted($text, $pre_style, $class, $leading_command, $leading_command_formatted, $preformatted_number, $format, $item_nr, $enumerate_type, $number,$state->{'command_stack'},$stack_at_beginning);
- }
- sub do_external_href($)
- {
- # node_id is a unique node identifier with only letters, digits, - and _
- # node_xhtml_id is almost the same, but xhtml id can only begin with
- # letters, so a prefix has to be appended
- my $texi_node = shift;
- my $file = '';
- my $node_file = '';
- my $node_id = '';
- my $node_xhtml_id = '';
- #print STDERR "do_external_href $texi_node\n";
- if ($texi_node =~ s/^\((.+?)\)//)
- {
- $file = $1;
- }
- $texi_node = normalise_node($texi_node);
- if ($texi_node ne '')
- {
- if (exists($nodes{$texi_node}) and ($nodes{$texi_node}->{'cross_manual_target'}))
- {
- $node_id = $nodes{$texi_node}->{'cross_manual_target'};
- if (get_conf('TRANSLITERATE_FILE_NAMES'))
- {
- $node_file = $nodes{$texi_node}->{'cross_manual_file'};
- }
- }
- else
- {
- if (get_conf('TRANSLITERATE_FILE_NAMES'))
- {
- ($node_id, $node_file) = cross_manual_line($texi_node,1);
- }
- else
- {
- $node_id = cross_manual_line($texi_node);
- }
- }
- $node_xhtml_id = node_to_id($node_id);
- $node_file = $node_id unless (get_conf('TRANSLITERATE_FILE_NAMES'));
- }
- return &$Texi2HTML::Config::external_href($texi_node, $node_file,
- $node_xhtml_id, $file);
- }
- # transform node for cross ref name to id suitable for xhtml: an xhtml id
- # must begin with a letter.
- sub node_to_id($)
- {
- my $cross_ref_node_name = shift;
- $cross_ref_node_name =~ s/^([0-9_])/g_t$1/;
- return $cross_ref_node_name;
- }
- # return an empty string if the command is not a index command, the prefix
- # if it is one
- sub index_command_prefix($)
- {
- my $command = shift;
- return $1 if ($command =~ /^(\w+?)index/ and ($1 ne 'print') and ($1 ne 'syncode') and ($1 ne 'syn') and ($1 ne 'def') and ($1 ne 'defcode'));
- return '';
- }
- # return 1 if the following tag shouldn't begin a line
- sub no_line($)
- {
- my $line = shift;
- my $next_tag = next_tag($line);
- return 1 if (($line =~ /^\s*$/) or $Texi2HTML::Config::no_paragraph_commands{$next_tag} or
- ($Texi2HTML::Config::no_paragraph_commands{'cindex'} and (index_command_prefix($next_tag) ne '')) or
- (($line =~ /^\@end\s+(\w+)/) and $Texi2HTML::Config::no_paragraph_commands{"end $1"}) or
- ($next_tag =~ /^special_(\w+)_(\d+)$/ and $Texi2HTML::Config::no_paragraph_commands{$1})
- );
- return 0;
- }
- sub no_paragraph($$)
- {
- my $state = shift;
- my $line = shift;
- return ($state->{'paragraph_context'} or $state->{'preformatted'} or $state->{'remove_texi'} or no_line($line) or $state->{'no_paragraph'});
- }
- # We restart the preformatted format which was stopped
- # by the format if in preformatted, and start a paragraph
- # for the text following the end of the format, if needed
- sub begin_paragraph_after_command($$$$)
- {
- my $state = shift;
- my $stack = shift;
- my $command = shift;
- my $text_following = shift;
-
- #if (($state->{'preformatted'}
- # and !$Texi2HTML::Config::format_in_paragraph{$command})
- if ($state->{'preformatted'}
- or (!no_paragraph($state,$text_following)))
- {
- begin_paragraph($stack, $state);
- }
- }
- # handle raw formatting, ignored regions...
- # called from scan_texi, so only in first pass.
- sub do_text_macro($$$$$)
- {
- my $type = shift;
- my $line = shift;
- my $state = shift;
- my $stack = shift;
- my $line_nr = shift;
- my $value;
- #print STDERR "do_text_macro $type\n";
- if ($Texi2HTML::Config::texi_formats_map{$type} eq 'raw')
- {
- $state->{'raw'} = $type;
- #print STDERR "RAW\n";
- if ($state->{'raw'})
- {
- push @$stack, { 'style' => $type, 'text' => '' };
- }
- }
- elsif ($Texi2HTML::Config::texi_formats_map{$type} eq 'value')
- {
- if (($line =~ s/(\s+)($VARRE)$//) or ($line =~ s/(\s+)($VARRE)(\s)//))
- {
- $value = $1 . $2;
- $value .= $3 if defined($3);
- if ($state->{'ignored'})
- {
- if ($type eq $state->{'ignored'})
- {
- $state->{'ifvalue_inside'}++;
- }
- # if 'ignored' we don't care about the command as long as
- # the nesting is correct
- return ($line,'');
- }
- my $open_ignored_ifvalue = 0;
- if ($type eq 'ifclear')
- {
- if (defined($value{$2}))
- {
- $open_ignored_ifvalue = 1;
- }
- else
- {
- push @{$state->{'text_macro_stack'}}, $type;
- }
- }
- elsif ($type eq 'ifset')
- {
- unless (defined($value{$2}))
- {
- $open_ignored_ifvalue = 1;
- }
- else
- {
- push @{$state->{'text_macro_stack'}}, $type;
- }
- }
- if ($open_ignored_ifvalue)
- {
- $state->{'ignored'} = $type;
- $state->{'ifvalue'} = $type;
- $state->{'ifvalue_inside'} = 1;
- # We add at the top of the stack to be able to close all
- # opened comands when closing the ifset/ifclear (and ignore
- # everything that is in those commands)
- push @$stack, { 'style' => 'ifvalue', 'text' => '' };
- }
- }
- else
- { # we accept a lone @ifset or @ifclear if it is nested in an @if*
- if ($state->{'ifvalue'} and $type eq $state->{'ifvalue'})
- {
- $state->{'ifvalue_inside'}++;
- return ($line,'');
- }
- line_error (sprintf(__("%c%s requires a name"), ord('@'), $type), $line_nr) unless ($state->{'ignored'});
- }
- }
- elsif (not $Texi2HTML::Config::texi_formats_map{$type})
- { # ignored text
- $state->{'ignored'} = $type;
- #print STDERR "IGNORED\n";
- }
- else
- {
- push @{$state->{'text_macro_stack'}}, $type unless($state->{'ignored'}) ;
- }
- my $text = "\@$type";
- $text .= $value if defined($value);
- return ($line, $text);
- }
- # do regions handled specially, for example tex or math going through latex2html
- sub init_special($$)
- {
- my $style = shift;
- my $text = shift;
- if (defined($Texi2HTML::Config::command_handler{$style}) and
- defined($Texi2HTML::Config::command_handler{$style}->{'init'}))
- {
- $special_commands{$style}->{'count'} = 0 if (!defined($special_commands{$style}));
- if ($Texi2HTML::Config::command_handler{$style}->{'init'}($style,$text,
- $special_commands{$style}->{'count'} +1))
- {
- $special_commands{$style}->{'count'}++;
- return "\@special_${style}_".$special_commands{$style}->{'count'}."{}";
- }
- return '';
- }
- }
- sub reset_index_entries($)
- {
- my $region = shift;
- if (defined($Texi2HTML::THISDOC{'index_entries'}->{$region}))
- {
- foreach my $entry (values(%{$Texi2HTML::THISDOC{'index_entries'}->{$region}}))
- {
- if (scalar(@{$entry->{'entries'}}) > 1)
- {
- $entry->{'index'} = 0;
- }
- }
- }
- if (defined($Texi2HTML::THISDOC{'indices_numbers'}->{$region}))
- {
- foreach my $index_name (keys(%{$Texi2HTML::THISDOC{'indices_numbers'}->{$region}}))
- {
- $Texi2HTML::THISDOC{'indices_numbers'}->{$region}->{$index_name} = undef;
- }
- }
- }
- # FIXME we cannot go through the commands too 'often'. The error messages
- # are duplicated and global stuff is changed.
- # -> identify what is global
- # -> use local state
- sub do_special_region_lines($;$$)
- {
- my $region = shift;
- my $state = shift;
- my $line_nr = shift;
- # this case covers something like
- # @copying
- # @insertcopying
- # @end copying
- if (defined($state) and exists($state->{'region'}) and ($region eq $state->{'region'}))
- {
- line_error(sprintf(__("Region %s inside region %s is not allowed"), $region, $state->{'region'}), $line_nr);
- return ('','', '');
- }
- print STDERR "# do_special_region_lines for region $region ['multiple_pass','region_pass']: ($region_initial_state{$region}->{'multiple_pass'}, $region_initial_state{$region}->{'region_pass'})" if ($T2H_DEBUG);
- if (!defined($state))
- {
- $state = {};
- fill_state($state);
- $state->{'outside_document'} = 1;
- print STDERR " outside document\n" if ($T2H_DEBUG);
- }
- elsif (!$state->{'outside_document'})
- {
- $region_initial_state{$region}->{'multiple_pass'}++;
- print STDERR " multiple pass $region_initial_state{$region}->{'multiple_pass'}\n" if ($T2H_DEBUG);
- }
- else
- {
- print STDERR " in $state->{'region'}, outside document\n" if ($T2H_DEBUG);
- }
- return ('','','') unless @{$region_lines{$region}};
-
- my @result;
- foreach my $context ('normal', 'remove_texi', 'simple_format')
- {
- print STDERR "# $context\n" if ($T2H_DEBUG);
- my $new_state = duplicate_formatting_state($state);
- reset_index_entries($region);
- foreach my $key (keys(%{$region_initial_state{$region}}))
- {
- $new_state->{$key} = $region_initial_state{$region}->{$key};
- }
- $new_state->{'remove_texi'} = 1 if ($context eq 'remove_texi');
- &$Texi2HTML::Config::begin_special_region($region,$new_state,$region_lines{$region})
- if (defined($Texi2HTML::Config::begin_special_region));
-
- my $line_numbers;
- my $context_string = "$region ($region_initial_state{$region}->{'multiple_pass'}, $region_initial_state{$region}->{'region_pass'})";
- if ($context eq 'normal')
- { # the line numbers are given only for the normal context, therefore
- # there will be error messages only in that case
- $line_numbers = [ @{$region_line_nrs{$region}} ];
- }
- else
- {
- $context_string = "$context $context_string";
- }
-
- my $result;
- if ($context ne 'simple_format')
- {
- $result = substitute_text($new_state, $line_numbers,
- $context_string, @{$region_lines{$region}});
- }
- else
- {
- $result = simple_format($new_state, $line_numbers,
- $context_string, @{$region_lines{$region}});
- }
- $result = &$Texi2HTML::Config::end_special_region($region,$new_state,$result)
- if (defined($Texi2HTML::Config::end_special_region));
- push @result, $result;
- $region_initial_state{$region}->{'region_pass'}++;
- }
- return @result;
- }
- sub do_insertcopying($$)
- {
- my $state = shift;
- my $line_nr = shift;
- my ($text, $comment, $simple_formatted) = do_special_region_lines('copying', $state, $line_nr);
- return &$Texi2HTML::Config::insertcopying($text, $comment, $simple_formatted);
- }
- sub get_deff_index($$$$)
- {
- my $tag = shift;
- my $line = shift;
- my $line_nr = shift;
- my $warn = shift;
-
- $tag =~ s/x$//;
- my ($command, $style, $category, $name, $type, $class, $arguments, $args_array, $args_type_array);
- ($command, $style, $category, $name, $type, $class, $arguments, $args_array, $args_type_array) = parse_def($tag, $line, $line_nr, $warn);
- $name = &$Texi2HTML::Config::definition_index_entry($name, $class, $style, $command);
- return ($style, '') if (!defined($name) or ($name =~ /^\s*$/));
- return ($style, $name, $arguments);
- }
- sub parse_def($$$;$)
- {
- my $command = shift;
- my $line = shift;
- my $line_nr = shift;
- my $report = shift;
- my $format = $command;
- if (!ref ($Texi2HTML::Config::def_map{$command}))
- {
- # substitute shortcuts for definition commands
- my $substituted = $Texi2HTML::Config::def_map{$command};
- $substituted =~ s/(\w+)//;
- $format = $1;
- $line = $substituted . $line;
- }
- #print STDERR "PARSE_DEF($command,$format) $line";
- my ($category, $name, $type, $class, $arguments);
- my @arguments = ();
- my @args = @{$Texi2HTML::Config::def_map{$format}};
- my $style = shift @args;
- my @arg_types = ();
- while (@args and $args[0] ne 'arg' and $args[0] ne 'argtype')
- {
- my $arg = shift @args;
- # backward compatibility, it was possible to have a { in front.
- $arg =~ s/^\{//;
- my ($item, $spaces);
- ($item, $line, $spaces) = next_def_param($line, $command, $line_nr, $report);
- last if (!defined($item));
- if ($arg eq 'category')
- {
- $category = $item;
- }
- elsif ($arg eq 'name')
- {
- $name = $item;
- }
- elsif ($arg eq 'type')
- {
- $type = $item;
- }
- elsif ($arg eq 'class')
- {
- $class = $item;
- }
- push @arg_types, $arg;
- push @arguments, $item;
- }
- my $line_remaining = $line;
- $line = '';
- my $arg_and_type = 1;
- foreach my $arg (@args)
- {
- if ($arg eq 'arg')
- {
- $arg_and_type = 0;
- last;
- }
- elsif ($arg eq 'argtype')
- {
- last;
- }
- }
- my $always_delimiter_quoted = quotemeta($Texi2HTML::Config::def_always_delimiters);
- my $in_type_delimiter_quoted = quotemeta($Texi2HTML::Config::def_in_type_delimiters);
- my $after_type = 0;
- while ($line_remaining !~ /^\s*$/)
- {
- my ($item, $spaces);
- ($item, $line_remaining,$spaces) = next_def_param($line_remaining, $command, $line_nr);
- if ($item =~ /^([$always_delimiter_quoted])/ or (!$arg_and_type and $item =~ /^([$in_type_delimiter_quoted].*)/))
- {
- $item = $1;
- push @arg_types, 'delimiter';
- $after_type = 0;
- }
- elsif (!$arg_and_type or $item =~ /^\@/ or $after_type)
- {
- push @arg_types, 'param';
- $after_type = 0;
- }
- elsif ($item =~ /^([$in_type_delimiter_quoted])/)
- {
- push @arg_types, 'delimiter';
- }
- else
- {
- push @arg_types, 'paramtype';
- $after_type = 1;
- }
- $spaces = ' ' if ($spaces);
- $line .= $spaces . $item;
- push @arguments, $spaces .$item;
- }
- #print STDERR "PARSE_DEF (style $style, category $category, name $name, type $type, class $class, line $line)\n";
- return ($format, $style, $category, $name, $type, $class, $line, \@arguments, \@arg_types);
- }
- sub begin_paragraph($$)
- {
- my $stack = shift;
- my $state = shift;
- my $command = { };
- my $top_format = top_format($stack);
- if (defined($top_format))
- {
- $command = $top_format;
- }
- $command->{'stack_at_beginning'} = [ @{$state->{'command_stack'}} ];
- my $paragraph_or_preformatted = 'paragraph';
- if ($state->{'preformatted'})
- {
- $paragraph_or_preformatted = 'preformatted';
- $state->{'preformatted_context'} = $command;
- }
- else
- {
- $state->{'paragraph_context'} = $command;
- $state->{'paragraph_nr'}++;
- }
- push @$stack, {'format' => $paragraph_or_preformatted, 'text' => '' };
- # FIXME give line, and modify line?
- &$Texi2HTML::Config::begin_paragraph_texi($paragraph_or_preformatted,
- $state->{'paragraph_macros'}, $command, $state, $stack)
- if (defined($Texi2HTML::Config::begin_paragraph_texi));
- # if there are macros which weren't closed when the previous
- # paragraph was closed we reopen them here
- push @$stack, @{$state->{'paragraph_macros'}} if $state->{'paragraph_macros'};
- delete $state->{'paragraph_macros'};
- }
- sub parse_format_command($$)
- {
- my $line = shift;
- my $tag = shift;
- my $command = '';
- my $orig_line = $line;
- # macro_regexp
- if ($line =~ s/^\s*\@([A-Za-z][\w-]*)(\{\})?\s*$//)
- {
- $command = $1;
- $command = $alias{$command} if (exists($alias{$command}));
- }
- return ('', $command) if ($line =~ /^\s*$/);
- chomp $line;
- $line = substitute_text ({'keep_nr' => 1, 'keep_texi' => 1, 'check_item' => $tag}, undef, "parse_format_command", $line);
- return ($line, $command);
- }
- sub parse_enumerate($)
- {
- my $line = shift;
- my $spec;
- if ($line =~ /^\s*(\w)\b/ and ($1 ne '_'))
- {
- $spec = $1;
- $line =~ s/^\s*(\w)\s*//;
- }
- return ($line, $spec);
- }
- sub parse_multitable($$)
- {
- my $line = shift;
- my $line_nr = shift;
- # first find the table width
- my $table_width = 0;
- my $fractions;
- my $elements;
- if ($line =~ s/^\s+\@columnfractions\s+//)
- {
- @$fractions = split /\s+/, $line;
- $table_width = scalar(@$fractions);
- foreach my $fraction (@$fractions)
- {
- unless ($fraction =~ /^(\d*\.\d+)|(\d+)\.?$/)
- {
- line_error (sprintf(__("column fraction not a number: %s"), $fraction), $line_nr);
- }
- }
- }
- else
- {
- my $element;
- my $line_orig = $line;
- while ($line !~ /^\s*$/)
- {
- my $spaces;
- ($element, $line, $spaces) = next_bracketed($line, 'multitable', $line_nr, 1);
- if ($element =~ /^\{/)
- {
- $table_width++;
- $element =~ s/^\{//;
- $element =~ s/\}\s*$//;
- push @$elements, $element;
- }
- else
- {
- line_warn (sprintf(__("ignoring stray text `%s' after \@multitable"), $element), $line_nr);
- }
- }
- }
- return ($table_width, $fractions, $elements);
- }
- sub end_format($$$$$)
- {
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $format = shift;
- my $line_nr = shift;
- #msg_debug ("END FORMAT $format", $line_nr);
- #dump_stack($text, $stack, $state);
- #sleep 1;
- if ($format_type{$format} eq 'menu')
- {
- $state->{$format}--;
- if ($state->{$format} < 0)
- { # FIXME currently happens, see invalid/not_closed_in_menu.texi
- line_error(sprintf(__("Too many %s closed"), $format), $line_nr);
- #print STDERR "Bug, $format counter negative: $state->{$format}\n";
- #dump_stack($text, $stack, $state);
- #exit 1;
- $state->{$format} = 0;
- }
- close_menu_comment($text, $stack, $state, "\@end $format", $line_nr);
- }
- if ($format_type{$format} eq 'list')
- { # those functions return if they detect an inapropriate context
- add_item($text, $stack, $state, $line_nr); # handle lists
- }
- elsif ($format eq 'multitable')
- {
- add_row($text, $stack, $state, $line_nr); # handle multitable
- }
- elsif ($format_type{$format} eq 'table')
- {
- add_term($text, $stack, $state, $line_nr); # handle table
- add_line($text, $stack, $state, $line_nr); # handle table
- }
- #print STDERR "END_FORMAT\n";
- #dump_stack($text, $stack, $state);
- # set to 1 if there is a mismatch between the closed format and format
- # opened before
- my $format_mismatch = 0;
- # set to 1 in normal menu context after an end menu or detailmenu
- my $begin_menu_comment_after_end_format = 0;
-
- my $format_ref = pop @$stack;
-
- ######################### debug
- if (!defined($format_ref->{'text'}))
- {
- push @$stack, $format_ref;
- print STDERR "Bug: text undef in end_format $format\n";
- dump_stack($text, $stack, $state);
- pop @$stack;
- }
- ######################### end debug
-
- if ($region_lines{$format})
- {
- ######################### debug
- if ($format ne $state->{'region_lines'}->{'format'})
- {
- msg_debug ("Bug: mismatched region `$format' ne `$state->{'region_lines'}->{'format'}'");
- }
- ######################### end debug
- $state->{'region_lines'}->{'number'}--;
- if ($state->{'region_lines'}->{'number'} == 0)
- {
- close_region($state);
- }
- }
- if ($format_type{$format} eq 'table' or $format_type{$format} eq 'list' or $format eq 'multitable')
- {
- if ($format_ref->{'format'} ne $format)
- { # for example vtable closing a table. Cannot be known
- # before if in a cell
- $format_mismatch = 1;
- line_error (sprintf(__("`\@end' expected `%s', but saw `%s'"), $format_ref->{'format'}, $format), $line_nr);
-
- }
- if (!$format_ref->{'empty_first'} and $format_ref->{'item_nr'} == 0)
- {
- line_warn (sprintf(__("\@%s has text but no \@item"),$format_ref->{'format'}), $line_nr);
- }
- }
- if (defined($Texi2HTML::Config::def_map{$format}))
- {
- close_stack($text, $stack, $state, $line_nr, 'deff_item')
- unless ($format_ref->{'format'} eq 'deff_item');
- add_prev($text, $stack, &$Texi2HTML::Config::def_item($format_ref->{'text'}, $format_ref->{'only_inter_commands'}, $format_ref->{'orig_command'}));
- $format_ref = pop @$stack; # pop deff
- ######################################### debug
- if (!defined($format_ref->{'format'}) or !defined($Texi2HTML::Config::def_map{$format_ref->{'format'}}))
- {
- print STDERR "Bug: not a def* under deff_item\n";
- push (@$stack, $format_ref);
- dump_stack($text, $stack, $state);
- pop @$stack;
- }
- ######################################### end debug
- elsif ($format_ref->{'format'} ne $format)
- {
- $format_mismatch = 1;
- line_error (sprintf(__("`\@end' expected `%s', but saw `%s'"), $format_ref->{'format'}, $format), $line_nr);
- }
- add_prev($text, $stack, &$Texi2HTML::Config::def($format_ref->{'text'}, $format_ref->{'orig_format'}));
- }
- elsif ($format eq 'float')
- {
- unless (defined($state->{'float'}))
- {
- msg_debug("state->{'float'} not defined in float", $line_nr);
- next;
- }
- my ($caption_lines, $shortcaption_lines) = &$Texi2HTML::Config::caption_shortcaption($state->{'float'});
- my ($caption_text, $shortcaption_text);
- my $caption_state = duplicate_formatting_state($state);
- push @{$caption_state->{'command_stack'}}, 'caption';
- $caption_text = substitute_text($caption_state, undef, '@caption in @end float', @$caption_lines) if (defined($caption_lines));
- my $shortcaption_state = duplicate_formatting_state($state);
- push @{$shortcaption_state->{'command_stack'}}, 'shortcaption';
- $shortcaption_text = substitute_text($shortcaption_state, undef, '@shortcaption in @end float', @$shortcaption_lines) if (defined($shortcaption_lines));
- add_prev($text, $stack, &$Texi2HTML::Config::float($format_ref->{'text'}, $state->{'float'}, $caption_text, $shortcaption_text));
- delete $state->{'float'};
- }
- # FIXME $complex_format_map obsoleted in nov 2009
- elsif ((exists ($Texi2HTML::Config::complex_format_map->{$format})
- or exists ($Texi2HTML::Config::complex_format_map{$format}))
- and ($format_type{$format} ne 'menu' or get_conf('SIMPLE_MENU')))
- {
- $state->{'preformatted'}--;
- pop @{$state->{'preformatted_stack'}};
- my $complex_format;
- if (exists ($Texi2HTML::Config::complex_format_map->{$format}))
- {
- $complex_format = $Texi2HTML::Config::complex_format_map->{$format};
- }
- else
- {
- $complex_format = $Texi2HTML::Config::complex_format_map{$format};
- }
- # debug
- if (!defined($complex_format->{'begin'}))
- {
- msg_debug ("Bug undef $format_ref->{'format'}" . "->{'begin'} (for $format...)", $line_nr);
- dump_stack ($text, $stack, $state);
- }
- if ($fake_format{$format_ref->{'format'}} and $format_ref->{'text'} =~ /^\s*$/)
- {
- # discard empty fake formats
- }
- #print STDERR "before $format\n";
- #dump_stack ($text, $stack, $state);
- else
- {
- add_prev($text, $stack, &$Texi2HTML::Config::complex_format($format_ref->{'format'}, $format_ref->{'text'}));
- }
- #print STDERR "after $format\n";
- #dump_stack ($text, $stack, $state);
- }
- elsif ($format_type{$format} eq 'table' or $format_type{$format} eq 'list' or $format eq 'multitable')
- {
- if (exists ($Texi2HTML::Config::format_map{$format}))
- { # table or list has a simple format
- add_prev($text, $stack, end_simple_format($format_ref->{'format'}, $format_ref->{'text'}, $state));
- }
- else
- { # table or list handler defined by the user
- add_prev($text, $stack, &$Texi2HTML::Config::table_list($format_ref->{'format'}, $format_ref->{'text'}, $format_ref->{'command'}, $format_ref->{'formatted_command'}, $format_ref->{'item_nr'}, $format_ref->{'spec'}, $format_ref->{'prepended'}, $format_ref->{'prepended_formatted'}, $format_ref->{'columnfractions'}, $format_ref->{'prototype_row'}, $format_ref->{'prototype_lengths'}, $format_ref->{'max_columns'}));
- }
- }
- elsif ($format_type{$format} eq 'quotation')
- {
- my $quotation_args = pop @{$state->{'quotation_stack'}};
- #add_prev($text, $stack, &$Texi2HTML::Config::quotation($format, $format_ref->{'text'}, $quotation_args->{'text'}, $quotation_args->{'text_texi'}));
- add_prev($text, $stack, &$Texi2HTML::Config::quotation($format, $format_ref->{'text'}, $format_ref->{'argument_text'}, $format_ref->{'argument_texi'}, $format_ref->{'quote_authors'}));
- }
- elsif ($Texi2HTML::Config::paragraph_style{$format})
- {
- if ($state->{'paragraph_style'}->[-1] eq $format)
- {
- pop @{$state->{'paragraph_style'}};
- }
- if ($fake_format{$format_ref->{'format'}} and $format_ref->{'text'} =~ /^\s*$/)
- {
- # discard empty fake formats
- }
- else
- {
- add_prev($text, $stack, &$Texi2HTML::Config::paragraph_style_command($format_ref->{'format'},$format_ref->{'text'}));
- }
- }
- elsif (exists($Texi2HTML::Config::format_map{$format}))
- {
- if ($fake_format{$format_ref->{'format'}} and $format_ref->{'text'} =~ /^\s*$/)
- {
- # discard empty fake formats
- }
- else
- {
- add_prev($text, $stack, end_simple_format($format_ref->{'format'}, $format_ref->{'text'}, $state));
- }
- }
- elsif ($format_type{$format} eq 'cartouche')
- {
- add_prev($text, $stack, &$Texi2HTML::Config::cartouche($format_ref->{'text'},$state->{'command_stack'}));
- }
- elsif ($format_type{$format} eq 'menu')
- {
- # it should be short-circuited if SIMPLE_MENU
- if ($state->{'preformatted'})
- {
- # remove the fake complex style
- $state->{'preformatted'}--;
- pop @{$state->{'preformatted_stack'}};
- }
-
- # backward compatibility with 1.78 jun 2007
- if (defined($Texi2HTML::Config::menu))
- {
- if ($format eq 'menu')
- {
- add_prev($text, $stack, &$Texi2HTML::Config::menu($format_ref->{'text'}));
- }
- elsif ($format eq 'detailmenu') # detailmenu
- {
- add_prev($text, $stack, $format_ref->{'text'});
- }
- else # direntry
- {
- }
- }
- else
- {
- add_prev($text, $stack, &$Texi2HTML::Config::menu_command($format, $format_ref->{'text'}, $state->{'preformatted'}));
- }
- $begin_menu_comment_after_end_format = 1;
- }
- else
- {
- line_warn(sprintf(__("Unknown format %s"), $format), $line_nr);
- }
-
- # fake formats are not on the command_stack
- return 1 if ($fake_format{$format_ref->{'format'}});
- # special case for center as it is at the bottom of the stack
- my $removed_from_stack;
- if ($format eq 'center')
- {
- $removed_from_stack = shift @{$state->{'command_stack'}};
- }
- else
- {
- $removed_from_stack = pop @{$state->{'command_stack'}};
- }
- if ($removed_from_stack ne $format and !$format_mismatch)
- {
- #line_error ("Bug: removed_from_stack $removed_from_stack ne format $format", $line_nr);
- # it may not be a bug. Consider, for example a @code{in code
- # @end cartouche
- # The @code is closed when the paragraph is closed by
- # @end cartouche but not really closed since it might have been
- # a multiple paragraph @code. So it is not removed from
- # command_stack but still have disapeared from the stack!
- line_error(sprintf(__("mismatched \@end %s with \@%s"), $format, $removed_from_stack), $line_nr);
- }
- if ($begin_menu_comment_after_end_format and $state->{'menu'})
- {
- begin_format($text, $stack, $state, 'menu_comment', '', $line_nr);
- return 0;
- }
- return 1;
- }
- sub push_complex_format_style($$$$)
- {
- my $command = shift;
- my $complex_format = shift;
- my $state = shift;
- my $line_nr = shift;
- my $class = $command;
- if (!defined($state->{'preformatted_stack'}))
- {
- msg_debug ("'preformatted_stack' not defined in push_complex_format_style", $line_nr);
- }
- $class = $complex_format->{'class'} if (defined($complex_format->{'class'}));
- my $format_style = {'pre_style' =>$complex_format->{'pre_style'}, 'class' => $class, 'command' => $command };
- if (defined($complex_format->{'style'}))
- {
- $format_style->{'style'} = $complex_format->{'style'};
- }
- else
- {
- if ($state->{'preformatted'} and defined($state->{'preformatted_stack'}->[-1]->{'style'}))
- {
- $format_style->{'style'} = $state->{'preformatted_stack'}->[-1]->{'style'};
- }
- my $index = scalar(@{$state->{'preformatted_stack'}}) -1;
- # since preformatted styles are not nested, the preformatted format
- # of the first format with style has to be used
- if ($index > 0)
- {
- while ($index)
- {
- if ($state->{'preformatted_stack'}->[$index]->{'style'})
- {
- $format_style->{'class'} = $state->{'preformatted_stack'}->[$index]->{'class'} if (defined($state->{'preformatted_stack'}->[$index]->{'class'}));
- last;
- }
- $index--;
- }
- }
- }
- $state->{'preformatted'}++;
- push @{$state->{'preformatted_stack'}}, $format_style;
- }
- sub prepare_state_multiple_pass($$)
- {
- my $command = shift;
- my $state = shift;
- my $return_state = {
- 'multiple_pass' => 1,
- 'element' => $state->{'element'},
- 'outside_document' => $state->{'outside_document'},
- 'new_state' => 1
- };
- if (defined($command))
- {
- $return_state->{'expansion'} = $command;
- $return_state->{'command_stack'} = ["$command"];
- }
- else
- {
- msg_debug("prepare_state_multiple_pass command not defined");
- }
- return $return_state;
- }
- sub begin_format($$$$$$);
- sub begin_format($$$$$$)
- {
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $macro = shift;
- my $line = shift;
- my $line_nr = shift;
- #msg_debug ("BEGIN FORMAT $macro",$line_nr);
- my $in_term;
- my $top_format = top_stack($stack, 2);
- $in_term = 1 if (defined($top_format->{'format'}) and $top_format->{'format'} eq 'term');
- if ($format_type{$macro} eq 'menu')
- {
- if ($state->{'menu'})
- {
- # there should not be any paragraph/preformatted to close
- # if the comment or the description were closed since they
- # close it
- if (! close_menu_comment($text, $stack, $state, "\@$macro", $line_nr)
- and !close_menu_description($text, $stack, $state, "\@$macro", $line_nr))
- {
- close_paragraph($text, $stack, $state, "\@$macro", $line_nr);
- }
- }
- else
- {
- close_paragraph($text, $stack, $state, "\@$macro", $line_nr);
- }
- $state->{$macro}++;
- }
- elsif (!$in_term)
- {
- close_paragraph($text, $stack, $state, "\@$macro", $line_nr);
- }
- # close def_item if this is a matching @def*x command
- if (defined($Texi2HTML::Config::def_map{$macro}))
- {
- my $top_format = top_format($stack);
- if (defined($top_format) and ("$top_format->{'format'}x" eq $macro))
- {
- # this is a matching @DEFx command.
- my $deff_item = pop @$stack;
- add_prev($text, $stack,
- &$Texi2HTML::Config::def_item($deff_item->{'text'}, $deff_item->{'only_inter_commands'}, $deff_item->{'orig_command'}));
- #print STDERR "DEFx $macro\n";
- }
- elsif ($macro =~ /x$/)
- {
- my $base_def_command = $macro;
- $base_def_command =~ s/x$//;
- line_error(sprintf(__("Must be in `\@%s' environment to use `\@%s'"), $base_def_command, $macro), $line_nr);
- }
- }
- $line = &$Texi2HTML::Config::begin_format_texi($macro, $line, $state)
- unless($fake_format{$macro});
- push (@{$state->{'command_stack'}}, $macro) unless ($fake_format{$macro});
- if ($region_lines{$macro})
- {
- open_region($macro,$state);
- }
- # A deff like macro
- if (defined($Texi2HTML::Config::def_map{$macro}))
- {
- my $top_format = top_format($stack);
- my $orig_command = $macro;
- if (defined($top_format) and ("$top_format->{'format'}x" eq $macro))
- {
- # this is a matching @DEFx command.
- # the @DEFx macro has been put at the top of the
- # command_stack, although there is no real format opening
- pop @{$state->{'command_stack'}};
- $macro =~ s/x$//o;
- #print STDERR "DEFx $macro\n";
- }
- else
- {
- # a new @def.
- $macro =~ s/x$//o;
- # we remove what is on the stack and put it back,
- # to make sure that it is the form without x.
- pop @{$state->{'command_stack'}};
- push @{$state->{'command_stack'}}, $macro;
- #print STDERR "DEF begin $macro\n";
- $top_format = { 'format' => $macro, 'text' => '', 'orig_format' =>$orig_command};
- push @$stack, $top_format;
- }
- #print STDERR "BEGIN_DEFF $macro\n";
- #dump_stack ($text, $stack, $state);
-
- my ($command, $style, $category, $name, $type, $class, $args_array, $args_type_array);
- ($command, $style, $category, $name, $type, $class, $line, $args_array, $args_type_array) = parse_def($macro, $line, $line_nr);
- my $class_name_texi = &$Texi2HTML::Config::definition_index_entry($name, $class, $style, $command);
- #print STDERR "AFTER parse_def $line";
- my @formatted_args = ();
- my $arguments = '';
- my %formatted_arguments = ();
- my @types = @$args_type_array;
- my $arg_nr = 0;
- my $previous_type;
- foreach my $arg (@$args_array)
- {
- $arg_nr++;
- my $type = shift @types;
- my $substitution_state = duplicate_formatting_state($state);
- # all @def* arguments are in code_style
- $substitution_state->{'code_style'}++;
- push @formatted_args, substitute_line($arg, sprintf(__("\@%s (argument nr %d)"), $macro, $arg_nr), $substitution_state, $line_nr);
- if (grep {$_ eq $type} ('param', 'paramtype', 'delimiter'))
- {
- $arguments .= $formatted_args[-1];
- }
- else
- {
- $formatted_arguments{$type} = $formatted_args[-1];
- }
- $previous_type = $type;
- }
- $name = $formatted_arguments{'name'};
- $category = $formatted_arguments{'category'};
- $type = $formatted_arguments{'type'};
- $class = $formatted_arguments{'class'};
- $name = '' if (!defined($name));
- $category = '' if (!defined($category));
-
- my $class_category = &$Texi2HTML::Config::definition_category($category, $class, $style, $command);
- my $class_name = &$Texi2HTML::Config::definition_index_entry($name, $class, $style, $command);
- my ($index_entry, $formatted_index_entry, $index_label) = do_index_entry_label($macro, $state, $line_nr, $class_name_texi, $line);
- add_prev($text, $stack, &$Texi2HTML::Config::def_line($class_category, $name, $type, $arguments, $index_label, \@formatted_args, $args_type_array, $args_array, $command, $class_name, $category, $class, $style, $orig_command));
- $line = '';
- push @$stack, { 'format' => 'deff_item', 'text' => '', 'only_inter_commands' => 1, 'format_ref' => $top_format, 'orig_command' => $orig_command};
- begin_paragraph_after_command($state, $stack, $macro, $line);
- }
- # FIXME $complex_format_map obsoleted in nov 2009
- elsif ((exists ($Texi2HTML::Config::complex_format_map->{$macro})
- or exists ($Texi2HTML::Config::complex_format_map{$macro}))
- and ($format_type{$macro} ne 'menu' or get_conf('SIMPLE_MENU')))
- { # handle menu if SIMPLE_MENU. see texi2html.pm
- my $complex_format;
- if (exists ($Texi2HTML::Config::complex_format_map->{$macro}))
- {
- $complex_format = $Texi2HTML::Config::complex_format_map->{$macro};
- }
- else
- {
- $complex_format = $Texi2HTML::Config::complex_format_map{$macro};
- }
- my $format = { 'format' => $macro, 'text' => '', 'pre_style' => $complex_format->{'pre_style'} };
- push_complex_format_style($macro, $complex_format, $state, $line_nr);
- push @$stack, $format;
- begin_paragraph($stack, $state);
- }
- elsif ($Texi2HTML::Config::paragraph_style{$macro})
- {
-
- push (@$stack, { 'format' => $macro, 'text' => '' });
- begin_paragraph_after_command($state,$stack,$macro,$line) unless ($in_term);
- push @{$state->{'paragraph_style'}}, $macro;
- if ($macro eq 'center')
- {
- # @center may be in a weird state with regard with
- # nesting, so we put it on the bottom of the stack
- pop @{$state->{'command_stack'}};
- unshift @{$state->{'command_stack'}}, $macro;
- # for similar reasons, we may have a bad stack nesting
- # which results in } after a closing.
- # The following isn't really true anymore, I think: for example
- # @center @samp{something @center end of samp}
- # resulted to samp being kept in the 'command_stack'
- }
- }
- elsif ($format_type{$macro} eq 'list' or $format_type{$macro} eq 'table' or $macro eq 'multitable')
- {
- my $format;
- #print STDERR "LIST_TABLE $macro\n";
- #dump_stack($text, $stack, $state);
- if ($macro eq 'itemize' or $format_type{$macro} eq 'table')
- {
- my $command;
- my $prepended;
- ($prepended, $command) = parse_format_command($line,$macro);
- if (($command eq '') and ($macro ne 'itemize'))
- {
- $command = 'asis';
- line_error(sprintf(__("%s requires an argument: the formatter for %citem"), $macro, ord('@')), $line_nr);
- }
- my $prepended_formatted;
- $prepended_formatted = substitute_line($prepended, sprintf(__("prepended for \@%s"), $macro), prepare_state_multiple_pass('item', $state)) if (defined($prepended));
- $format = { 'format' => $macro, 'text' => '', 'command' => $command, 'prepended' => $prepended, 'prepended_formatted' => $prepended_formatted };
- $line = '';
- }
- elsif ($macro eq 'enumerate')
- {
- my $spec;
- ($line, $spec) = parse_enumerate ($line);
- $spec = 1 if (!defined($spec));
- $format = { 'format' => $macro, 'text' => '', 'spec' => $spec };
- }
- elsif ($macro eq 'multitable')
- {
- my ($max_columns, $fractions, $prototype_row) = parse_multitable ($line, $line_nr);
- if (!$max_columns)
- {
- line_warn (__("empty multitable"), $line_nr);
- $max_columns = 0;
- }
- my @prototype_lengths = ();
- if (defined($prototype_row))
- {
- my $prototype_nr = 0;
- foreach my $prototype (@$prototype_row)
- {
- $prototype_nr++;
- push @prototype_lengths, 2+Texi2HTML::Config::t2h_default_string_width(substitute_line($prototype, sprintf(__("\@columnfraction (argument nr %d)"), $prototype_nr), prepare_state_multiple_pass('columnfractions', $state)));
- }
- }
- $format = { 'format' => $macro, 'text' => '', 'max_columns' => $max_columns, 'columnfractions' => $fractions, 'prototype_row' => $prototype_row, 'prototype_lengths' => \@prototype_lengths, 'cell' => 1 };
- }
- $format->{'first'} = 1;
- $format->{'item_nr'} = 0;
- $format->{'paragraph_number'} = 0;
- push @$stack, $format;
- if ($format_type{$macro} eq 'table')
- {
- push @$stack, { 'format' => 'line', 'text' => '', 'format_ref' => $format, 'only_inter_commands' => 1};
- }
- elsif ($macro eq 'multitable')
- {
- push @$stack, { 'format' => 'row', 'text' => '', 'format_ref' => $format, 'item_cmd' => $macro };
- push @$stack, { 'format' => 'cell', 'text' => '', 'format_ref' => $format, 'only_inter_commands' => 1};
- }
- if ($format_type{$macro} eq 'list')
- {
- push @$stack, { 'format' => 'item', 'text' => '', 'format_ref' => $format, 'only_inter_commands' => 1};
- }
- begin_paragraph_after_command($state,$stack,$macro,$line)
- if ($macro ne 'multitable');
- return '' unless ($macro eq 'enumerate');
- }
- elsif ($macro eq 'float' or $format_type{$macro} eq 'quotation')
- {
- push @$stack, {'format' => $macro, 'text' => '' };
- if ($macro eq 'float')
- {
-
- my @args = parse_line_arguments($line, 2, "\@$macro");
- do_float_line ($macro, \@args, $state->{'style_stack'}, $state, $line_nr);
- }
- elsif ($format_type{$macro} eq 'quotation')
- {
- my @args = parse_line_arguments($line, 1, "\@$macro", $line_nr);
- do_quotation_line ($macro, $stack->[-1], \@args, $state->{'style_stack'}, $state, $line_nr);
-
- }
- $line = '';
- if ($state->{'preformatted'})
- { # inconditionally begin a preformatted section if needed
- begin_paragraph($stack, $state);
- }
- #dump_stack($text, $stack, $state);
- }
- # keep this one at the end as there are some other formats
- # which are also in format_map
- elsif (defined($Texi2HTML::Config::format_map{$macro}) or ($format_type{$macro} eq 'cartouche'))
- {
- push @$stack, { 'format' => $macro, 'text' => '' };
- $state->{'code_style'}++ if ($Texi2HTML::Config::format_code_style{$macro});
- begin_paragraph_after_command($state,$stack,$macro,$line);
- }
- elsif ($format_type{$macro} eq 'menu')
- {
- # if SIMPLE_MENU we won't get there
- # as the menu is a complex format in that case, so it
- # is handled above
- push @$stack, { 'format' => $macro, 'text' => '' };
- if ($state->{'preformatted'})
- {
- # add a fake complex style in order to have a given pre style
- push_complex_format_style('menu',
- $Texi2HTML::Config::MENU_PRE_COMPLEX_FORMAT, $state, $line_nr);
- begin_paragraph_after_command($state,$stack,$macro,$line);
- }
- else
- {
- begin_format($text, $stack, $state, 'menu_comment', $line, $line_nr);
- }
- }
- # this is useful for @center, and also if there was something on the
- # line after a format that isn't there anymore, like
- # @format @c
- # if @center line is empty we don't remove the end of line
- $line =~ s/^\s*// unless ($macro eq 'center' and $line =~ /^\s*$/);
- return $line;
- }
- sub do_text($;$)
- {
- my $text = shift;
- my $state = shift;
- return $text if ($state->{'keep_texi'});
- my $remove_texi = 1 if ($state->{'remove_texi'} and !$state->{'simple_format'});
- my $preformatted_style = 0;
- if ($state->{'preformatted'})
- {
- $preformatted_style = $state->{'preformatted_stack'}->[-1]->{'style'};
- }
- # disabled since it is too expensive (because do_text is
- # called often) for a warning which rather questionable anyway.
- #if (Texi2HTML::Config::in_cmd($state->{'command_stack'}, 'var') and $text =~ /([$Texi2HTML::Config::warn_var_character_quoted])/)
- #{
- # line_warn (sprintf(__("unlikely character %c in \@var"), ord($1)), $Texi2HTML::THISDOC{'line_nr'});
- #}
- return (&$Texi2HTML::Config::normal_text($text, $remove_texi, $preformatted_style, $state->{'code_style'}, $state->{'math_style'}, $state->{'simple_format'},$state->{'command_stack'}, $state));
- }
- sub end_simple_format($$$)
- {
- my $command = shift;
- my $text = shift;
- my $state = shift;
- my $element = $Texi2HTML::Config::format_map{$command};
- my $result = &$Texi2HTML::Config::format($command, $element, $text);
- $state->{'code_style'}-- if ($Texi2HTML::Config::format_code_style{$command});
- return $result;
- }
- # only get there if not in SIMPLE_MENU and not in preformatted and
- # right in @menu
- sub close_menu_comment($$$$$)
- {
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $reason = shift;
- my $line_nr = shift;
-
- my $top_format = top_stack($stack,2);
- if (defined($top_format->{'format'}) and $top_format->{'format'} eq 'menu_comment')
- { # this is needed to avoid empty menu-comments <tr>...<pre></pre>
- abort_empty_preformatted($stack, $state);
- close_paragraph($text, $stack, $state, $reason, $line_nr);
- end_format($text, $stack, $state, 'menu_comment', $line_nr);
- return 1;
- }
- }
- # never get there if in SIMPLE_MENU
- # the last arg is used only if in description and an empty line may
- # stop it and begin a menu_comment
- sub close_menu_description($$$$$;$)
- {
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $reason = shift;
- my $line_nr = shift;
- my $line = shift;
- my $top_format = top_stack($stack,1);
- if (!$state->{'preformatted'})
- {
- $top_format = top_stack($stack);
- }
- if (defined($top_format->{'format'}) and $top_format->{'format'} eq 'menu_description' and (!defined($line) or $line =~ /^\s*$/) )
- {
- close_paragraph($text, $stack, $state, $reason, $line_nr) if ($state->{'preformatted'});
- my $descr = pop(@$stack);
- add_prev($text, $stack, do_menu_description($descr, $state));
- print STDERR "# close_menu: close description\n" if ($T2H_DEBUG & $DEBUG_MENU);
- $state->{'code_style'}-- if ($Texi2HTML::Config::format_code_style{'menu_description'});
- return 1;
- }
- }
- # Format menu link
- # FIXME also pass node and name?
- sub do_menu_link($$$)
- {
- my $state = shift;
- my $line_nr = shift;
- my $menu_entry = shift;
- my $file = $state->{'element'}->{'file'};
- my $node_name = normalise_node($menu_entry->{'node'});
- # normalise_node is used in fact to determine if name is empty.
- # It is not passed down to the function reference.
- my $name = normalise_node($menu_entry->{'name'});
- # there is one substitution with spaces kept, and one with spaces
- # normalized. In every cases nodes are in code_style
- my $node_substitution_state = duplicate_formatting_state($state);
- my $name_substitution_state = duplicate_formatting_state($state);
- my $node_normalized_substitution_state = duplicate_formatting_state($state);
- $node_substitution_state->{'code_style'} = 1;
- $node_normalized_substitution_state->{'code_style'} = 1;
- $name_substitution_state->{'code_style'} = 1 if ($Texi2HTML::Config::format_code_style{'menu_name'});
- my $node_formatted = substitute_line($menu_entry->{'node'}, __("node name in menu"), $node_substitution_state, $line_nr);
- my $node_normalized_formatted = substitute_line($node_name, __("normalized node name in menu"), $node_normalized_substitution_state);
- my $name_formatted;
- my $has_name = 0;
- if (defined($name) and $name ne '')
- {
- $name_formatted = substitute_line($menu_entry->{'name'}, __("menu entry name"), $name_substitution_state, $line_nr);
- $has_name = 1;
- }
- else
- {
- my $node_as_name = $menu_entry->{'node'};
- $node_as_name =~ s/^\s*//;
- $name_formatted = substitute_line($node_as_name, __("node name in menu"), $name_substitution_state);
- }
- my $entry = '';
- my $href;
- my $element;
- if ($state->{'direntry'})
- {
- $href = do_external_href($node_name);
- }
- else
- {
- $element = $nodes{$node_name};
- }
- # menu points to an unknown node
- if (defined($element) and !$element->{'seen'})
- {
- if ($menu_entry->{'node'} =~ /^\s*\(.*\)/o or Texi2HTML::Config::get_conf('novalidate'))
- {
- # menu entry points to another info manual or invalid nodes
- # and novalidate is set
- #$href = $nodes{$node_name}->{'file'};
- $href = do_external_href($node_name);
- }
- else
- {
- line_error (sprintf(__("Menu reference to nonexistent node `%s'"), $node_name), $line_nr);
- # try to find an equivalent node
- my $node_seen = find_equivalent_node($node_name);
- if (defined($node_seen))
- {
- document_warn("---> but equivalent node `$node_seen' found");
- $element = $nodes{$node_seen};
- }
- }
- }
- # the original node or an equivalent node was seen
- if (defined($element) and $element->{'seen'})
- {
- if ($element->{'reference_element'})
- {
- $element = $element->{'reference_element'};
- }
-
- #print STDERR "SUBHREF in menu for `$element->{'texi'}'\n";
- $href = href($element, $file, $line_nr);
- if (! $element->{'node'})
- {
- $entry = $element->{'text'}; # this is the section/node name
- $entry = "$Texi2HTML::Config::MENU_SYMBOL $entry" if (($entry ne '') and (!defined($element->{'number'}) or ($element->{'number'} =~ /^\s*$/)) and $Texi2HTML::Config::UNNUMBERED_SYMBOL_IN_MENU);
- }
- }
- # save the element used for the href for the description
- $menu_entry->{'menu_reference_element'} = $element;
- return &$Texi2HTML::Config::menu_link($entry, $state, $href, $node_formatted, $name_formatted, $menu_entry->{'ending'}, $has_name, $state->{'command_stack'}, $state->{'preformatted'}, $node_normalized_formatted);
- }
- sub do_menu_description($$)
- {
- my $descr = shift;
- my $state = shift;
- my $text = $descr->{'text'};
- my $menu_entry = $descr->{'menu_entry'};
- my $element = $menu_entry->{'menu_reference_element'};
-
- ############# debug
- # this is not a bug if element is not defined in direntry
- print STDERR "Bug: !defined(element) in do_menu_description\n" if (!defined($element) and ($state->{'menu'} or $state->{'detailmenu'}));
- ############# end debug
- my $element_text = '';
- $element_text = $element->{'text_nonumber'} if (defined($element));
- return &$Texi2HTML::Config::menu_description($text, duplicate_formatting_state($state),$element_text, $state->{'command_stack'}, $state->{'preformatted'});
- }
- sub do_xref($$$$)
- {
- my $macro = shift;
- my $args = shift;
- my $style_stack = shift;
- my $state = shift;
- my $line_nr = shift;
- my $result = '';
- my @args = @$args;
- my $j;
- for ($j = 0; $j <= $#$args; $j++)
- {
- $args[$j] = normalise_texi_space($args[$j]);
- # print STDERR " ($j)$args[$j]\n";
- }
- #print STDERR "DO_XREF: $macro\n";
- if ($macro eq 'inforef')
- {
- if ((@args < 1) or $args[0] eq '')
- {
- line_error (sprintf(__("First argument to \@%s may not be empty"), $macro), $line_nr);
- return '';
- }
- }
- my $node_texi = $args[0];
- $node_texi = normalise_node($node_texi);
-
- #print STDERR "XREF: (@args)\n";
- my $i;
- my $new_state = duplicate_formatting_state($state);
- $new_state->{'keep_texi'} = 0;
- $new_state->{'keep_nr'} = 0;
- my $remove_texi = $new_state->{'remove_texi'};
- my @formatted_args;
- for ($i = 0; $i < 5; $i++)
- {
- $args[$i] = '' if (!defined($args[$i]));
- my $in_file_style;
- $in_file_style = 1 if ($i == 2 and $macro eq 'inforef' or $i == 3 and $macro ne 'inforef');
- $new_state->{'code_style'}++ if ($in_file_style or $i == 0);
- $new_state->{'remove_texi'} = 1 if ($in_file_style);
- $formatted_args[$i] = substitute_line($args[$i], sprintf(__("\@%s (argument nr %d)"), $macro, $i), $new_state, $line_nr);
- $new_state->{'code_style'}-- if ($in_file_style or $i == 0);
- $new_state->{'remove_texi'} = $remove_texi if ($in_file_style);
- }
- my ($file_texi, $file);
- if ($macro eq 'inforef')
- {
- $file_texi = $args[2];
- $file = $formatted_args[2];
- }
- else
- {
- $file_texi = $args[3];
- $file = $formatted_args[3];
- }
- # Remark: makeinfo has this odd error message if the file is empty:
- # warning (_("Empty file name for HTML cross reference in `%s'")
- # This seems to be spurious.
-
- # can be an argument or extracted from the node name
- my $file_arg_or_node_texi = $file_texi;
- my $file_arg_or_node = $file;
- my $node_name;
- # the file in parenthesis is removed from node_without_file_texi if needed
- my $node_without_file_texi = $node_texi;
- # node with file, like (file)node
- my $node_and_file_texi;
- # the file in parenthesis present with the node
- my ($file_of_node_texi, $file_of_node);
- if ($node_without_file_texi =~ s/^\(([^\)]+)\)\s*//)
- {
- $file_of_node_texi = $1;
- $file_of_node = substitute_line($file_of_node_texi, sprintf(__p("\@*ref", "\@%s node file"), $macro), $new_state);
- $node_name = substitute_line($node_without_file_texi, sprintf(__p("\@*ref", "\@%s node name"), $macro), $new_state);
- $file_arg_or_node_texi = $file_of_node_texi if ($file_arg_or_node_texi eq '');
- $file_arg_or_node = $file_of_node if ($file_arg_or_node eq '');
- # the file argument takes precedence
- $node_and_file_texi = "($file_arg_or_node_texi)$node_without_file_texi";
- }
- else
- {
- # normalized node name
- $new_state->{'code_style'}++;
- $node_name = substitute_line($node_without_file_texi, sprintf(__p("\@*ref", "\@%s node name"), $macro), $new_state);
- $new_state->{'code_style'}--;
- if (defined ($file_texi) and $file_texi ne '')
- {
- $node_and_file_texi = "($file_texi)$node_texi";
- }
- }
- my $node_and_file;
- if (defined($node_and_file_texi))
- {
- $node_and_file = substitute_line($node_and_file_texi, sprintf(__p("\@*ref","\@%s node with file name"), $macro), $new_state);
- }
- else
- {
- $node_and_file_texi = $node_texi;
- $node_and_file = $node_name;
- }
- my $cross_ref_texi = $args[1];
- my $cross_ref = $formatted_args[1];
-
- my ($manual_texi, $section_texi, $manual, $section);
- if ($macro ne 'inforef')
- {
- $manual_texi = $args[4];
- $section_texi = $args[2];
- $manual = $formatted_args[4];
- $section = $formatted_args[2];
- }
- else
- {
- $manual = $section = '';
- }
-
- #print STDERR "XREF: (@args)\n";
-
- if (($macro eq 'inforef') or ($file_arg_or_node_texi ne '') or ($manual_texi ne ''))
- {# external ref
- my $href = '';
- if ($file_arg_or_node_texi ne '')
- {
- $href = do_external_href($node_and_file_texi);
- }
- else
- {
- $node_and_file = '';
- }
- #$result = &$Texi2HTML::Config::external_ref($macro, $section_or_node, $manual, $node_and_file, $href, $cross_ref, \@args, \@formatted_args);
- $result = &$Texi2HTML::Config::external_ref($macro, $section, $manual, $file_arg_or_node, $href, $cross_ref, \@args, \@formatted_args, $node_name);
- }
- else
- {
- my $element = $nodes{$node_without_file_texi};
- if ($element and $element->{'seen'})
- {
- if ($element->{'reference_element'})
- {
- $element = $element->{'reference_element'};
- }
- my $file = '';
- if (defined($state->{'element'}))
- {
- $file = $state->{'element'}->{'file'};
- }
- else
- {
- line_warn (sprintf(__("\@%s not in text (in anchor, node, section...)"), $macro), $line_nr);
- # if SPLIT the file is '' which ensures
- # a href with the file name. if ! SPLIT
- # the 2 file will be the same thus there won't be the file name
- $file = $element->{'file'} unless (get_conf('SPLIT'));
- }
- #print STDERR "SUBHREF in ref to node `$node_texi'";
- my $href = href($element, $file, $line_nr);
- my $section_or_cross_ref = $section;
- $section_or_cross_ref = $cross_ref if ($section eq '');
- if ($element->{'float'} and $section_or_cross_ref eq '')
- {
- my $style = substitute_line(&$Texi2HTML::Config::listoffloats_float_style($element->{'style_texi'}, $element), __("\@listoffloats \@float type"));
- $section_or_cross_ref = $style if (defined($style));
- }
- my $name = $section_or_cross_ref;
- my $short_name = $section_or_cross_ref;
- if ($section_or_cross_ref eq '')
- {
- # FIXME maybe one should use 'text' instead of 'text_nonumber'
- # However the real fix would be to have an internal_ref call
- # with more informations
- $name = $element->{'text_nonumber'};
- $short_name = $node_name;
- }
- $result = &$Texi2HTML::Config::internal_ref ($macro, $href, $short_name, $name, $element->{'section'}, \@args, \@formatted_args, $element);
- }
- else
- {
- if (($node_texi eq '') or (! Texi2HTML::Config::get_conf('novalidate')))
- {
- line_error (sprintf(__("\@%s reference to nonexistent node `%s'"), $macro, $node_texi), $line_nr);
- my $text = '';
- for (my $i = 0; $i < @$args -1; $i++)
- {
- $text .= $args->[$i] .',';
- }
- $text .= $args->[-1];
- $result = "\@$macro"."{${text}}";
- }
- else
- {
- #$result = &$Texi2HTML::Config::external_ref($macro, '', '', $node_name, do_external_href($node_texi), $cross_ref, \@args, \@formatted_args);
- $result = &$Texi2HTML::Config::external_ref($macro, '', '', '', do_external_href($node_texi), $cross_ref, \@args, \@formatted_args, $node_name);
- }
- }
- }
- return $result;
- }
- sub do_acronym_like($$$$$)
- {
- my $command = shift;
- my $args = shift;
- my $acronym_texi = shift @$args;
- my $explanation = shift @$args;
- my $style_stack = shift;
- my $state = shift;
- my $line_nr = shift;
- my $explanation_lines;
- my $explanation_text;
- my $explanation_simple_format;
- if (defined($explanation))
- {
- $explanation = trim_around_spaces($explanation);
- $explanation = undef if ($explanation eq '');
- }
- $acronym_texi = trim_around_spaces($acronym_texi);
-
- return '' if ($acronym_texi eq '');
-
- my $with_explanation = 0;
- my $normalized_text = cross_manual_line(normalise_node($acronym_texi));
- if (defined($explanation))
- {
- $with_explanation = 1;
- $acronyms_like{$command}->{$normalized_text} = $explanation;
- }
- elsif (exists($acronyms_like{$command}->{$normalized_text}))
- {
- $explanation = $acronyms_like{$command}->{$normalized_text};
- }
- if (defined($explanation))
- {
- @$explanation_lines = map {$_ = $_."\n"} split (/\n/, $explanation);
- my $text = '';
- foreach my $line(@$explanation_lines)
- {
- $line .= ' ' if (chomp ($line));
- $text .= $line
- }
- $text =~ s/ $//;
- $explanation_simple_format = simple_format($state, [ $line_nr ], "simple_format \@$command explanation", $text);
- $explanation_text = substitute_line($text, sprintf(__p("\@abbr or \@acronym", "\@%s explanation"), $command), duplicate_formatting_state($state), $line_nr);
- }
- return &$Texi2HTML::Config::acronym_like($command, $acronym_texi, substitute_line($acronym_texi, "\@$command", duplicate_formatting_state($state), $line_nr),
- $with_explanation, $explanation_lines, $explanation_text, $explanation_simple_format);
- }
- sub do_caption_shortcaption($$$$$$)
- {
- my $command = shift;
- my $args = shift;
- my $text_texi = $args->[0];
- my $style_stack = shift;
- my $state = shift;
- my $line_nr = shift;
- my $kept_line_nrs = shift;
- if (!exists($state->{'float'}))
- {
- line_error(sprintf(__("\@%s not meaningful outside `\@float' environment"), $command), $line_nr);
- return '';
- }
- my $float = $state->{'float'};
- my @texi_lines = map {$_ = $_."\n"} split (/\n/, $text_texi);
- $float->{"${command}_texi"} = \@texi_lines;
- if (defined($kept_line_nrs))
- {
- $float->{"${command}_keep_line_nr"} = [ @$kept_line_nrs ];
- msg_debug ("Empty $kept_line_nrs", $line_nr) unless (@{$kept_line_nrs});
- }
- else
- {
- $float->{"${command}_keep_line_nr"} = [ $line_nr ];
- msg_debug("do_caption_shortcaption $command, $float, kept_line_nrs not defined", $line_nr);
- }
- #print STDERR "GGGGGGG @$kept_line_nrs\n";
- return &$Texi2HTML::Config::caption_shortcaption_command($command,
- substitute_text(prepare_state_multiple_pass($command, $state), $kept_line_nrs, "\@$command in do_caption_shortcaption", @texi_lines), \@texi_lines, $float);
- }
- # function called when a @float is encountered. Don't do any output
- # but prepare $state->{'float'}
- sub do_float_line($$$$$)
- {
- my $command = shift;
- my $args = shift;
- my $style_stack = shift;
- my $state = shift;
- my $line_nr = shift;
- my @args = @$args;
- my $style_texi = shift @args;
- my $label_texi = shift @args;
- $style_texi = undef if (defined($style_texi) and $style_texi=~/^\s*$/);
- $label_texi = undef if (defined($label_texi) and $label_texi=~/^\s*$/);
- $style_texi = normalise_texi_space($style_texi) if (defined($style_texi));
- if (defined($label_texi))
- { # the float is considered as a node as it may be a target for refs.
- # it was entered as a node in the pass_structure and the float
- # line was parsed at that time
- $state->{'float'} = $nodes{normalise_node($label_texi)};
- #msg_debug("float: $state->{'float'}, $state->{'float'}->{'texi'}", $line_nr);
- }
- else
- { # a float without label. It can't be the target for refs.
- $state->{'float'} = { 'float' => 1 };
- if (defined($style_texi))
- {
- $state->{'float'}->{'style_texi'} = $style_texi;
- $state->{'float'}->{'style_id'} =
- cross_manual_line($state->{'float'}->{'style_texi'});
- }
- #print STDERR "float: (no label) $state->{'float'}\n";
- }
- $state->{'float'}->{'style'} = substitute_line($state->{'float'}->{'style_texi'}, __("\@float style"), undef, $line_nr);
- return '';
- }
- sub do_quotation_line($$$$$$)
- {
- my $command = shift;
- my $format_ref = shift;
- my $args = shift;
- my @args = @$args;
- my $text_texi = shift @args;
- my $style_stack = shift;
- my $state = shift;
- my $line_nr = shift;
- my $text;
- $text_texi = undef if (defined($text_texi) and $text_texi=~ /^\s*$/);
- if (defined($text_texi))
- {
- $text_texi = trim_around_spaces($text_texi);
- $text = substitute_line($text_texi, sprintf(__p("\@*quotation", "\@%s argument"), $command), duplicate_formatting_state($state), $line_nr);
- #$text =~ s/\s*$//;
- }
- my $quotation_args = { 'text' => $text, 'text_texi' => $text_texi };
- push @{$state->{'quotation_stack'}}, $quotation_args;
- $format_ref->{'argument_text'} = $text;
- $format_ref->{'argument_texi'} = $text_texi;
- $state->{'prepend_text'} = &$Texi2HTML::Config::quotation_prepend_text($command, $text_texi);
- return '';
- }
- sub do_footnote($$$$$$)
- {
- my $command = shift;
- my $args = shift;
- my $text = $args->[0];
- my $style_stack = shift;
- my $doc_state = shift;
- my $line_nr = shift;
- my $kept_line_nrs = shift;
- $text .= "\n";
- $text = &$Texi2HTML::Config::footnote_texi($text, $doc_state, $style_stack)
- if (defined($Texi2HTML::Config::footnote_texi));
- my $foot_state = duplicate_state($doc_state);
- fill_state($foot_state);
- push @{$foot_state->{'command_stack'}}, 'footnote';
- push_state($foot_state);
- my ($foot_num, $relative_foot_num);
- my $special_place;
- if (!defined($foot_state->{'expansion'}) and !defined($foot_state->{'region'}))
- {
- $foot_num = \$global_foot_num;
- $relative_foot_num = \$global_relative_foot_num;
- }
- else
- {
- $special_place = $foot_state->{'expansion'};
- $special_place = $foot_state->{'region'} if (!defined($special_place));
- $foot_num = \$doc_state->{'foot_num'};
- $relative_foot_num = \$doc_state->{'relative_foot_num'};
- }
- $$foot_num++;
- $$relative_foot_num++;
-
- my $docid = "DOCF$$foot_num";
- my $footid = "FOOT$$foot_num";
- if (defined($special_place))
- {
- $docid = $target_prefix . $special_place . "_$docid";
- $footid = $target_prefix . $special_place . "_$footid";
- }
- my $from_file = $docu_doc;
- if ($doc_state->{'element'})
- {
- $from_file = $doc_state->{'element'}->{'file'};
- }
-
- if (get_conf('footnotestyle') eq 'separate')
- {
- $foot_state->{'element'} = $footnote_element;
- }
-
- $foot_state->{'footnote_number_in_doc'} = $$foot_num;
- $foot_state->{'footnote_number_in_page'} = $$relative_foot_num;
- $foot_state->{'footnote_footnote_id'} = $footid;
- $foot_state->{'footnote_place_id'} = $docid;
- $foot_state->{'footnote_document_file'} = $from_file;
- $foot_state->{'footnote_footnote_file'} = $foot_state->{'element'}->{'file'};
- $foot_state->{'footnote_document_state'} = $doc_state;
-
- # FIXME use split_lines ? It seems to work like it is now ?
- msg_debug ("No line nnumbers in footnote", $line_nr) if (!defined($kept_line_nrs) or !@$kept_line_nrs);
- my @lines;
- if (defined($text))
- {
- @lines = substitute_text($foot_state, $kept_line_nrs, '@footnote', map {$_ = $_."\n"} split (/\n/, $text));
- }
- my ($foot_lines, $foot_label) = &$Texi2HTML::Config::foot_line_and_ref($$foot_num,
- $$relative_foot_num, $footid, $docid, $from_file, $foot_state->{'element'}->{'file'}, \@lines, $doc_state);
- if ($doc_state->{'outside_document'} or (defined($doc_state->{'multiple_pass'}) and $doc_state->{'multiple_pass'} > 0))
- {
- #print STDERR "multiple_pass $doc_state->{'multiple_pass'}, 'outside_document' $doc_state->{'outside_document'}\n";
- #print STDERR "REGION FOOTNOTE($$foot_num): $doc_state->{'region'} ($doc_state->{'region_pass'})\n";
- $region_initial_state{$doc_state->{'region'}}->{'footnotes'}->{$$foot_num}->{$doc_state->{'region_pass'}} = $foot_lines if (defined($doc_state->{'region'}));
- }
- else
- {
- #print STDERR "GLOBAL FOOTNOTE($$foot_num)\n";
- push(@foot_lines, @{$foot_lines});
- }
- pop_state();
- return $foot_label;
- }
- sub do_image($$$$$)
- {
- # replace images
- my $command = shift;
- my $args = shift;
- my $style_stack = shift;
- my $state = shift;
- my $line_nr = shift;
- my @args;
- foreach my $arg (@$args)
- {
- $arg = trim_around_spaces($arg) if (defined($arg));
- push @args, $arg;
- }
- my $base = substitute_line($args[0], __("\@image base name"),{'code_style' => 1, 'remove_texi' => 1});
- my $base_simple = substitute_line($args[0], __("\@image base name"), {'simple_format' => 1, 'code_style' => 1});
- if ($base eq '')
- {
- line_error ("\@image missing filename argument", $line_nr);
- return '';
- }
- $args[4] = '' if (!defined($args[4]));
- $args[3] = '' if (!defined($args[3]));
- my $image;
- my $extension = substitute_line($args[4], __("\@image extension"), {'code_style' => 1, 'remove_texi' => 1});
- my $extension_simple = substitute_line($args[4], __("\@image extension"), {'simple_format' => 1, 'code_style' => 1});
- my ($file_name, $image_name, $simple_file_name);
- my @file_locations;
- my @file_names = &$Texi2HTML::Config::image_files($base,$extension,$args[0],$args[4]);
- # $image = locate_include_file("$base.$args[4]") if ($args[4] ne '');
- foreach my $file (@file_names)
- {
- my $simple_file = substitute_line($file->[1], __("\@image file name"), {'simple_format' => 1, 'code_style' => 1});
- if ($image = locate_include_file($file->[0]))
- {
- if (!defined($file_name))
- {
- $file_name = $file->[0];
- $image_name = $image;
- $simple_file_name = $simple_file;
- }
- push @file_locations, [$file, $image, $simple_file];
- }
- else
- {
- push @file_locations, [$file, undef, $simple_file];
- }
- }
- $image_name = '' if (!defined($image_name));
- $simple_file_name = '' if (!defined($simple_file_name));
-
- my $alt;
- if ($args[3] =~ /\S/)
- {
- $alt = substitute_line($args[3], __("\@image alt text"), {'simple_format' => 1}, $line_nr);
- }
- return &$Texi2HTML::Config::image($path_to_working_dir . $image_name,
- $base,
- $state->{'preformatted'}, $file_name, $alt, $args[1], $args[2],
- $args[3], $extension, $path_to_working_dir, $image_name,
- $state->{'paragraph_context'}, \@file_locations, $base_simple,
- $extension_simple, $simple_file_name, $line_nr);
- }
- # usefull if we want to duplicate only the global state, nothing related with
- # formatting
- sub duplicate_state($)
- {
- my $state = shift;
- my $new_state = { 'element' => $state->{'element'},
- 'multiple_pass' => $state->{'multiple_pass'},
- 'region_pass' => $state->{'region_pass'},
- 'region' => $state->{'region'},
- 'expansion' => $state->{'expansion'},
- 'sec_num' => $state->{'sec_num'},
- 'outside_document' => $state->{'outside_document'},
- 'inside_document' => $state->{'inside_document'},
- 'duplicated' => 1
- };
- return $new_state;
- }
- # duplicate global and formatting state.
- sub duplicate_formatting_state($)
- {
- my $state = shift;
- my $new_state = duplicate_state($state);
- # Things passed here should be things that are not emptied/set to 0 by
- # any command. Also they shouldn't need anything to be on the
- # stack. This rules out paragraphs, for example.
- foreach my $format_key ('preformatted', 'code_style', 'keep_texi',
- 'keep_nr', 'preformatted_stack')
- {
- $new_state->{$format_key} = $state->{$format_key};
- }
- # this is needed for preformatted
- my $command_stack = $state->{'command_stack'};
- $command_stack = [] if (!defined($command_stack));
- $new_state->{'command_stack'} = [ @$command_stack ];
- $new_state->{'preformatted_context'} = {'stack_at_beginning' => [ @$command_stack ]};
- $new_state->{'code_style'} = 0 if (!defined($new_state->{'code_style'}));
- return $new_state;
- }
- sub expand_macro($$$$$)
- {
- my $name = shift;
- my $args = shift;
- my $end_line = shift;
- my $line_nr = shift;
- my $state = shift;
- # we dont expand macros when in ignored environment.
- return if ($state->{'ignored'});
- die "Bug end_line not defined" if (!defined($end_line));
-
- my $index = 0;
- foreach my $arg (@$args)
- { # expand @macros in arguments. It is complicated because we must be
- # carefull not to expand macros in @ignore section or the like, and
- # still keep every single piece of text (including the @ignore macros).
- $args->[$index] = substitute_text({'texi' => 1, 'arg_expansion' => 1}, undef, "expand_macro in $name", split_lines($arg));
- $index++;
- }
- # retrieve the macro definition
- my $macrobody = $macros->{$name}->{'body'};
- my $formal_args = $macros->{$name}->{'args'};
- my $args_index = $macros->{$name}->{'args_index'};
- my $i;
- for ($i=0; $i<=$#$formal_args; $i++)
- {
- $args->[$i] = "" unless (defined($args->[$i]));
- print STDERR "# arg($i): $args->[$i]\n" if ($T2H_DEBUG & $DEBUG_MACROS);
- }
- line_error (sprintf(__("Macro `%s' called with too many args"), $name), $line_nr) if (defined($args->[$i + 1]));
- my $result = '';
- while ($macrobody ne '')
- {
- if ($macrobody =~ s/^([^\\]*)\\//o)
- {
- $result .= $1 if defined($1);
- if ($macrobody =~ s/^\\//)
- {
- $result .= '\\';
- }
- elsif ($macrobody =~ s/^(\@end\sr?macro)$// or $macrobody =~ s/^(\@end\sr?macro\s)// or $macrobody =~ s/^(\@r?macro\s+\w+\s*.*)//)
- { # \ protect @end macro
- $result .= $1;
- }
- elsif ($macrobody =~ s/^([^\\]*)\\//)
- {
- my $arg = $1;
- if (defined($args_index->{$arg}))
- {
- $result .= $args->[$args_index->{$arg}];
- }
- else
- {
- line_error (sprintf(__("\\ in macro expansion followed `%s' instead of parameter name or \\"), $arg), $macros->{$name}->{'line_nr'});
- $result .= '\\' . $arg;
- }
- }
- next;
- }
- $result .= $macrobody;
- last;
- }
- my @result = split(/^/m, $result);
- # for a completly empty macro, $result = '', and the split leads
- # to an empty array, so add back an empty string
- @result = ('') if (!scalar(@result));
- # Add the result of the macro expansion back to the input_spool.
- # Set the macro name if in the outer macro
- if ($state->{'arg_expansion'})
- { # in that case we are in substitute_text for an arg
- unshift @{$state->{'spool'}}, (@result, $end_line);
- }
- else
- {
- #$result[-1].=$end_line;
- #foreach my $res (@result)
- #{
- # print STDERR "RESULT:$res";
- #}
- #print STDERR "#########end->$end_line";
- my $last_line = $result[-1];
- if (chomp($last_line))
- {
- push @result, $end_line;
- }
- else
- {
- $result[-1] .= $end_line;
- }
- unshift @{$state->{'input_spool'}->{'spool'}}, (@result); #, $end_line);
- $state->{'input_spool'}->{'macro'} = $name if ($state->{'input_spool'}->{'macro'} eq '');
- }
- if ($T2H_DEBUG & $DEBUG_MACROS)
- {
- print STDERR "# macro expansion result:\n";
- #print STDERR "$first_line";
- foreach my $line (@result)
- {
- print STDERR "$line";
- }
- print STDERR "# macro expansion result end\n";
- }
- }
- sub do_index_summary_file($$)
- {
- my $name = shift;
- my $docu_name = shift;
- &$Texi2HTML::Config::index_summary_file_begin ($name, $printed_indices{$name}, $docu_name);
- print STDERR "# writing $name index summary for $docu_name\n" if $T2H_VERBOSE;
- foreach my $letter_entries (@{$Texi2HTML::THISDOC{'index_letters_array'}->{$name}})
- {
- #print STDERR "$name: $letter_entries->{'letter'}\n";
- foreach my $entry (@{$letter_entries->{'entries'}})
- {
- #my $entry = $entries->{$key};
- my $indexed_element = $entry->{'element'};
- my $entry_element = $indexed_element;
- $entry_element = $entry_element->{'element_ref'} if (defined($entry_element->{'element_ref'}));
- my $origin_href = $entry->{'file'};
- #print STDERR "$entry $entry->{'entry'}, real elem $indexed_element->{'texi'}, section $entry_element->{'texi'}, real $indexed_element->{'file'}, entry file $entry->{'file'}\n";
- if ($entry->{'target'})
- {
- $origin_href .= '#' . $entry->{'target'};
- }
- else
- {
- $origin_href .= '#' . $indexed_element->{'target'};
- }
- &$Texi2HTML::Config::index_summary_file_entry ($name,
- $entry->{'key'}, $origin_href,
- substitute_line($entry->{'entry'}, "\@$entry->{'command'}"), $entry->{'entry'},
- href($entry_element, ''),
- $entry_element->{'text'},
- $printed_indices{$name},
- $docu_name);
- }
- }
- &$Texi2HTML::Config::index_summary_file_end ($name, $printed_indices{$name}, $docu_name);
- }
- sub get_index_entry_infos($$;$)
- {
- my $entry = shift;
- my $element = shift;
- my $line_nr = shift;
- my $index_heading_element = $entry->{'element'};
- my $entry_heading_element = $index_heading_element;
- my $real_index_element = $entry->{'real_element'};
- if (!defined($entry->{'real_element'}))
- {
- print STDERR "BUG: entry->{'real_element'} not defined\n";
- }
- # we always use the associated element_ref, instead of the original
- # element
- $entry_heading_element = $entry_heading_element->{'element_ref'}
- if (defined($entry_heading_element->{'element_ref'}));
- if ($entry->{'real_element'} eq $element_before_anything)
- {
- $real_index_element = $element_top;
- }
- else
- {
- $real_index_element = $entry->{'real_element'}->{'element_ref'};
- if (!defined($real_index_element))
- { # happens when $USE_NODES = 0 and there are only sections,
- # and vice-versa
- $real_index_element = $entry->{'real_element'};
- }
- }
- my $origin_href = '';
- print STDERR "BUG: entry->{'file'} not defined for `$entry->{'entry'}'\n"
- if (!defined($entry->{'file'}));
- print STDERR "BUG: element->{'file'} not defined for `$entry->{'entry'}', `$element->{'texi'}'\n"
- if (!defined($element->{'file'}));
- $origin_href = $entry->{'file'} if ($entry->{'file'} ne $element->{'file'});
- #print STDERR "$entry $entry->{'entry'}, real heading elem $index_heading_element->{'texi'}, section $entry_element->{'texi'}, real $index_heading_element->{'file'}, entry file $entry->{'file'}\n";
- if (defined($entry->{'target'}))
- {
- $origin_href .= '#' . $entry->{'target'};
- }
- else
- { # this means that the index entry is in a special region like @copying...
- $origin_href .= '#' . $index_heading_element->{'target'};
- }
- #print STDERR "SUBHREF in index entry `$entry->{'entry'}' for `$entry_element->{'texi'}'\n";
- return ($origin_href,
- $entry->{'file'},
- $element->{'file'},
- $entry->{'target'},
- $index_heading_element->{'target'},
- substitute_line($entry->{'entry'}, "\@$entry->{'command'} index infos"),
- href($entry_heading_element, $element->{'file'}, $line_nr),
- $entry_heading_element->{'text'},
- (!$entry->{'seen_in_output'} and defined($entry->{'region'})));
- }
- # remove texi commands, replacing with what seems adequate. see simple_map_texi
- # and texi_map.
- # Doesn't protect html
- sub remove_texi(@)
- {
- return substitute_text ({ 'remove_texi' => 1}, undef, undef, @_);
- }
- # Same as remove texi but protect text and use special maps for @-commands
- sub simple_format($$$@)
- {
- my $state = shift;
- my $line_nrs = shift;
- my $context = shift;
- if (!defined($state))
- {
- $state = {};
- }
- else
- {
- $state = duplicate_formatting_state($state);
- }
- $state->{'remove_texi'} = 1;
- $state->{'simple_format'} = 1;
- $::simple_map_texi_ref = \%Texi2HTML::Config::simple_format_simple_map_texi;
- $::style_map_texi_ref = \%Texi2HTML::Config::simple_format_style_map_texi;
- $::texi_map_ref = \%Texi2HTML::Config::simple_format_texi_map;
- my $text = substitute_text($state, $line_nrs, $context, @_);
- $::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi;
- $::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi;
- $::texi_map_ref = \%Texi2HTML::Config::texi_map;
- return $text;
- }
- sub index_entry_command_prefix($$$)
- {
- my $command = shift;
- my $line = shift;
- my $line_nr = shift;
- if ($command =~ /^(v|f)table$/)
- {
- return $1;
- }
- elsif (defined($Texi2HTML::Config::def_map{$command}))
- {
- my ($prefix, $entry, $argument) = get_deff_index($command, $line, undef, 0);
- return $prefix;
- }
- my $prefix = index_command_prefix($command);
- line_error(sprintf(__("No index prefix found for \@%s"),$command),$line_nr) if ($prefix eq '');
- return $prefix;
- }
- sub enter_table_index_entry($$$$)
- {
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $line_nr = shift;
- if ($state->{'item'})
- {
- my $item_command = $state->{'item'};
- delete $state->{'item'};
- my $item = pop @$stack;
- if ($state->{'table_stack'}->[-1] =~ /^(v|f)table$/)
- {
- my $index = $1;
- enter_index_entry($index, $line_nr,
- $item->{'text'}, $state->{'table_stack'}->[-1], $state);
- }
- add_prev($text, $stack, "\@$item_command" . $item->{'text'});
- }
- }
- sub end_macro($$$)
- {
- my $state = shift;
- my $end_string = shift;
- my $remaining_on_the_line = shift;
- $state->{'macro_inside'}--;
- return (0, undef) if ($state->{'ignored'});
- if ($state->{'macro_inside'})
- {
- $state->{'macro'}->{'body'} .= $end_string;
- return (0, undef);
- }
- my $macro_text = $state->{'macro'}->{'header'} . $state->{'macro'}->{'body'}.$end_string;
- chomp $state->{'macro'}->{'body'};
- print STDERR "# end macro def. Body:\n$state->{'macro'}->{'body'}"
- if ($T2H_DEBUG & $DEBUG_MACROS);
- $macros->{$state->{'macro'}->{'name'}} = $state->{'macro'} unless ($state->{'arg_expansion'});
- delete $state->{'macro'};
- return (1, $macro_text.$remaining_on_the_line) if ($remaining_on_the_line =~ /^\s*$/);
- return (0, $macro_text);
- }
- sub close_macro_arg($$$)
- {
- my $state = shift;
- my $current_line = shift;
- my $line_nr = shift;
- # balanced } ends the macro call, otherwise it is in the arg
- $state->{'macro_depth'}--;
- if ($state->{'macro_depth'} == 0)
- {
- #print STDERR "BEFORE: $current_line";
- print STDERR "# expanding macro $state->{'macro_name'}\n" if ($T2H_DEBUG & $DEBUG_MACROS);
- #$current_line =
- expand_macro($state->{'macro_name'}, $state->{'macro_args'}, $current_line, $line_nr, $state);
- delete $state->{'macro_name'};
- delete $state->{'macro_depth'};
- delete $state->{'macro_args'};
- #print STDERR "AFTER: $current_line";
- #return $current_line;
- return 1;
- }
- else
- {
- print STDERR "# macro call: closing }\n" if ($T2H_DEBUG & $DEBUG_MACROS);
- add_text('}', \$state->{'macro_args'}->[-1]);
- return undef;
- }
- }
- sub close_style_texi($$$$;$)
- {
- my $style = shift;
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $no_close = shift;
- $no_close = 0 if (!defined($no_close));
- my $result;
- if (!defined($style->{'style'}))
- {
- msg_debug("'style' not defined in close_style_texi ($no_close)");
- foreach my $key (keys(%$style))
- {
- print STDERR " --> $key: ".var_to_str($style->{$key})."\n";
- }
- }
- if (($style->{'style'} ne '') and exists($info_enclose{$style->{'style'}}) and !$state->{'arg_expansion'})
- {
- $result = $info_enclose{$style->{'style'}}->[0] . $style->{'text'} . $info_enclose{$style->{'style'}}->[1];
- }
- elsif ($style->{'style'} ne '')
- {
- $result = '@' . $style->{'style'} . '{' . $style->{'text'};
- $result .= '}' unless ($no_close);
- }
- else
- {
- $result = '{' . $style->{'text'};
- # don't close { if we are closing stack as we are not
- # sure this is a { ... } construct. i.e. we are
- # not sure that the user properly closed the matching
- # brace, so we don't close it ourselves
- $result .= '}' unless ($no_close or $state->{'arg_expansion'});
- }
- if ($state->{'ignored'})
- {# ARG_EXPANSION
- print STDERR "# Popped `$style->{'style'}' in ifset/ifclear\n" if ($T2H_DEBUG);
- }
- else
- {
- add_prev ($text, $stack, $result);
- }
- }
- sub close_ignored ($$)
- {
- my $state = shift;
- my $stack = shift;
- if (($state->{'ifvalue_inside'}) and $state->{'ignored'} eq $state->{'ifvalue'})
- {
- if ($state->{'ifvalue_inside'} == 1)
- {# closing still opened @-commands with braces
- pop (@$stack) while (@$stack and $stack->[-1]->{'style'} ne 'ifvalue')
- }
- pop (@$stack);
- $state->{'ifvalue_inside'}--;
- }
- $state->{'ignored'} = undef;
- delete $state->{'ignored'};
- # We are stil in the ignored ifset or ifclear section
- $state->{'ignored'} = $state->{'ifvalue'} if ($state->{'ifvalue_inside'});
- #dump_stack($text, $stack, $state);
- }
- # Called in 2 contexts:
- # * in main document
- # * from substitute_text, called in turn from arg_expansion. In that case
- # 'texi' is true, and so is 'arg_expansion'. In that case constructs are
- # expanded but no action is performed. Therefore $line_nr is not of use.
- sub scan_texi($$$$;$)
- {
- my $scanned_line = shift;
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $line_nr = shift;
-
- die "stack not an array ref" unless (ref($stack) eq "ARRAY");
- my $cline = $scanned_line;
- while(1)
- {
- # scan_texi
- #print STDERR "WHILE(t):$cline";
- #print STDERR "ARG_EXPANSION: $state->{'arg_expansion'}\n" if ($state->{'arg_expansion'});
- #dump_stack($text, $stack, $state);
- #print STDERR "ifvalue_inside $state->{'ifvalue_inside'}\n";
- # first we handle special cases:
- # macro definition: $state->{'macro_inside'}
- # macro arguments: $state->{'macro_name'}
- # raw format: $state->{'raw'}
- # @verb: $state->{'verb'}
- # ignored: $state->{'ignored'}
- # and then the remaining text/macros.
- # in macro definition
- if ($state->{'macro_inside'})
- {
- if ($cline =~ s/^([^\\\@]*\\)//)
- {# protected character or @end macro
- $state->{'macro'}->{'body'} .= $1 unless ($state->{'ignored'});
- if ($cline =~ s/^\\//)
- {
- $state->{'macro'}->{'body'} .= '\\' unless ($state->{'ignored'});
- next;
- }
- # I believe it is correct, although makeinfo don't do that.
- elsif ($cline =~ s/^(\@end\sr?macro)$//o or $cline =~ s/^(\@end\sr?macro\s)//o
- or $cline =~ s/^(\@r?macro\s+\w+\s*.*)//o)
- {
- $state->{'macro'}->{'body'} .= $1 unless ($state->{'ignored'});
- next;
- }
- }
- #if ($cline =~ s/^(.*?)\@end\sr?macro$//o or $cline =~ s/^(.*?)\@end\sr?macro\s+//o)
- if ($cline =~ s/^(\@end\sr?macro)$//o or $cline =~ s/^(\@end\sr?macro\s+)//o)
- {
- my ($no_remaining, $result) = end_macro($state, $1, $cline);
- add_prev ($text, $stack, $result) if (defined($result));
- return 1 if ($no_remaining);
- next;
- }
- elsif($cline =~ /^(\@r?macro\s+\w+\s*.*)/)
- {
- $state->{'macro'}->{'body'} .= $cline unless ($state->{'ignored'});
- $state->{'macro_inside'}++;
- #return;
- return 1;
- }
- elsif ($cline =~ s/^\@(.)//)
- {
- $state->{'macro'}->{'body'} .= '@' . $1 unless ($state->{'ignored'});
- next;
- }
- elsif ($cline =~ s/^\@//)
- {
- $state->{'macro'}->{'body'} .= '@' unless ($state->{'ignored'});
- next;
- }
- else
- {
- $cline =~ s/([^\@\\]*)//;
- if ($state->{'ignored'})
- {
- return if ($cline =~ /^$/);
- next;
- }
- $state->{'macro'}->{'body'} .= $1 if (defined($1));
- if ($cline =~ /^$/)
- {
- $state->{'macro'}->{'body'} .= $cline;
- #return;
- return 1;
- }
- next;
- }
- }
- # in macro arguments parsing/expansion. Here \ { } and , if this is a
- # multi args macro have a signification, the remaining is passed
- # unmodified
- if (defined($state->{'macro_name'}))
- {
- my $special_chars = quotemeta ('\{}');
- my $multi_args = 0;
- my $formal_args = $macros->{$state->{'macro_name'}}->{'args'};
- $multi_args = 1 if ($#$formal_args >= 1);
- $special_chars .= quotemeta(',') if ($multi_args);
- if ($state->{'macro_args'}->[-1] eq '')
- {# remove space at the very beginning
- $cline =~ s/^\s*//o;
- }
- if ($cline =~ s/^([^$special_chars]*)([$special_chars])//)
- {
- $state->{'macro_args'}->[-1] .= $1 if defined($1);
- # \ protects any character in macro arguments
- if ($2 eq '\\')
- {
- print STDERR "# macro call: protected char\n" if ($T2H_DEBUG & $DEBUG_MACROS);
- if ($cline =~ s/^(.)//)
- {
- $state->{'macro_args'}->[-1] .= $1;
- }
- else
- {
- $state->{'macro_args'}->[-1] .= '\\';
- }
- }
- elsif ($2 eq ',')
- { # in texinfo 4.8.90 a comma in braces is protected
- if ($state->{'macro_depth'} > 1)
- {
- $state->{'macro_args'}->[-1] .= ',';
- }
- else
- { # separate args
- print STDERR "# macro call: new arg\n" if ($T2H_DEBUG & $DEBUG_MACROS);
- $cline =~ s/^\s*//o;
- push @{$state->{'macro_args'}}, '';
- }
- }
- elsif ($2 eq '}')
- {
- #my $macro_result_line = close_macro_arg($state, $cline);
- return if (close_macro_arg($state, $cline, $line_nr));
- #if (defined($macro_result_line))
- #{
- # $cline = $macro_result_line;
- # return;
- #}
- }
- elsif ($2 eq '{')
- {
- print STDERR "# macro call: opening {\n" if ($T2H_DEBUG & $DEBUG_MACROS);
- $state->{'macro_depth'}++;
- add_text('{', \$state->{'macro_args'}->[-1]);
- }
- next;
- }
- print STDERR "# macro call: end of line\n" if ($T2H_DEBUG & $DEBUG_MACROS);
- $state->{'macro_args'}->[-1] .= $cline;
- return;
- }
- # in a raw format, verbatim, tex or html
- if ($state->{'raw'})
- {
- my $tag = $state->{'raw'};
- # debugging
- if (! @$stack or ($stack->[-1]->{'style'} ne $tag))
- {
- print STDERR "Bug: raw or special: $tag but not on top of stack\n";
- print STDERR "line: $cline";
- dump_stack($text, $stack, $state);
- exit 1;
- }
-
- # macro_regexp
- if ($cline =~ /^(.*?)\@end\s([a-zA-Z][\w-]*)/o and ($2 eq $tag))
- {
- $cline =~ s/^(.*?)(\@end\s$tag)//;
- # we add it even if 'ignored', it'll be discarded just below
- # with the @end
- add_prev ($text, $stack, $1);
- my $end = $2;
- my $style = pop @$stack;
- # if 'arg_expansion' and 'ignored' are both true text
- # is ignored.
- add_prev ($text, $stack, $style->{'text'} . $end) unless ($state->{'ignored'});
- delete $state->{'raw'};
- next;
- }
- else
- {# we add it even if 'ignored', it'll be discarded when there is
- # the @end
- add_prev ($text, $stack, $cline);
- last;
- }
- }
- # in a @verb{ .. } macro
- if (defined($state->{'verb'}))
- {
- #dump_stack($text, $stack, $state);
- my $char = quotemeta($state->{'verb'});
- #print STDERR "VERB $char\n";
- if ($cline =~ s/^(.*?)$char\}/\}/)
- {# we add it even if 'ignored', it'll be discarded when closing
- add_prev($text, $stack, $1 . $state->{'verb'});
- $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'};
- delete $state->{'verb'};
- next;
- }
- else
- {# we add it even if 'ignored', it'll be discarded when closing
- add_prev($text, $stack, $cline);
- last;
- }
- }
- # In ignored region
- if ($state->{'ignored'})
- {
- #print STDERR "IGNORED(ifvalue($state->{'ifvalue_inside'})): $state->{'ignored'}\n";
- if ($cline =~ /^.*?\@end(\s+)([a-zA-Z]\w+)/)
- {
- if ($2 eq $state->{'ignored'})
- {
- $cline =~ s/^(.*?\@end)(\s+)([a-zA-Z]\w+)//;
- my $end_ignore = $1.$2.$3;
- close_ignored($state, $stack);
- #dump_stack($text, $stack, $state);
- # MACRO_ARG => keep ignored text
- if ($state->{'arg_expansion'})
- {# this may not be very usefull as it'll be remove later
- add_prev ($text, $stack, $end_ignore);
- next;
- }
- return if ($cline =~ /^\s*$/o);
- next;
- }
- }
- add_prev ($text, $stack, $cline) if ($state->{'arg_expansion'});
- # we could theoretically continue for ignored commands other
- # than ifset or ifclear, however it isn't usefull.
- return unless ($state->{'ifvalue_inside'} and ($state->{'ignored'} eq $state->{'ifvalue'}));
- }
-
- # an @end tag
- # macro_regexp
- if ($cline =~ s/^([^{}@]*)\@end(\s+)([a-zA-Z][\w-]*)//)
- {
- my $leading_text = $1;
- my $space = $2;
- my $end_tag = $3;
- # when 'ignored' we don't open environments that aren't associated
- # with ignored regions, so we don't need to close them.
- next if ($state->{'ignored'});# ARG_EXPANSION
- add_prev($text, $stack, $leading_text);
- if (defined($state->{'text_macro_stack'})
- and @{$state->{'text_macro_stack'}}
- and ($end_tag eq $state->{'text_macro_stack'}->[-1]))
- {
- pop @{$state->{'text_macro_stack'}};
- # we keep menu and titlepage for the following pass
- if (($Texi2HTML::Config::texi_formats_map{$end_tag} eq 'normal') or ($region_lines{$end_tag}) or $state->{'arg_expansion'})
- {
- add_prev($text, $stack, "\@end${space}$end_tag");
- }
- else
- {
- #print STDERR "End $end_tag\n";
- #dump_stack($text, $stack, $state);
- return if ($cline =~ /^\s*$/);
- }
- }
- elsif ($Texi2HTML::Config::texi_formats_map{$end_tag})
- {
- line_error (sprintf(__("Unmatched `%c%s'"), ord('@'), 'end'), $line_nr);
- }
- else # a format that is not handled during the first pass
- {# ARG_EXPANSION
- add_prev($text, $stack, "\@end${space}$end_tag");
- }
- next;
- }
- # macro_regexp
- elsif ($cline =~ s/^([^{}@]*)\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/\\])//o or $cline =~ s/^([^{}@]*)\@([a-zA-Z][\w-]*)//o)
- {# ARG_EXPANSION
- add_prev($text, $stack, $1) unless $state->{'ignored'};
- my $command = $2;
- # FIXME: if it is an alias, it is substituted below, in the
- # diverse add_prev and output of \@$command. Maybe it could be
- # kept and only substituted in the last passes?
- $command = $alias{$command} if (exists($alias{$command}));
- #print STDERR "MACRO $command\n";
- # handle skipped @-commands
- $state->{'bye'} = 1 if ($command eq 'bye' and !$state->{'ignored'} and !$state->{'arg_expansion'});
- # 'ignored' and 'arg_expansion' are handled in misc_command_texi
- # these are the commands in which the @value and @macro
- # and @-commands in general should not be expanded
- if (defined($Texi2HTML::Config::misc_command{$command}) and
- ($command eq 'c' or $command eq 'comment' or $command eq 'set'
- or $command eq 'clear' or $command eq 'bye' or $command eq 'alias'))
- {
- my $cmd_arg;
- ($cline, $cmd_arg) = misc_command_texi($cline, $command, $state,
- $line_nr);
- add_prev ($text, $stack, "\@$command" . $cmd_arg) unless $state->{'ignored'};
- }
- elsif ($command eq 'setfilename' or $command eq 'documentencoding'
- or $command eq 'definfoenclose' or $command eq 'include')
- { # special commands whose arguments will have @macro and
- # @value expanded, and that are processed in this pass
- if ($state->{'ignored'} or ($line_nr->{'file_name'} ne $Texi2HTML::THISDOC{'input_file_name'} and $command eq 'setfilename'))
- { # @setfilename is ignored in @include file as said in the manual
- $cline = '';
- }
- elsif ($state->{'arg_expansion'})
- {
- add_prev($text, $stack, "\@$command" . $cline);
- return;
- }
- else
- {
- $cline =~ s/^(\s+)//;
- my $space = $1;
- # not sure if it happpens at end of line, or with
- # special char following the @-command or only at end of file
- $space = '' if (!defined($space));
- if (!$state->{'line_command'})
- {
- #print STDERR "LINE_COMMAND Start line_command $command, cline $cline";
- $state->{'line_command'} = $command;
- push @$stack, { 'line_command' => $command, 'text' => $space };
- }
- else
- {
- line_error (sprintf(__("\@%s not allowed in argument to \@%s"), $command, $state->{'line_command'}), $line_nr);
- #add_prev($text, $stack, "\@$command" . $space);
- add_prev($text, $stack, $space);
- }
- }
- }
- # pertusus: it seems that value substitution are performed after
- # macro argument expansions: if we have
- # @set comma ,
- # and a call to a macro @macro {arg1 @value{comma} arg2}
- # the macro arg is arg1 , arg2 and the comma don't separate
- # args. Likewise it seems that the @value are not expanded
- # in macro definitions
- elsif ($command =~ /^r?macro$/)
- { # in 'arg_expansion' (ie within another macro call arguments)
- # the macro is parsed as usual, but isn't registered in
- # end_macro.
- if ($cline =~ /^\s+(\w[\w-]*)\s*(.*)/)
- {
- my $name = $1;
- my $args_def = $2;
- unless ($state->{'ignored'} or $state->{'arg_expansion'})
- {
- if (exists($macros->{$name}))
- {
- #line_warn ("macro `$name' already defined " .
- # format_line_number($macros->{$name}->{'line_nr'}) . " redefined", $line_nr);
- line_warn (sprintf(__("macro `%s' previously defined"), $name), $line_nr);
- line_warn (sprintf(__("here is the previous definition of `%s'"), $name), $macros->{$name}->{'line_nr'});
- }
- }
- $state->{'macro_inside'} = 1;
- next if ($state->{'ignored'});
- my @args = ();
- if ($args_def =~ /^\s*{\s*(.*?)\s*}\s*/)
- {
- @args = split(/\s*,\s*/ , $1)
- }
- # keep the context information of the definition
- my $macro = { 'name' => $name };
- $macro->{'line_nr'} = { 'file_name' => $line_nr->{'file_name'},
- 'line_nr' => $line_nr->{'line_nr'}, 'macro' => $line_nr->{'macro'} } if (defined($line_nr));
- $macro->{'args'} = \@args;
- $macro->{'header'} = "\@$command" .$cline;
- my $arg_index = 0;
- my $debug_msg = '';
- foreach my $arg (@args)
- { # when expanding macros, the argument index is retrieved
- # with args_index
- $macro->{'args_index'}->{$arg} = $arg_index;
- $debug_msg .= "$arg($arg_index) ";
- $arg_index++;
- }
- $macro->{'body'} = '';
- $state->{'macro'} = $macro;
- print STDERR "# macro def $name: $debug_msg\n"
- if ($T2H_DEBUG & $DEBUG_MACROS);
- }
- else
- {# it means we have a macro without a name
- line_error (sprintf(__("Macro definition without macro name: %s"), $cline), $line_nr)
- unless ($state->{'ignored'});
- }
- return 1;
- }
- elsif (defined($Texi2HTML::Config::texi_formats_map{$command}))
- {
- my $tag;
- ($cline, $tag) = do_text_macro($command, $cline, $state, $stack, $line_nr);
- # if it is a raw formatting command or a menu command
- # we must keep it for later, unless we are in an 'ignored'.
- # if in 'arg_expansion' we keep everything.
- my $command_kept;
- if ((($state->{'raw'} or ($Texi2HTML::Config::texi_formats_map{$command} eq 'normal') or (exists($region_lines{$command}))) and !$state->{'ignored'}) or $state->{'arg_expansion'})
- {
- add_prev($text, $stack, $tag);
- $command_kept = 1;
- }
- #dump_stack ($text, $stack, $state);
- next if $command_kept;
- return if ($cline =~ /^\s*$/);
- }
- elsif ($command eq 'value')
- {
- if ($cline =~ s/^{($VARRE)}//)
- {
- my $value = $1;
- if ($state->{'arg_expansion'})
- {
- add_prev($text, $stack, "\@$command" .'{'. $value .'}');
- next;
- }
- next if ($state->{'ignored'});
- my $expansion;
- if (defined($value{$value}))
- {
- $expansion = $value{$value}
- }
- else
- {
- $expansion = gdt('@{No value for `{value}\'@}', {'value' => $value}, {'keep_texi'=> 1});
- line_warn (sprintf(__("undefined flag: %s"), $value), $line_nr);
- }
- $cline = $expansion . $cline;
- }
- else
- {
- if ($state->{'arg_expansion'})
- {
- add_prev($text, $stack, "\@$command");
- next;
- }
- next if ($state->{'ignored'});
- line_error (__("Bad syntax for \@value"), $line_nr);
- }
- }
- elsif ($command eq 'unmacro')
- { #FIXME with 'arg_expansion' should it be passed unmodified ?
- if ($state->{'ignored'})
- {
- $cline =~ s/^\s+(\w+)//;
- }
- else
- {
- delete $macros->{$1} if ($cline =~ s/^\s+(\w+)//);
- }
- return if ($cline =~ /^\s*$/);
- $cline =~ s/^\s*//;
- }
- elsif (exists($macros->{$command}))
- {# it must be before the handling of {, otherwise it is considered
- # to be regular texinfo @-command. Maybe it could be placed higher
- # if we want user defined macros to override texinfo @-commands
- # in 'ignored' we parse macro defined args anyway as it removes
- # some text, but we don't expand the macro
- my $ref = $macros->{$command}->{'args'};
- my $args_number = $#$ref +1;
- # we remove any space/new line before the argument
- if ($cline =~ s/^\s*{\s*//)
- { # the macro has args
- $state->{'macro_args'} = [ "" ];
- $state->{'macro_name'} = $command;
- $state->{'macro_depth'} = 1;
- }
- elsif (($args_number >= 2) or ($args_number <1))
- { # no brace -> no arg
- #$cline =
- #line_warn("\@$command defined with $args_number arguments should be invoked with {}", $line_nr);
- line_warn(sprintf(__("\@%s defined with zero or more than one argument should be invoked with {}"), $command), $line_nr)
- if ($args_number >= 2);
- expand_macro ($command, [], $cline, $line_nr, $state);
- return;
- }
- else
- { # macro with one arg on the line
- chomp $cline;
- #$cline =
- expand_macro ($command, [$cline], "\n", $line_nr, $state);
- return;
- }
- }
- elsif ($cline =~ s/^{//)
- {# we add nested commands in a stack. verb is also on the stack
- # but handled specifically.
- # we add it the comands even in 'ignored' as their result is
- # discarded when the closing brace appear, or the ifset or
- # iclear is closed.
- if ($command eq 'verb')
- {
- if ($cline =~ /^$/)
- {
- line_error (sprintf(__("\@%s without associated character"), $command), $line_nr);
- }
- else
- {
- $cline =~ s/^(.)//;
- $state->{'verb'} = $1;
- }
- }
- if ($state->{'line_command'} and $command eq 'verb')
- { # have to close it now to catch if it is not
- # closed at te end of the line. In subsequent passes this
- # is done in scan_line_separator.
- my $result;
- if (defined($state->{'verb'}))
- {
- $result = '@verb{'.$state->{'verb'};
- my $verb_char = quotemeta($state->{'verb'});
- if ($cline =~ s/^(.*?${verb_char}\})//)
- {
- $result .= $1;
- }
- else
- {
- $cline =~ s/^(.*)//;
- $result .= $1;
- }
- delete $state->{'verb'};
- }
- else
- {
- $result = '@verb{'
- }
- add_prev($text, $stack, $result) unless($state->{'ignored'});
- }
- else
- {
- push (@$stack, { 'style' => $command, 'text' => '' });
- }
- }
- else
- {
- $cline = do_unknown(0, $command, $cline, $text, $stack, $state, $line_nr);
- }
- next;
- }
- #elsif(s/^([^{}@]*)\@(.)//o)
- elsif($cline =~ s/^([^{}@]*)\@([^\s\}\{\@]*)//o)
- {# ARG_EXPANSION
- # No need to warn here for @ followed by a character that
- # is not in any @-command and it is done later
- add_prev($text, $stack, $1) unless($state->{'ignored'});
- $cline = do_unknown(0, $2, $cline, $text, $stack, $state, $line_nr);
- next;
- }
- elsif ($cline =~ s/^([^{}]*)([{}])//o)
- {
- # in ignored section we cannot be sure that there is an @-command
- # already opened so we must discard the text.
- # ARG_EXPANSION
- add_prev($text, $stack, $1) unless($state->{'ignored'});
- if ($2 eq '{')
- {
- # this empty style is for a lone brace.
- # we add it even in 'ignored' as it is discarded when the closing
- # brace appear, or the ifset or iclear is closed.
- push @$stack, { 'style' => '', 'text' => '' };
- }
- else
- {
- if (@$stack)
- {
- my $style = pop @$stack;
- close_style_texi($style, $text, $stack, $state);
- #print STDERR "MACRO end $style->{'style'} remaining: $cline";
- next;
- }
- else
- {# ARG_EXPANSION
- # we warn in the last pass that there is a } without open
- add_prev ($text, $stack, '}') unless($state->{'ignored'});
- }
- }
- }
- else
- {# ARG_EXPANSION
- #print STDERR "END_LINE $cline";
- add_prev($text, $stack, $cline) unless($state->{'ignored'});
- if ($state->{'line_command'})
- {
- if (!scalar(@$stack))
- {
- print STDERR "BUG: empty state for $state->{'line_command'}\n";
- return;
- delete $state->{'line_command'};
- }
- while (!defined($stack->[-1]->{'line_command'}))
- {
- my $top = pop @$stack;
- # defer this to later?
- #line_error ("unclosed command in \@$state->{'line_command'}: $top->{'style'}");
- add_prev($text, $stack, "\@$top->{'style'}".'{'.$top->{'text'}.'}');
- }
- my $command = pop @$stack;
- ###################### debug
- if (!defined($command) or !defined($command->{'text'}) or
- !defined($command->{'line_command'}) or ($command->{'line_command'} ne $state->{'line_command'}))
- {
- msg_debug ("BUG: messed $state->{'line_command'} stack", $line_nr);
- delete $state->{'line_command'};
- return;
- }
- ###################### end debug
- else
- {
- delete $state->{'line_command'};
- my $macro = $command->{'line_command'};
- # include are not kept
- if ($macro eq 'include')
- {
- #if (s/^\s+([\/\w.+-]+)//o)
- if ($command->{'text'} =~ s/^(\s+)(.+)//o)
- {
- my $file_name = $2;
- # FIXME scan_line_separators
- $file_name = trim_around_spaces($file_name);
- $file_name = substitute_line($file_name, "\@$macro", {'code_style' => 1, 'remove_texi' => 1});
- my $file = locate_include_file($file_name);
- if (defined($file))
- {
- my ($line_nr_file, $input_spool_file) = open_file($file, $line_nr->{'macro'}, $state->{'files_stack'});
- ($line_nr, $state->{'input_spool'}) = ($line_nr_file, $input_spool_file) if (defined($line_nr_file));
- print STDERR "# including $file\n" if $T2H_VERBOSE;
- }
- else
- {
- line_error (sprintf(__("\@%s: Cannot find %s"), $macro, $file_name), $line_nr);
- }
- }
- else
- {
- line_error (sprintf(__("Bad argument to \@%s: %s"), $macro, $command->{'text'}), $line_nr);
- }
- return;
- }
- else
- { # these are kept (setfilename, documentencoding, definfoenclose)
- if ($macro eq 'setfilename' and get_conf('USE_SETFILENAME'))
- {
- if (defined(get_conf('setfilename')))
- {
- line_error (sprintf(__("\@%s already set"), $macro), $line_nr);
- # the line is removed, because we don't want to reset
- # get_conf('setfilename') between passes, and we don't want
- # the last one to be picked up
- $cline = "\n";
- next;
- }
- }
- my $cmd_arg;
- ($cline, $cmd_arg) = misc_command_texi($command->{'text'},
- $macro, $state, $line_nr);
- add_prev ($text, $stack, "\@$macro" . $cmd_arg);
- next;
- }
- }
- }
- last;
- }
- }
- return undef if ($state->{'ignored'});
- return 1;
- } # end scan_texi
- sub close_structure_command($$$$)
- {
- my $cmd_ref = shift;
- my $state = shift;
- my $unclosed_commands = shift;
- my $line_nr = shift;
- my $result;
-
- #print STDERR "close_structure_command $cmd_ref->{'style'}\n";
- # If the anchor is in @titlepage or @copying, it is nevertheless only
- # expanded once in pass_structure, during the @copying or @titlepage
- # expansion.
- # It is not true, however if INLINE_INSERTCOPYING is true.
- # See indices/index_special_region.texi tests.
- if ($cmd_ref->{'style'} eq 'anchor')
- {
- my $anchor = $cmd_ref->{'text'};
- $anchor = normalise_node($anchor);
- #print STDERR "Anchor $anchor\n";
- if ($nodes{$anchor})
- {# makeinfo error message are the following:
- # "Anchor `%s' and node `%s' map to the same file name"
- # "This @anchor command ignored; references to it will not work"
- # "Rename this anchor or use the `--no-split' option"
- #
- # "Anchors `%s' and `%s' map to the same file name"
- # "Anchor `%s' and node `%s' map to the same file name"
- # "@anchor command ignored; references to it will not work"
- # "Rename this anchor or use the `--no-split' option"
- line_error (sprintf(__("Anchor `%s' previously defined %s"), $anchor, format_line_number($nodes{$anchor}->{'line_nr'})), $line_nr);
- return '';
- }
- elsif ($anchor =~ /^\(.+\)/)
- {
- line_error (sprintf(__("Syntax for an external node used for `%s'"), $anchor), $line_nr);
- return '';
- }
- $document_anchor_num++;
- $nodes{$anchor} = { 'anchor' => 1, 'seen' => 1, 'texi' => $anchor, 'id' => 'ANC' . $document_anchor_num, 'line_nr' => $line_nr, 'tag' => 'anchor'};
- push @{$state->{'place'}}, $nodes{$anchor};
- }
- elsif ($cmd_ref->{'style'} eq 'footnote')
- {
- if (get_conf('footnotestyle') eq 'separate')
- {
- $state->{'heading_element'} = $state->{'footnote_heading_element'};
- $state->{'place'} = $state->{'footnote_place'};
- }
- }
- elsif ($cmd_ref->{'style'} eq 'caption' or $cmd_ref->{'style'}
- eq 'shortcaption' and $state->{'float'})
- {
- my @texi_lines = map {$_ = $_."\n"} split (/\n/, $cmd_ref->{'text'});
- $state->{'float'}->{$cmd_ref->{'style'} . "_texi"} = \@texi_lines;
- }
- if (($cmd_ref->{'style'} eq 'titlefont') and ($cmd_ref->{'text'} =~ /\S/))
- {
- $state->{'heading_element'}->{'titlefont'} = $cmd_ref->{'text'} unless ((exists($state->{'region'}) and ($state->{'region'} eq 'titlepage')) or defined($state->{'heading_element'}->{'titlefont'})) ;
- }
- if (defined($Texi2HTML::Config::command_handler{$cmd_ref->{'style'}}))
- {
- $result = init_special($cmd_ref->{'style'},$cmd_ref->{'text'});
- if ($unclosed_commands)
- {
- $result .= "\n"; # the end of line is eaten by init_special
- line_error(sprintf(__("No closing brace for specially handled command %s"), $cmd_ref->{'style'}),$line_nr);
- }
- }
- elsif ($cmd_ref->{'style'})
- {
- $result = '@' . $cmd_ref->{'style'} . '{' . $cmd_ref->{'text'};
- $result .= '}' unless ($unclosed_commands);
- }
- else
- {
- $result = '{' . $cmd_ref->{'text'};
- # don't close { if we are closing stack as we are not
- # sure this is a licit { ... } construct.
- $result .= '}' unless ($unclosed_commands);
- }
- return $result;
- }
- sub end_format_structure($$$$$$)
- {
- my $end_tag = shift;
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $line_nr = shift;
- my $remaining_on_line = shift;
- if (defined($state->{'text_macro_stack'})
- and @{$state->{'text_macro_stack'}}
- and ($end_tag eq $state->{'text_macro_stack'}->[-1]))
- {
- pop @{$state->{'text_macro_stack'}};
- if (exists($region_lines{$end_tag}))
- { # end a region_line macro, like documentdescription, copying
- print STDERR "Bug: end_tag $end_tag ne $state->{'region_lines'}->{'format'}\n"
- if ($end_tag ne $state->{'region_lines'}->{'format'});
- print STDERR "Bug: end_tag $end_tag ne $state->{'region'}\n"
- if ($end_tag ne $state->{'region'});
- $state->{'region_lines'}->{'number'}--;
- if ($state->{'region_lines'}->{'number'} == 0)
- {
- close_region($state);
- }
- #dump_stack($text, $stack, $state);
- }
- if (($Texi2HTML::Config::texi_formats_map{$end_tag} eq 'normal') or $Texi2HTML::Config::region_formats_kept{$end_tag})
- {
- $state->{$end_tag}-- if ($Texi2HTML::Config::texi_formats_map{$end_tag} eq 'normal');
- add_prev($text, $stack, "\@end $end_tag");
- }
- else
- {
- #print STDERR "End $end_tag\n";
- #dump_stack($text, $stack, $state);
- return 1 if ($remaining_on_line =~ /^\s*$/);
- }
- }
- elsif ($Texi2HTML::Config::texi_formats_map{$end_tag})
- {
- line_error (sprintf(__("Unmatched `%c%s'"), ord('@'), 'end'), $line_nr);
- #dump_stack($text, $stack, $state);
- }
- elsif ($end_tag eq 'detailmenu' or $end_tag eq 'direntry')
- {
- $state->{$end_tag}-- if $state->{$end_tag};
- add_prev($text, $stack, "\@end $end_tag");
- }
- else
- {
- if ($end_tag eq 'float' and $state->{'float'})
- {
- delete $state->{'float'};
- }
- elsif ($end_tag eq $state->{'table_stack'}->[-1])
- {
- enter_table_index_entry($text, $stack, $state, $line_nr);
- pop @{$state->{'table_stack'}};
- }
- #add end tag
- add_prev($text, $stack, "\@end $end_tag");
- }
- return 0;
- }
- sub parse_menu_entry($)
- {
- my $menu_line = shift;
- my ($node, $name, $ending, $remaining);
- return ($node, $name, $ending, $remaining) unless $menu_line =~ s/^\*//;
- my ($before_colon, $separator);
- ($before_colon, $remaining, $separator) = scan_line_separators($menu_line, ':', 'menu entry');
- if (defined($before_colon) and defined($separator))
- {
- if ($remaining =~ s/^://)
- {
- $node = $before_colon;
- $ending = '::';
- }
- elsif ($remaining =~ /\S/)
- {
- my $after_colon;
- $ending = "";
- ($after_colon, $remaining, $separator) = scan_line_separators($remaining, '\t,\.', 'menu entry node');
- # this certainly corresponds with an error in the node.
- # this is considered not to be a menu entry.
- return (undef, $name, $ending, $remaining) if (!defined($after_colon));
- $node = $after_colon;
- while (1)
- {
- if (!defined($separator) or (defined($separator) and $separator ne '.') or (defined($separator) and (!defined($remaining) or $remaining =~ /^\s/)))
- {
- last;
- }
- $node .= $separator;
- my $after_dot;
- ($after_dot, $remaining, $separator) = scan_line_separators($remaining, '\t,\.', 'menu entry node');
- $after_dot = '' if (!defined($after_dot));
- $node .= $after_dot;
- }
- $name = $before_colon;
- $ending = $separator if (defined($separator));
- # only spaces after the :, this is not a menu entry:
- $node = undef if ($node !~ /\S/);
- }
- }
- # remaining may be defined even if $node isn't.
- #print STDERR "\nLLLL $menu_line";
- #print STDERR " --> node:$node, name:$name, ending:$ending -> $remaining";
- return ($node, $name, $ending, $remaining);
- }
- sub scan_structure($$$$;$)
- {
- my $line = shift;
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $line_nr = shift;
- die "stack not an array ref" unless (ref($stack) eq "ARRAY");
- my $cline = $line;
- #print STDERR "SCAN_STRUCTURE: $line";
- #dump_stack ($text, $stack, $state);
- if (!$state->{'raw'} and (!exists($state->{'region_lines'})))
- {
- #if (!$state->{'verb'} and $state->{'menu'} and $cline =~ /^\*\s+/o)
- if (!$state->{'verb'} and $state->{'menu'})
- {
- # new menu entry
- my ($node, $name, $ending, $remaining) = parse_menu_entry($cline);
- if (defined($node))
- {
- menu_entry_texi(normalise_node($node), $state, $line_nr);
- }
- }
- }
- while(1)
- {
- # scan structure
- #dump_stack($text, $stack, $state);
- #print STDERR "WHILE(s):$cline";
- # as texinfo 4.5
- # verbatim might begin at another position than beginning
- # of line, and end verbatim might too. To end a verbatim section
- # @end verbatim must have exactly one space between end and verbatim
- # things following end verbatim are not ignored.
- #
- # html might begin at another position than beginning
- # of line, but @end html must begin the line, and have
- # exactly one space. Things following end html are ignored.
- # tex and ignore works like html
- #
- # ifnothtml might begin at another position than beginning
- # of line, and @end ifnothtml might too, there might be more
- # than one space between @end and ifnothtml but nothing more on
- # the line.
- # @end itemize, @end ftable works like @end ifnothtml.
- # except that @item on the same line than @end vtable doesn't work
- #
- # text right after the itemize before an item is displayed.
- # @item might be somewhere in a line.
- # strangely @item on the same line than @end vtable doesn't work
- # there should be nothing else than a command following @itemize...
- #
- # see more examples in formatting directory
- if ($state->{'raw'})
- {
- my $tag = $state->{'raw'};
- ################# debug
- if (! @$stack or ($stack->[-1]->{'style'} ne $tag))
- {
- print STDERR "Bug: raw or special: $tag but not on top of stack\n";
- print STDERR "line: $cline";
- dump_stack($text, $stack, $state);
- exit 1;
- }
- ################# end debug
- if ($tag eq 'macro')
- {
- if ($cline =~ /^\s*\@macro\s+(\w[\w-]*)\s*(.*)/)
- {
- $state->{$tag}++;
- }
- }
- # macro_regexp
- if ($cline =~ /^(.*?)\@end\s([a-zA-Z][\w-]*)/o and ($2 eq $tag))
- {
- $cline =~ s/^(.*?)(\@end\s$tag)//;
- add_prev ($text, $stack, $1);
- my $end_text = $2;
- if ($tag eq 'macro')
- {
- $state->{$tag}--;
- if ($state->{$tag})
- {
- add_prev ($text, $stack, $end_text);
- next;
- }
- }
- delete $state->{'raw'};
- my $style = pop @$stack;
- if (defined($Texi2HTML::Config::command_handler{$tag}))
- { # replace the special region by what init_special give
- if ($style->{'text'} !~ /^\s*$/)
- {
- add_prev ($text, $stack, init_special($style->{'style'}, $style->{'text'}));
- }
- }
- else
- {
- add_prev ($text, $stack, $style->{'text'} . "\@end $tag");
- }
- next;
- }
- else
- {
- add_prev ($text, $stack, $cline);
- return if (defined($Texi2HTML::Config::command_handler{$tag}));
- last;
- }
- }
-
- if (defined($state->{'verb'}))
- {
- my $char = quotemeta($state->{'verb'});
- if ($cline =~ s/^(.*?)$char\}/\}/)
- {
- add_prev($text, $stack, $1 . $state->{'verb'});
- $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'};
- delete $state->{'verb'};
- next;
- }
- else
- {
- add_prev($text, $stack, $cline);
- last;
- }
- }
-
- # macro_regexp
- if ($cline =~ s/^([^{}@]*)\@end\s+([a-zA-Z][\w-]*)//)
- {
- add_prev($text, $stack, $1);
- my $end_tag = $2;
- #print STDERR "END STRUCTURE $end_tag\n";
- return if (end_format_structure($end_tag, $text, $stack, $state, $line_nr, $cline));
- next;
- }
- # macro_regexp
- elsif ($cline =~ s/^([^{}@]*)\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/\\])//o or $cline =~ s/^([^{}@]*)\@([a-zA-Z][\w-]*)//o)
- {
- add_prev($text, $stack, $1);
- my $macro = $2;
- #print STDERR "MACRO $macro\n";
- $macro = $alias{$macro} if (exists($alias{$macro}));
- if (defined($Texi2HTML::Config::deprecated_commands{$macro}))
- {
- # makeinfo has
- # "%c%s is obsolete; use %c%s instead"
- if ($Texi2HTML::Config::deprecated_commands{$macro} eq '')
- {
- line_warn(sprintf(__("%c%s is obsolete."), ord('@'), $macro), $line_nr);
- }
- else
- {
- line_warn(sprintf(__("%c%s is obsolete; %s"),ord('@'), $macro, __($Texi2HTML::Config::deprecated_commands{$macro})), $line_nr);
- }
- }
- if (defined($Texi2HTML::Config::misc_command{$macro}))
- {
- my $line;
- ($cline, $line) = misc_command_structure($cline, $macro, $state,
- $line_nr);
- add_prev ($text, $stack, "\@$macro".$line);
- next;
- }
- elsif ($macro eq 'printindex' and ($cline =~ /^\s+(\w+)/))
- {
- my $index_name = $1;
- if (!exists($index_names{$index_name}))
- {
- line_error (sprintf(__("Unknown index `%s' in \@printindex"),$index_name), $line_nr);
- }
- my $associated_element;
- if ($state->{'current_element'} eq $element_before_anything)
- {
- line_warn (sprintf(__("Printindex before document beginning: \@printindex %s"), $index_name), $line_nr);
- }
- else
- {
- # $element_index is the first element with index
- $element_index = $state->{'current_element'} unless (defined($element_index));
- $associated_element = $state->{'current_element'};
- }
- my $region = $state->{'region'};
- $region = 'document' if (!defined($region));
- # FIXME use 'index_name' instead of 'name'
- my $printindex = { 'associated_element' => $associated_element, 'name' => $index_name, 'region' => $region, 'command' => 'printindex' };
- # prepare association of the index to the element by
- # putting it in the current place
- push @{$state->{'place'}}, $printindex;
- push @{$Texi2HTML::THISDOC{'indices'}->{$region}->{$index_name}}, $printindex;
- #print STDERR "PRINTINDEX add($printindex) region $region name $index_name, nr ".scalar(@{$Texi2HTML::THISDOC{'indices'}->{$region}->{$index_name}})."\n";
- add_prev ($text, $stack, "\@$macro" . $cline);
- last;
- }
- elsif ($macro eq 'listoffloats')
- {
- add_prev ($text, $stack, "\@$macro" . $cline);
- last;
- }
- elsif ($sec2level{$macro})
- {
- if ($cline =~ /^\s*(.*)$/)
- {
- my $name = $1;
- my $heading_ref = new_section_heading($macro, $name, $state, $line_nr);
- if (exists($state->{'region_lines'}) and $state->{'region_lines'}->{'format'})
- {
- my $region = $state->{'region_lines'}->{'format'};
- $state->{'region_lines'}->{'head_num'}++;
- my $num = $state->{'region_lines'}->{'head_num'};
- $heading_ref->{'id'} = "${target_prefix}${region}_HEAD$num";
- $heading_ref->{'sec_num'} = "${region}_$num";
- $heading_ref->{'region'} = $region;
- $heading_ref->{'region_head_num'} = $num;
- }
- else
- {
- $document_head_num++;
- $heading_ref->{'id'} = "HEAD$document_head_num";
- $heading_ref->{'sec_num'} = $document_head_num;
- }
- # this is only used when there is a index entry after the
- # heading
- $heading_ref->{'target'} = $heading_ref->{'id'};
- $heading_ref->{'heading'} = 1;
- $heading_ref->{'tag_level'} = $macro;
- $heading_ref->{'number'} = '';
- $state->{'heading_element'} = $heading_ref;
- push @{$state->{'place'}}, $heading_ref;
- $headings{$heading_ref->{'sec_num'}} = $heading_ref;
- push @headings_list, $heading_ref;
- }
- add_prev ($text, $stack, "\@$macro" . $cline);
- last;
- }
- elsif (index_command_prefix($macro) ne '')
- { # if we are already in a (v|f)table the construct is quite
- # wrong
- # FIXME should it be discarded?
- if ($state->{'item'})
- {
- line_error(sprintf(__("ignored \@%s already in an \@%s entry"), $macro, $state->{'item'}), $line_nr);
- next;
- }
- my $index_prefix = index_command_prefix($macro);
- enter_index_entry($index_prefix, $line_nr, $cline, $macro, $state);
- add_prev ($text, $stack, "\@$macro" . $cline);
- last;
- }
- elsif (defined($Texi2HTML::Config::texi_formats_map{$macro}))
- {
- my $macro_kept;
- #print STDERR "TEXT_MACRO: $macro\n";
- if ($Texi2HTML::Config::texi_formats_map{$macro} eq 'raw')
- {
- $state->{'raw'} = $macro;
- $state->{$macro}++ if ($macro eq 'macro');
- #print STDERR "RAW\n";
- }
- elsif ($Texi2HTML::Config::texi_formats_map{$macro} eq 'normal')
- {
- if ($macro eq 'menu')
- {
- delete ($state->{'prev_menu_node'});
- if (!$state->{'node_ref'})
- {
- line_error (sprintf(__("\@%s seen before first \@node"), $macro), $line_nr);
- line_error (__("perhaps your \@top node should be wrapped in \@ifnottex rather than \@ifinfo?"), $line_nr);
- }
- if ($state->{'menu_in_node'})
- {
- line_error (sprintf(__("Multiple \@%s"), $macro), $line_nr);
- }
- $state->{'menu_in_node'}++;
- }
- $state->{$macro}++;
- push @{$state->{'text_macro_stack'}}, $macro;
- #print STDERR "MENU (text_macro_stack: @{$state->{'text_macro_stack'}})\n";
- }
- elsif (exists($region_lines{$macro}))
- {
- if (exists($state->{'region_lines'}) and ($state->{'region_lines'}->{'format'} ne $macro))
- {
- line_error(sprintf(__("\@%s not allowed within %s"), $macro, $state->{'region_lines'}->{'format'}), $line_nr);
- next;
- }
- open_region ($macro, $state);
- if ($Texi2HTML::Config::region_formats_kept{$macro})
- {
- add_prev($text, $stack, "\@$macro");
- $macro_kept = 1;
- $state->{'region_lines'}->{'first_line'} = 1;
- }
- push @{$state->{'text_macro_stack'}}, $macro;
- }
- # if it is a raw formatting command or a menu command
- # we must keep it for later
- if (($state->{'raw'} and (!defined($Texi2HTML::Config::command_handler{$macro}))) or ($Texi2HTML::Config::texi_formats_map{$macro} eq 'normal'))
- {
- add_prev($text, $stack, "\@$macro");
- $macro_kept = 1;
- }
- if ($state->{'raw'})
- {
- push @$stack, { 'style' => $macro, 'text' => '' };
- }
- next if $macro_kept;
- #dump_stack ($text, $stack, $state);
- return if ($cline =~ /^\s*$/);
- }
- elsif ($macro eq 'detailmenu' or $macro eq 'direntry')
- {
- if ($macro eq 'detailmenu' and !$state->{'node_ref'})
- {
- line_error (sprintf(__("\@%s seen before first \@node"), $macro), $line_nr);
- }
- add_prev ($text, $stack, "\@$macro" . $cline);
- $state->{$macro}++;
- last;
- }
- elsif ($macro eq 'float')
- {
- my ($style_texi, $label_texi) = parse_line_arguments($cline, 2, "\@$macro", $line_nr);
- $style_texi = normalise_texi_space($style_texi);
- $label_texi = undef if (defined($label_texi) and ($label_texi =~ /^\s*$/));
- if (defined($label_texi))
- { # The float may be a target for refs if it has a label
- my $error_with_label = 1;
- $label_texi = normalise_node($label_texi);
- if (exists($nodes{$label_texi}) and defined($nodes{$label_texi})
- and $nodes{$label_texi}->{'seen'})
- {
- line_error (sprintf(__("Float label `%s' previously defined %s"), $label_texi, format_line_number($nodes{$label_texi}->{'line_nr'})), $line_nr);
- }
- elsif ($label_texi =~ /^\(.+\)/)
- {
- line_error (sprintf(__("Syntax for an external node used for `%s'"), $label_texi), $line_nr);
- }
- else
- {
- $error_with_label = 0;
- my $float = { };
- if (exists($nodes{$label_texi}) and defined($nodes{$label_texi}))
- { # float appeared in a menu
- $float = $nodes{$label_texi};
- }
- else
- {
- $nodes{$label_texi} = $float;
- }
- $float->{'float'} = 1;
- $float->{'tag'} = 'float';
- $float->{'texi'} = $label_texi;
- $float->{'seen'} = 1;
- $float->{'id'} = $label_texi;
- $float->{'target'} = $label_texi;
- #print STDERR "FLOAT: $float $float->{'texi'}, place $state->{'place'}\n";
- push @{$state->{'place'}}, $float;
- $float->{'element'} = $state->{'current_element'};
- $state->{'float'} = $float;
- $float->{'style_texi'} = $style_texi;
- $float->{'line_nr'} = $line_nr;
- push @floats, $float;
- }
- if ($error_with_label)
- {
- while ($cline =~ /,/)
- {
- $cline =~ s/,.*$//;
- }
- }
- }
- add_prev($text, $stack, "\@$macro" . $cline);
- last;
- }
- elsif (defined($Texi2HTML::Config::def_map{$macro}))
- {
- # @ may protect end of line in @def. We reconstruct lines here.
- # in the texinfo manual is said that spaces after @ collapse
- if ($cline =~ /(\@+)\s*$/)
- {
- my $at_at_end_of_line = $1;
- if ((length($at_at_end_of_line) % 2) == 1)
- {
- #print STDERR "Line continue $cline";
- my $def_line = $cline;
- $def_line =~ s/\@\s*$//;
- chomp($def_line);
- $state->{'in_deff_line'} = "\@$macro" .$def_line;
- return;
- }
- }
- #We must enter the index entries
- my ($prefix, $entry, $argument) = get_deff_index($macro, $cline, $line_nr,1);
- # use deffn instead of deffnx for @-command record
- # associated with index entry
- my $idx_macro = $macro;
- $idx_macro =~ s/x$//;
- enter_index_entry($prefix, $line_nr, $entry, $idx_macro, $state)
- if ($prefix);
- $cline =~ s/(.*)//;
- add_prev($text, $stack, "\@$macro" . $1);
- }
- elsif ($macro =~ /^itemx?$/)
- {
- enter_table_index_entry($text, $stack, $state, $line_nr);
- if ($state->{'table_stack'}->[-1] =~ /^(v|f)?table$/)
- {
- $state->{'item'} = $macro;
- push @$stack, { 'format' => 'index_item', 'text' => '', 'command' => $macro };
- }
- else
- {
- add_prev($text, $stack, "\@$macro");
- }
- }
- elsif ($format_type{$macro} and ($format_type{$macro} eq 'table' or $format_type{$macro} eq 'list' or $macro eq 'multitable'))
- { # We must enter the index entries of (v|f)table thus we track
- # in which table we are
- push @{$state->{'table_stack'}}, $macro;
- add_prev($text, $stack, "\@$macro");
- }
- elsif ($cline =~ s/^{//)
- {
- if ($macro eq 'verb')
- {
- if ($cline =~ /^$/)
- {
- # We already warned in pass texi
- }
- else
- {
- $cline =~ s/^(.)//;
- $state->{'verb'} = $1;
- }
- }
- elsif ($macro eq 'footnote' and (get_conf('footnotestyle') eq 'separate'))
- {
- $state->{'footnote_heading_element'} = $state->{'heading_element'};
- $state->{'footnote_place'} = $state->{'place'};
- $state->{'heading_element'} = $footnote_element;
- $state->{'place'} = $footnote_element->{'place'};
- }
- push (@$stack, { 'style' => $macro, 'text' => '' });
- }
- else
- {
- $cline = do_unknown (1, $macro, $cline, $text, $stack, $state, $line_nr);
- }
- next;
- }
- #elsif($cline =~ s/^([^{}@]*)\@(.)//o)
- elsif($cline =~ s/^([^{}@]*)\@([^\s\}\{\@]*)//o)
- {
- add_prev($text, $stack, $1);
- $cline = do_unknown (1, $2, $cline, $text, $stack, $state, $line_nr);
- next;
- }
- elsif ($cline =~ s/^([^{}]*)([{}])//o)
- {
- add_prev($text, $stack, $1);
- if ($2 eq '{')
- {
- push @$stack, { 'style' => '', 'text' => '' };
- }
- else
- {
- if (@$stack)
- {
- my $style = pop @$stack;
- my $result;
- add_prev ($text, $stack,
- close_structure_command($style, $state, 0, $line_nr));
- next;
- }
- else
- {
- # We warn in the last pass
- add_prev ($text, $stack, '}');
- }
- }
- }
- else
- {
- add_prev($text, $stack, $cline);
- # in case of user mistake, with an @-command not closed on an @item line
- close_stack_structure($text, $stack, $state, $line_nr, 1) if ($state->{'item'});
- enter_table_index_entry($text, $stack, $state, $line_nr);
- #print STDERR "END_LINE(s) $cline";
- #dump_stack($text, $stack, $state);
- last;
- }
- }
- return 1;
- } # end scan_structure
- sub check_bad_end_argument ($$$)
- {
- my $command = shift;
- my $line = shift;
- my $line_nr = shift;
- if ($line =~ /^(\S+)/)
- {
- my $symbols = $1;
- line_error (sprintf(__("Bad argument `%s' to `\@%s', using `%s'"), "${command}${symbols}", 'end', $command), $line_nr);
- }
- }
- sub close_style_command($$$$$;$)
- {
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $line_nr = shift;
- my $line = shift;
- # not the end of the style, but the paragraph the style is in is closed
- my $no_close = shift;
- my $style = pop @$stack;
- my $command = $style->{'style'};
- my $result;
- if (!defined($command))
- {
- print STDERR "Bug: empty style in pass_text\n";
- return ($result, $command);
- }
- if (ref($::style_map_ref->{$command}) eq 'HASH')
- {
- push (@{$style->{'args'}}, $style->{'text'});
- $style->{'fulltext'} .= $style->{'text'};
- if (!defined($style->{'arg_nr'}))
- {
- msg_debug("Bug: undefined 'arg_nr' for $command", $line_nr);
- }
- #print STDERR "DEBUG $command ($style->{'arg_nr'})\n";
- #my $number = 0;
- #foreach my $arg(@{$style->{'args'}})
- #{
- # print STDERR " $number: $arg\n";
- # $number++;
- #}
- #print STDERR "END DEBUG\n";
- $style->{'text'} = $style->{'fulltext'};
- $state->{'keep_texi'} = 0 if (
- ($::style_map_ref->{$command}->{'args'}->[$style->{'arg_nr'}] eq 'keep')
- and ($state->{'keep_nr'} == 1));
- }
- if ($no_paragraph_macro{$command})
- {
- $state->{'no_paragraph'}--;
- pop @{$state->{'no_paragraph_stack'}};
- }
- if ($::style_map_ref->{$command} and (defined($style_type{$command})) and ((!$no_close and ($style_type{$command} eq 'style')) or ($style_type{$command} eq 'accent')))
- {
- my $style_command = pop @{$state->{'command_stack'}};
- if ($style_command ne $command)
- {
- #line_warn ("Bug: $style_command on 'command_stack', not $command", $line_nr);
- # This can be a bug in case of bad nesting, see bad_style_nesting.texi
- line_warn("Bad nesting of \@$style_command and \@$command", $line_nr);
- push @{$state->{'command_stack'}}, $style_command;
- ############################ debug
- if ($T2H_DEBUG)
- {
- push @$stack, $style;
- print STDERR "Stacks before pop top:\n";
- dump_stack($text, $stack, $state);
- pop @$stack;
- ############################ end debug
- }
- }
- }
- if ($state->{'keep_texi'})
- { # don't expand @-commands in anchor, refs...
- close_arg ($command, $style->{'arg_nr'}, $state);
- $result = '@' . $command . '{' . $style->{'text'} . '}';
- }
- elsif ($::things_map_ref->{$command})
- {
- $result = do_thing_command ($command, $style->{'text'}, $state, $line_nr);
- }
- else
- {
- $result = do_style_command($command, $style->{'text'}, $state, $style->{'args'}, $line_nr, $style->{'no_open'}, $no_close, $style->{'keep_line_nr'});
- if ($state->{'code_style'} < 0)
- {
- msg_debug ("Bug: negative code_style: $state->{'code_style'}, line:$line", $line_nr);
- }
- if ($state->{'math_style'} < 0)
- {
- msg_debug ("Bug: negative math_style: $state->{'math_style'}, line:$line", $line_nr);
- }
- }
- return ($result, $command);
- }
- sub top_stack_is_menu($)
- {
- my $stack = shift;
- my $top_stack = top_stack($stack, 1);
- return 0 if (!$format_type{$top_stack->{'format'}} or $format_type{$top_stack->{'format'}} ne 'menu');
- return 1;
- }
- sub scan_line($$$$;$)
- {
- my $original_line = shift;
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $line_nr = shift;
- die "stack not an array ref" unless (ref($stack) eq "ARRAY");
- my $cline = $original_line;
- #msg_debug("SCAN_LINE (@{$state->{'command_stack'}}): $original_line", $line_nr);
- #dump_stack($text, $stack, $state);
- my $new_menu_entry; # true if there is a new menu entry
- # my $menu_description_in_format; # true if we are in a menu description
- # # but in another format section (@table....)
- # this can happen currently with quotations
- if (defined($state->{'prepend_text'}))
- {
- $cline = $state->{'prepend_text'} . $cline;
- $state->{'prepend_text'} = undef;
- delete $state->{'prepend_text'};
- }
- if (!$state->{'raw'} and !$state->{'verb'} and ($state->{'menu'} or $state->{'direntry'}))
- { # new menu entry
- my ($node, $name, $ending, $remaining) = parse_menu_entry($cline);
- if (defined($node))
- {
- $cline = $remaining;
- print STDERR "# Potential menu entry: $node\n" if ($T2H_DEBUG & $DEBUG_MENU);
- $new_menu_entry = 1;
- my $menu_entry = { 'name' => $name, 'node' => $node, 'ending' => $ending };
- # in SIMPLE_MENU case we don't begin a description, description is
- # just some normal (preformatted) text
- if (get_conf('SIMPLE_MENU'))
- {
- add_prev ($text, $stack, do_menu_link($state, $line_nr, $menu_entry));
- #dump_stack($text, $stack, $state);
- }
- else
- {
- # close description and comment, if they are opened.
- #dump_stack($text, $stack, $state);
- if (!close_menu_comment($text, $stack, $state, __("new menu entry"), $line_nr)
- and !close_menu_description($text, $stack, $state, __("new menu entry"), $line_nr)
- and $state->{'preformatted'})
- {
- close_paragraph($text, $stack, $state, __("new menu entry"), $line_nr);
- }
- print STDERR "# New menu entry: $node\n" if ($T2H_DEBUG & $DEBUG_MENU);
- #dump_stack($text, $stack, $state);
- my $fusionned_description = 0;
- # fusionned looks better in preformatted. But some formats
- # want to always distinguish link and description
- if (get_conf('SEPARATE_DESCRIPTION') or !$state->{'preformatted'})
- {
- add_prev ($text, $stack, do_menu_link($state, $line_nr, $menu_entry));
- }
- else
- {
- $fusionned_description = 1;
- }
- push @$stack, {'format' => 'menu_description', 'text' => '', 'menu_entry' => $menu_entry, 'fusionned_description' => $fusionned_description};
- $state->{'code_style'}++ if ($Texi2HTML::Config::format_code_style{'menu_description'});
- if ($fusionned_description)
- {
- begin_paragraph($stack, $state) if $state->{'preformatted'};
- add_prev ($text, $stack, do_menu_link($state, $line_nr, $menu_entry));
- }
- }
- }
- # we may be in a menu entry description, we close it
- # if there is an empty line, so the last arg is $cline.
- # also if right in menu we always open a menu_comment, it
- # means that there was no menu entry seen since the menu beginning.
- if (!$new_menu_entry and (close_menu_description($text, $stack, $state, "end menu description", $line_nr, $cline) or ($stack->[-1]->{'format'} and $format_type{$stack->[-1]->{'format'}} and $format_type{$stack->[-1]->{'format'}} eq 'menu')))
- {
- if ($state->{'preformatted'})
- {
- begin_paragraph($stack, $state);
- }
- else
- {
- # only start a menu_comment if right in menu and not in
- # a format below a menu because if not right
- # in a menu we have no way to distinguish a menu_comment
- # and some normal text in the format.
- # also it is not started in preformatted environment
- begin_format($text, $stack, $state, 'menu_comment', $cline, $line_nr) if ($stack->[-1]->{'format'} and $format_type{$stack->[-1]->{'format'}} and $format_type{$stack->[-1]->{'format'}} eq 'menu');
- }
- }
- }
- my $first_command_on_line;
- my $commands_count = -1;
- unless ($state->{'raw'} or $state->{'verb'} or $state->{'keep_texi'})
- {
- # first the line commands are taken into account
- $first_command_on_line = next_tag($cline);
- if (defined($first_command_on_line) and defined($Texi2HTML::Config::line_command_map{$first_command_on_line}))
- {
- close_paragraph($text, $stack, $state, "\@$first_command_on_line", $line_nr, 1) if (stop_paragraph_command($first_command_on_line));
- my $arg_texi = $cline;
- $arg_texi =~ s/^\s*\@$first_command_on_line\s*//;
- $arg_texi = trim_comment_spaces ($arg_texi, "\@$first_command_on_line", $line_nr);
- my $arg_line = substitute_line($arg_texi, "\@$first_command_on_line", duplicate_formatting_state($state));
- add_prev ($text, $stack, &$Texi2HTML::Config::line_command($first_command_on_line, $arg_line, $arg_texi, $state));
- enter_author_command ($first_command_on_line, $arg_texi, $arg_line, $stack, $state, $line_nr) if ($first_command_on_line eq 'author');
- return '';
- }
- elsif (defined($first_command_on_line) and ($first_command_on_line eq 'contents') or ($first_command_on_line eq 'summarycontents') or ($first_command_on_line eq 'shortcontents'))
- {
- my $element_tag = $first_command_on_line;
- $element_tag = 'shortcontents' if ($element_tag ne 'contents');
- # at that point the content_element is defined for sure since
- # we already saw the tag
- if (get_conf('INLINE_CONTENTS') and !get_conf('set' . $element_tag . 'aftertitlepage'))
- {
- my $content_element = shift (@{$all_content_elements{$element_tag}});
- my $toc_lines = &$Texi2HTML::Config::inline_contents($Texi2HTML::THISDOC{'FH'}, $element_tag, $content_element, \@sections_list);
- add_prev ($text, $stack, join('',@$toc_lines)) if (defined($toc_lines));
- }
- return '' unless (exists($Texi2HTML::Config::misc_command{$first_command_on_line}) and $Texi2HTML::Config::misc_command{$first_command_on_line}->{'keep'});
- }
- # The commands to ignore are ignored now in case after ignoring them
- # there is an empty line, to be able to stop the paragraph
- #my $leading_spaces = '';
-
- while (1)
- {
- my $next_tag = next_tag($cline);
- close_paragraph($text, $stack, $state, "\@$next_tag", $line_nr, 1) if (stop_paragraph_command($next_tag));
- if (defined($next_tag) and defined($Texi2HTML::Config::misc_command{$next_tag}) and !$Texi2HTML::Config::misc_command{$next_tag}->{'keep'})
- {
- $commands_count++;
- # FIXME reenable when it is possible
- #line_warn (sprintf(__('%s must only appear at the beginning of a line'), $next_tag), $line_nr) if ($commands_count and $begin_line_command{$next_tag});
- $cline =~ s/^(\s*)\@$next_tag//;
- #$leading_spaces .= $1;
- add_prev ($text, $stack, do_text($1, $state));
- my $result;
- ($cline, $result) = misc_command_text($cline, $next_tag, $stack, $state, $text, $line_nr);
- add_prev($text, $stack, $result) if (defined($result));
- }
- else
- {
- last;
- }
- }
- #add_prev ($text, $stack, $leading_spaces);
- return '' if (!defined($cline) or $cline eq '');
- }
- my $top_stack = top_stack($stack);
- if (($top_stack->{'format'} and $top_stack->{'format'} eq 'menu_description') or $state->{'raw'} or $state->{'preformatted'} or $state->{'no_paragraph'} or $state->{'keep_texi'} or $state->{'remove_texi'})
- { # empty lines are left unmodified in these contexts.
- # it is also possible to be in preformatted within a menu_description
- if ($cline =~ /^\s*$/)
- {
- if ($state->{'raw'})
- {
- print STDERR "#within raw $state->{'raw'}(empty line):$cline" if ($T2H_DEBUG & $DEBUG_FORMATS);
- add_prev($text, $stack, $cline);
- }
- else
- {
- add_prev($text, $stack, do_text($cline,$state));
- }
- return;
- }
- }
- else
- {
- if ($cline =~ /^\s*$/)
- {
- if ($state->{'paragraph_context'})
- { # An empty line ends a paragraph
- close_paragraph($text, $stack, $state, __("paragraph end"), $line_nr);
- }
- add_prev($text, $stack, &$Texi2HTML::Config::empty_line($cline,$state));
- return 1;
- }
- else
- {
- if (!no_paragraph($state,$cline))
- { # open a paragraph, unless the line begins with a macro that
- # shouldn't trigger a paragraph opening
- begin_paragraph($stack, $state);
- }
- }
- }
- # we flag specially deff_item and table line that contain only
- # inter_item_command, which typically is be @c, @comment, @*index, such
- # that the formatter can treat those specifically.
- my $top_format = top_stack($stack,2);
- if ($top_format->{'only_inter_commands'} and !$state->{'keep_texi'})
- {
- my $real_format = $top_format->{'format_ref'}->{'format'};
- my $next_tag = next_tag($cline);
- $next_tag = '' if (!defined($next_tag));
- my $next_end_tag = next_end_tag($cline);
- $next_end_tag = '' if (!defined($next_end_tag));
- #msg_debug("$top_format->{'format'} $next_tag, end $next_end_tag :::$cline");
- delete $top_format->{'only_inter_commands'} unless
- (
- $Texi2HTML::Config::inter_item_commands{$next_tag} or
- (index_command_prefix($next_tag) ne '' and $Texi2HTML::Config::inter_item_commands{'cindex'}) or
- ($top_format->{'format'} eq 'deff_item' and "${real_format}x" eq $next_tag) or
- ($top_format->{'format'} ne 'deff_item' and $next_tag =~ /^itemx?$/) or
- ( $next_end_tag eq $real_format )
- );
- #print STDERR "STILL $top_format->{'only_inter_commands'}\n" if ($top_format->{'only_inter_commands'});
- }
- while(1)
- {
- # scan_line
- #print STDERR "WHILE(l): $cline|";
- #msg_debug("Dump stack in scan_line", $line_nr);
- #dump_stack($text, $stack, $state);
- # we're in a raw format (html, tex if !L2H, verbatim)
- if (defined($state->{'raw'}))
- {
- (dump_stack($text, $stack, $state), die "Bug for raw ($state->{'raw'})") if (! @$stack or ! ($stack->[-1]->{'style'} eq $state->{'raw'}));
- if ($state->{'raw'} eq 'macro')
- {
- if ($cline =~ /^\s*\@macro\s+(\w[\w-]*)\s*(.*)/)
- {
- $state->{$state->{'raw'}}++;
- }
- }
- # macro_regexp
- if ($cline =~ /^(.*?)\@end\s([a-zA-Z][\w-]*)/o and ($2 eq $state->{'raw'}))
- # don't protect html, it is done by Texi2HTML::Config::raw if needed
- {
- $cline =~ s/^(.*?)(\@end\s$state->{'raw'})//;
- my $remaining = $1;
- my $end_text = $2;
- if ($state->{'raw'} eq 'macro')
- {
- $state->{$state->{'raw'}}--;
- if ($state->{$state->{'raw'}})
- {
- add_prev ($text, $stack, $remaining.$end_text);
- last;
- }
- }
- check_bad_end_argument ($state->{'raw'}, $cline, $line_nr);
- add_prev ($text, $stack, $remaining);
- my $style = pop @$stack;
- if ($style->{'text'} !~ /^\s*$/)
- {
- if ($state->{'keep_texi'})
- {
- add_prev ($text, $stack, $style->{'text'} . "\@end $state->{'raw'}");
- }
- elsif ($state->{'remove_texi'})
- {
- add_prev ($text, $stack, &$Texi2HTML::Config::raw_no_texi($style->{'style'}, $style->{'text'}));
- }
- else
- {
- add_prev($text, $stack, &$Texi2HTML::Config::raw($style->{'style'}, $style->{'text'}, $line_nr));
- }
- }
- if (!$state->{'keep_texi'} and !$state->{'remove_texi'})
- {
- # reopen preformatted if it was interrupted by the raw format
- # if raw format is html the preformatted wasn't interrupted
- begin_paragraph($stack, $state) if ($state->{'preformatted'} and (!$Texi2HTML::Config::format_in_paragraph{$state->{'raw'}}));
- delete $state->{'raw'};
- return if ($cline =~ /^\s*$/);
- }
- delete $state->{'raw'};
- return if (($cline =~ /^\s*$/) and $state->{'remove_texi'});
- next;
- }
- else
- {
- print STDERR "#within raw $state->{'raw'}:$cline" if ($T2H_DEBUG & $DEBUG_FORMATS);
- add_prev ($text, $stack, $cline);
- last;
- }
- }
- # we are within a @verb
- if (defined($state->{'verb'}))
- {
- my $char = quotemeta($state->{'verb'});
- if ($cline =~ s/^(.*?)$char\}/\}/)
- {
- if ($state->{'keep_texi'})
- {
- add_prev($text, $stack, $1 . $state->{'verb'});
- $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'};
- }
- else
- {
- add_prev($text, $stack, do_text($1, $state));
- }
- delete $state->{'verb'};
- next;
- }
- else
- {
- add_prev($text, $stack, $cline);
- last;
- }
- }
- # We handle now the end tags
- # macro_regexp
- if ($cline =~ s/^([^{}@]*)\@end\s+([a-zA-Z][\w-]*)//)
- {
- $commands_count++;
- my $end_tag = $2;
- my $prev_text = $1;
- if ($state->{'keep_texi'})
- {
- add_prev($text, $stack, $prev_text . "\@end $end_tag");
- next;
- }
- elsif ($state->{'remove_texi'})
- {
- add_prev($text, $stack, $prev_text);
- next;
- }
- add_prev($text, $stack, do_text($prev_text, $state));
- #print STDERR "END_MACRO $end_tag\n";
- #dump_stack ($text, $stack, $state);
- # FIXME reenable when it is possible
- #line_warn (sprintf(__('%s must only appear at the beginning of a line'), 'end'), $line_nr) if ($commands_count or !$first_command_on_line);
- # First we test if the stack is not empty.
- # Then we test if the end tag is a format tag.
- # We then close paragraphs and preformatted at top of the stack.
- # We handle the end tag (even when it was not the tag which appears
- # on the top of the stack; in that case we close anything
- # until that element)
- my $top_stack = top_stack($stack);
- if (!$top_stack)
- {
- line_error (sprintf(__("Unmatched `%c%s'"), ord('@'), 'end'), $line_nr);
- add_prev($text, $stack, "\@end $end_tag");
- next;
- }
- if (!$format_type{$end_tag})
- {
- line_warn ("Unknown \@end $end_tag", $line_nr);
- add_prev($text, $stack, "\@end $end_tag");
- next;
- }
- check_bad_end_argument ($end_tag, $cline, $line_nr);
- if (!close_menu_description($text, $stack, $state, "\@end $end_tag", $line_nr))
- {
- close_paragraph($text, $stack, $state, "\@end $end_tag", $line_nr);
- }
- $top_stack = top_stack($stack);
- if (!$top_stack or (!defined($top_stack->{'format'})))
- {
- line_error (sprintf(__("Unmatched `%c%s'"), ord('@'), 'end'), $line_nr);
- add_prev($text, $stack, "\@end $end_tag");
- dump_stack ($text, $stack, $state) if ($T2H_DEBUG);
- next;
- }
- # Warn if the format on top of stack is not compatible with the
- # end tag, and find the end tag.
- unless (
- ($top_stack->{'format'} eq $end_tag)
- or
- (
- $format_type{$end_tag} eq 'menu' and
- $top_stack->{'format'} eq 'menu_comment'
- ) or
- (
- $end_tag eq 'multitable' and $top_stack->{'format'} eq 'cell'
- ) or
- (
- $format_type{$end_tag} eq 'list' and $top_stack->{'format'} eq 'item'
- ) or
- (
- $format_type{$end_tag} eq 'table'
- and
- ($top_stack->{'format'} eq 'term' or $top_stack->{'format'} eq 'line')
- ) or
- (
- defined($Texi2HTML::Config::def_map{$end_tag}) and
- $top_stack->{'format'} eq 'deff_item'
- )
- )
- {
- # this is not the right format. We try to close other
- # formats to find the format we are searching for.
- # First we close paragraphs, as with a wrong $end_format
- # they may not be closed properly.
- #print STDERR " MISMATCH got $top_stack->{'format'} waited \@end $end_tag($top_stack->{'format'})\n";
- #dump_stack ($text, $stack, $state);
- close_paragraph($text, $stack, $state, "\@end $end_tag", $line_nr);
- $top_stack = top_stack($stack);
- if (!$top_stack or (!defined($top_stack->{'format'})))
- {
- line_error (sprintf(__("Unmatched `%c%s'"), ord('@'), 'end'), $line_nr);
- add_prev($text, $stack, "\@end $end_tag");
- # at that point the dump_stack is not very useful, since
- # close_paragraph above may hide interesting info
- dump_stack ($text, $stack, $state) if ($T2H_DEBUG);
- next;
- }
- my $waited_format = $top_stack->{'format'};
- $waited_format = $fake_format{$top_stack->{'format'}} if ($format_type{$top_stack->{'format'}} eq 'fake');
- if ($end_tag ne $waited_format)
- {
- line_error (sprintf(__("`\@end' expected `%s', but saw `%s'"), $waited_format, $end_tag), $line_nr);
- }
- else
- {
- msg_debug ("\@end is $end_tag, was waiting for $top_stack->{'format'}", $line_nr);
- dump_stack ($text, $stack, $state);
- }
- close_stack($text, $stack, $state, $line_nr, $end_tag);
- # FIXME this is too complex
- # an empty preformatted may appear when closing things as
- # when closed, formats reopen the preformatted environment
- # in case there is some text following, but we know it isn't
- # the case here, thus we can close paragraphs.
- close_paragraph($text, $stack, $state, "\@end $end_tag");
- my $new_top_stack = top_stack($stack);
- next unless ($new_top_stack and defined($new_top_stack->{'format'}) and (($new_top_stack->{'format'} eq $end_tag)
- or (($format_type{$new_top_stack->{'format'}} eq 'fake') and ($fake_format{$new_top_stack->{'format'}} eq $format_type{$end_tag}))));
- }
- # We should now be able to handle the format
- if (defined($format_type{$end_tag}))
- {# remove the space or new line following the @end command
- $cline =~ s/\s//;
- if (end_format($text, $stack, $state, $end_tag, $line_nr))
- { # if end_format is false, paragraph is already begun
- begin_paragraph_after_command($state,$stack,$end_tag,$cline);
- }
- }
- next;
- }
- # This is a macro
- #elsif (s/^([^{}@]*)\@([a-zA-Z]\w*|["'~\@\}\{,\.!\?\s\*\-\^`=:\/])//o)
- # macro_regexp
- elsif ($cline =~ s/^([^{},@]*)\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/\\])//o or $cline =~ s/^([^{}@,]*)\@([a-zA-Z][\w-]*)//o)
- {
- my $before_macro = $1;
- my $macro = $2;
- $commands_count++;
- $macro = $alias{$macro} if (exists($alias{$macro}));
- my $punct;
- if (!$state->{'keep_texi'} and $macro eq ':' and $before_macro =~ /(.)$/ and $Texi2HTML::Config::colon_command_punctuation_characters{$1})
- {
- $before_macro =~ s/(.)$//;
- $punct = $1;
- }
- add_prev($text, $stack, do_text($before_macro, $state));
- add_prev($text, $stack, &$Texi2HTML::Config::colon_command($punct)) if (defined($punct));
- #print STDERR "MACRO $macro\n";
- #print STDERR "LINE $cline";
- #dump_stack ($text, $stack, $state);
- # FIXME reenable when it is possible
- #line_warn (sprintf(__('%s must only appear at the beginning of a line'), $macro), $line_nr) if ($begin_line_command{$macro} and ($commands_count or !$first_command_on_line) and !$state->{'keep_texi'});
- close_paragraph($text, $stack, $state, "\@$macro", $line_nr, 1) if (stop_paragraph_command($macro) and !$state->{'keep_texi'});
- if ($macro eq 'listoffloats' or $macro eq 'printindex')
- {
- if ($state->{'keep_texi'})
- {
- if ($cline =~ s/(.*)//o)
- {
- add_prev($text, $stack, "\@$macro" . $1);
- }
- next;
- }
- close_paragraph($text, $stack, $state, "\@$macro", $line_nr);
- return undef if ($state->{'remove_texi'});
- if ($macro eq 'listoffloats')
- {
- # remove possible comments
- my $arg = normalise_texi_space(trim_comment_spaces ($cline, "\@$macro", $line_nr));
- my $style_id = cross_manual_line($arg);
- my $style = substitute_line (&$Texi2HTML::Config::listoffloats_style($arg), __("\@listoffloats type"), undef, $line_nr);
- my $style_no_texi = remove_texi (&$Texi2HTML::Config::listoffloats_style($arg));
- if (exists ($floats{$style_id}))
- {
- my @listoffloats_entries = ();
- foreach my $float (@{$floats{$style_id}->{'floats'}})
- {
- my $float_style = substitute_line(&$Texi2HTML::Config::listoffloats_float_style($arg, $float), __("\@listoffloats \@float type"));
- my ($caption_lines, $caption_or_shortcaption) = &$Texi2HTML::Config::listoffloats_caption($float);
- # we set 'multiple_pass', and 'expansion'
- # such that index entries
- # and anchors are not handled one more time;
- # the caption has already been formatted,
- # and these have been handled at the right place
- # FIXME footnotes?
- my $caption = '';
- $caption = substitute_text(prepare_state_multiple_pass($macro, $state), undef, "\@$caption_or_shortcaption in listoffloats", @$caption_lines) if (defined($caption_or_shortcaption));
- push @listoffloats_entries, &$Texi2HTML::Config::listoffloats_entry($arg, $float, $float_style, $caption, href($float, $state->{'element'}->{'file'}, $line_nr));
- }
- add_prev($text, $stack, &$Texi2HTML::Config::listoffloats($arg, $style, \@listoffloats_entries));
- }
- else
- {
- line_warn (sprintf(__("Requested float type `%s' not previously used"), $arg), $line_nr);
- }
- }
- elsif ($macro eq 'printindex' and $cline =~ s/\s+(\w+)\s*//)
- {
- my $index_name = $1;
- my $region = $state->{'region'};
- $region = 'document' if (!defined($region));
- if (!defined($Texi2HTML::THISDOC{'indices'}->{$region}))
- {
- msg_debug ("\@printindex $index_name THISDOC{'indices'}->{$region} not defined", $line_nr);
- }
- elsif (!defined($Texi2HTML::THISDOC{'indices'}->{$region}->{$index_name}))
- {
- msg_debug ("\@printindex $index_name THISDOC{'indices'}->{$region}->{$index_name} not defined", $line_nr);
- }
- if (!defined($Texi2HTML::THISDOC{'indices_numbers'}->{$region}->{$index_name}))
- {
- $Texi2HTML::THISDOC{'indices_numbers'}->{$region}->{$index_name} = -1;
- }
- $Texi2HTML::THISDOC{'indices_numbers'}->{$region}->{$index_name}++;
- my $printindex = $Texi2HTML::THISDOC{'indices'}->{$region}->{$index_name}->[$Texi2HTML::THISDOC{'indices_numbers'}->{$region}->{$index_name}];
- if (!defined($printindex))
- {
- # this printindex hasn't been seen in the previous pass.
- # rint STDERR "Index $index_name not in sync, number $Texi2HTML::THISDOC{'indices_numbers'}->{$index_name} not defined\n";
- line_warn("\@printindex $index_name expanded more than once may lead to wrong references", $line_nr);
- $printindex = $Texi2HTML::THISDOC{'indices'}->{$region}->{$index_name}->[-1];
- }
- elsif ($printindex->{'name'} ne $index_name)
- {
- print STDERR "BUG: THISDOC{'indices'} $printindex->{'name'} ne $index_name\n";
- }
- #print STDERR "PRINTINDEX use($printindex) region $region, name $index_name number $Texi2HTML::THISDOC{'indices_numbers'}->{$region}->{$index_name}\n";
- add_prev($text, $stack, &$Texi2HTML::Config::printindex($index_name, $printindex));
- }
- else
- {
- $cline =~ s/^\s*//;
- chomp ($cline);
- line_error (sprintf(__("Bad argument to \@%s: %s"), $macro, $cline), $line_nr);
- }
- begin_paragraph ($stack, $state) if ($state->{'preformatted'});
- return undef;
- }
- if (defined($Texi2HTML::Config::misc_command{$macro}))
- {
- # Handle the misc command
- my $result;
- ($cline, $result) = misc_command_text($cline, $macro, $stack, $state, $text, $line_nr);
- add_prev($text, $stack, $result) if (defined($result));
- return unless (defined($cline));
- unless ($Texi2HTML::Config::misc_command{$macro}->{'keep'})
- {
- begin_paragraph($stack, $state) if
- (!no_paragraph($state,$cline));
- next;
- }
- }
- # This is a @macroname{...} construct. We add it on top of stack
- # It will be handled when we encounter the '}'
- # There is a special case for def macros as @deffn{def} is licit
- if (!$Texi2HTML::Config::def_map{$macro} and $cline =~ s/^{//) #}
- {
- if ($macro eq 'verb')
- {
- if ($cline =~ /^$/)
- {
- # Allready warned
- }
- else
- {
- $cline =~ s/^(.)//;
- $state->{'verb'} = $1;
- }
- }
- # currently if remove_texi and anchor/ref/footnote
- # the text within the command is ignored
- # see t2h_remove_command in texi2html.pm
- my $new_command_ref = { 'style' => $macro, 'text' => '', 'arg_nr' => 0, 'line_nr' => $line_nr };
- push (@$stack, $new_command_ref);
- if ($no_paragraph_macro{$macro})
- {
- $state->{'no_paragraph'}++;
- push @{$state->{'no_paragraph_stack'}}, "\@$macro";
- }
- open_arg($macro, 0, $state);
- if ($state->{'keep_texi'})
- {
- $new_command_ref->{'keep_line_nr'} = [ $line_nr ];
- }
- my $real_style_command = 0;
- if (defined($style_type{$macro}) and (($style_type{$macro} eq 'style') or ($style_type{$macro} eq 'accent')))
- {
- push (@{$state->{'command_stack'}}, $macro);
- $real_style_command = 1;
- #print STDERR "# Stacked $macro (@{$state->{'command_stack'}})\n" if ($T2H_DEBUG);
- }
- # FIXME give line, and modify line?
- &$Texi2HTML::Config::begin_style_texi($macro, $state, $stack, $real_style_command, $state->{'remove_texi'})
- if (defined($Texi2HTML::Config::begin_style_texi)
- and !($state->{'keep_texi'}));
- next;
- }
- # special case if we are checking itemize line. In that case
- # we want to make sure that there is no @item on the @itemize
- # line, otherwise it will be added on the front of another @item,
- # leading to an infinite loop...
- if ($state->{'check_item'} and ($macro =~ /^itemx?$/ or $macro eq 'headitem'))
- {
- line_error(sprintf(__("\@%s not allowed in argument to \@%s"), $macro, $state->{'check_item'}), $line_nr);
- next;
- }
- # if we're keeping texi unmodified we can do it now
- if ($state->{'keep_texi'})
- {
- # We treat specially formats accepting {} on command line
- if ($macro eq 'multitable' or defined($Texi2HTML::Config::def_map{$macro}) or defined($sec2level{$macro}) or $macro eq 'macro')
- {
- add_prev($text, $stack, "\@$macro" . $cline);
- $cline = '';
- next;
- }
- add_prev($text, $stack, "\@$macro");
- if ($Texi2HTML::Config::texi_formats_map{$macro} and $Texi2HTML::Config::texi_formats_map{$macro} eq 'raw')
- {
- $state->{'raw'} = $macro;
- $state->{$macro}++ if ($macro eq 'macro');
- push (@$stack, {'style' => $macro, 'text' => ''});
- }
- next;
- }
- # If we are removing texi, the following macros are not removed
- # as is but modified. So they are collected first, as if we were
- # in normal text
- # a raw macro beginning
- if ($Texi2HTML::Config::texi_formats_map{$macro} and $Texi2HTML::Config::texi_formats_map{$macro} eq 'raw')
- {
- if (!$Texi2HTML::Config::format_in_paragraph{$macro})
- { # close paragraph before verbatim (and tex if !L2H)
- close_paragraph($text, $stack, $state, "\@$macro", $line_nr);
- }
- $state->{'raw'} = $macro;
- push (@$stack, {'style' => $macro, 'text' => ''});
- $state->{$macro}++ if ($macro eq 'macro');
- return if ($cline =~ /^\s*$/ or ($macro eq 'macro'));
- next;
- }
- my $simple_macro = 1;
- # An accent macro
- if (exists($Texi2HTML::Config::accent_map{$macro}))
- {
- # the command itself is not in the command stack, since with
- # braces, it is already popped when do_simple is called
- #push (@{$state->{'command_stack'}}, $macro);
- if ($macro =~ /^[a-zA-Z]/)
- {
- $cline =~ s/^\s*//;
- }
- elsif ($cline =~ /^\s/)
- {
- line_warn (sprintf(__("Accent command `\@%s' must not be followed by whitespace"), $macro), $line_nr);
- }
- if ($cline =~ /^\@/)
- {
- line_error (sprintf(__("Use braces to give a command as an argument to \@%s"), $macro), $line_nr);
- }
- if ($cline =~ s/^(\S)//o)
- {
- add_prev($text, $stack, do_style_command($macro, $1, $state, [ $1 ], $line_nr, undef, undef, undef));
- }
- else
- { # The accent is at end of line
- # FIXME warn? And test case? Maybe this is catched
- # above, by "Accent command `@%s' must not be followed by whitespace"
- # for commands with letter.
- add_prev($text, $stack, do_text($macro, $state));
- }
- #pop @{$state->{'command_stack'}};
- }
- # an @-command which should be like @command{}. We handle it...
- elsif ($::things_map_ref->{$macro})
- {
- line_error (sprintf(__("\@%s expected braces"), $macro), $line_nr);
- add_prev($text, $stack, do_thing_command($macro, '', $state, $line_nr));
- }
- # an @-command like @command
- elsif (defined($::simple_map_ref->{$macro}) or ($state->{'math_style'} and defined($::simple_map_math_ref->{$macro})))
- {
- add_prev($text, $stack, do_simple_command($macro, $state, $line_nr));
- }
- else
- {
- $simple_macro = 0;
- }
- if ($simple_macro)
- {# if the macro didn't triggered a paragraph start it might now
- begin_paragraph($stack, $state) if
- ($Texi2HTML::Config::no_paragraph_commands{$macro} and !no_paragraph($state,$cline));
- next;
- }
- # the following macros are modified or ignored if we are
- # removing texi, and they are not handled like macros in normal text
- if ($state->{'remove_texi'})
- {
- # handle specially some macros
- if ((index_command_prefix($macro) ne '') or
- ($macro eq 'itemize') or
- ($format_type{$macro} and ($format_type{$macro} eq 'table' or $format_type{$macro} eq 'quotation'))
- or ($macro eq 'multitable'))
- {
- return;
- }
- elsif ($macro eq 'enumerate')
- {
- my $spec;
- ($cline, $spec) = parse_enumerate ($cline);
- return if ($cline =~ /^\s*$/);
- next;
- }
- elsif (defined($Texi2HTML::Config::def_map{$macro}))
- {
- my ($command, $style, $category, $name, $type, $class, $arguments, $args_array);
- ($command, $style, $category, $name, $type, $class, $arguments, $args_array) = parse_def($macro, $cline, $line_nr);
- # FIXME -- --- ''... lead to simple text in texi2html
- # while they are kept as is in html coments by makeinfo
- $category = remove_texi($category) if (defined($category));
- $name = remove_texi($name) if (defined($name));
- $type = remove_texi($type) if (defined($type));
- $class = remove_texi($class) if (defined($class));
- $arguments = remove_texi($arguments) if (defined($arguments));
- chomp($arguments);
- add_prev($text, $stack, &$Texi2HTML::Config::def_line_no_texi($category, $name, $type, $arguments));
- return;
- }
- elsif (defined($sec2level{$macro}) and $macro =~ /heading/)
- { #FIXME there is certainly more intelligent stuff to do
- my $num;
- if ($state->{'region'})
- {
- $state->{'head_num'}++;
- $num = "$state->{'region'}_$state->{'head_num'}";
- }
- else
- {
- $num = $global_head_num;
- }
- my $heading_element = $headings{$num};
- $cline = trim_comment_spaces ($cline, "\@$macro");
- add_prev($text, $stack, &$Texi2HTML::Config::heading_no_texi($heading_element, $macro, $cline));
- return;
- }
- # ignore other macros
- next;
- }
- # handle the other macros, we are in the context of normal text
- if (defined($sec2level{$macro}) and $macro =~ /heading/)
- {
- #dump_stack($text, $stack, $state);
- my $num;
- if ($state->{'region'})
- {
- $state->{'head_num'}++;
- $num = "$state->{'region'}_$state->{'head_num'}";
- }
- else
- {
- $global_head_num++;
- $num = $global_head_num;
- }
- my $heading_element = $headings{$num};
- $cline = trim_comment_spaces($cline, "\@$macro", $line_nr);
- add_prev($text, $stack, &$Texi2HTML::Config::element_label($heading_element->{'id'}, $heading_element, $macro, $cline));
- add_prev($text, $stack, &$Texi2HTML::Config::heading($heading_element, $macro, $cline, substitute_line($cline, "\@$macro"), $state->{'preformatted'}));
- return;
- }
- elsif (index_command_prefix($macro) ne '')
- {
- my $index_name = index_command_prefix($macro);
- my $entry_texi = trim_comment_spaces($cline, "\@$macro", $line_nr);
- chomp($entry_texi);
- # multiple_pass is not really necessary, since it may be the place
- # where it is expanded once. However, this ensures that things
- # that are ignored with multiple_pass are ignored.
- my $entry_text = substitute_line($entry_texi, "\@$macro", prepare_state_multiple_pass($macro, $state));
- my ($index_entry, $formatted_index_entry, $index_label) = do_index_entry_label($macro,$state,$line_nr, $entry_texi);
- if (defined($index_entry))
- {
- msg_debug ("(bug?) Index out of sync `$index_entry->{'texi'}' ne `$entry_texi'", $line_nr) if ($index_entry->{'texi'} ne $entry_texi);
- }
- add_prev($text, $stack, &$Texi2HTML::Config::index_entry_command($macro, $index_name, $index_label, $entry_texi, $entry_text, $index_entry));
- # it eats the end of line and therefore don't start
- # table entries nor close @center. These should be stopped
- # on the next line, though.
- return;
- }
- elsif ($macro eq 'insertcopying')
- {
- #close_paragraph($text, $stack, $state, $line_nr);
- add_prev($text, $stack, do_insertcopying($state, $line_nr));
- # reopen a preformatted format if it was interrupted by the macro
- begin_paragraph ($stack, $state) if ($state->{'preformatted'});
- return;
- }
- elsif ($macro =~ /^itemx?$/o or ($macro eq 'headitem'))
- {
- #print STDERR "ITEM: $cline";
- #dump_stack($text, $stack, $state);
- abort_empty_preformatted($stack, $state);
- # FIXME let the user be able not to close the paragraph
- close_paragraph($text, $stack, $state, "\@$macro", $line_nr);
- #print STDERR "ITEM after close para: $cline";
- #dump_stack($text, $stack, $state);
- # these functions return the format if in the right context
- my $in_list_enumerate;
- my $format;
- if ($format = add_item($text, $stack, $state, $line_nr))
- { # handle lists
- $in_list_enumerate = 1;
- if ($macro ne 'item')
- {
- line_error (sprintf(__("\@%s not meaningful inside `\@%s' block"), $macro, $format->{'format'}), $line_nr);
- }
- }
- elsif ($format = add_term($text, $stack, $state, $line_nr))
- { # close table term
- }
- elsif ($format = add_line($text, $stack, $state, $line_nr))
- { # close table definition
- }
- if ($format)
- {
- if ($macro eq 'headitem')
- {
- line_error (sprintf(__("\@%s not meaningful inside `\@%s' block"), $macro, $format->{'format'}), $line_nr);
- }
- if (defined($Texi2HTML::Config::tab_item_texi))
- {
- my $resline = &$Texi2HTML::Config::tab_item_texi($macro, $state->{'command_stack'}, $stack, $state, $cline, $line_nr);
- $cline = $resline if (defined($resline));
- }
- if ($in_list_enumerate)
- {
- push (@$stack, { 'format' => 'item', 'text' => '', 'format_ref' => $format, 'item_cmd' => $macro });
- begin_paragraph($stack, $state) if ($state->{'preformatted'} or !no_line($cline));
- }
- else
- {# handle table @item term and restart another one
- # or after table text restart a term
- push (@$stack, { 'format' => 'term', 'text' => '', 'format_ref' => $format, 'item_cmd' => $macro });
- }
- $format->{'texi_line'} = $cline;
- my ($line, $open_command) = &$Texi2HTML::Config::format_list_item_texi($format->{'format'}, $cline, $format->{'prepended'}, $format->{'command'}, $format->{'number'});
- $cline = $line if (defined($line));
- #if ($open_command)
- #{
- # open_arg($format->{'command'},0, $state);
- # $format->{'command_opened'} = 1;
- #}
- $format->{'item_cmd'} = $macro;
- $format->{'texi_line_texi_formatted'} = $cline;
- next;
- }
- $format = add_row ($text, $stack, $state, $line_nr); # handle multitable
- if (!$format)
- { # makeinfo has:
- # "@%s not meaningful inside `@%s' block" for menu/quotation...
- # and, if outside of any format
- # "%c%s found outside of an insertion block"
- # The following error message seems better.
- line_error (sprintf(__("\@%s outside of table or list"), $macro), $line_nr);
- }
- else
- {
- push @$stack, {'format' => 'row', 'text' => '', 'item_cmd' => $macro, 'format_ref' => $format };
- push @$stack, {'format' => 'cell', 'text' => '', 'format_ref' => $format};
- $format->{'cell'} = 1;
- if ($format->{'max_columns'})
- {
- if (defined($Texi2HTML::Config::tab_item_texi))
- {
- my $resline = &$Texi2HTML::Config::tab_item_texi($macro, $state->{'command_stack'}, $stack, $state, $cline, $line_nr);
- $cline = $resline if (defined($resline));
- }
- begin_paragraph_after_command($state,$stack,$macro,$cline);
- }
- else
- {
- line_warn (sprintf(__("\@%s in empty multitable"), $macro), $line_nr);
- }
- }
- next;
- }
- elsif ($macro eq 'tab')
- {
- abort_empty_preformatted($stack, $state);
- # FIXME let the user be able not to close the paragraph?
- close_paragraph($text, $stack, $state, "\@$macro", $line_nr);
- my $format = add_cell ($text, $stack, $state, $line_nr);
- if (!$format)
- {
- line_error(__("ignoring \@tab outside of multitable"), $line_nr);
- }
- else
- {
- push @$stack, {'format' => 'cell', 'text' => '', 'format_ref' => $format};
- if (!$format->{'max_columns'})
- {
- line_warn (__("ignoring \@tab in empty multitable"), $line_nr);
- }
- elsif ($format->{'cell'} > $format->{'max_columns'})
- {
- line_error (sprintf(__("Too many columns in multitable item (max %d)"), $format->{'max_columns'}), $line_nr);
- }
- else
- {
- if (defined($Texi2HTML::Config::tab_item_texi))
- {
- my $resline = &$Texi2HTML::Config::tab_item_texi($macro, $state->{'command_stack'}, $stack, $state, $cline, $line_nr);
- $cline = $resline if (defined($resline));
- }
- }
- }
- begin_paragraph_after_command($state,$stack,$macro,$cline);
- next;
- }
- # Macro opening a format (table, list, deff, example...)
- elsif ($format_type{$macro} and ($format_type{$macro} ne 'fake'))
- {
- my $ignore_center = 0;
- # @center is forbidden in @-command with braces, @*table
- # @item line, @multitable, or another @center
- if ($macro eq 'center' and @$stack)
- {
- my $top_stack = top_stack($stack, 1);
- if (exists($top_stack->{'style'}) or (defined($top_stack->{'format'}) and ($top_stack->{'format'} eq 'term' or $top_stack->{'format'} eq 'cell')) or $state->{'preformatted'} or $state->{'paragraph_style'}->[-1] eq 'center')
- {
- $ignore_center = 1;
- }
- #dump_stack ($text, $stack, $state);
- }
- if ($ignore_center)
- {
- line_error(__("\@center should not appear in another format"), $line_nr);
- }
- else
- {
- $cline = begin_format($text, $stack, $state, $macro, $cline, $line_nr);
- }
- # we keep the end of line for @center, and for formats
- # that have cmd_line opened and need to see the end of line
- next if (($macro eq 'center') or
- (defined($Texi2HTML::Config::def_map{$macro}))
- or ($macro eq 'float') or ($format_type{$macro} eq 'quotation'));
- return if ($cline =~ /^\s*$/);
- next;
- }
- $cline = do_unknown (2, $macro, $cline, $text, $stack, $state, $line_nr);
- next;
- }
- elsif($cline =~ s/^([^{}@,]*)\@([^\s\}\{\@]*)//o)
- { # A macro with a character which shouldn't appear in macro name
- add_prev($text, $stack, do_text($1, $state));
- $cline = do_unknown (2, $2, $cline, $text, $stack, $state, $line_nr);
- next;
- }
- # a brace
- elsif ($cline =~ s/^([^{},]*)([{}])//o)
- {
- my $leading_text = $1;
- my $brace = $2;
- add_prev($text, $stack, do_text($leading_text, $state));
- if (defined($brace) and ($brace eq '{')) #'}'
- {
- add_prev($text, $stack, do_text('{',$state)); #}
- if ($state->{'math_style'})
- {
- $state->{'math_brace'}++;
- }
- else
- {
- unless ($state->{'keep_texi'} or $state->{'remove_texi'})
- {
- line_error (sprintf(__("Misplaced %c"), ord('{')), $line_nr);
- }
- }
- }
- elsif (defined($brace) and ($brace eq '}') and
- (!@$stack or (!defined($stack->[-1]->{'style'}))
- # braces are allowed in math
- or $state->{'math_brace'}))
- {
- if ($state->{'keep_texi'})
- {
- add_prev($text, $stack, '}');
- }
- elsif($state->{'math_style'} and $state->{'math_brace'})
- {
- add_prev($text, $stack, do_text('}',$state));
- $state->{'math_brace'}--;
- }
- else
- {
- line_error (sprintf(__("Misplaced %c"), ord('}')), $line_nr);
- #dump_stack($text, $stack, $state);
- }
- }
- else
- { # A @-command{ ...} is closed
- my ($result, $command) = close_style_command($text, $stack, $state, $line_nr, $cline);
- add_prev($text, $stack, $result);
- if ($Texi2HTML::Config::no_paragraph_commands{$command}
- and !$state->{'keep_texi'} and !no_paragraph($state,$cline))
- {
- begin_paragraph($stack, $state);
- }
- }
- }
- elsif ($cline =~ s/^([^,]*)[,]//o)
- {
- add_prev($text, $stack, do_text($1, $state));
- if (@$stack and defined($stack->[-1]->{'style'})
- and (ref($::style_map_ref->{$stack->[-1]->{'style'}}) eq 'HASH'))
- {
- my $macro = $stack->[-1]->{'style'};
- my $style_args = $::style_map_ref->{$macro}->{'args'};
- if (defined($style_args->[$stack->[-1]->{'arg_nr'} + 1]))
- {
- push (@{$stack->[-1]->{'args'}}, $stack->[-1]->{'text'});
- $stack->[-1]->{'fulltext'} .= $stack->[-1]->{'text'} . do_text(',', $state);
- $stack->[-1]->{'text'} = '';
- close_arg ($macro, $stack->[-1]->{'arg_nr'}, $state);
- $stack->[-1]->{'arg_nr'}++;
- open_arg ($macro, $stack->[-1]->{'arg_nr'}, $state);
- next;
- }
- }
- add_prev($text, $stack, do_text(',', $state));
- }
- else
- { # no macro nor '}', but normal text
- add_prev($text, $stack, do_text($cline, $state));
- # @center/line term is closed at the end of line. When a
- # @-command which
- # keeps the texi as is happens on the @center line, the @center
- # is closed at the end of line appearing after the @-command
- # closing (for example @ref, @footnote).
- last if ($state->{'keep_texi'});
- #print STDERR "END_LINE(l):$cline!!!\n";
- #dump_stack($text, $stack, $state);
- my $maybe_format_to_close = 1;
- my $in_table;
- while ($maybe_format_to_close)
- {
- $maybe_format_to_close = 0;
- #my $top_format = top_stack($stack, 1);
- my $top_format = top_stack($stack, 2);
- # the stack cannot easily be used, because there may be
- # opened commands in paragraphs if the center is in a
- # style command, like
- # @b{
- # bold
- #
- # @center centered bold
- #
- # }
- #
- # Therefore $state->{'paragraph_style'}->[-1] is used.
- #
- # The close_stack until 'center' is needed because
- # of constructs like
- #
- # @center something @table
- #
- # In that case what would be removed from the stack after
- # paragraph closing wold not be the @center. Such construct
- # is certainly incorrect, though.
- #
- # when 'closing_center' is true we don't retry to close
- # the @center line.
- if ($state->{'paragraph_style'}->[-1] eq 'center'
- and !$state->{'closing_center'} and !$state->{'keep_texi'})
- {
- $state->{'closing_center'} = 1;
- close_paragraph($text, $stack, $state, "\@center", $line_nr);
- close_stack($text, $stack, $state, $line_nr, 'center');
- delete $state->{'closing_center'};
- my $center = pop @$stack;
- add_prev($text, $stack, &$Texi2HTML::Config::paragraph_style_command('center',$center->{'text'}));
- my $top_paragraph_style = pop @{$state->{'paragraph_style'}};
-
- # center is at the bottom of the comand_stack because it
- # may be nested in many way
- my $bottom_command_stack = shift @{$state->{'command_stack'}};
- print STDERR "Bug: closing center, top_paragraph_style: $top_paragraph_style, bottom_command_stack: $bottom_command_stack.\n"
- if ($bottom_command_stack ne 'center' or $top_paragraph_style ne 'center');
- $maybe_format_to_close = 1;
- next;
- }
-
- # @item line is closed by end of line. In general there should
- # not be a paragraph in a term. However it may currently
- # happen in construct like
- #
- # @table @asis
- # @item @cindex index entry
- # some text still in term, and in paragraph
- # Not in term anymore
- # ....
- #
- if (defined($top_format->{'format'}) and $top_format->{'format'} eq 'term')
- {
- #close_paragraph($text, $stack, $state, $line_nr)
- # if ($state->{'paragraph_context'});
- close_stack($text, $stack, $state, $line_nr, 'term');
- $in_table = add_term($text, $stack, $state, $line_nr);
- if ($in_table)
- {
- $maybe_format_to_close = 1;
- next;
- }
- }
- }
- if ($in_table)
- {
- push (@$stack, { 'format' => 'line', 'text' => '', 'only_inter_commands' => 1, 'format_ref' => $in_table });
- begin_paragraph($stack, $state) if ($state->{'preformatted'});
- }
- last;
- }
- }
- return 1;
- } # end scan_line
- sub open_arg($$$)
- {
- my $macro = shift;
- my $arg_nr = shift;
- my $state = shift;
- if (ref($::style_map_ref->{$macro}) eq 'HASH')
- {
- my $arg = $::style_map_ref->{$macro}->{'args'}->[$arg_nr];
- if ($arg eq 'keep')
- {
- $state->{'keep_nr'}++;
- $state->{'keep_texi'} = 1;
- }
- elsif (!$state->{'keep_texi'})
- {
- if ($arg eq 'code')
- {
- $state->{'code_style'}++;
- }
- elsif ($arg eq 'math')
- {
- $state->{'math_style'}++;
- $state->{'code_style'}++;
- if ($state->{'math_style'} == 1)
- {
- $state->{'math_brace'} = 0;
- }
- }
- }
- }
- elsif ($code_style_map{$macro} and !$state->{'keep_texi'})
- {
- $state->{'code_style'}++;
- }
- }
- sub close_arg($$$)
- {
- my $macro = shift;
- my $arg_nr = shift;
- my $state = shift;
- if (ref($::style_map_ref->{$macro}) eq 'HASH')
- {
- my $arg = $::style_map_ref->{$macro}->{'args'}->[$arg_nr];
- if ($arg eq 'keep')
- {
- $state->{'keep_nr'}--;
- $state->{'keep_texi'} = 0 if ($state->{'keep_nr'} == 0);
- }
- elsif (!$state->{'keep_texi'})
- {
- if ($arg eq 'code')
- {
- $state->{'code_style'}--;
- }
- elsif ($arg eq 'math')
- {
- $state->{'math_style'}--;
- $state->{'code_style'}--;
- }
- }
- #print STDERR "c $arg_nr $macro $arg $state->{'code_style'}\n";
- }
- elsif ($code_style_map{$macro} and !$state->{'keep_texi'})
- {
- $state->{'code_style'}--;
- }
- }
- # add a special style on the top of the stack. This is used for commands
- # that extend until the end of the line. Also add an entry in the @-command
- # hashes for this fakes style.
- #sub open_cmd_line($$$$$)
- #{
- # my $command = shift;
- # my $stack = shift;
- # my $state = shift;
- # my $args = shift;
- # my $function = shift;
- # push @$stack, {'style' => 'cmd_line', 'text' => '', 'arg_nr' => 0};
- # foreach my $hash (\%Texi2HTML::Config::style_map, \%Texi2HTML::Config::style_map_pre, \%Texi2HTML::Config::style_map_texi, \%Texi2HTML::Config::simple_format_style_map_texi)
- # {
- # $hash->{'cmd_line'}->{'args'} = $args;
- # $hash->{'cmd_line'}->{'function'} = $function;
- # }
- # $state->{'no_paragraph'}++;
- # push @{$state->{'no_paragraph_stack'}}, "\@$command line";
- ## $state->{'cmd_line'} = 1;
- # open_arg ('cmd_line', 0, $state);
- #}
- # finish @item line in @*table
- sub add_term($$$$)
- {
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $line_nr = shift;
- my $top_format = top_stack($stack,2);
- return unless (defined($top_format->{'format'}) and $top_format->{'format'} eq 'term');
- #print STDERR "ADD_TERM\n";
- my $term = pop @$stack;
- my $format = $stack->[-1];
- $format->{'paragraph_number'} = 0;
- chomp ($term->{'text'});
- my ($index_label, $formatted_index_entry);
- if ($format->{'format'} =~ /^(f|v)/o)
- {
- my $index_entry;
- ($index_entry, $formatted_index_entry, $index_label) = do_index_entry_label($format->{'format'}, $state,$line_nr, $format->{'texi_line'});
- print STDERR "Bug: no index entry for $term->{'text'}\n" unless defined($index_label);
- }
- my $item_result = &$Texi2HTML::Config::table_item($term->{'text'}, $index_label,$format->{'format'},$format->{'command'}, $state->{'command_stack'}, $term->{'item_cmd'}, $formatted_index_entry);
- add_prev($text, $stack, $item_result);
- return $format;
- }
- sub add_row($$$$)
- {
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $line_nr = shift;
-
- my $top_format = top_stack($stack);
- # @center a @item
- # will lead to row not being closed since a close paragraph doesn't
- # end the center.
- return unless (defined($top_format->{'format'}) and $top_format->{'format'} eq 'cell');
- my $cell = $top_format;
- my $format = $stack->[-3];
- print STDERR "Bug under row cell row not a multitable\n" if (!defined($format->{'format'}) or $format->{'format'} ne 'multitable');
- #print STDERR "ADD_ROW $format->{'item_nr'} first: $format->{'first'}\n";
- # dump_stack($text, $stack, $state);
- $format->{'item_nr'}++ unless ($format->{'first'});
- my $empty_first;
- if ($format->{'first'} and $format->{'cell'} == 1 and $stack->[-1]->{'text'} =~ /^\s*$/)
- {
- $empty_first = 1;
- $format->{'empty_first'} = 1;
- }
- if ($format->{'cell'} > $format->{'max_columns'} or $empty_first)
- {
- my $cell = pop @$stack;
- print STDERR "Bug: not a cell ($cell->{'format'}) in multitable\n" if ($cell->{'format'} ne 'cell');
- }
- else
- {
- add_cell($text, $stack, $state);
- }
- my $row = pop @$stack;
- print STDERR "Bug: not a row ($row->{'format'}) in multitable\n" if ($row->{'format'} ne 'row');
- if ($format->{'max_columns'} and !$empty_first)
- {
- # FIXME have the cell count in row and not in table. table could have
- # the whole structure, but cell count doesn't make much sense
- add_prev($text, $stack, &$Texi2HTML::Config::row($row->{'text'}, $row->{'item_cmd'}, $format->{'columnfractions'}, $format->{'prototype_row'}, $format->{'prototype_lengths'}, $format->{'max_columns'}, $cell->{'only_inter_commands'}, $format->{'first'}));
- }
- $format->{'first'} = 0 if ($format->{'first'});
- return $format;
- }
- # FIXME remove and merge, too much double checks and code
- sub add_cell($$$$)
- {
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $line_nr = shift;
- my $top_format = top_stack($stack);
- #print STDERR "ADD_CELL\n";
- return unless (defined($top_format) and $top_format->{'format'} eq 'cell');
- # print STDERR "ADD_CELL, really\n";
- my $cell = pop @$stack;
- my $row = top_stack($stack);
- print STDERR "Bug: top_stack of cell not a row\n" if (!defined($row->{'format'}) or ($row->{'format'} ne 'row'));
- my $format = $stack->[-2];
- print STDERR "Bug under cell row not a multitable\n" if (!defined($format->{'format'}) or $format->{'format'} ne 'multitable');
- if ($format->{'first'} and $format->{'cell'} == 1)
- {
- line_warn(__("\@tab before \@item"), $line_nr);
- }
- if ($format->{'cell'} <= $format->{'max_columns'})
- {
- add_prev($text, $stack, &$Texi2HTML::Config::cell($cell->{'text'}, $row->{'item_cmd'}, $format->{'columnfractions'}, $format->{'prototype_row'}, $format->{'prototype_lengths'}, $format->{'max_columns'}, $cell->{'only_inter_commands'}, $format->{'first'}));
- }
- $format->{'cell'}++;
- $format->{'first'} = 0 if ($format->{'first'});
- return $format;
- }
- sub add_line($$$$)
- {
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $line_nr = shift;
- my $top_stack = top_stack($stack);
- # if there is something like
- # @center centered @item new item
- # the item isn't opened since it is in @center, and center isn't closed
- # by an @item appearing here (unlike a paragraph).
- # the error message is '@item outside of table or list'.
- # texi2dvi also has issue, but makeinfo is happy, however it
- # produces bad nesting.
- return unless(defined($top_stack->{'format'}) and $top_stack->{'format'} eq 'line');
- #print STDERR "ADD_LINE\n";
- #dump_stack($text, $stack, $state);
- my $line = pop @$stack;
- my $format = $stack->[-1];
- $format->{'paragraph_number'} = 0;
- if ($format->{'first'})
- {
- $format->{'first'} = 0;
- # we must have <dd> or <dt> following <dl> thus we do a
- # &$Texi2HTML::Config::table_line here too, although it could have
- # been a normal paragraph.
- if ($line->{'text'} =~ /\S/o)
- {
- add_prev($text, $stack, &$Texi2HTML::Config::table_line($line->{'text'}, $line->{'only_inter_commands'}, 1));
- $format->{'empty_first'} = 1 if ($line->{'only_inter_commands'});
- }
- else
- {
- $format->{'empty_first'} = 1;
- }
- }
- else
- {
- $format->{'item_nr'}++;
- add_prev($text, $stack, &$Texi2HTML::Config::table_line($line->{'text'}, $line->{'only_inter_commands'}, 0));
- }
- return $format;
- }
- # finish @enumerate or @itemize @item
- sub add_item($$$$)
- {
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $line_nr = shift;
- my $top_stack = top_stack($stack);
- return unless (defined($top_stack->{'format'}) and $top_stack->{'format'} eq 'item');
- #print STDERR "ADD_ITEM: \n";
- #dump_stack($text, $stack, $state);
- # as in pre the end of line are kept, we must explicitely abort empty
- # preformatted, close_stack doesn't do that.
- my $item = pop @$stack;
- my $format = $stack->[-1];
- #my $item_command = $item->{'format'};
- my $item_command = $item->{'item_cmd'};
- # first has no associated item, it is more like a 'title'
- $item_command = '' if ($format->{'first'});
- # debug message if it is the first item (much like a title) although
- # there is an item command.
- msg_debug("First in $format->{'format'} but item_cmd defined $item->{'item_cmd'}",$line_nr) if ($format->{'first'} and defined($item->{'item_cmd'}));
-
- $format->{'paragraph_number'} = 0;
-
- #dump_stack ($text, $stack, $state);
- # the element following ol or ul must be li. Thus even though there
- # is no @item we put a normal item.
- # don't do an item if it is the first and it is empty
- if (!$format->{'first'} or ($item->{'text'} =~ /\S/o))
- {
- my $formatted_command;
- if (defined($format->{'command'}) and $format->{'command'} ne '')# and exists($::things_map_ref->{$format->{'command'}}))
- {
- $formatted_command = substitute_line("\@$format->{'command'}\{\}", "\@item \@$format->{'command'}", duplicate_formatting_state($state));
- $format->{'formatted_command'} = $formatted_command;
- }
- #chomp($item->{'text'});
- add_prev($text, $stack, &$Texi2HTML::Config::list_item($item->{'text'},$format->{'format'},$format->{'command'}, $formatted_command, $format->{'item_nr'}, $format->{'spec'}, $format->{'number'}, $format->{'prepended'}, $format->{'prepended_formatted'}, $item->{'only_inter_commands'}, $format->{'first'},$item_command));
- }
- else
- {
- $format->{'empty_first'} = 1;
- }
- if ($format->{'first'})
- {
- $format->{'first'} = 0;
- }
- else
- {
- $format->{'item_nr'}++;
- }
- if ($format->{'format'} eq 'enumerate')
- {
- $format->{'number'} = '';
- my $spec = $format->{'spec'};
- if ($spec =~ /^[0-9]$/)
- {
- $format->{'number'} = $spec + $format->{'item_nr'};
- }
- else
- {
- my $base_letter = ord('a');
- $base_letter = ord('A') if (ucfirst($spec) eq $spec);
- my @letter_ords = decompose(ord($spec) - $base_letter + $format->{'item_nr'}, 26);
- foreach my $ord (@letter_ords)
- {# FIXME we go directly to 'ba' after 'z', and not 'aa'
- #because 'ba' is 1,0 and 'aa' is 0,0.
- $format->{'number'} = chr($base_letter + $ord) . $format->{'number'};
- }
- }
- }
- return $format;
- }
- # format ``simple'' macros, that is macros without arg or style macros
- sub do_simple_command($$$)
- {
- my $macro = shift;
- my $state = shift;
- my $line_nr = shift;
-
- #msg_debug ("DO_SIMPLE $macro $args $arg_nr (@$args)", $line_nr) if (defined($args));
- if ($state->{'remove_texi'})
- {
- #print STDERR "DO_SIMPLE remove_texi $macro\n";
- return $::simple_map_texi_ref->{$macro};
- }
- else
- {
- return &$Texi2HTML::Config::simple_command($macro, $state->{'preformatted'}, $state->{'math_style'}, $line_nr, $state);
- }
- }
- sub do_thing_command($$$$)
- {
- my $macro = shift;
- my $text = shift;
- my $state = shift;
- my $line_nr = shift;
- if ($state->{'remove_texi'})
- {
- return $::texi_map_ref->{$macro}.$text;
- #print STDERR "DO_SIMPLE remove_texi texi_map $macro\n";
- }
- else
- {
- return &$Texi2HTML::Config::thing_command($macro, $text, $state->{'preformatted'}, $state->{'math_style'}, $line_nr, $state);
- }
- }
- sub do_style_command($$$$$$$$)
- {
- my $macro = shift;
- my $text = shift;
- my $state = shift;
- my $args = shift;
- my $line_nr = shift;
- my $no_open = shift;
- my $no_close = shift;
- my $kept_line_nrs = shift;
- my $arg_nr = 0;
- $arg_nr = @$args - 1 if (defined($args));
-
- if (defined($::style_map_ref->{$macro}))
- {
- my $style;
- my $result;
- if ($state->{'remove_texi'})
- {
- #print STDERR "REMOVE $macro, $style_map_texi_ref->{$macro}, fun $style_map_texi_ref->{$macro}->{'function'} remove cmd " . \&Texi2HTML::Config::t2h_remove_command . " ascii acc " . \&t2h_default_accent;
- $style = $::style_map_texi_ref->{$macro};
- }
- elsif ($state->{'math_style'} and defined($::style_map_math_ref->{$macro}))
- { # FIXME we are still in math when the @math is closed here, since
- # close_arg that does 'math_style'-- is called below.
- $style = $::style_map_math_ref->{$macro};
- }
- elsif ($state->{'preformatted'})
- {
- if ($macro eq 'kbd' and (get_conf('kbdinputstyle') ne 'distinct'))
- {
- $style = $::style_map_pre_ref->{'code'};
- }
- else
- {
- $style = $::style_map_pre_ref->{$macro};
- }
- }
- else
- {
- # kbd is in code_style, so it is 'code_style' > 1
- if ($macro eq 'kbd' and ((get_conf('kbdinputstyle') eq 'code') or ($state->{'code_style'} > 1 and get_conf('kbdinputstyle') eq 'example')))
- {
- $style = $::style_map_ref->{'code'};
- }
- else
- {
- $style = $::style_map_ref->{$macro};
- }
- }
- if ($macro eq 'dotless')
- {
- if (scalar(@$args) ne 1)
- {
- line_error(sprintf(__("%c%s expects a single character `i' or `j' as argument"), ord('@'), $macro), $line_nr);
- }
- elsif ($args->[0] ne 'i' and $args->[0] ne 'j')
- { # FIXME an unformatted arg would have been better. Not a big deal.
- line_error (sprintf(__("%c%s expects `i' or `j' as argument, not `%s'"), ord('@'), $macro, $args->[0]), $line_nr);
- }
- }
- if (defined($style))
- { # known style
- $result = &$Texi2HTML::Config::style($style, $macro, $text, $args, $no_close, $no_open, $line_nr, $state, $state->{'command_stack'}, $kept_line_nrs);
- }
- if (!$no_close)
- {
- close_arg($macro,$arg_nr, $state);
- }
- return $result;
- }
- elsif ($macro =~ /^special_(\w+)_(\d+)$/o)
- {
- my $style = $1;
- my $count = $2;
- msg_debug ("Bug? text in \@$macro not empty", $line_nr) if ($text ne '');
- if (defined($Texi2HTML::Config::command_handler{$style}) and
- defined($Texi2HTML::Config::command_handler{$style}->{'expand'}))
- {
- my $struct_count = 1+ $special_commands{$style}->{'max'} - $special_commands{$style}->{'count'};
- # may happen for text expanded more than once, for example
- # in invalid/tex_in_copying
- if (($count != $struct_count) and $T2H_DEBUG)
- {
- msg_debug ("count $count in \@special $style and structure $struct_count differ", $line_nr);
- }
- $special_commands{$style}->{'count'}--;
- }
- my $result = $Texi2HTML::Config::command_handler{$style}->{'expand'}
- ($style,$count,$state,$text);
- $result = '' if (!defined($result));
- return $result;
- }
- # Unknown macro
- my $result = '';
- my ($done, $result_text, $message) = &$Texi2HTML::Config::unknown_style($macro, $text, $state, $no_close, $no_open);
- if ($done)
- {
- line_warn($message, $line_nr) if (defined($message));
- if (defined($result_text))
- {
- $result = $result_text;
- }
- }
- else
- {
- unless ($no_open)
- { # we warn only if no_open is true, i.e. it is the first time we
- # close the macro for a multiline macro
- line_error (sprintf(__("Unknown command with braces `\@%s'"), $macro), $line_nr);
- $result = do_text("\@${macro}{");
- }
- $result .= $text;
- $result .= do_text('}') unless ($no_close);
- }
- return $result;
- }
- sub do_unknown($$$$$$$)
- {
- my $pass = shift;
- my $macro = shift;
- my $line = shift;
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $line_nr = shift;
- #print STDERR "do_unknown[$pass]($macro) ::: $line";
- my ($result_line, $result, $result_text, $message) = &$Texi2HTML::Config::unknown($macro, $line, $pass, $stack,$state);
- if ($result)
- {
- add_prev ($text, $stack, $result_text) if (defined($result_text));
- line_warn($message, $line_nr) if (defined($message));
- # if $state->{'preformatted'}, assume that the preformatted is
- # already opened. Otherwise we may end up opening one each time
- # there is an unknown command.
- begin_paragraph_after_command($state, $stack, $macro, $result_line)
- if (!$state->{'preformatted'});
- return $result_line;
- }
- elsif ($pass == 2)
- {
- if ($Texi2HTML::Config::style_map{$macro})
- {
- line_error (sprintf(__("%c%s expected braces"), ord('@'), $macro), $line_nr);
- }
- elsif ($begin_line_command{$macro})
- {
- line_error (sprintf(__("Unexpected command `%s' here"), $macro), $line_nr);
- }
- else
- {
- line_error (sprintf(__("Unknown command `%s'"), $macro), $line_nr);
- }
- add_prev ($text, $stack, do_text("\@$macro"));
- return $line;
- }
- elsif ($pass == 1)
- {
- add_prev ($text, $stack, "\@$macro");
- return $line;
- }
- elsif ($pass == 0)
- {
- add_prev ($text, $stack, "\@$macro") unless($state->{'ignored'});
- return $line;
- }
- }
- # used only during @macro processing
- sub add_text($@)
- {
- my $string = shift;
- return if (!defined($string));
- foreach my $scalar_ref (@_)
- {
- next unless defined($scalar_ref);
- if (!defined($$scalar_ref))
- {
- $$scalar_ref = $string;
- }
- else
- {
- $$scalar_ref .= $string;
- }
- return;
- }
- }
- sub add_prev ($$$)
- {
- my $text = shift;
- my $stack = shift;
- my $string = shift;
- unless (defined($text) and ref($text) eq "SCALAR")
- {
- die "text not a SCALAR ref: " . ref($text) . "";
- }
-
- return if (!defined($string));
- if (@$stack)
- {
- $stack->[-1]->{'text'} .= $string;
- return;
- }
- if (!defined($$text))
- {
- $$text = $string;
- }
- else
- {
- $$text .= $string;
- }
- }
- sub close_stack_texi($$$$)
- {
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $line_nr = shift;
-
- return undef unless (@$stack or $state->{'raw'} or $state->{'macro'} or $state->{'macro_name'} or $state->{'ignored'});
- if ($state->{'ignored'})
- {
- line_error (sprintf(__("Reached eof before matching \@end %s"), $state->{'ignored'}), $line_nr);
- close_ignored($state, $stack);
- }
- if ($state->{'macro'})
- {
- my ($no_remaining, $result) = end_macro($state, '@end macro', "\n");
- add_prev ($text, $stack, $result) if (defined($result));
- line_error (sprintf(__("%cend macro not found"), ord('@')), $line_nr);
- }
- elsif ($state->{'macro_name'})
- {
- #line_warn ("closing $state->{'macro_name'} ($state->{'macro_depth'} braces missing)", $line_nr);
- line_error (sprintf(__("\@%s missing close brace"), $state->{'macro_name'}), $line_nr);
- while ($state->{'macro_name'})
- {
- close_macro_arg($state, '', $line_nr);
- }
- }
- elsif ($state->{'verb'})
- {
- # warning in next pass
- #line_warn ("closing \@verb", $line_nr);
- $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'};
- delete $state->{'verb'};
- }
- elsif ($state->{'raw'})
- {
- line_error (sprintf(__("Expected \@end %s"), $state->{'raw'}), $line_nr);
- my $style = pop @$stack;
- add_prev ($text, $stack, $style->{'text'} . "\@end $state->{'raw'}");
- delete $state->{'raw'};
- }
- my $stack_level = $#$stack + 1;
-
- while ($stack_level--)
- {
- my $style = pop(@$stack);
- # would be better in close_stack_structure
- #line_warn ("closing \@-command $style->{'style'}", $line_nr) if ($style->{'style'} ne '');
- close_style_texi($style, $text, $stack, $state, 1);
- }
- #$stack = [ ];
- }
- sub close_stack_structure($$$$;$)
- {
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $line_nr = shift;
- my $close_only_item = shift;
- $close_only_item = 0 if (!defined($close_only_item));
- return undef unless (@$stack or $state->{'raw'});
- #print STDERR "close_stack_structure ($close_only_item)\n";
- #dump_stack ($text, $stack, $state);
- my $stack_level = $#$stack + 1;
- my $string = '';
-
- if ($state->{'verb'})
- {
- $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'};
- #$string .= $state->{'verb'};
- }
- while ($stack_level--)
- {
- last if ($close_only_item and defined($stack->[-1]->{'format'}));
- my $top_stack = pop @$stack;
- if ($top_stack->{'format'})
- {
- my $format = $top_stack->{'format'};
- if ($format eq 'index_item')
- {
- enter_table_index_entry($text, $stack, $state, $line_nr);
- }
- elsif (!defined($format_type{$format}) or ($format_type{$format} ne 'fake'))
- {
- end_format_structure($format_type{$format}, $text, $stack, $state, $line_nr, "\n");
- }
- }
- elsif (defined($top_stack->{'style'}))
- {
- add_prev($text, $stack,
- close_structure_command($top_stack, $state, 1, $line_nr));
- }
- }
- #$stack = [ ];
- }
- # This is used in pass 2 and 3.
- sub open_region($$)
- {
- my $command = shift;
- my $state = shift;
- if (!exists($state->{'region_lines'}))
- {
- # FIXME 'format' is badly choosen 'region_name' would be much better
- $state->{'region_lines'}->{'format'} = $command;
- $state->{'region_lines'}->{'number'} = 1;
- $state->{'region_lines'}->{'kept_place'} = $state->{'place'};
- $state->{'place'} = $no_element_associated_place;
- $state->{'region'} = $command;
- $state->{'multiple_pass'}++;
- $state->{'region_pass'} = 1;
- }
- else
- {
- $state->{'region_lines'}->{'number'}++;
- }
- }
- # close region like @insertcopying, titlepage...
- # restore $state and delete the structure
- # This is used in pass 2 and 3.
- sub close_region($)
- {
- my $state = shift;
- $state->{'place'} = $state->{'region_lines'}->{'kept_place'};
- $state->{'multiple_pass'}--;
- delete $state->{'region_lines'}->{'number'};
- delete $state->{'region_lines'}->{'format'};
- delete $state->{'region_lines'}->{'kept_place'};
- delete $state->{'region_lines'};
- delete $state->{'region'};
- delete $state->{'region_pass'};
- }
- # close the stack, closing @-commands and formats left open.
- # if a $format is given if $format is encountered the closing stops
- sub close_stack($$$$;$)
- {
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $line_nr = shift;
- my $format = shift;
-
- #print STDERR "sub_close_stack\n";
- if (@$stack)
- {
- my $stack_level = $#$stack + 1;
-
- #debugging
- #my $print_format = 'NO FORMAT';
- #$print_format = $format if ($format);
- #msg_debug ("Close_stack: format $print_format", $line_nr);
-
- while ($stack_level--)
- {
- if ($stack->[$stack_level]->{'format'})
- {
- my $stack_format = $stack->[$stack_level]->{'format'};
- last if (defined($format) and $stack_format eq $format);
- # We silently close paragraphs, preformatted sections and fake formats
- if ($stack_format eq 'paragraph')
- {
- my $paragraph = pop @$stack;
- add_prev ($text, $stack, do_paragraph($paragraph->{'text'}, $state, $stack));
- }
- elsif ($stack_format eq 'preformatted')
- {
- my $paragraph = pop @$stack;
- add_prev ($text, $stack, do_preformatted($paragraph->{'text'}, $state, $stack));
- }
- else
- {
- if ($fake_format{$stack_format})
- {
- warn "# Closing a fake format `$stack_format'\n" if ($T2H_VERBOSE);
- }
- elsif ($stack_format ne 'center')
- { # we don't warn for center
- line_error (sprintf(__("No matching `%cend %s'"), ord('@'), $stack_format), $line_nr);
- #dump_stack ($text, $stack, $state);
- }
- if ($state->{'keep_texi'})
- {
- add_prev($text, $stack, "\@end $stack_format");
- }
- elsif (!$state->{'remove_texi'})
- {
- end_format($text, $stack, $state, $stack_format, $line_nr)
- unless ($format_type{$stack_format} eq 'fake');
- }
- }
- }
- else
- {
- my $style = $stack->[$stack_level]->{'style'};
- ########################## debug
- if (!defined($style))
- {
- print STDERR "Bug: style not defined, on stack\n";
- dump_stack ($text, $stack, $state); # bug
- }
- ########################## end debug
- my $located_line_nr = $line_nr;
- # use the beginning of the @-command for the error message
- # line number if available.
- $located_line_nr = $stack->[$stack_level]->{'line_nr'} if (defined($stack->[$stack_level]->{'line_nr'}));
- # $state->{'verb'} may not be defined if the @verb{ opening
- # is followed by an end of line.
- if ($style eq 'verb' and defined($state->{'verb'}))
- {
- line_error (sprintf(__("\@%s missing closing delimiter sequence: %s}"), $style, $state->{'verb'}), $located_line_nr);
- }
- else
- {
- line_error (sprintf(__("%c%s missing close brace"), ord('@'), $style), $located_line_nr);
- }
- my ($result, $command) = close_style_command($text, $stack, $state, $line_nr, '');
- add_prev($text, $stack, $result) if (defined($result));
- }
- }
- }
- # This tries to avoid cases where the command_stack is not empty
- # for a good reason, for example when doing a @def formatting the
- # outside command_stack is preserved. Also when expanding for
- # example @titleplage or @copying.
- # FIXME sort out which cases it is.
- return if ($format or (defined($state->{'multiple_pass'}) and $state->{'multiple_pass'} > 0) or $state->{'no_paragraph'});
- # The pending style commands are cleared here; And are closed next.
- delete $state->{'paragraph_macros'};
- # go through the command_stack and warn for each opened style format
- # and remove it. Those should be there because there is an opened style
- # that was stopped by a paragraph
- my @command_stack = @{$state->{'command_stack'}};
- @{$state->{'command_stack'}} = ();
- while (@command_stack)
- {
- my $latest_command = pop @command_stack;
- if (defined($style_type{$latest_command}) and $style_type{$latest_command} ne 'special')
- {
- line_error (sprintf(__("%c%s missing close brace"), ord('@'), $latest_command), $line_nr);
- }
- else
- {
- unshift @{$state->{'command_stack'}}, $latest_command;
- }
- }
- }
- # given a stack and a list of formats, return true if the stack contains
- # these formats, first on top
- sub stack_order($@)
- {
- my $stack = shift;
- my $stack_level = $#$stack + 1;
- while (@_)
- {
- my $format = shift;
- while ($stack_level--)
- {
- if ($stack->[$stack_level]->{'format'})
- {
- if ($stack->[$stack_level]->{'format'} eq $format)
- {
- $format = undef;
- last;
- }
- else
- {
- return 0;
- }
- }
- }
- return 0 if ($format);
- }
- return 1;
- }
- sub top_format($)
- {
- my $stack = shift;
- my $stack_level = $#$stack + 1;
- while ($stack_level--)
- {
- if ($stack->[$stack_level]->{'format'} and !$fake_format{$stack->[$stack_level]->{'format'}})
- {
- return $stack->[$stack_level];
- }
- }
- return undef;
- }
- sub close_paragraph($$$$;$$)
- {
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- my $reason = shift;
- my $line_nr = shift;
- my $no_preformatted_closing = shift;
- #print STDERR "CLOSE_PARAGRAPH\n";
- #dump_stack($text, $stack, $state);
- # close until the first format,
- # duplicate stack of styles not closed
- my $new_stack;
- my $stack_level = $#$stack + 1;
- # In general close_paragraph is called because of a end of line, or
- # a format is opened or closed, or there is a @tab or @item and other
- # similar cases. In most cases there is a paragraph to be closed or
- # there are no style opened since most @-commands cause paragraph
- # opening and those that don't should not lead to a style opening.
- #
- # But in term or in @index (and maybe @node, @section, @ref), if
- # there is a command opened it won't be closed, since it is in
- # 'no_paragraph'. But @-commands that trigger close_paragraph should not
- # be called when in those no_paragraph settings.
- if ($state->{'no_paragraph'})
- { # This plays the role of "Multiline command %c%s used improperly"
- line_error(sprintf(__("%s should not appear in %s"), $reason, $state->{'no_paragraph_stack'}->[-1]), $line_nr);
- }
- while ($stack_level--)
- {
- last if ($stack->[$stack_level]->{'format'});
- my $style = $stack->[$stack_level]->{'style'};
- # the !exists($style_type{$style}) condition catches the unknown
- # @-commands: by default they are considered as style commands
- if (!$state->{'no_paragraph'})
- {
- if (!exists($style_type{$style}) or $style_type{$style} eq 'style')
- {
- unshift @$new_stack, { 'style' => $style, 'text' => '', 'no_open' => 1, 'arg_nr' => 0 };
- }
- elsif (($style_type{$style} eq 'simple_style') or ($style_type{$style} eq 'accent'))
- {
- }
- else
- {
- # it shouldn't be possible to have 'special' styles, like
- # images, footnotes, xrefs, anchors, as
- # close_paragraph shouldn't be called with keep_texi
- # and when the arguments are expanded, there is a
- # substitute_line or similar with a new stack.
- msg_debug("BUG: special $style while closing paragraph", $line_nr);
- }
- }
- # if not in a paragraph, the command is simply closed, and not recorded
- # in new_stack.
- my ($result, $command) = close_style_command($text, $stack, $state, $line_nr, '', (!$state->{'no_paragraph'}));
- add_prev($text, $stack, $result) if (defined($result));
- }
- if (!$state->{'paragraph_context'} and !$state->{'preformatted'} and defined($new_stack) and scalar(@$new_stack))
- { # in that case the $new_stack isn't recorded in $state->{'paragraph_macros'}
- # and therefore, it is lost
- msg_debug ("closing paragraph, but not in paragraph/preformatted, and new_stack not empty", $line_nr);
- dump_stack($text, $stack, $state);
- }
- my $top_stack = top_stack($stack);
- if ($top_stack and !defined($top_stack->{'format'}))
- { #debug
- msg_debug("Bug: no format on top stack", $line_nr);
- dump_stack($text, $stack, $state);
- }
- if ($top_stack and ($top_stack->{'format'} eq 'paragraph'))
- {
- my $paragraph = pop @$stack;
- add_prev($text, $stack, do_paragraph($paragraph->{'text'}, $state, $stack));
- $state->{'paragraph_macros'} = $new_stack;
- return 1;
- }
- elsif ($top_stack and ($top_stack->{'format'} eq 'preformatted') and !$no_preformatted_closing)
- {
- my $paragraph = pop @$stack;
- add_prev($text, $stack, do_preformatted($paragraph->{'text'}, $state, $stack));
- $state->{'paragraph_macros'} = $new_stack;
- return 1;
- }
- return;
- }
- sub abort_empty_preformatted($$)
- {
- my $stack = shift;
- my $state = shift;
- if (@$stack and $stack->[-1]->{'format'}
- and ($stack->[-1]->{'format'} eq 'preformatted')
- and ($stack->[-1]->{'text'} !~ /\S/))
- {
- if (defined($Texi2HTML::Config::empty_preformatted))
- {
- return if (&$Texi2HTML::Config::empty_preformatted($stack->[-1]->{'text'}));
- }
- pop @$stack;
- }
- }
- # for debugging
- sub dump_stack($$$)
- {
- my $text = shift;
- my $stack = shift;
- my $state = shift;
- if (defined($$text))
- {
- print STDERR "text: $$text\n";
- }
- else
- {
- print STDERR "text: UNDEF\n";
- }
- my $in_remove = 0;
- my $in_simple_format = 0;
- my $in_keep = 0;
- $in_keep = 1 if ($state->{'keep_texi'});
- if (!$in_keep)
- {
- $in_simple_format = 1 if ($state->{'simple_format'});
- $in_remove = 1 if ($state->{'remove_texi'} and !$in_simple_format);
- }
- print STDERR "state[$state](k${in_keep}s${in_simple_format}r${in_remove}): ";
- foreach my $key (keys(%$state))
- {
- my $value = 'UNDEF';
- $value = $state->{$key} if (defined($state->{$key}));
- print STDERR "$key: $value " if (!ref($value));
- }
- print STDERR "\n";
- my $stack_level = $#$stack + 1;
- while ($stack_level--)
- {
- print STDERR " $stack_level-> ";
- foreach my $key (keys(%{$stack->[$stack_level]}))
- {
- my $value = 'UNDEF';
- $value = $stack->[$stack_level]->{$key} if
- (defined($stack->[$stack_level]->{$key}));
- print STDERR "$key: $value ";
- }
- print STDERR "\n";
- }
- if (defined($state->{'command_stack'}))
- {
- print STDERR "command_stack: ";
- foreach my $style (@{$state->{'command_stack'}})
- {
- print STDERR "($style) ";
- }
- print STDERR "\n";
- }
- if (defined($state->{'region_lines'}))
- {
- print STDERR "region_lines($state->{'region_lines'}->{'number'}): $state->{'region_lines'}->{'format'}\n";
- }
- if (defined($state->{'paragraph_macros'}))
- {
- print STDERR "paragraph_macros: ";
- foreach my $style (@{$state->{'paragraph_macros'}})
- {
- print STDERR "($style->{'style'})";
- }
- print STDERR "\n";
- }
- if (defined($state->{'preformatted_stack'}))
- {
- print STDERR "preformatted_stack: ";
- foreach my $preformatted_style (@{$state->{'preformatted_stack'}})
- {
- if ($preformatted_style eq '')
- {
- print STDERR ".";
- next;
- }
- my $pre_style = '';
- $pre_style = $preformatted_style->{'pre_style'} if (exists $preformatted_style->{'pre_style'});
- my $class = '';
- $class = $preformatted_style->{'class'} if (exists $preformatted_style->{'class'});
- my $style = '';
- $style = $preformatted_style->{'style'} if (exists $preformatted_style->{'style'});
- print STDERR "($pre_style, $class,$style)";
- }
- print STDERR "\n";
- }
- if (defined($state->{'text_macro_stack'}) and @{$state->{'text_macro_stack'}})
- {
- print STDERR "text_macro_stack: (@{$state->{'text_macro_stack'}})\n";
- }
- }
- # for debugging
- sub print_elements($)
- {
- my $elements = shift;
- foreach my $elem(@$elements)
- {
- if ($elem->{'node'})
- {
- print STDERR "node-> $elem ";
- }
- else
- {
- print STDERR "chap=> $elem ";
- }
- foreach my $key (keys(%$elem))
- {
- my $value = "UNDEF";
- $value = $elem->{$key} if (defined($elem->{$key}));
- print STDERR "$key: $value ";
- }
- print STDERR "\n";
- }
- }
- # for debugging
- sub context_string(;$$$)
- {
- my $state = shift;
- my $line_nr = shift;
- my $message = shift;
-
- $state = $Texi2HTML::THISDOC{'state'}
- if (!defined($state) and defined($Texi2HTML::THISDOC{'state'}));
- $line_nr = $Texi2HTML::THISDOC{'line_nr'}
- if (!defined($line_nr) and defined($Texi2HTML::THISDOC{'line_nr'}));
- my $result = "Pass $global_pass";
- my $line_info = ', no line information';
- $line_info = ' ' .format_line_number($line_nr) if (defined($line_nr));
- $result .= $line_info;
- if (!defined($state))
- {
- $result .= ', no state information';
- }
- else
- {
- $result .= ", context $state->{'context'}" if defined($state->{'context'});
- my $expand = '';
- if ($state->{'keep_texi'})
- {
- $expand .= ' no expansion';
- }
- if ($state->{'remove_texi'})
- {
- $expand .= ' raw';
- }
- if ($state->{'preformatted'})
- {
- $expand .= ' preformatted';
- }
- if ($state->{'code_style'})
- {
- $expand .= " 'code'";
- }
- if ($state->{'simple_format'})
- {
- $expand .= ' simple';
- }
- $expand = ' normal' if (!$expand);
- $result .= ',' . $expand;
- if ($state->{'expansion'})
- {
- $result .= ", \@$state->{'expansion'}";
- }
- if ($state->{'region'})
- {
- $result .= ", region $state->{'region'}";
- }
- if ($state->{'outside_document'})
- {
- $result .= "; out";
- }
- if ($state->{'inside_document'})
- {
- $result .= "; in";
- }
- if ($state->{'multiple_pass'})
- {
- $result .= "; multiple $state->{'multiple_pass'}";
- }
- if ($state->{'new_state'})
- {
- $result .= "; new";
- }
- if ($state->{'duplicated'})
- {
- $result .= "; duplicated";
- }
- }
- $result .= "(in @{$Texi2HTML::THISDOC{'command_stack'}})"
- if (defined ($Texi2HTML::THISDOC{'command_stack'}) and @{$Texi2HTML::THISDOC{'command_stack'}});
- $result .= ' ' .$message if ($message);
- return $result;
- }
- my @states_stack = ();
- sub push_state($)
- {
- my $new_state = shift;
- push @states_stack, $new_state;
- $Texi2HTML::THISDOC{'state'} = $new_state;
- }
- sub pop_state()
- {
- pop @states_stack;
- if (@states_stack)
- {
- $Texi2HTML::THISDOC{'state'} = $states_stack[-1];
- }
- else
- {
- $Texi2HTML::THISDOC{'state'} = undef;
- }
- }
- sub substitute_line($$;$$)
- {
- my $line = shift;
- my $context_string = shift;
- my $state = shift;
- my $line_nr = shift;
- $state = {} if (!defined($state));
- $state->{'no_paragraph'} = 1;
- if (($state->{'inside_document'} or $state->{'outside_document'}) and (!$state->{'duplicated'} and !$state->{'new_state'}))
- {
- msg_debug("substitute_line with main state in: ".var_to_str($context_string), $line_nr);
- }
- push @{$state->{'no_paragraph_stack'}}, $context_string;
- # this is usefull when called from &$I, and also for image files
- return simple_format($state, [ $line_nr ], $context_string, $line) if ($state->{'simple_format'});
- return substitute_text($state, [ $line_nr ], $context_string, $line);
- }
- sub substitute_text($$$@)
- {
- my $state = shift;
- my $line_nrs = shift;
- my $context = shift;
- my @stack = ();
- my $text = '';
- my $result = '';
- my $line_nr;
- if ($state->{'structure'})
- {
- initialise_state_structure($state);
- }
- elsif ($state->{'texi'})
- { # only in arg_expansion
- initialise_state_texi($state);
- msg_bug("substitute_text, 'texi' true but not 'arg_expansion'") if (!$state->{'arg_expansion'});
- }
- else
- {
- #print STDERR "FILL_STATE substitute_text ($state->{'preformatted'}): @_\n";
- if (($state->{'inside_document'} or $state->{'outside_document'}) and (!$state->{'duplicated'} and !$state->{'new_state'}))
- {
- msg_debug("substitute_text with main state in: ".var_to_str($context), $line_nr);
- }
- fill_state($state);
- $state->{'context'} = $context;
- }
- $state->{'spool'} = [];
- #print STDERR "SUBST_TEXT ".var_to_str($context)."\n";
- push_state($state);
- my $line_nrs_kept = $Texi2HTML::THISDOC{'line_nr'};
- $Texi2HTML::THISDOC{'line_nr'} = undef;
-
- while (@_ or @{$state->{'spool'}} or $state->{'in_deff_line'})
- {
- my $line;
- if ($line_nrs and @{$line_nrs})
- {
- $line_nr = shift @{$line_nrs};
- $Texi2HTML::THISDOC{'line_nr'} = $line_nr;
- }
- if (@{$state->{'spool'}})
- {
- $line = shift @{$state->{'spool'}};
- }
- else
- {
- $line = shift @_;
- }
- # msg_debug ("SUBSTITUTE_TEXT $line", $line_nr) if (defined($line_nr));
- if ($state->{'in_deff_line'})
- {
- if (defined($line))
- {
- $line = $state->{'in_deff_line'} . $line;
- }
- else
- {
- $line = $state->{'in_deff_line'};
- }
- delete $state->{'in_deff_line'};
- }
- else
- {
- next unless (defined($line));
- }
- #{ my $p_line = $line; chomp($p_line); print STDERR "SUBST_TEXT $p_line\n"; }
- if ($state->{'structure'})
- {
- scan_structure ($line, \$text, \@stack, $state);
- }
- elsif ($state->{'texi'})
- {
- scan_texi ($line, \$text, \@stack, $state);
- }
- else
- {
- set_line_nr_in_stack($state, \@stack, $line_nr);
- scan_line($line, \$text, \@stack, $state, $line_nr);
- }
- next if (@stack);
- $result .= $text;
- $text = '';
- }
- if ($line_nrs and @{$line_nrs})
- {
- $line_nr = shift @{$line_nrs};
- $Texi2HTML::THISDOC{'line_nr'} = $line_nr;
- }
- # close stack in substitute_text
- if ($state->{'texi'})
- {
- close_stack_texi(\$text, \@stack, $state, $line_nr);
- }
- elsif ($state->{'structure'})
- {
- close_stack_structure(\$text, \@stack, $state, $line_nr);
- }
- else
- {
- close_stack(\$text, \@stack, $state, $line_nr);
- }
- #print STDERR "SUBST_TEXT end\n";
- pop_state();
- $Texi2HTML::THISDOC{'line_nr'} = $line_nrs_kept;
- return $result . $text;
- }
- sub print_lines($;$)
- {
- my ($fh, $lines) = @_;
- $lines = $Texi2HTML::THIS_SECTION unless $lines;
- my @cnt;
- my $cnt;
- for my $line (@$lines)
- {
- print $fh $line;
- if (get_conf('WORDS_IN_PAGE') and (get_conf('SPLIT') eq 'node'))
- {
- @cnt = split(/\W*\s+\W*/, $line);
- $cnt += scalar(@cnt);
- }
- }
- return $cnt;
- }
- sub do_index_entry_label($$$$;$)
- {
- my $command = shift;
- my $state = shift;
- my $line_nr = shift;
- my $entry_texi = shift;
- # this is only needed for definitions since the whole line is parsed to
- # reuse get_deff_index.
- my $line = shift;
- my $prefix = index_entry_command_prefix($command, $line, $line_nr);
- my $index_name = $index_prefix_to_name{$prefix};
- msg_debug("do_index_entry_label($command): Undefined entry_texi", $line_nr)
- if (!defined($entry_texi));
- $entry_texi = trim_comment_spaces($entry_texi, "index label in \@$command", $line_nr);
- # index entries are not entered in special regions
- my $region = 'document';
- $region = $state->{'region'} if (defined($state->{'region'}));
- my $entry;
- # Can be within a @caption expanded within a listoffloat. In that
- # case the 2 conditions on state are not set.
- if (defined($state->{'region'}) or !defined($state->{'expansion'}))
- {
- # index entry on a line that is not searched for index entries, like
- # a @def* line
- if (!defined($Texi2HTML::THISDOC{'index_entries'}->{$region}) or !defined($Texi2HTML::THISDOC{'index_entries'}->{$region}->{$entry_texi}))
- {
- line_warn(sprintf(__("Index entry not caught: `%s' in %s"), $entry_texi, $region), $line_nr);
- }
- else
- {
- my $entry_ref = $Texi2HTML::THISDOC{'index_entries'}->{$region}->{$entry_texi};
- # ============================ debug
- if (!defined($entry_ref->{'entries'}))
- {
- msg_debug("BUG, not defined: {'index_entries'}->{$region}->{$entry_texi}->{'entries'}", $line_nr);
- }
- # ============================ end debug
- if (scalar(@{$entry_ref->{'entries'}}) > 1)
- {
- if (!defined($entry_ref->{'index'}))
- {
- $entry_ref->{'index'} = 0;
- }
- $entry = $entry_ref->{'entries'}->[$entry_ref->{'index'}];
- $entry_ref->{'index'}++;
- }
- else
- {
- $entry = $entry_ref->{'entries'}->[0];
- }
- $entry->{'seen_in_output'} = 1 if (!$state->{'outside_document'});
- ############################################# debug
- # verify that the old way of getting index entries (in an array) is
- # synchronized with the document
- if (!$state->{'region'})
- {
- my $entry_from_array = shift @index_labels;
- if ($entry_from_array ne $entry)
- {
- msg_debug ("entry `$entry->{'texi'}' ne entry_from_array `$entry_from_array->{'texi'}'", $line_nr);
- }
- if (!defined($entry_from_array))
- {
- mesg_debug ("Not enough index entries !", $line_nr);
- }
- }
- ############################################# end debug
- }
- }
- if (!defined($entry))
- {
- # this can happen for listoffloats and caption without being a user
- # error. Well, in fact, it could be argued that it is indeed a user
- # error, putting an index entry in a snippet that can be expanded
- # more than once and is not strictly associated with a node/section.
- #print STDERR "Entry for index $index_name not gathered in usual places ($region)\n";
- $entry = {
- 'command' => $command,
- 'texi' => $entry_texi,
- 'entry' => $entry_texi,
- 'prefix' => $prefix,
- 'index_name' => $index_name,
- };
- $entry->{'key'} = sorted_line($entry_texi);
- $entry->{'entry'} = '@code{'.$entry->{'entry'}.'}'
- if (defined($index_name) and
- defined($index_names{$index_name}) and
- $index_names{$index_name}->{$prefix}
- and $entry->{'key'} =~ /\S/);
- }
- ###################################### debug
- else
- {
- if ($entry->{'prefix'} ne $prefix)
- {
- msg_debug ("prefix in entry $entry->{'prefix'} ne $prefix from $command", $line_nr);
- }
- }
- if ($command ne $entry->{'command'})
- {
- # happened with bad texinfo with a line like
- # @deffn func aaaa args @defvr c--ategory d--efvr_name
- # now this case is caught above by "Index entry not caught:
- msg_debug ("($region) Waiting for index cmd \@$entry->{'command'} got \@$command", $line_nr);
- }
- if ($entry->{'texi'} ne $entry_texi)
- {
- msg_debug ("Waiting for index `$entry->{'texi'}', got `$entry_texi'", $line_nr);
- }
-
- my $id = 'no id';
- $id = $entry->{'id'} if (defined($entry->{'id'}));
- print STDERR "(index($index_name) $command) [$entry->{'entry'}] $id\n"
- if ($T2H_DEBUG & $DEBUG_INDEX);
- ###################################### end debug
- #return (undef,'','') if ($state->{'region'});
- if ($entry->{'key'} =~ /^\s*$/)
- {
- line_warn(sprintf(__("Empty index entry for \@%s"), $command), $entry->{'line_nr'});
- }
- my $formatted_entry = substitute_line($entry->{'entry'}, "\@$command", prepare_state_multiple_pass("${command}_index", $state),$entry->{'line_nr'});
- my $formatted_entry_reference = substitute_line($entry->{'texi'}, "\@$command", prepare_state_multiple_pass("${command}_index", $state));
- return ($entry, $formatted_entry, &$Texi2HTML::Config::index_entry_label($entry->{'id'}, $state->{'preformatted'}, $formatted_entry,
- $index_name,
- $command, $entry->{'texi'}, $formatted_entry_reference,
- (!$entry->{'seen_in_output'} and defined($entry->{'region'})),$entry));
- }
- # decompose a decimal number on a given base. The algorithm looks like
- # the division with growing powers (division suivant les puissances
- # croissantes) ?
- sub decompose($$)
- {
- my $number = shift;
- my $base = shift;
- my @result = ();
- return (0) if ($number == 0);
- my $power = 1;
- my $remaining = $number;
- while ($remaining)
- {
- my $factor = $remaining % ($base ** $power);
- $remaining -= $factor;
- push (@result, $factor / ($base ** ($power - 1)));
- $power++;
- }
- return @result;
- }
- # process a css file
- sub process_css_file ($$)
- {
- my $fh =shift;
- my $file = shift;
- my $in_rules = 0;
- my $in_comment = 0;
- my $in_import = 0;
- my $in_string = 0;
- my $rules = [];
- my $imports = [];
- my $line_nr = 0;
- while (my $line = <$fh>)
- {
- $line_nr++;
- #print STDERR "Line: $line";
- if ($in_rules)
- {
- push @$rules, $line;
- next;
- }
- my $text = '';
- while (1)
- {
- #sleep 1;
- #print STDERR "${text}!in_comment $in_comment in_rules $in_rules in_import $in_import in_string $in_string: $line";
- if ($in_comment)
- {
- if ($line =~ s/^(.*?\*\/)//)
- {
- $text .= $1;
- $in_comment = 0;
- }
- else
- {
- push @$imports, $text . $line;
- last;
- }
- }
- elsif (!$in_string and $line =~ s/^\///)
- { # what do '\' do here ?
- if ($line =~ s/^\*//)
- {
- $text .= '/*';
- $in_comment = 1;
- }
- else
- {
- push (@$imports, $text. "\n") if ($text ne '');
- push (@$rules, '/' . $line);
- $in_rules = 1;
- last;
- }
- }
- elsif (!$in_string and $in_import and $line =~ s/^([\"\'])//)
- { # strings outside of import start rules
- $text .= "$1";
- $in_string = quotemeta("$1");
- }
- elsif ($in_string and $line =~ s/^(\\$in_string)//)
- {
- $text .= $1;
- }
- elsif ($in_string and $line =~ s/^($in_string)//)
- {
- $text .= $1;
- $in_string = 0;
- }
- elsif ((! $in_string and !$in_import) and ($line =~ s/^([\\]?\@import)$// or $line =~ s/^([\\]?\@import\s+)//))
- {
- $text .= $1;
- $in_import = 1;
- }
- elsif (!$in_string and $in_import and $line =~ s/^\;//)
- {
- $text .= ';';
- $in_import = 0;
- }
- elsif (($in_import or $in_string) and $line =~ s/^(.)//)
- {
- $text .= $1;
- }
- elsif (!$in_import and $line =~ s/^([^\s])//)
- {
- push (@$imports, $text. "\n") if ($text ne '');
- push (@$rules, $1 . $line);
- $in_rules = 1;
- last;
- }
- elsif ($line =~ s/^(\s)//)
- {
- $text .= $1;
- }
- elsif ($line eq '')
- {
- push (@$imports, $text);
- last;
- }
- }
- }
- #file_line_warn (__("string not closed in css file"), $file) if ($in_string);
- #file_line_warn (__("--css-file ended in comment"), $file) if ($in_comment);
- #file_line_warn (__("\@import not finished in css file"), $file) if ($in_import and !$in_comment and !$in_string);
- warn (sprintf(__("%s:%d: string not closed in css file"), $file, $line_nr)) if ($in_string);
- warn (sprintf(__("%s:%d: --css-file ended in comment"), $file, $line_nr)) if ($in_comment);
- warn (sprintf(__("%s:%d \@import not finished in css file"), $file, $line_nr)) if ($in_import and !$in_comment and !$in_string);
- return ($imports, $rules);
- }
- sub collect_all_css_files()
- {
- my @css_import_lines;
- my @css_rule_lines;
- # process css files
- return ([],[]) if (get_conf('NO_CSS'));
- foreach my $file (@Texi2HTML::Config::CSS_FILES)
- {
- my $css_file_fh;
- my $css_file;
- if ($file eq '-')
- {
- $css_file_fh = \*STDIN;
- $css_file = '-';
- }
- else
- {
- $css_file = locate_include_file ($file);
- unless (defined($css_file))
- {
- document_warn ("css file $file not found");
- next;
- }
- unless (open (CSSFILE, "$css_file"))
- {
- warn (sprintf(__("%s: could not open --css-file %s: %s\n"), $real_command_name, $css_file, $!));
- next;
- }
- $css_file_fh = \*CSSFILE;
- }
- my ($import_lines, $rules_lines);
- ($import_lines, $rules_lines) = process_css_file ($css_file_fh, $css_file);
- push @css_import_lines, @$import_lines;
- push @css_rule_lines, @$rules_lines;
- }
- if ($T2H_DEBUG & $DEBUG_USER)
- {
- if (@css_import_lines)
- {
- print STDERR "# css import lines\n";
- foreach my $line (@css_import_lines)
- {
- print STDERR "$line";
- }
- }
- if (@css_rule_lines)
- {
- print STDERR "# css rule lines\n";
- foreach my $line (@css_rule_lines)
- {
- print STDERR "$line";
- }
- }
- }
- return (\@css_import_lines, \@css_rule_lines);
- }
- sub collect_renamed_nodes()
- {
- # try to set the default if the file exists.
- if (-f $Texi2HTML::THISDOC{'file_base_name'} . '-noderename.cnf')
- {
- set_from_document ('RENAMED_NODES_FILE', $Texi2HTML::THISDOC{'file_base_name'} . '-noderename.cnf');
- }
-
- if (defined(get_conf('RENAMED_NODES_FILE')))
- {
- my $renamed_nodes_file = get_conf('RENAMED_NODES_FILE');
- if (open(RENAMEDFILE, "<$renamed_nodes_file"))
- {
- my $in_encoding = get_conf('IN_ENCODING');
- if (defined($in_encoding) and get_conf('USE_UNICODE'))
- {
- binmode(RENAMEDFILE, ":encoding($in_encoding)");
- }
- my $renamd_nodes_line_nr = 0;
- my @old_names = ();
- while (<RENAMEDFILE>)
- {
- $renamd_nodes_line_nr++;
- next unless (/\S/);
- next if (/^\s*\@c\b/);
- if (s/^\s*\@\@\{\}\s+(\S)/$1/)
- {
- chomp;
- if (scalar(@old_names))
- {
- foreach my $old_node_name (@old_names)
- {
- $Texi2HTML::Config::renamed_nodes{$old_node_name} = normalise_node($_);
- }
- @old_names = ();
- }
- else
- {
- warn (sprintf(__("%s:%d: no node to be renamed\n"), $renamed_nodes_file, $renamd_nodes_line_nr));
- }
- }
- else
- {
- chomp;
- push @old_names, normalise_node($_);
- }
- }
- if (scalar(@old_names))
- {
- warn (sprintf(__("%s:%d: nodes without a new name at the end of file\n"), $renamed_nodes_file, $renamd_nodes_line_nr));
- }
- close(RENAMEDFILE);
- }
- else
- {
- warn (sprintf(__("Cannot read %s: %s"), $renamed_nodes_file, $!));
- }
- }
- }
- sub init_with_file_name($)
- {
- my $base_file = shift;
- set_docu_names($base_file, $Texi2HTML::THISDOC{'input_file_number'});
- foreach my $handler(@Texi2HTML::Config::command_handler_init)
- {
- &$handler;
- }
- }
- #######################################################################
- #
- # Main processing, process all the files given on the command line
- #
- #######################################################################
- my @input_files = @ARGV;
- # use STDIN if not a tty, like makeinfo does
- @input_files = ('-') if (!scalar(@input_files) and !-t STDIN);
- die sprintf(__("%s: missing file argument.\n"), $real_command_name) .$T2H_FAILURE_TEXT unless (scalar(@input_files) >= 1);
- my $file_number = 0;
- # main processing
- while(@input_files)
- {
- my $input_file_arg = shift(@input_files);
- %Texi2HTML::THISDOC = ();
- $Texi2HTML::THIS_ELEMENT = undef;
- foreach my $global_key (keys(%Texi2HTML::GLOBAL))
- {
- $Texi2HTML::THISDOC{$global_key} = $Texi2HTML::GLOBAL{$global_key};
- }
- # copy the keys, otherwise a modification in THISDOC will also modify
- # the global value. This is an issue for other keys too, but they should
- # not be modified.
- $Texi2HTML::THISDOC{'variables'} = {};
- foreach my $variable (keys(%{$Texi2HTML::GLOBAL{'variables'}}))
- {
- $Texi2HTML::THISDOC{'variables'}->{$variable} = $Texi2HTML::GLOBAL{'variables'}->{$variable};
- }
- my $input_file_name;
- # try to concatenate with different suffixes. The last suffix is ''
- # such that the plain file name is checked.
- foreach my $suffix (@Texi2HTML::Config::INPUT_FILE_SUFFIXES)
- {
- $input_file_name = $input_file_arg.$suffix if (-e $input_file_arg.$suffix);
- }
- # in case no file was found, still set the file name
- $input_file_name = $input_file_arg if (!defined($input_file_name));
- $Texi2HTML::THISDOC{'input_file_name'} = $input_file_name;
- $Texi2HTML::THISDOC{'input_file_number'} = $file_number;
- $Texi2HTML::THISDOC{'input_directory'} = '.';
- if ($input_file_name =~ /(.*\/)/)
- {
- $Texi2HTML::THISDOC{'input_directory'} = $1;
- }
- prepare_htmlxref($Texi2HTML::THISDOC{'input_directory'});
- my $input_file_base = $input_file_name;
- $input_file_base =~ s/\.te?x(i|info)?$//;
- @{$Texi2HTML::TOC_LINES} = (); # table of contents
- @{$Texi2HTML::OVERVIEW} = (); # short table of contents
- # this could be done here, but perl warns that
- # `"Texi2HTML::TITLEPAGE" used only once' and it is reset in
- # &$Texi2HTML::Config::titlepage anyway
- # $Texi2HTML::TITLEPAGE = undef;
- @{$Texi2HTML::THIS_SECTION} = ();
- # the reference to these hashes may be used before this point (for example
- # see makeinfo.pm), so they should be kept as is and the values undef
- # but the key should not be deleted because the ref is on the key.
- foreach my $hash (\%Texi2HTML::HREF, \%Texi2HTML::NAME, \%Texi2HTML::NODE,
- \%Texi2HTML::NO_TEXI, \%Texi2HTML::SIMPLE_TEXT)
- {
- foreach my $key (keys(%$hash))
- {
- $hash->{$key} = undef;
- }
- }
- %region_lines = ();
- %region_line_nrs = ();
- foreach my $region (@special_regions)
- {
- $region_lines{$region} = [];
- $region_line_nrs{$region} = [];
- }
- @created_directories = ();
- $docu_dir = undef; # directory of the document
- $docu_name = undef; # basename of the document
- $docu_rdir = undef; # directory for the output
- $docu_toc = undef; # document's table of contents
- $docu_stoc = undef; # document's short toc
- $docu_foot = undef; # document's footnotes
- $docu_about = undef; # about this document
- $docu_top = undef; # document top
- $docu_doc = undef; # document (or document top of split)
- $docu_frame = undef; # main frame file
- $docu_toc_frame = undef; # toc frame file
- $path_to_working_dir = undef; # relative path leading to the working
- # directory from the document directory
- $docu_doc_file = undef;
- $docu_toc_file = undef;
- $docu_stoc_file = undef;
- $docu_foot_file = undef;
- $docu_about_file = undef;
- $docu_top_file = undef;
- $docu_frame_file = undef;
- $docu_toc_frame_file = undef;
- $global_pass = '0';
- # done before any processing, this is not necessarily
- # the case with command_handler_init
- foreach my $handler(@Texi2HTML::Config::command_handler_setup)
- {
- &$handler;
- }
- if (!get_conf('USE_SETFILENAME'))
- {
- init_with_file_name ($input_file_base);
- }
- @Texi2HTML::Config::INCLUDE_DIRS = @include_dirs_orig;
- my @prependended_include_directories = ('.');
- push @prependended_include_directories, $Texi2HTML::THISDOC{'input_directory'} if ($Texi2HTML::THISDOC{'input_directory'} ne '.');
- unshift(@Texi2HTML::Config::INCLUDE_DIRS, @prependended_include_directories);
- unshift(@Texi2HTML::Config::INCLUDE_DIRS, @Texi2HTML::Config::PREPEND_DIRS);
- # FIXME when to do that?
- ($Texi2HTML::THISDOC{'css_import_lines'}, $Texi2HTML::THISDOC{'css_rule_lines'})
- = collect_all_css_files();
- texinfo_initialization(0);
- print STDERR "# reading from $input_file_name\n" if $T2H_VERBOSE;
- $macros = undef; # macros. reference on a hash
- %info_enclose = (); # macros defined with definfoenclose
- @floats = (); # floats list
- %floats = (); # floats by style
- %nodes = (); # nodes hash. The key is the texi node name
- %cross_reference_nodes = (); # normalized node names arrays
- $global_pass = '1';
- my ($texi_lines, $first_texi_lines, $lines_numbers)
- = pass_texi($input_file_name);
- if (get_conf('USE_SETFILENAME') and !defined($docu_name))
- {
- init_with_file_name ($input_file_base);
- }
- $global_pass = '1 expand macros';
- Texi2HTML::Config::t2h_default_set_out_encoding();
- collect_renamed_nodes() if (get_conf('RENAMED_NODES_REDIRECTIONS'));
- dump_texi($texi_lines, 'texi', $lines_numbers) if (($T2H_DEBUG & $DEBUG_TEXI)
- or get_conf('DUMP_TEXI'));
- if (defined(get_conf('MACRO_EXPAND')))
- {
- my @texi_lines = (@$first_texi_lines, @$texi_lines);
- dump_texi(\@texi_lines, '', undef, get_conf('MACRO_EXPAND'));
- }
- %content_element = ();
- foreach my $command('contents', 'shortcontents')
- {
- $all_content_elements{$command} = [];
- foreach my $key (keys(%{$reference_content_element{$command}}))
- {
- $content_element{$command}->{$key} = $reference_content_element{$command}->{$key};
- }
- }
- %sec2level = %reference_sec2level;
- $element_before_anything =
- {
- 'before_anything' => 1,
- 'place' => [],
- 'texi' => 'VIRTUAL ELEMENT BEFORE ANYTHING',
- };
- $footnote_element =
- {
- 'id' => $Texi2HTML::Config::misc_pages_targets{'Footnotes'},
- 'target' => $Texi2HTML::Config::misc_pages_targets{'Footnotes'},
- 'file' => $docu_foot,
- 'footnote' => 1,
- 'place' => [],
- };
- %region_initial_state = ();
- foreach my $region (@special_regions)
- {
- $region_initial_state{$region} = { };
- }
- # to determine if a command has to be processed the following are interesting
- # (and can be faked):
- # 'region': the name of the special region we are processing
- # 'region_pass': the number of passes in that specific region (both outside
- # of the main document, and in the main document)
- # 'multiple_pass': the number of pass in the formatting of the region in the
- # main document
- # It is set to 0 the first time the region is seen, before
- # it will be -1, for example when doing the
- # copying_comment, the titlepage... before starting with
- # the document itself.
- # 'outside_document': set to 1 if outside of the main document formatting
- foreach my $key (keys(%region_initial_state))
- {
- $region_initial_state{$key}->{'multiple_pass'} = -1;
- $region_initial_state{$key}->{'region_pass'} = 0;
- $region_initial_state{$key}->{'num_head'} = 0;
- $region_initial_state{$key}->{'foot_num'} = 0;
- $region_initial_state{$key}->{'relative_foot_num'} = 0;
- $region_initial_state{$key}->{'region'} = $key;
- }
- @opened_files = (); # all the files opened by the program to remove
- # them if FORCE is not set and an error occured
- texinfo_initialization(1);
-
- $no_element_associated_place = [];
- $document_idx_num = 0;
- $document_sec_num = 0;
- $document_head_num = 0;
- $document_anchor_num = 0;
- @nodes_list = (); # nodes in document reading order
- # each member is a reference on a hash
- @sections_list = (); # sections in reading order
- # each member is a reference on a hash
- @all_elements = (); # sectioning elements (nodes and sections)
- # in reading order. Each member is a reference
- # on a hash which also appears in %nodes,
- # @sections_list @nodes_list, @elements_list
- @headings_list = (); # headings in reading order.
- @elements_list = (); # all the resulting elements in document order
- %sections = (); # sections hash. The key is the section number
- %headings = (); # headings hash. The key is the heading number
- $section_top = undef; # @top section
- $element_top = undef; # Top element
- $node_top = undef; # Top node
- $node_first = undef; # First node
- $element_index = undef; # element with first index
- $element_chapter_index = undef; # chapter with first index
- $element_first = undef; # first element
- $element_last = undef; # last element
- %special_commands = (); # hash for the commands specially handled
- # by the user
- @index_labels = (); # array corresponding with @?index commands
- # constructed during pass_texi, used to
- # put labels in pass_text
- # right now it is only used for debugging
- # purposes.
- @unknown_index_index_entries = (); # holds index entries not associated
- # with any index
- %{$Texi2HTML::THISDOC{'index_entries_array'}} = (); # holds the index
- # entries in order of appearance in the document
- # for each index name.
- %{$Texi2HTML::THISDOC{'index_letters_array'}} = (); # holds the sorted
- # index letters for each index name. The sorted
- # letters hold the sorted index entries
- $global_pass = 2;
- my ($doc_lines, $doc_numbers) = pass_structure($texi_lines, $lines_numbers);
- foreach my $handler(@Texi2HTML::Config::command_handler_names)
- {
- &$handler;
- }
- if (($T2H_DEBUG & $DEBUG_TEXI) or get_conf('DUMP_TEXI'))
- {
- dump_texi($doc_lines, 'first', $doc_numbers);
- if (defined(get_conf('MACRO_EXPAND') and get_conf('DUMP_TEXI')))
- {
- my @all_doc_lines = (@$first_texi_lines, @$doc_lines);
- #push (@$doc_lines, "\@bye\n");
- dump_texi(\@all_doc_lines, '', undef, get_conf('MACRO_EXPAND') . ".first");
- }
- }
- next if (get_conf('DUMP_TEXI'));
- foreach my $style (keys(%special_commands))
- {
- $special_commands{$style}->{'max'} = $special_commands{$style}->{'count'};
- }
- %files = (); # keys are files. This is used to avoid reusing an already
- # used file name
- %printed_indices = (); # value is true for an index name not empty and
- # printed
- $global_pass = '2 prepare indices';
- prepare_indices();
- $global_pass = '2 element directions';
- rearrange_elements();
- do_names();
- $global_pass = '2-3 user functions';
- #Texi2HTML::LaTeX2HTML::latex2html();
- foreach my $handler(@Texi2HTML::Config::command_handler_process)
- {
- &$handler;
- }
- # maybe do that later to have more elements ready?
- &$Texi2HTML::Config::toc_body(\@sections_list);
- &$Texi2HTML::Config::css_lines($Texi2HTML::THISDOC{'css_import_lines'},
- $Texi2HTML::THISDOC{'css_rule_lines'});
- $global_head_num = 0; # heading index. it is global for the main doc,
- # and taken from the state if in multiple_pass.
- $global_foot_num = 0;
- $global_relative_foot_num = 0;
- @foot_lines = (); # footnotes
- $copying_comment = ''; # comment constructed from text between
- # @copying and @end copying with licence
- %acronyms_like = (); # acronyms or similar commands associated texts
- # the key are the commands, the values are
- # hash references associating shorthands to
- # texts.
- @states_stack = ();
- pass_text($doc_lines, $doc_numbers);
- print STDERR "BUG: " . scalar(@index_labels) . " index entries pending\n"
- if (scalar(@index_labels));
- foreach my $special (keys(%special_commands))
- {
- my $count = $special_commands{$special}->{'count'};
- if (($count != 0) and $T2H_VERBOSE)
- {
- document_warn ("$count special \@$special were not processed.\n");
- }
- }
- if (get_conf('IDX_SUMMARY'))
- {
- foreach my $entry (sort(keys(%index_names)))
- {
- do_index_summary_file($entry, $docu_name);
- }
- }
- if (defined(get_conf('INTERNAL_LINKS')))
- {
- my $FH = open_out(get_conf('INTERNAL_LINKS'));
- &$Texi2HTML::Config::internal_links($FH, \@elements_list, $Texi2HTML::THISDOC{'index_letters_array'});
- close ($FH);
- }
- do_node_files() if (get_conf('NODE_FILES'));
- do_renamed_node_files() if (get_conf('RENAMED_NODES_REDIRECTIONS'));
- #l2h_FinishFromHtml() if (get_conf('L2H'));
- #l2h_Finish() if(get_conf('L2H'));
- #Texi2HTML::LaTeX2HTML::finish();
- foreach my $handler(@Texi2HTML::Config::command_handler_finish)
- {
- &$handler;
- }
- &$Texi2HTML::Config::finish_out();
- print STDERR "# File ($file_number) $input_file_name processed\n" if $T2H_VERBOSE;
- $file_number++;
- }
- print STDERR "# that's all folks\n" if $T2H_VERBOSE;
- exit(0);
- ##############################################################################
- # These next few lines are legal in both Perl and nroff.
- .00 ; # finish .ig
- 'di \" finish diversion--previous line must be blank
- .nr nl 0-1 \" fake up transition to first page again
- .nr % 0 \" start at page 1
- '; __END__ ############# From here on it's a standard manual page ############
- .so @mandir@/man1/texi2html.1
|