xpath.c 410 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137
  1. /*
  2. * xpath.c: XML Path Language implementation
  3. * XPath is a language for addressing parts of an XML document,
  4. * designed to be used by both XSLT and XPointer
  5. *f
  6. * Reference: W3C Recommendation 16 November 1999
  7. * http://www.w3.org/TR/1999/REC-xpath-19991116
  8. * Public reference:
  9. * http://www.w3.org/TR/xpath
  10. *
  11. * See Copyright for the status of this software
  12. *
  13. * Author: daniel@veillard.com
  14. *
  15. */
  16. #define IN_LIBXML
  17. #include "libxml.h"
  18. #include <string.h>
  19. #ifdef HAVE_SYS_TYPES_H
  20. #include <sys/types.h>
  21. #endif
  22. #ifdef HAVE_MATH_H
  23. #include <math.h>
  24. #endif
  25. #ifdef HAVE_FLOAT_H
  26. #include <float.h>
  27. #endif
  28. #ifdef HAVE_CTYPE_H
  29. #include <ctype.h>
  30. #endif
  31. #ifdef HAVE_SIGNAL_H
  32. #include <signal.h>
  33. #endif
  34. #include <libxml/xmlmemory.h>
  35. #include <libxml/tree.h>
  36. #include <libxml/valid.h>
  37. #include <libxml/xpath.h>
  38. #include <libxml/xpathInternals.h>
  39. #include <libxml/parserInternals.h>
  40. #include <libxml/hash.h>
  41. #ifdef LIBXML_XPTR_ENABLED
  42. #include <libxml/xpointer.h>
  43. #endif
  44. #ifdef LIBXML_DEBUG_ENABLED
  45. #include <libxml/debugXML.h>
  46. #endif
  47. #include <libxml/xmlerror.h>
  48. #include <libxml/threads.h>
  49. #include <libxml/globals.h>
  50. #ifdef LIBXML_PATTERN_ENABLED
  51. #include <libxml/pattern.h>
  52. #endif
  53. #ifdef LIBXML_PATTERN_ENABLED
  54. #define XPATH_STREAMING
  55. #endif
  56. #define TODO \
  57. xmlGenericError(xmlGenericErrorContext, \
  58. "Unimplemented block at %s:%d\n", \
  59. __FILE__, __LINE__);
  60. /*
  61. * XP_OPTIMIZED_NON_ELEM_COMPARISON:
  62. * If defined, this will use xmlXPathCmpNodesExt() instead of
  63. * xmlXPathCmpNodes(). The new function is optimized comparison of
  64. * non-element nodes; actually it will speed up comparison only if
  65. * xmlXPathOrderDocElems() was called in order to index the elements of
  66. * a tree in document order; Libxslt does such an indexing, thus it will
  67. * benefit from this optimization.
  68. */
  69. #define XP_OPTIMIZED_NON_ELEM_COMPARISON
  70. /*
  71. * XP_OPTIMIZED_FILTER_FIRST:
  72. * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
  73. * in a way, that it stop evaluation at the first node.
  74. */
  75. #define XP_OPTIMIZED_FILTER_FIRST
  76. /*
  77. * XP_DEBUG_OBJ_USAGE:
  78. * Internal flag to enable tracking of how much XPath objects have been
  79. * created.
  80. */
  81. /* #define XP_DEBUG_OBJ_USAGE */
  82. /*
  83. * TODO:
  84. * There are a few spots where some tests are done which depend upon ascii
  85. * data. These should be enhanced for full UTF8 support (see particularly
  86. * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
  87. */
  88. #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
  89. /************************************************************************
  90. * *
  91. * Floating point stuff *
  92. * *
  93. ************************************************************************/
  94. #ifndef TRIO_REPLACE_STDIO
  95. #define TRIO_PUBLIC static
  96. #endif
  97. #include "trionan.c"
  98. /*
  99. * The lack of portability of this section of the libc is annoying !
  100. */
  101. double xmlXPathNAN = 0;
  102. double xmlXPathPINF = 1;
  103. double xmlXPathNINF = -1;
  104. static double xmlXPathNZERO = 0; /* not exported from headers */
  105. static int xmlXPathInitialized = 0;
  106. /**
  107. * xmlXPathInit:
  108. *
  109. * Initialize the XPath environment
  110. */
  111. void
  112. xmlXPathInit(void) {
  113. if (xmlXPathInitialized) return;
  114. xmlXPathPINF = trio_pinf();
  115. xmlXPathNINF = trio_ninf();
  116. xmlXPathNAN = trio_nan();
  117. xmlXPathNZERO = trio_nzero();
  118. xmlXPathInitialized = 1;
  119. }
  120. /**
  121. * xmlXPathIsNaN:
  122. * @val: a double value
  123. *
  124. * Provides a portable isnan() function to detect whether a double
  125. * is a NotaNumber. Based on trio code
  126. * http://sourceforge.net/projects/ctrio/
  127. *
  128. * Returns 1 if the value is a NaN, 0 otherwise
  129. */
  130. int
  131. xmlXPathIsNaN(double val) {
  132. return(trio_isnan(val));
  133. }
  134. /**
  135. * xmlXPathIsInf:
  136. * @val: a double value
  137. *
  138. * Provides a portable isinf() function to detect whether a double
  139. * is a +Infinite or -Infinite. Based on trio code
  140. * http://sourceforge.net/projects/ctrio/
  141. *
  142. * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
  143. */
  144. int
  145. xmlXPathIsInf(double val) {
  146. return(trio_isinf(val));
  147. }
  148. #endif /* SCHEMAS or XPATH */
  149. #ifdef LIBXML_XPATH_ENABLED
  150. /**
  151. * xmlXPathGetSign:
  152. * @val: a double value
  153. *
  154. * Provides a portable function to detect the sign of a double
  155. * Modified from trio code
  156. * http://sourceforge.net/projects/ctrio/
  157. *
  158. * Returns 1 if the value is Negative, 0 if positive
  159. */
  160. static int
  161. xmlXPathGetSign(double val) {
  162. return(trio_signbit(val));
  163. }
  164. /*
  165. * TODO: when compatibility allows remove all "fake node libxslt" strings
  166. * the test should just be name[0] = ' '
  167. */
  168. #ifdef DEBUG_XPATH_EXPRESSION
  169. #define DEBUG_STEP
  170. #define DEBUG_EXPR
  171. #define DEBUG_EVAL_COUNTS
  172. #endif
  173. static xmlNs xmlXPathXMLNamespaceStruct = {
  174. NULL,
  175. XML_NAMESPACE_DECL,
  176. XML_XML_NAMESPACE,
  177. BAD_CAST "xml",
  178. NULL,
  179. NULL
  180. };
  181. static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
  182. #ifndef LIBXML_THREAD_ENABLED
  183. /*
  184. * Optimizer is disabled only when threaded apps are detected while
  185. * the library ain't compiled for thread safety.
  186. */
  187. static int xmlXPathDisableOptimizer = 0;
  188. #endif
  189. /************************************************************************
  190. * *
  191. * Error handling routines *
  192. * *
  193. ************************************************************************/
  194. /**
  195. * XP_ERRORNULL:
  196. * @X: the error code
  197. *
  198. * Macro to raise an XPath error and return NULL.
  199. */
  200. #define XP_ERRORNULL(X) \
  201. { xmlXPathErr(ctxt, X); return(NULL); }
  202. /*
  203. * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
  204. */
  205. static const char *xmlXPathErrorMessages[] = {
  206. "Ok\n",
  207. "Number encoding\n",
  208. "Unfinished literal\n",
  209. "Start of literal\n",
  210. "Expected $ for variable reference\n",
  211. "Undefined variable\n",
  212. "Invalid predicate\n",
  213. "Invalid expression\n",
  214. "Missing closing curly brace\n",
  215. "Unregistered function\n",
  216. "Invalid operand\n",
  217. "Invalid type\n",
  218. "Invalid number of arguments\n",
  219. "Invalid context size\n",
  220. "Invalid context position\n",
  221. "Memory allocation error\n",
  222. "Syntax error\n",
  223. "Resource error\n",
  224. "Sub resource error\n",
  225. "Undefined namespace prefix\n",
  226. "Encoding error\n",
  227. "Char out of XML range\n",
  228. "Invalid or incomplete context\n",
  229. "?? Unknown error ??\n" /* Must be last in the list! */
  230. };
  231. #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
  232. sizeof(xmlXPathErrorMessages[0])) - 1)
  233. /**
  234. * xmlXPathErrMemory:
  235. * @ctxt: an XPath context
  236. * @extra: extra informations
  237. *
  238. * Handle a redefinition of attribute error
  239. */
  240. static void
  241. xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
  242. {
  243. if (ctxt != NULL) {
  244. if (extra) {
  245. xmlChar buf[200];
  246. xmlStrPrintf(buf, 200,
  247. BAD_CAST "Memory allocation failed : %s\n",
  248. extra);
  249. ctxt->lastError.message = (char *) xmlStrdup(buf);
  250. } else {
  251. ctxt->lastError.message = (char *)
  252. xmlStrdup(BAD_CAST "Memory allocation failed\n");
  253. }
  254. ctxt->lastError.domain = XML_FROM_XPATH;
  255. ctxt->lastError.code = XML_ERR_NO_MEMORY;
  256. if (ctxt->error != NULL)
  257. ctxt->error(ctxt->userData, &ctxt->lastError);
  258. } else {
  259. if (extra)
  260. __xmlRaiseError(NULL, NULL, NULL,
  261. NULL, NULL, XML_FROM_XPATH,
  262. XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
  263. extra, NULL, NULL, 0, 0,
  264. "Memory allocation failed : %s\n", extra);
  265. else
  266. __xmlRaiseError(NULL, NULL, NULL,
  267. NULL, NULL, XML_FROM_XPATH,
  268. XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
  269. NULL, NULL, NULL, 0, 0,
  270. "Memory allocation failed\n");
  271. }
  272. }
  273. /**
  274. * xmlXPathPErrMemory:
  275. * @ctxt: an XPath parser context
  276. * @extra: extra informations
  277. *
  278. * Handle a redefinition of attribute error
  279. */
  280. static void
  281. xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
  282. {
  283. if (ctxt == NULL)
  284. xmlXPathErrMemory(NULL, extra);
  285. else {
  286. ctxt->error = XPATH_MEMORY_ERROR;
  287. xmlXPathErrMemory(ctxt->context, extra);
  288. }
  289. }
  290. /**
  291. * xmlXPathErr:
  292. * @ctxt: a XPath parser context
  293. * @error: the error code
  294. *
  295. * Handle an XPath error
  296. */
  297. void
  298. xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
  299. {
  300. if ((error < 0) || (error > MAXERRNO))
  301. error = MAXERRNO;
  302. if (ctxt == NULL) {
  303. __xmlRaiseError(NULL, NULL, NULL,
  304. NULL, NULL, XML_FROM_XPATH,
  305. error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  306. XML_ERR_ERROR, NULL, 0,
  307. NULL, NULL, NULL, 0, 0,
  308. "%s", xmlXPathErrorMessages[error]);
  309. return;
  310. }
  311. ctxt->error = error;
  312. if (ctxt->context == NULL) {
  313. __xmlRaiseError(NULL, NULL, NULL,
  314. NULL, NULL, XML_FROM_XPATH,
  315. error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  316. XML_ERR_ERROR, NULL, 0,
  317. (const char *) ctxt->base, NULL, NULL,
  318. ctxt->cur - ctxt->base, 0,
  319. "%s", xmlXPathErrorMessages[error]);
  320. return;
  321. }
  322. /* cleanup current last error */
  323. xmlResetError(&ctxt->context->lastError);
  324. ctxt->context->lastError.domain = XML_FROM_XPATH;
  325. ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
  326. XPATH_EXPRESSION_OK;
  327. ctxt->context->lastError.level = XML_ERR_ERROR;
  328. ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
  329. ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
  330. ctxt->context->lastError.node = ctxt->context->debugNode;
  331. if (ctxt->context->error != NULL) {
  332. ctxt->context->error(ctxt->context->userData,
  333. &ctxt->context->lastError);
  334. } else {
  335. __xmlRaiseError(NULL, NULL, NULL,
  336. NULL, ctxt->context->debugNode, XML_FROM_XPATH,
  337. error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  338. XML_ERR_ERROR, NULL, 0,
  339. (const char *) ctxt->base, NULL, NULL,
  340. ctxt->cur - ctxt->base, 0,
  341. "%s", xmlXPathErrorMessages[error]);
  342. }
  343. }
  344. /**
  345. * xmlXPatherror:
  346. * @ctxt: the XPath Parser context
  347. * @file: the file name
  348. * @line: the line number
  349. * @no: the error number
  350. *
  351. * Formats an error message.
  352. */
  353. void
  354. xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
  355. int line ATTRIBUTE_UNUSED, int no) {
  356. xmlXPathErr(ctxt, no);
  357. }
  358. /************************************************************************
  359. * *
  360. * Utilities *
  361. * *
  362. ************************************************************************/
  363. /**
  364. * xsltPointerList:
  365. *
  366. * Pointer-list for various purposes.
  367. */
  368. typedef struct _xmlPointerList xmlPointerList;
  369. typedef xmlPointerList *xmlPointerListPtr;
  370. struct _xmlPointerList {
  371. void **items;
  372. int number;
  373. int size;
  374. };
  375. /*
  376. * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
  377. * and here, we should make the functions public.
  378. */
  379. static int
  380. xmlPointerListAddSize(xmlPointerListPtr list,
  381. void *item,
  382. int initialSize)
  383. {
  384. if (list->items == NULL) {
  385. if (initialSize <= 0)
  386. initialSize = 1;
  387. list->items = (void **) xmlMalloc(
  388. initialSize * sizeof(void *));
  389. if (list->items == NULL) {
  390. xmlXPathErrMemory(NULL,
  391. "xmlPointerListCreate: allocating item\n");
  392. return(-1);
  393. }
  394. list->number = 0;
  395. list->size = initialSize;
  396. } else if (list->size <= list->number) {
  397. list->size *= 2;
  398. list->items = (void **) xmlRealloc(list->items,
  399. list->size * sizeof(void *));
  400. if (list->items == NULL) {
  401. xmlXPathErrMemory(NULL,
  402. "xmlPointerListCreate: re-allocating item\n");
  403. list->size = 0;
  404. return(-1);
  405. }
  406. }
  407. list->items[list->number++] = item;
  408. return(0);
  409. }
  410. /**
  411. * xsltPointerListCreate:
  412. *
  413. * Creates an xsltPointerList structure.
  414. *
  415. * Returns a xsltPointerList structure or NULL in case of an error.
  416. */
  417. static xmlPointerListPtr
  418. xmlPointerListCreate(int initialSize)
  419. {
  420. xmlPointerListPtr ret;
  421. ret = xmlMalloc(sizeof(xmlPointerList));
  422. if (ret == NULL) {
  423. xmlXPathErrMemory(NULL,
  424. "xmlPointerListCreate: allocating item\n");
  425. return (NULL);
  426. }
  427. memset(ret, 0, sizeof(xmlPointerList));
  428. if (initialSize > 0) {
  429. xmlPointerListAddSize(ret, NULL, initialSize);
  430. ret->number = 0;
  431. }
  432. return (ret);
  433. }
  434. /**
  435. * xsltPointerListFree:
  436. *
  437. * Frees the xsltPointerList structure. This does not free
  438. * the content of the list.
  439. */
  440. static void
  441. xmlPointerListFree(xmlPointerListPtr list)
  442. {
  443. if (list == NULL)
  444. return;
  445. if (list->items != NULL)
  446. xmlFree(list->items);
  447. xmlFree(list);
  448. }
  449. /************************************************************************
  450. * *
  451. * Parser Types *
  452. * *
  453. ************************************************************************/
  454. /*
  455. * Types are private:
  456. */
  457. typedef enum {
  458. XPATH_OP_END=0,
  459. XPATH_OP_AND,
  460. XPATH_OP_OR,
  461. XPATH_OP_EQUAL,
  462. XPATH_OP_CMP,
  463. XPATH_OP_PLUS,
  464. XPATH_OP_MULT,
  465. XPATH_OP_UNION,
  466. XPATH_OP_ROOT,
  467. XPATH_OP_NODE,
  468. XPATH_OP_RESET, /* 10 */
  469. XPATH_OP_COLLECT,
  470. XPATH_OP_VALUE, /* 12 */
  471. XPATH_OP_VARIABLE,
  472. XPATH_OP_FUNCTION,
  473. XPATH_OP_ARG,
  474. XPATH_OP_PREDICATE,
  475. XPATH_OP_FILTER, /* 17 */
  476. XPATH_OP_SORT /* 18 */
  477. #ifdef LIBXML_XPTR_ENABLED
  478. ,XPATH_OP_RANGETO
  479. #endif
  480. } xmlXPathOp;
  481. typedef enum {
  482. AXIS_ANCESTOR = 1,
  483. AXIS_ANCESTOR_OR_SELF,
  484. AXIS_ATTRIBUTE,
  485. AXIS_CHILD,
  486. AXIS_DESCENDANT,
  487. AXIS_DESCENDANT_OR_SELF,
  488. AXIS_FOLLOWING,
  489. AXIS_FOLLOWING_SIBLING,
  490. AXIS_NAMESPACE,
  491. AXIS_PARENT,
  492. AXIS_PRECEDING,
  493. AXIS_PRECEDING_SIBLING,
  494. AXIS_SELF
  495. } xmlXPathAxisVal;
  496. typedef enum {
  497. NODE_TEST_NONE = 0,
  498. NODE_TEST_TYPE = 1,
  499. NODE_TEST_PI = 2,
  500. NODE_TEST_ALL = 3,
  501. NODE_TEST_NS = 4,
  502. NODE_TEST_NAME = 5
  503. } xmlXPathTestVal;
  504. typedef enum {
  505. NODE_TYPE_NODE = 0,
  506. NODE_TYPE_COMMENT = XML_COMMENT_NODE,
  507. NODE_TYPE_TEXT = XML_TEXT_NODE,
  508. NODE_TYPE_PI = XML_PI_NODE
  509. } xmlXPathTypeVal;
  510. #define XP_REWRITE_DOS_CHILD_ELEM 1
  511. typedef struct _xmlXPathStepOp xmlXPathStepOp;
  512. typedef xmlXPathStepOp *xmlXPathStepOpPtr;
  513. struct _xmlXPathStepOp {
  514. xmlXPathOp op; /* The identifier of the operation */
  515. int ch1; /* First child */
  516. int ch2; /* Second child */
  517. int value;
  518. int value2;
  519. int value3;
  520. void *value4;
  521. void *value5;
  522. void *cache;
  523. void *cacheURI;
  524. int rewriteType;
  525. };
  526. struct _xmlXPathCompExpr {
  527. int nbStep; /* Number of steps in this expression */
  528. int maxStep; /* Maximum number of steps allocated */
  529. xmlXPathStepOp *steps; /* ops for computation of this expression */
  530. int last; /* index of last step in expression */
  531. xmlChar *expr; /* the expression being computed */
  532. xmlDictPtr dict; /* the dictionnary to use if any */
  533. #ifdef DEBUG_EVAL_COUNTS
  534. int nb;
  535. xmlChar *string;
  536. #endif
  537. #ifdef XPATH_STREAMING
  538. xmlPatternPtr stream;
  539. #endif
  540. };
  541. /************************************************************************
  542. * *
  543. * Forward declarations *
  544. * *
  545. ************************************************************************/
  546. static void
  547. xmlXPathFreeValueTree(xmlNodeSetPtr obj);
  548. static void
  549. xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
  550. static int
  551. xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
  552. xmlXPathStepOpPtr op, xmlNodePtr *first);
  553. static int
  554. xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
  555. xmlXPathStepOpPtr op,
  556. int isPredicate);
  557. /************************************************************************
  558. * *
  559. * Parser Type functions *
  560. * *
  561. ************************************************************************/
  562. /**
  563. * xmlXPathNewCompExpr:
  564. *
  565. * Create a new Xpath component
  566. *
  567. * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
  568. */
  569. static xmlXPathCompExprPtr
  570. xmlXPathNewCompExpr(void) {
  571. xmlXPathCompExprPtr cur;
  572. cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
  573. if (cur == NULL) {
  574. xmlXPathErrMemory(NULL, "allocating component\n");
  575. return(NULL);
  576. }
  577. memset(cur, 0, sizeof(xmlXPathCompExpr));
  578. cur->maxStep = 10;
  579. cur->nbStep = 0;
  580. cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
  581. sizeof(xmlXPathStepOp));
  582. if (cur->steps == NULL) {
  583. xmlXPathErrMemory(NULL, "allocating steps\n");
  584. xmlFree(cur);
  585. return(NULL);
  586. }
  587. memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
  588. cur->last = -1;
  589. #ifdef DEBUG_EVAL_COUNTS
  590. cur->nb = 0;
  591. #endif
  592. return(cur);
  593. }
  594. /**
  595. * xmlXPathFreeCompExpr:
  596. * @comp: an XPATH comp
  597. *
  598. * Free up the memory allocated by @comp
  599. */
  600. void
  601. xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
  602. {
  603. xmlXPathStepOpPtr op;
  604. int i;
  605. if (comp == NULL)
  606. return;
  607. if (comp->dict == NULL) {
  608. for (i = 0; i < comp->nbStep; i++) {
  609. op = &comp->steps[i];
  610. if (op->value4 != NULL) {
  611. if (op->op == XPATH_OP_VALUE)
  612. xmlXPathFreeObject(op->value4);
  613. else
  614. xmlFree(op->value4);
  615. }
  616. if (op->value5 != NULL)
  617. xmlFree(op->value5);
  618. }
  619. } else {
  620. for (i = 0; i < comp->nbStep; i++) {
  621. op = &comp->steps[i];
  622. if (op->value4 != NULL) {
  623. if (op->op == XPATH_OP_VALUE)
  624. xmlXPathFreeObject(op->value4);
  625. }
  626. }
  627. xmlDictFree(comp->dict);
  628. }
  629. if (comp->steps != NULL) {
  630. xmlFree(comp->steps);
  631. }
  632. #ifdef DEBUG_EVAL_COUNTS
  633. if (comp->string != NULL) {
  634. xmlFree(comp->string);
  635. }
  636. #endif
  637. #ifdef XPATH_STREAMING
  638. if (comp->stream != NULL) {
  639. xmlFreePatternList(comp->stream);
  640. }
  641. #endif
  642. if (comp->expr != NULL) {
  643. xmlFree(comp->expr);
  644. }
  645. xmlFree(comp);
  646. }
  647. /**
  648. * xmlXPathCompExprAdd:
  649. * @comp: the compiled expression
  650. * @ch1: first child index
  651. * @ch2: second child index
  652. * @op: an op
  653. * @value: the first int value
  654. * @value2: the second int value
  655. * @value3: the third int value
  656. * @value4: the first string value
  657. * @value5: the second string value
  658. *
  659. * Add a step to an XPath Compiled Expression
  660. *
  661. * Returns -1 in case of failure, the index otherwise
  662. */
  663. static int
  664. xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
  665. xmlXPathOp op, int value,
  666. int value2, int value3, void *value4, void *value5) {
  667. if (comp->nbStep >= comp->maxStep) {
  668. xmlXPathStepOp *real;
  669. comp->maxStep *= 2;
  670. real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
  671. comp->maxStep * sizeof(xmlXPathStepOp));
  672. if (real == NULL) {
  673. comp->maxStep /= 2;
  674. xmlXPathErrMemory(NULL, "adding step\n");
  675. return(-1);
  676. }
  677. comp->steps = real;
  678. }
  679. comp->last = comp->nbStep;
  680. comp->steps[comp->nbStep].rewriteType = 0;
  681. comp->steps[comp->nbStep].ch1 = ch1;
  682. comp->steps[comp->nbStep].ch2 = ch2;
  683. comp->steps[comp->nbStep].op = op;
  684. comp->steps[comp->nbStep].value = value;
  685. comp->steps[comp->nbStep].value2 = value2;
  686. comp->steps[comp->nbStep].value3 = value3;
  687. if ((comp->dict != NULL) &&
  688. ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
  689. (op == XPATH_OP_COLLECT))) {
  690. if (value4 != NULL) {
  691. comp->steps[comp->nbStep].value4 = (xmlChar *)
  692. (void *)xmlDictLookup(comp->dict, value4, -1);
  693. xmlFree(value4);
  694. } else
  695. comp->steps[comp->nbStep].value4 = NULL;
  696. if (value5 != NULL) {
  697. comp->steps[comp->nbStep].value5 = (xmlChar *)
  698. (void *)xmlDictLookup(comp->dict, value5, -1);
  699. xmlFree(value5);
  700. } else
  701. comp->steps[comp->nbStep].value5 = NULL;
  702. } else {
  703. comp->steps[comp->nbStep].value4 = value4;
  704. comp->steps[comp->nbStep].value5 = value5;
  705. }
  706. comp->steps[comp->nbStep].cache = NULL;
  707. return(comp->nbStep++);
  708. }
  709. /**
  710. * xmlXPathCompSwap:
  711. * @comp: the compiled expression
  712. * @op: operation index
  713. *
  714. * Swaps 2 operations in the compiled expression
  715. */
  716. static void
  717. xmlXPathCompSwap(xmlXPathStepOpPtr op) {
  718. int tmp;
  719. #ifndef LIBXML_THREAD_ENABLED
  720. /*
  721. * Since this manipulates possibly shared variables, this is
  722. * disabled if one detects that the library is used in a multithreaded
  723. * application
  724. */
  725. if (xmlXPathDisableOptimizer)
  726. return;
  727. #endif
  728. tmp = op->ch1;
  729. op->ch1 = op->ch2;
  730. op->ch2 = tmp;
  731. }
  732. #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
  733. xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
  734. (op), (val), (val2), (val3), (val4), (val5))
  735. #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
  736. xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
  737. (op), (val), (val2), (val3), (val4), (val5))
  738. #define PUSH_LEAVE_EXPR(op, val, val2) \
  739. xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
  740. #define PUSH_UNARY_EXPR(op, ch, val, val2) \
  741. xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
  742. #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
  743. xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
  744. (val), (val2), 0 ,NULL ,NULL)
  745. /************************************************************************
  746. * *
  747. * XPath object cache structures *
  748. * *
  749. ************************************************************************/
  750. /* #define XP_DEFAULT_CACHE_ON */
  751. #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
  752. typedef struct _xmlXPathContextCache xmlXPathContextCache;
  753. typedef xmlXPathContextCache *xmlXPathContextCachePtr;
  754. struct _xmlXPathContextCache {
  755. xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
  756. xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
  757. xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
  758. xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
  759. xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
  760. int maxNodeset;
  761. int maxString;
  762. int maxBoolean;
  763. int maxNumber;
  764. int maxMisc;
  765. #ifdef XP_DEBUG_OBJ_USAGE
  766. int dbgCachedAll;
  767. int dbgCachedNodeset;
  768. int dbgCachedString;
  769. int dbgCachedBool;
  770. int dbgCachedNumber;
  771. int dbgCachedPoint;
  772. int dbgCachedRange;
  773. int dbgCachedLocset;
  774. int dbgCachedUsers;
  775. int dbgCachedXSLTTree;
  776. int dbgCachedUndefined;
  777. int dbgReusedAll;
  778. int dbgReusedNodeset;
  779. int dbgReusedString;
  780. int dbgReusedBool;
  781. int dbgReusedNumber;
  782. int dbgReusedPoint;
  783. int dbgReusedRange;
  784. int dbgReusedLocset;
  785. int dbgReusedUsers;
  786. int dbgReusedXSLTTree;
  787. int dbgReusedUndefined;
  788. #endif
  789. };
  790. /************************************************************************
  791. * *
  792. * Debugging related functions *
  793. * *
  794. ************************************************************************/
  795. #define STRANGE \
  796. xmlGenericError(xmlGenericErrorContext, \
  797. "Internal error at %s:%d\n", \
  798. __FILE__, __LINE__);
  799. #ifdef LIBXML_DEBUG_ENABLED
  800. static void
  801. xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
  802. int i;
  803. char shift[100];
  804. for (i = 0;((i < depth) && (i < 25));i++)
  805. shift[2 * i] = shift[2 * i + 1] = ' ';
  806. shift[2 * i] = shift[2 * i + 1] = 0;
  807. if (cur == NULL) {
  808. fprintf(output, "%s", shift);
  809. fprintf(output, "Node is NULL !\n");
  810. return;
  811. }
  812. if ((cur->type == XML_DOCUMENT_NODE) ||
  813. (cur->type == XML_HTML_DOCUMENT_NODE)) {
  814. fprintf(output, "%s", shift);
  815. fprintf(output, " /\n");
  816. } else if (cur->type == XML_ATTRIBUTE_NODE)
  817. xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
  818. else
  819. xmlDebugDumpOneNode(output, cur, depth);
  820. }
  821. static void
  822. xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
  823. xmlNodePtr tmp;
  824. int i;
  825. char shift[100];
  826. for (i = 0;((i < depth) && (i < 25));i++)
  827. shift[2 * i] = shift[2 * i + 1] = ' ';
  828. shift[2 * i] = shift[2 * i + 1] = 0;
  829. if (cur == NULL) {
  830. fprintf(output, "%s", shift);
  831. fprintf(output, "Node is NULL !\n");
  832. return;
  833. }
  834. while (cur != NULL) {
  835. tmp = cur;
  836. cur = cur->next;
  837. xmlDebugDumpOneNode(output, tmp, depth);
  838. }
  839. }
  840. static void
  841. xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
  842. int i;
  843. char shift[100];
  844. for (i = 0;((i < depth) && (i < 25));i++)
  845. shift[2 * i] = shift[2 * i + 1] = ' ';
  846. shift[2 * i] = shift[2 * i + 1] = 0;
  847. if (cur == NULL) {
  848. fprintf(output, "%s", shift);
  849. fprintf(output, "NodeSet is NULL !\n");
  850. return;
  851. }
  852. if (cur != NULL) {
  853. fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
  854. for (i = 0;i < cur->nodeNr;i++) {
  855. fprintf(output, "%s", shift);
  856. fprintf(output, "%d", i + 1);
  857. xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
  858. }
  859. }
  860. }
  861. static void
  862. xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
  863. int i;
  864. char shift[100];
  865. for (i = 0;((i < depth) && (i < 25));i++)
  866. shift[2 * i] = shift[2 * i + 1] = ' ';
  867. shift[2 * i] = shift[2 * i + 1] = 0;
  868. if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
  869. fprintf(output, "%s", shift);
  870. fprintf(output, "Value Tree is NULL !\n");
  871. return;
  872. }
  873. fprintf(output, "%s", shift);
  874. fprintf(output, "%d", i + 1);
  875. xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
  876. }
  877. #if defined(LIBXML_XPTR_ENABLED)
  878. static void
  879. xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
  880. int i;
  881. char shift[100];
  882. for (i = 0;((i < depth) && (i < 25));i++)
  883. shift[2 * i] = shift[2 * i + 1] = ' ';
  884. shift[2 * i] = shift[2 * i + 1] = 0;
  885. if (cur == NULL) {
  886. fprintf(output, "%s", shift);
  887. fprintf(output, "LocationSet is NULL !\n");
  888. return;
  889. }
  890. for (i = 0;i < cur->locNr;i++) {
  891. fprintf(output, "%s", shift);
  892. fprintf(output, "%d : ", i + 1);
  893. xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
  894. }
  895. }
  896. #endif /* LIBXML_XPTR_ENABLED */
  897. /**
  898. * xmlXPathDebugDumpObject:
  899. * @output: the FILE * to dump the output
  900. * @cur: the object to inspect
  901. * @depth: indentation level
  902. *
  903. * Dump the content of the object for debugging purposes
  904. */
  905. void
  906. xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
  907. int i;
  908. char shift[100];
  909. if (output == NULL) return;
  910. for (i = 0;((i < depth) && (i < 25));i++)
  911. shift[2 * i] = shift[2 * i + 1] = ' ';
  912. shift[2 * i] = shift[2 * i + 1] = 0;
  913. fprintf(output, "%s", shift);
  914. if (cur == NULL) {
  915. fprintf(output, "Object is empty (NULL)\n");
  916. return;
  917. }
  918. switch(cur->type) {
  919. case XPATH_UNDEFINED:
  920. fprintf(output, "Object is uninitialized\n");
  921. break;
  922. case XPATH_NODESET:
  923. fprintf(output, "Object is a Node Set :\n");
  924. xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
  925. break;
  926. case XPATH_XSLT_TREE:
  927. fprintf(output, "Object is an XSLT value tree :\n");
  928. xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
  929. break;
  930. case XPATH_BOOLEAN:
  931. fprintf(output, "Object is a Boolean : ");
  932. if (cur->boolval) fprintf(output, "true\n");
  933. else fprintf(output, "false\n");
  934. break;
  935. case XPATH_NUMBER:
  936. switch (xmlXPathIsInf(cur->floatval)) {
  937. case 1:
  938. fprintf(output, "Object is a number : Infinity\n");
  939. break;
  940. case -1:
  941. fprintf(output, "Object is a number : -Infinity\n");
  942. break;
  943. default:
  944. if (xmlXPathIsNaN(cur->floatval)) {
  945. fprintf(output, "Object is a number : NaN\n");
  946. } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
  947. fprintf(output, "Object is a number : 0\n");
  948. } else {
  949. fprintf(output, "Object is a number : %0g\n", cur->floatval);
  950. }
  951. }
  952. break;
  953. case XPATH_STRING:
  954. fprintf(output, "Object is a string : ");
  955. xmlDebugDumpString(output, cur->stringval);
  956. fprintf(output, "\n");
  957. break;
  958. case XPATH_POINT:
  959. fprintf(output, "Object is a point : index %d in node", cur->index);
  960. xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
  961. fprintf(output, "\n");
  962. break;
  963. case XPATH_RANGE:
  964. if ((cur->user2 == NULL) ||
  965. ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
  966. fprintf(output, "Object is a collapsed range :\n");
  967. fprintf(output, "%s", shift);
  968. if (cur->index >= 0)
  969. fprintf(output, "index %d in ", cur->index);
  970. fprintf(output, "node\n");
  971. xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
  972. depth + 1);
  973. } else {
  974. fprintf(output, "Object is a range :\n");
  975. fprintf(output, "%s", shift);
  976. fprintf(output, "From ");
  977. if (cur->index >= 0)
  978. fprintf(output, "index %d in ", cur->index);
  979. fprintf(output, "node\n");
  980. xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
  981. depth + 1);
  982. fprintf(output, "%s", shift);
  983. fprintf(output, "To ");
  984. if (cur->index2 >= 0)
  985. fprintf(output, "index %d in ", cur->index2);
  986. fprintf(output, "node\n");
  987. xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
  988. depth + 1);
  989. fprintf(output, "\n");
  990. }
  991. break;
  992. case XPATH_LOCATIONSET:
  993. #if defined(LIBXML_XPTR_ENABLED)
  994. fprintf(output, "Object is a Location Set:\n");
  995. xmlXPathDebugDumpLocationSet(output,
  996. (xmlLocationSetPtr) cur->user, depth);
  997. #endif
  998. break;
  999. case XPATH_USERS:
  1000. fprintf(output, "Object is user defined\n");
  1001. break;
  1002. }
  1003. }
  1004. static void
  1005. xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
  1006. xmlXPathStepOpPtr op, int depth) {
  1007. int i;
  1008. char shift[100];
  1009. for (i = 0;((i < depth) && (i < 25));i++)
  1010. shift[2 * i] = shift[2 * i + 1] = ' ';
  1011. shift[2 * i] = shift[2 * i + 1] = 0;
  1012. fprintf(output, "%s", shift);
  1013. if (op == NULL) {
  1014. fprintf(output, "Step is NULL\n");
  1015. return;
  1016. }
  1017. switch (op->op) {
  1018. case XPATH_OP_END:
  1019. fprintf(output, "END"); break;
  1020. case XPATH_OP_AND:
  1021. fprintf(output, "AND"); break;
  1022. case XPATH_OP_OR:
  1023. fprintf(output, "OR"); break;
  1024. case XPATH_OP_EQUAL:
  1025. if (op->value)
  1026. fprintf(output, "EQUAL =");
  1027. else
  1028. fprintf(output, "EQUAL !=");
  1029. break;
  1030. case XPATH_OP_CMP:
  1031. if (op->value)
  1032. fprintf(output, "CMP <");
  1033. else
  1034. fprintf(output, "CMP >");
  1035. if (!op->value2)
  1036. fprintf(output, "=");
  1037. break;
  1038. case XPATH_OP_PLUS:
  1039. if (op->value == 0)
  1040. fprintf(output, "PLUS -");
  1041. else if (op->value == 1)
  1042. fprintf(output, "PLUS +");
  1043. else if (op->value == 2)
  1044. fprintf(output, "PLUS unary -");
  1045. else if (op->value == 3)
  1046. fprintf(output, "PLUS unary - -");
  1047. break;
  1048. case XPATH_OP_MULT:
  1049. if (op->value == 0)
  1050. fprintf(output, "MULT *");
  1051. else if (op->value == 1)
  1052. fprintf(output, "MULT div");
  1053. else
  1054. fprintf(output, "MULT mod");
  1055. break;
  1056. case XPATH_OP_UNION:
  1057. fprintf(output, "UNION"); break;
  1058. case XPATH_OP_ROOT:
  1059. fprintf(output, "ROOT"); break;
  1060. case XPATH_OP_NODE:
  1061. fprintf(output, "NODE"); break;
  1062. case XPATH_OP_RESET:
  1063. fprintf(output, "RESET"); break;
  1064. case XPATH_OP_SORT:
  1065. fprintf(output, "SORT"); break;
  1066. case XPATH_OP_COLLECT: {
  1067. xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
  1068. xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
  1069. xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
  1070. const xmlChar *prefix = op->value4;
  1071. const xmlChar *name = op->value5;
  1072. fprintf(output, "COLLECT ");
  1073. switch (axis) {
  1074. case AXIS_ANCESTOR:
  1075. fprintf(output, " 'ancestors' "); break;
  1076. case AXIS_ANCESTOR_OR_SELF:
  1077. fprintf(output, " 'ancestors-or-self' "); break;
  1078. case AXIS_ATTRIBUTE:
  1079. fprintf(output, " 'attributes' "); break;
  1080. case AXIS_CHILD:
  1081. fprintf(output, " 'child' "); break;
  1082. case AXIS_DESCENDANT:
  1083. fprintf(output, " 'descendant' "); break;
  1084. case AXIS_DESCENDANT_OR_SELF:
  1085. fprintf(output, " 'descendant-or-self' "); break;
  1086. case AXIS_FOLLOWING:
  1087. fprintf(output, " 'following' "); break;
  1088. case AXIS_FOLLOWING_SIBLING:
  1089. fprintf(output, " 'following-siblings' "); break;
  1090. case AXIS_NAMESPACE:
  1091. fprintf(output, " 'namespace' "); break;
  1092. case AXIS_PARENT:
  1093. fprintf(output, " 'parent' "); break;
  1094. case AXIS_PRECEDING:
  1095. fprintf(output, " 'preceding' "); break;
  1096. case AXIS_PRECEDING_SIBLING:
  1097. fprintf(output, " 'preceding-sibling' "); break;
  1098. case AXIS_SELF:
  1099. fprintf(output, " 'self' "); break;
  1100. }
  1101. switch (test) {
  1102. case NODE_TEST_NONE:
  1103. fprintf(output, "'none' "); break;
  1104. case NODE_TEST_TYPE:
  1105. fprintf(output, "'type' "); break;
  1106. case NODE_TEST_PI:
  1107. fprintf(output, "'PI' "); break;
  1108. case NODE_TEST_ALL:
  1109. fprintf(output, "'all' "); break;
  1110. case NODE_TEST_NS:
  1111. fprintf(output, "'namespace' "); break;
  1112. case NODE_TEST_NAME:
  1113. fprintf(output, "'name' "); break;
  1114. }
  1115. switch (type) {
  1116. case NODE_TYPE_NODE:
  1117. fprintf(output, "'node' "); break;
  1118. case NODE_TYPE_COMMENT:
  1119. fprintf(output, "'comment' "); break;
  1120. case NODE_TYPE_TEXT:
  1121. fprintf(output, "'text' "); break;
  1122. case NODE_TYPE_PI:
  1123. fprintf(output, "'PI' "); break;
  1124. }
  1125. if (prefix != NULL)
  1126. fprintf(output, "%s:", prefix);
  1127. if (name != NULL)
  1128. fprintf(output, "%s", (const char *) name);
  1129. break;
  1130. }
  1131. case XPATH_OP_VALUE: {
  1132. xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
  1133. fprintf(output, "ELEM ");
  1134. xmlXPathDebugDumpObject(output, object, 0);
  1135. goto finish;
  1136. }
  1137. case XPATH_OP_VARIABLE: {
  1138. const xmlChar *prefix = op->value5;
  1139. const xmlChar *name = op->value4;
  1140. if (prefix != NULL)
  1141. fprintf(output, "VARIABLE %s:%s", prefix, name);
  1142. else
  1143. fprintf(output, "VARIABLE %s", name);
  1144. break;
  1145. }
  1146. case XPATH_OP_FUNCTION: {
  1147. int nbargs = op->value;
  1148. const xmlChar *prefix = op->value5;
  1149. const xmlChar *name = op->value4;
  1150. if (prefix != NULL)
  1151. fprintf(output, "FUNCTION %s:%s(%d args)",
  1152. prefix, name, nbargs);
  1153. else
  1154. fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
  1155. break;
  1156. }
  1157. case XPATH_OP_ARG: fprintf(output, "ARG"); break;
  1158. case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
  1159. case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
  1160. #ifdef LIBXML_XPTR_ENABLED
  1161. case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
  1162. #endif
  1163. default:
  1164. fprintf(output, "UNKNOWN %d\n", op->op); return;
  1165. }
  1166. fprintf(output, "\n");
  1167. finish:
  1168. if (op->ch1 >= 0)
  1169. xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
  1170. if (op->ch2 >= 0)
  1171. xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
  1172. }
  1173. /**
  1174. * xmlXPathDebugDumpCompExpr:
  1175. * @output: the FILE * for the output
  1176. * @comp: the precompiled XPath expression
  1177. * @depth: the indentation level.
  1178. *
  1179. * Dumps the tree of the compiled XPath expression.
  1180. */
  1181. void
  1182. xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
  1183. int depth) {
  1184. int i;
  1185. char shift[100];
  1186. if ((output == NULL) || (comp == NULL)) return;
  1187. for (i = 0;((i < depth) && (i < 25));i++)
  1188. shift[2 * i] = shift[2 * i + 1] = ' ';
  1189. shift[2 * i] = shift[2 * i + 1] = 0;
  1190. fprintf(output, "%s", shift);
  1191. fprintf(output, "Compiled Expression : %d elements\n",
  1192. comp->nbStep);
  1193. i = comp->last;
  1194. xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
  1195. }
  1196. #ifdef XP_DEBUG_OBJ_USAGE
  1197. /*
  1198. * XPath object usage related debugging variables.
  1199. */
  1200. static int xmlXPathDebugObjCounterUndefined = 0;
  1201. static int xmlXPathDebugObjCounterNodeset = 0;
  1202. static int xmlXPathDebugObjCounterBool = 0;
  1203. static int xmlXPathDebugObjCounterNumber = 0;
  1204. static int xmlXPathDebugObjCounterString = 0;
  1205. static int xmlXPathDebugObjCounterPoint = 0;
  1206. static int xmlXPathDebugObjCounterRange = 0;
  1207. static int xmlXPathDebugObjCounterLocset = 0;
  1208. static int xmlXPathDebugObjCounterUsers = 0;
  1209. static int xmlXPathDebugObjCounterXSLTTree = 0;
  1210. static int xmlXPathDebugObjCounterAll = 0;
  1211. static int xmlXPathDebugObjTotalUndefined = 0;
  1212. static int xmlXPathDebugObjTotalNodeset = 0;
  1213. static int xmlXPathDebugObjTotalBool = 0;
  1214. static int xmlXPathDebugObjTotalNumber = 0;
  1215. static int xmlXPathDebugObjTotalString = 0;
  1216. static int xmlXPathDebugObjTotalPoint = 0;
  1217. static int xmlXPathDebugObjTotalRange = 0;
  1218. static int xmlXPathDebugObjTotalLocset = 0;
  1219. static int xmlXPathDebugObjTotalUsers = 0;
  1220. static int xmlXPathDebugObjTotalXSLTTree = 0;
  1221. static int xmlXPathDebugObjTotalAll = 0;
  1222. static int xmlXPathDebugObjMaxUndefined = 0;
  1223. static int xmlXPathDebugObjMaxNodeset = 0;
  1224. static int xmlXPathDebugObjMaxBool = 0;
  1225. static int xmlXPathDebugObjMaxNumber = 0;
  1226. static int xmlXPathDebugObjMaxString = 0;
  1227. static int xmlXPathDebugObjMaxPoint = 0;
  1228. static int xmlXPathDebugObjMaxRange = 0;
  1229. static int xmlXPathDebugObjMaxLocset = 0;
  1230. static int xmlXPathDebugObjMaxUsers = 0;
  1231. static int xmlXPathDebugObjMaxXSLTTree = 0;
  1232. static int xmlXPathDebugObjMaxAll = 0;
  1233. /* REVISIT TODO: Make this static when committing */
  1234. static void
  1235. xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
  1236. {
  1237. if (ctxt != NULL) {
  1238. if (ctxt->cache != NULL) {
  1239. xmlXPathContextCachePtr cache =
  1240. (xmlXPathContextCachePtr) ctxt->cache;
  1241. cache->dbgCachedAll = 0;
  1242. cache->dbgCachedNodeset = 0;
  1243. cache->dbgCachedString = 0;
  1244. cache->dbgCachedBool = 0;
  1245. cache->dbgCachedNumber = 0;
  1246. cache->dbgCachedPoint = 0;
  1247. cache->dbgCachedRange = 0;
  1248. cache->dbgCachedLocset = 0;
  1249. cache->dbgCachedUsers = 0;
  1250. cache->dbgCachedXSLTTree = 0;
  1251. cache->dbgCachedUndefined = 0;
  1252. cache->dbgReusedAll = 0;
  1253. cache->dbgReusedNodeset = 0;
  1254. cache->dbgReusedString = 0;
  1255. cache->dbgReusedBool = 0;
  1256. cache->dbgReusedNumber = 0;
  1257. cache->dbgReusedPoint = 0;
  1258. cache->dbgReusedRange = 0;
  1259. cache->dbgReusedLocset = 0;
  1260. cache->dbgReusedUsers = 0;
  1261. cache->dbgReusedXSLTTree = 0;
  1262. cache->dbgReusedUndefined = 0;
  1263. }
  1264. }
  1265. xmlXPathDebugObjCounterUndefined = 0;
  1266. xmlXPathDebugObjCounterNodeset = 0;
  1267. xmlXPathDebugObjCounterBool = 0;
  1268. xmlXPathDebugObjCounterNumber = 0;
  1269. xmlXPathDebugObjCounterString = 0;
  1270. xmlXPathDebugObjCounterPoint = 0;
  1271. xmlXPathDebugObjCounterRange = 0;
  1272. xmlXPathDebugObjCounterLocset = 0;
  1273. xmlXPathDebugObjCounterUsers = 0;
  1274. xmlXPathDebugObjCounterXSLTTree = 0;
  1275. xmlXPathDebugObjCounterAll = 0;
  1276. xmlXPathDebugObjTotalUndefined = 0;
  1277. xmlXPathDebugObjTotalNodeset = 0;
  1278. xmlXPathDebugObjTotalBool = 0;
  1279. xmlXPathDebugObjTotalNumber = 0;
  1280. xmlXPathDebugObjTotalString = 0;
  1281. xmlXPathDebugObjTotalPoint = 0;
  1282. xmlXPathDebugObjTotalRange = 0;
  1283. xmlXPathDebugObjTotalLocset = 0;
  1284. xmlXPathDebugObjTotalUsers = 0;
  1285. xmlXPathDebugObjTotalXSLTTree = 0;
  1286. xmlXPathDebugObjTotalAll = 0;
  1287. xmlXPathDebugObjMaxUndefined = 0;
  1288. xmlXPathDebugObjMaxNodeset = 0;
  1289. xmlXPathDebugObjMaxBool = 0;
  1290. xmlXPathDebugObjMaxNumber = 0;
  1291. xmlXPathDebugObjMaxString = 0;
  1292. xmlXPathDebugObjMaxPoint = 0;
  1293. xmlXPathDebugObjMaxRange = 0;
  1294. xmlXPathDebugObjMaxLocset = 0;
  1295. xmlXPathDebugObjMaxUsers = 0;
  1296. xmlXPathDebugObjMaxXSLTTree = 0;
  1297. xmlXPathDebugObjMaxAll = 0;
  1298. }
  1299. static void
  1300. xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
  1301. xmlXPathObjectType objType)
  1302. {
  1303. int isCached = 0;
  1304. if (ctxt != NULL) {
  1305. if (ctxt->cache != NULL) {
  1306. xmlXPathContextCachePtr cache =
  1307. (xmlXPathContextCachePtr) ctxt->cache;
  1308. isCached = 1;
  1309. cache->dbgReusedAll++;
  1310. switch (objType) {
  1311. case XPATH_UNDEFINED:
  1312. cache->dbgReusedUndefined++;
  1313. break;
  1314. case XPATH_NODESET:
  1315. cache->dbgReusedNodeset++;
  1316. break;
  1317. case XPATH_BOOLEAN:
  1318. cache->dbgReusedBool++;
  1319. break;
  1320. case XPATH_NUMBER:
  1321. cache->dbgReusedNumber++;
  1322. break;
  1323. case XPATH_STRING:
  1324. cache->dbgReusedString++;
  1325. break;
  1326. case XPATH_POINT:
  1327. cache->dbgReusedPoint++;
  1328. break;
  1329. case XPATH_RANGE:
  1330. cache->dbgReusedRange++;
  1331. break;
  1332. case XPATH_LOCATIONSET:
  1333. cache->dbgReusedLocset++;
  1334. break;
  1335. case XPATH_USERS:
  1336. cache->dbgReusedUsers++;
  1337. break;
  1338. case XPATH_XSLT_TREE:
  1339. cache->dbgReusedXSLTTree++;
  1340. break;
  1341. default:
  1342. break;
  1343. }
  1344. }
  1345. }
  1346. switch (objType) {
  1347. case XPATH_UNDEFINED:
  1348. if (! isCached)
  1349. xmlXPathDebugObjTotalUndefined++;
  1350. xmlXPathDebugObjCounterUndefined++;
  1351. if (xmlXPathDebugObjCounterUndefined >
  1352. xmlXPathDebugObjMaxUndefined)
  1353. xmlXPathDebugObjMaxUndefined =
  1354. xmlXPathDebugObjCounterUndefined;
  1355. break;
  1356. case XPATH_NODESET:
  1357. if (! isCached)
  1358. xmlXPathDebugObjTotalNodeset++;
  1359. xmlXPathDebugObjCounterNodeset++;
  1360. if (xmlXPathDebugObjCounterNodeset >
  1361. xmlXPathDebugObjMaxNodeset)
  1362. xmlXPathDebugObjMaxNodeset =
  1363. xmlXPathDebugObjCounterNodeset;
  1364. break;
  1365. case XPATH_BOOLEAN:
  1366. if (! isCached)
  1367. xmlXPathDebugObjTotalBool++;
  1368. xmlXPathDebugObjCounterBool++;
  1369. if (xmlXPathDebugObjCounterBool >
  1370. xmlXPathDebugObjMaxBool)
  1371. xmlXPathDebugObjMaxBool =
  1372. xmlXPathDebugObjCounterBool;
  1373. break;
  1374. case XPATH_NUMBER:
  1375. if (! isCached)
  1376. xmlXPathDebugObjTotalNumber++;
  1377. xmlXPathDebugObjCounterNumber++;
  1378. if (xmlXPathDebugObjCounterNumber >
  1379. xmlXPathDebugObjMaxNumber)
  1380. xmlXPathDebugObjMaxNumber =
  1381. xmlXPathDebugObjCounterNumber;
  1382. break;
  1383. case XPATH_STRING:
  1384. if (! isCached)
  1385. xmlXPathDebugObjTotalString++;
  1386. xmlXPathDebugObjCounterString++;
  1387. if (xmlXPathDebugObjCounterString >
  1388. xmlXPathDebugObjMaxString)
  1389. xmlXPathDebugObjMaxString =
  1390. xmlXPathDebugObjCounterString;
  1391. break;
  1392. case XPATH_POINT:
  1393. if (! isCached)
  1394. xmlXPathDebugObjTotalPoint++;
  1395. xmlXPathDebugObjCounterPoint++;
  1396. if (xmlXPathDebugObjCounterPoint >
  1397. xmlXPathDebugObjMaxPoint)
  1398. xmlXPathDebugObjMaxPoint =
  1399. xmlXPathDebugObjCounterPoint;
  1400. break;
  1401. case XPATH_RANGE:
  1402. if (! isCached)
  1403. xmlXPathDebugObjTotalRange++;
  1404. xmlXPathDebugObjCounterRange++;
  1405. if (xmlXPathDebugObjCounterRange >
  1406. xmlXPathDebugObjMaxRange)
  1407. xmlXPathDebugObjMaxRange =
  1408. xmlXPathDebugObjCounterRange;
  1409. break;
  1410. case XPATH_LOCATIONSET:
  1411. if (! isCached)
  1412. xmlXPathDebugObjTotalLocset++;
  1413. xmlXPathDebugObjCounterLocset++;
  1414. if (xmlXPathDebugObjCounterLocset >
  1415. xmlXPathDebugObjMaxLocset)
  1416. xmlXPathDebugObjMaxLocset =
  1417. xmlXPathDebugObjCounterLocset;
  1418. break;
  1419. case XPATH_USERS:
  1420. if (! isCached)
  1421. xmlXPathDebugObjTotalUsers++;
  1422. xmlXPathDebugObjCounterUsers++;
  1423. if (xmlXPathDebugObjCounterUsers >
  1424. xmlXPathDebugObjMaxUsers)
  1425. xmlXPathDebugObjMaxUsers =
  1426. xmlXPathDebugObjCounterUsers;
  1427. break;
  1428. case XPATH_XSLT_TREE:
  1429. if (! isCached)
  1430. xmlXPathDebugObjTotalXSLTTree++;
  1431. xmlXPathDebugObjCounterXSLTTree++;
  1432. if (xmlXPathDebugObjCounterXSLTTree >
  1433. xmlXPathDebugObjMaxXSLTTree)
  1434. xmlXPathDebugObjMaxXSLTTree =
  1435. xmlXPathDebugObjCounterXSLTTree;
  1436. break;
  1437. default:
  1438. break;
  1439. }
  1440. if (! isCached)
  1441. xmlXPathDebugObjTotalAll++;
  1442. xmlXPathDebugObjCounterAll++;
  1443. if (xmlXPathDebugObjCounterAll >
  1444. xmlXPathDebugObjMaxAll)
  1445. xmlXPathDebugObjMaxAll =
  1446. xmlXPathDebugObjCounterAll;
  1447. }
  1448. static void
  1449. xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
  1450. xmlXPathObjectType objType)
  1451. {
  1452. int isCached = 0;
  1453. if (ctxt != NULL) {
  1454. if (ctxt->cache != NULL) {
  1455. xmlXPathContextCachePtr cache =
  1456. (xmlXPathContextCachePtr) ctxt->cache;
  1457. isCached = 1;
  1458. cache->dbgCachedAll++;
  1459. switch (objType) {
  1460. case XPATH_UNDEFINED:
  1461. cache->dbgCachedUndefined++;
  1462. break;
  1463. case XPATH_NODESET:
  1464. cache->dbgCachedNodeset++;
  1465. break;
  1466. case XPATH_BOOLEAN:
  1467. cache->dbgCachedBool++;
  1468. break;
  1469. case XPATH_NUMBER:
  1470. cache->dbgCachedNumber++;
  1471. break;
  1472. case XPATH_STRING:
  1473. cache->dbgCachedString++;
  1474. break;
  1475. case XPATH_POINT:
  1476. cache->dbgCachedPoint++;
  1477. break;
  1478. case XPATH_RANGE:
  1479. cache->dbgCachedRange++;
  1480. break;
  1481. case XPATH_LOCATIONSET:
  1482. cache->dbgCachedLocset++;
  1483. break;
  1484. case XPATH_USERS:
  1485. cache->dbgCachedUsers++;
  1486. break;
  1487. case XPATH_XSLT_TREE:
  1488. cache->dbgCachedXSLTTree++;
  1489. break;
  1490. default:
  1491. break;
  1492. }
  1493. }
  1494. }
  1495. switch (objType) {
  1496. case XPATH_UNDEFINED:
  1497. xmlXPathDebugObjCounterUndefined--;
  1498. break;
  1499. case XPATH_NODESET:
  1500. xmlXPathDebugObjCounterNodeset--;
  1501. break;
  1502. case XPATH_BOOLEAN:
  1503. xmlXPathDebugObjCounterBool--;
  1504. break;
  1505. case XPATH_NUMBER:
  1506. xmlXPathDebugObjCounterNumber--;
  1507. break;
  1508. case XPATH_STRING:
  1509. xmlXPathDebugObjCounterString--;
  1510. break;
  1511. case XPATH_POINT:
  1512. xmlXPathDebugObjCounterPoint--;
  1513. break;
  1514. case XPATH_RANGE:
  1515. xmlXPathDebugObjCounterRange--;
  1516. break;
  1517. case XPATH_LOCATIONSET:
  1518. xmlXPathDebugObjCounterLocset--;
  1519. break;
  1520. case XPATH_USERS:
  1521. xmlXPathDebugObjCounterUsers--;
  1522. break;
  1523. case XPATH_XSLT_TREE:
  1524. xmlXPathDebugObjCounterXSLTTree--;
  1525. break;
  1526. default:
  1527. break;
  1528. }
  1529. xmlXPathDebugObjCounterAll--;
  1530. }
  1531. /* REVISIT TODO: Make this static when committing */
  1532. static void
  1533. xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
  1534. {
  1535. int reqAll, reqNodeset, reqString, reqBool, reqNumber,
  1536. reqXSLTTree, reqUndefined;
  1537. int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
  1538. caNumber = 0, caXSLTTree = 0, caUndefined = 0;
  1539. int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
  1540. reNumber = 0, reXSLTTree = 0, reUndefined = 0;
  1541. int leftObjs = xmlXPathDebugObjCounterAll;
  1542. reqAll = xmlXPathDebugObjTotalAll;
  1543. reqNodeset = xmlXPathDebugObjTotalNodeset;
  1544. reqString = xmlXPathDebugObjTotalString;
  1545. reqBool = xmlXPathDebugObjTotalBool;
  1546. reqNumber = xmlXPathDebugObjTotalNumber;
  1547. reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
  1548. reqUndefined = xmlXPathDebugObjTotalUndefined;
  1549. printf("# XPath object usage:\n");
  1550. if (ctxt != NULL) {
  1551. if (ctxt->cache != NULL) {
  1552. xmlXPathContextCachePtr cache =
  1553. (xmlXPathContextCachePtr) ctxt->cache;
  1554. reAll = cache->dbgReusedAll;
  1555. reqAll += reAll;
  1556. reNodeset = cache->dbgReusedNodeset;
  1557. reqNodeset += reNodeset;
  1558. reString = cache->dbgReusedString;
  1559. reqString += reString;
  1560. reBool = cache->dbgReusedBool;
  1561. reqBool += reBool;
  1562. reNumber = cache->dbgReusedNumber;
  1563. reqNumber += reNumber;
  1564. reXSLTTree = cache->dbgReusedXSLTTree;
  1565. reqXSLTTree += reXSLTTree;
  1566. reUndefined = cache->dbgReusedUndefined;
  1567. reqUndefined += reUndefined;
  1568. caAll = cache->dbgCachedAll;
  1569. caBool = cache->dbgCachedBool;
  1570. caNodeset = cache->dbgCachedNodeset;
  1571. caString = cache->dbgCachedString;
  1572. caNumber = cache->dbgCachedNumber;
  1573. caXSLTTree = cache->dbgCachedXSLTTree;
  1574. caUndefined = cache->dbgCachedUndefined;
  1575. if (cache->nodesetObjs)
  1576. leftObjs -= cache->nodesetObjs->number;
  1577. if (cache->stringObjs)
  1578. leftObjs -= cache->stringObjs->number;
  1579. if (cache->booleanObjs)
  1580. leftObjs -= cache->booleanObjs->number;
  1581. if (cache->numberObjs)
  1582. leftObjs -= cache->numberObjs->number;
  1583. if (cache->miscObjs)
  1584. leftObjs -= cache->miscObjs->number;
  1585. }
  1586. }
  1587. printf("# all\n");
  1588. printf("# total : %d\n", reqAll);
  1589. printf("# left : %d\n", leftObjs);
  1590. printf("# created: %d\n", xmlXPathDebugObjTotalAll);
  1591. printf("# reused : %d\n", reAll);
  1592. printf("# max : %d\n", xmlXPathDebugObjMaxAll);
  1593. printf("# node-sets\n");
  1594. printf("# total : %d\n", reqNodeset);
  1595. printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
  1596. printf("# reused : %d\n", reNodeset);
  1597. printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
  1598. printf("# strings\n");
  1599. printf("# total : %d\n", reqString);
  1600. printf("# created: %d\n", xmlXPathDebugObjTotalString);
  1601. printf("# reused : %d\n", reString);
  1602. printf("# max : %d\n", xmlXPathDebugObjMaxString);
  1603. printf("# booleans\n");
  1604. printf("# total : %d\n", reqBool);
  1605. printf("# created: %d\n", xmlXPathDebugObjTotalBool);
  1606. printf("# reused : %d\n", reBool);
  1607. printf("# max : %d\n", xmlXPathDebugObjMaxBool);
  1608. printf("# numbers\n");
  1609. printf("# total : %d\n", reqNumber);
  1610. printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
  1611. printf("# reused : %d\n", reNumber);
  1612. printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
  1613. printf("# XSLT result tree fragments\n");
  1614. printf("# total : %d\n", reqXSLTTree);
  1615. printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
  1616. printf("# reused : %d\n", reXSLTTree);
  1617. printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
  1618. printf("# undefined\n");
  1619. printf("# total : %d\n", reqUndefined);
  1620. printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
  1621. printf("# reused : %d\n", reUndefined);
  1622. printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
  1623. }
  1624. #endif /* XP_DEBUG_OBJ_USAGE */
  1625. #endif /* LIBXML_DEBUG_ENABLED */
  1626. /************************************************************************
  1627. * *
  1628. * XPath object caching *
  1629. * *
  1630. ************************************************************************/
  1631. /**
  1632. * xmlXPathNewCache:
  1633. *
  1634. * Create a new object cache
  1635. *
  1636. * Returns the xmlXPathCache just allocated.
  1637. */
  1638. static xmlXPathContextCachePtr
  1639. xmlXPathNewCache(void)
  1640. {
  1641. xmlXPathContextCachePtr ret;
  1642. ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
  1643. if (ret == NULL) {
  1644. xmlXPathErrMemory(NULL, "creating object cache\n");
  1645. return(NULL);
  1646. }
  1647. memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
  1648. ret->maxNodeset = 100;
  1649. ret->maxString = 100;
  1650. ret->maxBoolean = 100;
  1651. ret->maxNumber = 100;
  1652. ret->maxMisc = 100;
  1653. return(ret);
  1654. }
  1655. static void
  1656. xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
  1657. {
  1658. int i;
  1659. xmlXPathObjectPtr obj;
  1660. if (list == NULL)
  1661. return;
  1662. for (i = 0; i < list->number; i++) {
  1663. obj = list->items[i];
  1664. /*
  1665. * Note that it is already assured that we don't need to
  1666. * look out for namespace nodes in the node-set.
  1667. */
  1668. if (obj->nodesetval != NULL) {
  1669. if (obj->nodesetval->nodeTab != NULL)
  1670. xmlFree(obj->nodesetval->nodeTab);
  1671. xmlFree(obj->nodesetval);
  1672. }
  1673. xmlFree(obj);
  1674. #ifdef XP_DEBUG_OBJ_USAGE
  1675. xmlXPathDebugObjCounterAll--;
  1676. #endif
  1677. }
  1678. xmlPointerListFree(list);
  1679. }
  1680. static void
  1681. xmlXPathFreeCache(xmlXPathContextCachePtr cache)
  1682. {
  1683. if (cache == NULL)
  1684. return;
  1685. if (cache->nodesetObjs)
  1686. xmlXPathCacheFreeObjectList(cache->nodesetObjs);
  1687. if (cache->stringObjs)
  1688. xmlXPathCacheFreeObjectList(cache->stringObjs);
  1689. if (cache->booleanObjs)
  1690. xmlXPathCacheFreeObjectList(cache->booleanObjs);
  1691. if (cache->numberObjs)
  1692. xmlXPathCacheFreeObjectList(cache->numberObjs);
  1693. if (cache->miscObjs)
  1694. xmlXPathCacheFreeObjectList(cache->miscObjs);
  1695. xmlFree(cache);
  1696. }
  1697. /**
  1698. * xmlXPathContextSetCache:
  1699. *
  1700. * @ctxt: the XPath context
  1701. * @active: enables/disables (creates/frees) the cache
  1702. * @value: a value with semantics dependant on @options
  1703. * @options: options (currently only the value 0 is used)
  1704. *
  1705. * Creates/frees an object cache on the XPath context.
  1706. * If activates XPath objects (xmlXPathObject) will be cached internally
  1707. * to be reused.
  1708. * @options:
  1709. * 0: This will set the XPath object caching:
  1710. * @value:
  1711. * This will set the maximum number of XPath objects
  1712. * to be cached per slot
  1713. * There are 5 slots for: node-set, string, number, boolean, and
  1714. * misc objects. Use <0 for the default number (100).
  1715. * Other values for @options have currently no effect.
  1716. *
  1717. * Returns 0 if the setting succeeded, and -1 on API or internal errors.
  1718. */
  1719. int
  1720. xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
  1721. int active,
  1722. int value,
  1723. int options)
  1724. {
  1725. if (ctxt == NULL)
  1726. return(-1);
  1727. if (active) {
  1728. xmlXPathContextCachePtr cache;
  1729. if (ctxt->cache == NULL) {
  1730. ctxt->cache = xmlXPathNewCache();
  1731. if (ctxt->cache == NULL)
  1732. return(-1);
  1733. }
  1734. cache = (xmlXPathContextCachePtr) ctxt->cache;
  1735. if (options == 0) {
  1736. if (value < 0)
  1737. value = 100;
  1738. cache->maxNodeset = value;
  1739. cache->maxString = value;
  1740. cache->maxNumber = value;
  1741. cache->maxBoolean = value;
  1742. cache->maxMisc = value;
  1743. }
  1744. } else if (ctxt->cache != NULL) {
  1745. xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
  1746. ctxt->cache = NULL;
  1747. }
  1748. return(0);
  1749. }
  1750. /**
  1751. * xmlXPathCacheWrapNodeSet:
  1752. * @ctxt: the XPath context
  1753. * @val: the NodePtr value
  1754. *
  1755. * This is the cached version of xmlXPathWrapNodeSet().
  1756. * Wrap the Nodeset @val in a new xmlXPathObjectPtr
  1757. *
  1758. * Returns the created or reused object.
  1759. */
  1760. static xmlXPathObjectPtr
  1761. xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
  1762. {
  1763. if ((ctxt != NULL) && (ctxt->cache != NULL)) {
  1764. xmlXPathContextCachePtr cache =
  1765. (xmlXPathContextCachePtr) ctxt->cache;
  1766. if ((cache->miscObjs != NULL) &&
  1767. (cache->miscObjs->number != 0))
  1768. {
  1769. xmlXPathObjectPtr ret;
  1770. ret = (xmlXPathObjectPtr)
  1771. cache->miscObjs->items[--cache->miscObjs->number];
  1772. ret->type = XPATH_NODESET;
  1773. ret->nodesetval = val;
  1774. #ifdef XP_DEBUG_OBJ_USAGE
  1775. xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
  1776. #endif
  1777. return(ret);
  1778. }
  1779. }
  1780. return(xmlXPathWrapNodeSet(val));
  1781. }
  1782. /**
  1783. * xmlXPathCacheWrapString:
  1784. * @ctxt: the XPath context
  1785. * @val: the xmlChar * value
  1786. *
  1787. * This is the cached version of xmlXPathWrapString().
  1788. * Wraps the @val string into an XPath object.
  1789. *
  1790. * Returns the created or reused object.
  1791. */
  1792. static xmlXPathObjectPtr
  1793. xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
  1794. {
  1795. if ((ctxt != NULL) && (ctxt->cache != NULL)) {
  1796. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  1797. if ((cache->stringObjs != NULL) &&
  1798. (cache->stringObjs->number != 0))
  1799. {
  1800. xmlXPathObjectPtr ret;
  1801. ret = (xmlXPathObjectPtr)
  1802. cache->stringObjs->items[--cache->stringObjs->number];
  1803. ret->type = XPATH_STRING;
  1804. ret->stringval = val;
  1805. #ifdef XP_DEBUG_OBJ_USAGE
  1806. xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
  1807. #endif
  1808. return(ret);
  1809. } else if ((cache->miscObjs != NULL) &&
  1810. (cache->miscObjs->number != 0))
  1811. {
  1812. xmlXPathObjectPtr ret;
  1813. /*
  1814. * Fallback to misc-cache.
  1815. */
  1816. ret = (xmlXPathObjectPtr)
  1817. cache->miscObjs->items[--cache->miscObjs->number];
  1818. ret->type = XPATH_STRING;
  1819. ret->stringval = val;
  1820. #ifdef XP_DEBUG_OBJ_USAGE
  1821. xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
  1822. #endif
  1823. return(ret);
  1824. }
  1825. }
  1826. return(xmlXPathWrapString(val));
  1827. }
  1828. /**
  1829. * xmlXPathCacheNewNodeSet:
  1830. * @ctxt: the XPath context
  1831. * @val: the NodePtr value
  1832. *
  1833. * This is the cached version of xmlXPathNewNodeSet().
  1834. * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
  1835. * it with the single Node @val
  1836. *
  1837. * Returns the created or reused object.
  1838. */
  1839. static xmlXPathObjectPtr
  1840. xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
  1841. {
  1842. if ((ctxt != NULL) && (ctxt->cache)) {
  1843. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  1844. if ((cache->nodesetObjs != NULL) &&
  1845. (cache->nodesetObjs->number != 0))
  1846. {
  1847. xmlXPathObjectPtr ret;
  1848. /*
  1849. * Use the nodset-cache.
  1850. */
  1851. ret = (xmlXPathObjectPtr)
  1852. cache->nodesetObjs->items[--cache->nodesetObjs->number];
  1853. ret->type = XPATH_NODESET;
  1854. ret->boolval = 0;
  1855. if (val) {
  1856. if ((ret->nodesetval->nodeMax == 0) ||
  1857. (val->type == XML_NAMESPACE_DECL))
  1858. {
  1859. xmlXPathNodeSetAddUnique(ret->nodesetval, val);
  1860. } else {
  1861. ret->nodesetval->nodeTab[0] = val;
  1862. ret->nodesetval->nodeNr = 1;
  1863. }
  1864. }
  1865. #ifdef XP_DEBUG_OBJ_USAGE
  1866. xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
  1867. #endif
  1868. return(ret);
  1869. } else if ((cache->miscObjs != NULL) &&
  1870. (cache->miscObjs->number != 0))
  1871. {
  1872. xmlXPathObjectPtr ret;
  1873. /*
  1874. * Fallback to misc-cache.
  1875. */
  1876. ret = (xmlXPathObjectPtr)
  1877. cache->miscObjs->items[--cache->miscObjs->number];
  1878. ret->type = XPATH_NODESET;
  1879. ret->boolval = 0;
  1880. ret->nodesetval = xmlXPathNodeSetCreate(val);
  1881. #ifdef XP_DEBUG_OBJ_USAGE
  1882. xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
  1883. #endif
  1884. return(ret);
  1885. }
  1886. }
  1887. return(xmlXPathNewNodeSet(val));
  1888. }
  1889. /**
  1890. * xmlXPathCacheNewCString:
  1891. * @ctxt: the XPath context
  1892. * @val: the char * value
  1893. *
  1894. * This is the cached version of xmlXPathNewCString().
  1895. * Acquire an xmlXPathObjectPtr of type string and of value @val
  1896. *
  1897. * Returns the created or reused object.
  1898. */
  1899. static xmlXPathObjectPtr
  1900. xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
  1901. {
  1902. if ((ctxt != NULL) && (ctxt->cache)) {
  1903. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  1904. if ((cache->stringObjs != NULL) &&
  1905. (cache->stringObjs->number != 0))
  1906. {
  1907. xmlXPathObjectPtr ret;
  1908. ret = (xmlXPathObjectPtr)
  1909. cache->stringObjs->items[--cache->stringObjs->number];
  1910. ret->type = XPATH_STRING;
  1911. ret->stringval = xmlStrdup(BAD_CAST val);
  1912. #ifdef XP_DEBUG_OBJ_USAGE
  1913. xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
  1914. #endif
  1915. return(ret);
  1916. } else if ((cache->miscObjs != NULL) &&
  1917. (cache->miscObjs->number != 0))
  1918. {
  1919. xmlXPathObjectPtr ret;
  1920. ret = (xmlXPathObjectPtr)
  1921. cache->miscObjs->items[--cache->miscObjs->number];
  1922. ret->type = XPATH_STRING;
  1923. ret->stringval = xmlStrdup(BAD_CAST val);
  1924. #ifdef XP_DEBUG_OBJ_USAGE
  1925. xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
  1926. #endif
  1927. return(ret);
  1928. }
  1929. }
  1930. return(xmlXPathNewCString(val));
  1931. }
  1932. /**
  1933. * xmlXPathCacheNewString:
  1934. * @ctxt: the XPath context
  1935. * @val: the xmlChar * value
  1936. *
  1937. * This is the cached version of xmlXPathNewString().
  1938. * Acquire an xmlXPathObjectPtr of type string and of value @val
  1939. *
  1940. * Returns the created or reused object.
  1941. */
  1942. static xmlXPathObjectPtr
  1943. xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
  1944. {
  1945. if ((ctxt != NULL) && (ctxt->cache)) {
  1946. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  1947. if ((cache->stringObjs != NULL) &&
  1948. (cache->stringObjs->number != 0))
  1949. {
  1950. xmlXPathObjectPtr ret;
  1951. ret = (xmlXPathObjectPtr)
  1952. cache->stringObjs->items[--cache->stringObjs->number];
  1953. ret->type = XPATH_STRING;
  1954. if (val != NULL)
  1955. ret->stringval = xmlStrdup(val);
  1956. else
  1957. ret->stringval = xmlStrdup((const xmlChar *)"");
  1958. #ifdef XP_DEBUG_OBJ_USAGE
  1959. xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
  1960. #endif
  1961. return(ret);
  1962. } else if ((cache->miscObjs != NULL) &&
  1963. (cache->miscObjs->number != 0))
  1964. {
  1965. xmlXPathObjectPtr ret;
  1966. ret = (xmlXPathObjectPtr)
  1967. cache->miscObjs->items[--cache->miscObjs->number];
  1968. ret->type = XPATH_STRING;
  1969. if (val != NULL)
  1970. ret->stringval = xmlStrdup(val);
  1971. else
  1972. ret->stringval = xmlStrdup((const xmlChar *)"");
  1973. #ifdef XP_DEBUG_OBJ_USAGE
  1974. xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
  1975. #endif
  1976. return(ret);
  1977. }
  1978. }
  1979. return(xmlXPathNewString(val));
  1980. }
  1981. /**
  1982. * xmlXPathCacheNewBoolean:
  1983. * @ctxt: the XPath context
  1984. * @val: the boolean value
  1985. *
  1986. * This is the cached version of xmlXPathNewBoolean().
  1987. * Acquires an xmlXPathObjectPtr of type boolean and of value @val
  1988. *
  1989. * Returns the created or reused object.
  1990. */
  1991. static xmlXPathObjectPtr
  1992. xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
  1993. {
  1994. if ((ctxt != NULL) && (ctxt->cache)) {
  1995. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  1996. if ((cache->booleanObjs != NULL) &&
  1997. (cache->booleanObjs->number != 0))
  1998. {
  1999. xmlXPathObjectPtr ret;
  2000. ret = (xmlXPathObjectPtr)
  2001. cache->booleanObjs->items[--cache->booleanObjs->number];
  2002. ret->type = XPATH_BOOLEAN;
  2003. ret->boolval = (val != 0);
  2004. #ifdef XP_DEBUG_OBJ_USAGE
  2005. xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
  2006. #endif
  2007. return(ret);
  2008. } else if ((cache->miscObjs != NULL) &&
  2009. (cache->miscObjs->number != 0))
  2010. {
  2011. xmlXPathObjectPtr ret;
  2012. ret = (xmlXPathObjectPtr)
  2013. cache->miscObjs->items[--cache->miscObjs->number];
  2014. ret->type = XPATH_BOOLEAN;
  2015. ret->boolval = (val != 0);
  2016. #ifdef XP_DEBUG_OBJ_USAGE
  2017. xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
  2018. #endif
  2019. return(ret);
  2020. }
  2021. }
  2022. return(xmlXPathNewBoolean(val));
  2023. }
  2024. /**
  2025. * xmlXPathCacheNewFloat:
  2026. * @ctxt: the XPath context
  2027. * @val: the double value
  2028. *
  2029. * This is the cached version of xmlXPathNewFloat().
  2030. * Acquires an xmlXPathObjectPtr of type double and of value @val
  2031. *
  2032. * Returns the created or reused object.
  2033. */
  2034. static xmlXPathObjectPtr
  2035. xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
  2036. {
  2037. if ((ctxt != NULL) && (ctxt->cache)) {
  2038. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  2039. if ((cache->numberObjs != NULL) &&
  2040. (cache->numberObjs->number != 0))
  2041. {
  2042. xmlXPathObjectPtr ret;
  2043. ret = (xmlXPathObjectPtr)
  2044. cache->numberObjs->items[--cache->numberObjs->number];
  2045. ret->type = XPATH_NUMBER;
  2046. ret->floatval = val;
  2047. #ifdef XP_DEBUG_OBJ_USAGE
  2048. xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
  2049. #endif
  2050. return(ret);
  2051. } else if ((cache->miscObjs != NULL) &&
  2052. (cache->miscObjs->number != 0))
  2053. {
  2054. xmlXPathObjectPtr ret;
  2055. ret = (xmlXPathObjectPtr)
  2056. cache->miscObjs->items[--cache->miscObjs->number];
  2057. ret->type = XPATH_NUMBER;
  2058. ret->floatval = val;
  2059. #ifdef XP_DEBUG_OBJ_USAGE
  2060. xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
  2061. #endif
  2062. return(ret);
  2063. }
  2064. }
  2065. return(xmlXPathNewFloat(val));
  2066. }
  2067. /**
  2068. * xmlXPathCacheConvertString:
  2069. * @ctxt: the XPath context
  2070. * @val: an XPath object
  2071. *
  2072. * This is the cached version of xmlXPathConvertString().
  2073. * Converts an existing object to its string() equivalent
  2074. *
  2075. * Returns a created or reused object, the old one is freed (cached)
  2076. * (or the operation is done directly on @val)
  2077. */
  2078. static xmlXPathObjectPtr
  2079. xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
  2080. xmlChar *res = NULL;
  2081. if (val == NULL)
  2082. return(xmlXPathCacheNewCString(ctxt, ""));
  2083. switch (val->type) {
  2084. case XPATH_UNDEFINED:
  2085. #ifdef DEBUG_EXPR
  2086. xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
  2087. #endif
  2088. break;
  2089. case XPATH_NODESET:
  2090. case XPATH_XSLT_TREE:
  2091. res = xmlXPathCastNodeSetToString(val->nodesetval);
  2092. break;
  2093. case XPATH_STRING:
  2094. return(val);
  2095. case XPATH_BOOLEAN:
  2096. res = xmlXPathCastBooleanToString(val->boolval);
  2097. break;
  2098. case XPATH_NUMBER:
  2099. res = xmlXPathCastNumberToString(val->floatval);
  2100. break;
  2101. case XPATH_USERS:
  2102. case XPATH_POINT:
  2103. case XPATH_RANGE:
  2104. case XPATH_LOCATIONSET:
  2105. TODO;
  2106. break;
  2107. }
  2108. xmlXPathReleaseObject(ctxt, val);
  2109. if (res == NULL)
  2110. return(xmlXPathCacheNewCString(ctxt, ""));
  2111. return(xmlXPathCacheWrapString(ctxt, res));
  2112. }
  2113. /**
  2114. * xmlXPathCacheObjectCopy:
  2115. * @ctxt: the XPath context
  2116. * @val: the original object
  2117. *
  2118. * This is the cached version of xmlXPathObjectCopy().
  2119. * Acquire a copy of a given object
  2120. *
  2121. * Returns a created or reused created object.
  2122. */
  2123. static xmlXPathObjectPtr
  2124. xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
  2125. {
  2126. if (val == NULL)
  2127. return(NULL);
  2128. if (XP_HAS_CACHE(ctxt)) {
  2129. switch (val->type) {
  2130. case XPATH_NODESET:
  2131. return(xmlXPathCacheWrapNodeSet(ctxt,
  2132. xmlXPathNodeSetMerge(NULL, val->nodesetval)));
  2133. case XPATH_STRING:
  2134. return(xmlXPathCacheNewString(ctxt, val->stringval));
  2135. case XPATH_BOOLEAN:
  2136. return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
  2137. case XPATH_NUMBER:
  2138. return(xmlXPathCacheNewFloat(ctxt, val->floatval));
  2139. default:
  2140. break;
  2141. }
  2142. }
  2143. return(xmlXPathObjectCopy(val));
  2144. }
  2145. /**
  2146. * xmlXPathCacheConvertBoolean:
  2147. * @ctxt: the XPath context
  2148. * @val: an XPath object
  2149. *
  2150. * This is the cached version of xmlXPathConvertBoolean().
  2151. * Converts an existing object to its boolean() equivalent
  2152. *
  2153. * Returns a created or reused object, the old one is freed (or the operation
  2154. * is done directly on @val)
  2155. */
  2156. static xmlXPathObjectPtr
  2157. xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
  2158. xmlXPathObjectPtr ret;
  2159. if (val == NULL)
  2160. return(xmlXPathCacheNewBoolean(ctxt, 0));
  2161. if (val->type == XPATH_BOOLEAN)
  2162. return(val);
  2163. ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
  2164. xmlXPathReleaseObject(ctxt, val);
  2165. return(ret);
  2166. }
  2167. /**
  2168. * xmlXPathCacheConvertNumber:
  2169. * @ctxt: the XPath context
  2170. * @val: an XPath object
  2171. *
  2172. * This is the cached version of xmlXPathConvertNumber().
  2173. * Converts an existing object to its number() equivalent
  2174. *
  2175. * Returns a created or reused object, the old one is freed (or the operation
  2176. * is done directly on @val)
  2177. */
  2178. static xmlXPathObjectPtr
  2179. xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
  2180. xmlXPathObjectPtr ret;
  2181. if (val == NULL)
  2182. return(xmlXPathCacheNewFloat(ctxt, 0.0));
  2183. if (val->type == XPATH_NUMBER)
  2184. return(val);
  2185. ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
  2186. xmlXPathReleaseObject(ctxt, val);
  2187. return(ret);
  2188. }
  2189. /************************************************************************
  2190. * *
  2191. * Parser stacks related functions and macros *
  2192. * *
  2193. ************************************************************************/
  2194. /**
  2195. * valuePop:
  2196. * @ctxt: an XPath evaluation context
  2197. *
  2198. * Pops the top XPath object from the value stack
  2199. *
  2200. * Returns the XPath object just removed
  2201. */
  2202. xmlXPathObjectPtr
  2203. valuePop(xmlXPathParserContextPtr ctxt)
  2204. {
  2205. xmlXPathObjectPtr ret;
  2206. if ((ctxt == NULL) || (ctxt->valueNr <= 0))
  2207. return (NULL);
  2208. ctxt->valueNr--;
  2209. if (ctxt->valueNr > 0)
  2210. ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
  2211. else
  2212. ctxt->value = NULL;
  2213. ret = ctxt->valueTab[ctxt->valueNr];
  2214. ctxt->valueTab[ctxt->valueNr] = NULL;
  2215. return (ret);
  2216. }
  2217. /**
  2218. * valuePush:
  2219. * @ctxt: an XPath evaluation context
  2220. * @value: the XPath object
  2221. *
  2222. * Pushes a new XPath object on top of the value stack
  2223. *
  2224. * returns the number of items on the value stack
  2225. */
  2226. int
  2227. valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
  2228. {
  2229. if ((ctxt == NULL) || (value == NULL)) return(-1);
  2230. if (ctxt->valueNr >= ctxt->valueMax) {
  2231. xmlXPathObjectPtr *tmp;
  2232. tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
  2233. 2 * ctxt->valueMax *
  2234. sizeof(ctxt->valueTab[0]));
  2235. if (tmp == NULL) {
  2236. xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
  2237. return (0);
  2238. }
  2239. ctxt->valueMax *= 2;
  2240. ctxt->valueTab = tmp;
  2241. }
  2242. ctxt->valueTab[ctxt->valueNr] = value;
  2243. ctxt->value = value;
  2244. return (ctxt->valueNr++);
  2245. }
  2246. /**
  2247. * xmlXPathPopBoolean:
  2248. * @ctxt: an XPath parser context
  2249. *
  2250. * Pops a boolean from the stack, handling conversion if needed.
  2251. * Check error with #xmlXPathCheckError.
  2252. *
  2253. * Returns the boolean
  2254. */
  2255. int
  2256. xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
  2257. xmlXPathObjectPtr obj;
  2258. int ret;
  2259. obj = valuePop(ctxt);
  2260. if (obj == NULL) {
  2261. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2262. return(0);
  2263. }
  2264. if (obj->type != XPATH_BOOLEAN)
  2265. ret = xmlXPathCastToBoolean(obj);
  2266. else
  2267. ret = obj->boolval;
  2268. xmlXPathReleaseObject(ctxt->context, obj);
  2269. return(ret);
  2270. }
  2271. /**
  2272. * xmlXPathPopNumber:
  2273. * @ctxt: an XPath parser context
  2274. *
  2275. * Pops a number from the stack, handling conversion if needed.
  2276. * Check error with #xmlXPathCheckError.
  2277. *
  2278. * Returns the number
  2279. */
  2280. double
  2281. xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
  2282. xmlXPathObjectPtr obj;
  2283. double ret;
  2284. obj = valuePop(ctxt);
  2285. if (obj == NULL) {
  2286. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2287. return(0);
  2288. }
  2289. if (obj->type != XPATH_NUMBER)
  2290. ret = xmlXPathCastToNumber(obj);
  2291. else
  2292. ret = obj->floatval;
  2293. xmlXPathReleaseObject(ctxt->context, obj);
  2294. return(ret);
  2295. }
  2296. /**
  2297. * xmlXPathPopString:
  2298. * @ctxt: an XPath parser context
  2299. *
  2300. * Pops a string from the stack, handling conversion if needed.
  2301. * Check error with #xmlXPathCheckError.
  2302. *
  2303. * Returns the string
  2304. */
  2305. xmlChar *
  2306. xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
  2307. xmlXPathObjectPtr obj;
  2308. xmlChar * ret;
  2309. obj = valuePop(ctxt);
  2310. if (obj == NULL) {
  2311. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2312. return(NULL);
  2313. }
  2314. ret = xmlXPathCastToString(obj); /* this does required strdup */
  2315. /* TODO: needs refactoring somewhere else */
  2316. if (obj->stringval == ret)
  2317. obj->stringval = NULL;
  2318. xmlXPathReleaseObject(ctxt->context, obj);
  2319. return(ret);
  2320. }
  2321. /**
  2322. * xmlXPathPopNodeSet:
  2323. * @ctxt: an XPath parser context
  2324. *
  2325. * Pops a node-set from the stack, handling conversion if needed.
  2326. * Check error with #xmlXPathCheckError.
  2327. *
  2328. * Returns the node-set
  2329. */
  2330. xmlNodeSetPtr
  2331. xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
  2332. xmlXPathObjectPtr obj;
  2333. xmlNodeSetPtr ret;
  2334. if (ctxt == NULL) return(NULL);
  2335. if (ctxt->value == NULL) {
  2336. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2337. return(NULL);
  2338. }
  2339. if (!xmlXPathStackIsNodeSet(ctxt)) {
  2340. xmlXPathSetTypeError(ctxt);
  2341. return(NULL);
  2342. }
  2343. obj = valuePop(ctxt);
  2344. ret = obj->nodesetval;
  2345. #if 0
  2346. /* to fix memory leak of not clearing obj->user */
  2347. if (obj->boolval && obj->user != NULL)
  2348. xmlFreeNodeList((xmlNodePtr) obj->user);
  2349. #endif
  2350. obj->nodesetval = NULL;
  2351. xmlXPathReleaseObject(ctxt->context, obj);
  2352. return(ret);
  2353. }
  2354. /**
  2355. * xmlXPathPopExternal:
  2356. * @ctxt: an XPath parser context
  2357. *
  2358. * Pops an external object from the stack, handling conversion if needed.
  2359. * Check error with #xmlXPathCheckError.
  2360. *
  2361. * Returns the object
  2362. */
  2363. void *
  2364. xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
  2365. xmlXPathObjectPtr obj;
  2366. void * ret;
  2367. if ((ctxt == NULL) || (ctxt->value == NULL)) {
  2368. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2369. return(NULL);
  2370. }
  2371. if (ctxt->value->type != XPATH_USERS) {
  2372. xmlXPathSetTypeError(ctxt);
  2373. return(NULL);
  2374. }
  2375. obj = valuePop(ctxt);
  2376. ret = obj->user;
  2377. obj->user = NULL;
  2378. xmlXPathReleaseObject(ctxt->context, obj);
  2379. return(ret);
  2380. }
  2381. /*
  2382. * Macros for accessing the content. Those should be used only by the parser,
  2383. * and not exported.
  2384. *
  2385. * Dirty macros, i.e. one need to make assumption on the context to use them
  2386. *
  2387. * CUR_PTR return the current pointer to the xmlChar to be parsed.
  2388. * CUR returns the current xmlChar value, i.e. a 8 bit value
  2389. * in ISO-Latin or UTF-8.
  2390. * This should be used internally by the parser
  2391. * only to compare to ASCII values otherwise it would break when
  2392. * running with UTF-8 encoding.
  2393. * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
  2394. * to compare on ASCII based substring.
  2395. * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
  2396. * strings within the parser.
  2397. * CURRENT Returns the current char value, with the full decoding of
  2398. * UTF-8 if we are using this mode. It returns an int.
  2399. * NEXT Skip to the next character, this does the proper decoding
  2400. * in UTF-8 mode. It also pop-up unfinished entities on the fly.
  2401. * It returns the pointer to the current xmlChar.
  2402. */
  2403. #define CUR (*ctxt->cur)
  2404. #define SKIP(val) ctxt->cur += (val)
  2405. #define NXT(val) ctxt->cur[(val)]
  2406. #define CUR_PTR ctxt->cur
  2407. #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
  2408. #define COPY_BUF(l,b,i,v) \
  2409. if (l == 1) b[i++] = (xmlChar) v; \
  2410. else i += xmlCopyChar(l,&b[i],v)
  2411. #define NEXTL(l) ctxt->cur += l
  2412. #define SKIP_BLANKS \
  2413. while (IS_BLANK_CH(*(ctxt->cur))) NEXT
  2414. #define CURRENT (*ctxt->cur)
  2415. #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
  2416. #ifndef DBL_DIG
  2417. #define DBL_DIG 16
  2418. #endif
  2419. #ifndef DBL_EPSILON
  2420. #define DBL_EPSILON 1E-9
  2421. #endif
  2422. #define UPPER_DOUBLE 1E9
  2423. #define LOWER_DOUBLE 1E-5
  2424. #define LOWER_DOUBLE_EXP 5
  2425. #define INTEGER_DIGITS DBL_DIG
  2426. #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
  2427. #define EXPONENT_DIGITS (3 + 2)
  2428. /**
  2429. * xmlXPathFormatNumber:
  2430. * @number: number to format
  2431. * @buffer: output buffer
  2432. * @buffersize: size of output buffer
  2433. *
  2434. * Convert the number into a string representation.
  2435. */
  2436. static void
  2437. xmlXPathFormatNumber(double number, char buffer[], int buffersize)
  2438. {
  2439. switch (xmlXPathIsInf(number)) {
  2440. case 1:
  2441. if (buffersize > (int)sizeof("Infinity"))
  2442. snprintf(buffer, buffersize, "Infinity");
  2443. break;
  2444. case -1:
  2445. if (buffersize > (int)sizeof("-Infinity"))
  2446. snprintf(buffer, buffersize, "-Infinity");
  2447. break;
  2448. default:
  2449. if (xmlXPathIsNaN(number)) {
  2450. if (buffersize > (int)sizeof("NaN"))
  2451. snprintf(buffer, buffersize, "NaN");
  2452. } else if (number == 0 && xmlXPathGetSign(number) != 0) {
  2453. snprintf(buffer, buffersize, "0");
  2454. } else if (number == ((int) number)) {
  2455. char work[30];
  2456. char *ptr, *cur;
  2457. int value = (int) number;
  2458. ptr = &buffer[0];
  2459. if (value == 0) {
  2460. *ptr++ = '0';
  2461. } else {
  2462. snprintf(work, 29, "%d", value);
  2463. cur = &work[0];
  2464. while ((*cur) && (ptr - buffer < buffersize)) {
  2465. *ptr++ = *cur++;
  2466. }
  2467. }
  2468. if (ptr - buffer < buffersize) {
  2469. *ptr = 0;
  2470. } else if (buffersize > 0) {
  2471. ptr--;
  2472. *ptr = 0;
  2473. }
  2474. } else {
  2475. /*
  2476. For the dimension of work,
  2477. DBL_DIG is number of significant digits
  2478. EXPONENT is only needed for "scientific notation"
  2479. 3 is sign, decimal point, and terminating zero
  2480. LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
  2481. Note that this dimension is slightly (a few characters)
  2482. larger than actually necessary.
  2483. */
  2484. char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
  2485. int integer_place, fraction_place;
  2486. char *ptr;
  2487. char *after_fraction;
  2488. double absolute_value;
  2489. int size;
  2490. absolute_value = fabs(number);
  2491. /*
  2492. * First choose format - scientific or regular floating point.
  2493. * In either case, result is in work, and after_fraction points
  2494. * just past the fractional part.
  2495. */
  2496. if ( ((absolute_value > UPPER_DOUBLE) ||
  2497. (absolute_value < LOWER_DOUBLE)) &&
  2498. (absolute_value != 0.0) ) {
  2499. /* Use scientific notation */
  2500. integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
  2501. fraction_place = DBL_DIG - 1;
  2502. size = snprintf(work, sizeof(work),"%*.*e",
  2503. integer_place, fraction_place, number);
  2504. while ((size > 0) && (work[size] != 'e')) size--;
  2505. }
  2506. else {
  2507. /* Use regular notation */
  2508. if (absolute_value > 0.0) {
  2509. integer_place = (int)log10(absolute_value);
  2510. if (integer_place > 0)
  2511. fraction_place = DBL_DIG - integer_place - 1;
  2512. else
  2513. fraction_place = DBL_DIG - integer_place;
  2514. } else {
  2515. fraction_place = 1;
  2516. }
  2517. size = snprintf(work, sizeof(work), "%0.*f",
  2518. fraction_place, number);
  2519. }
  2520. /* Remove fractional trailing zeroes */
  2521. after_fraction = work + size;
  2522. ptr = after_fraction;
  2523. while (*(--ptr) == '0')
  2524. ;
  2525. if (*ptr != '.')
  2526. ptr++;
  2527. while ((*ptr++ = *after_fraction++) != 0);
  2528. /* Finally copy result back to caller */
  2529. size = strlen(work) + 1;
  2530. if (size > buffersize) {
  2531. work[buffersize - 1] = 0;
  2532. size = buffersize;
  2533. }
  2534. memmove(buffer, work, size);
  2535. }
  2536. break;
  2537. }
  2538. }
  2539. /************************************************************************
  2540. * *
  2541. * Routines to handle NodeSets *
  2542. * *
  2543. ************************************************************************/
  2544. /**
  2545. * xmlXPathOrderDocElems:
  2546. * @doc: an input document
  2547. *
  2548. * Call this routine to speed up XPath computation on static documents.
  2549. * This stamps all the element nodes with the document order
  2550. * Like for line information, the order is kept in the element->content
  2551. * field, the value stored is actually - the node number (starting at -1)
  2552. * to be able to differentiate from line numbers.
  2553. *
  2554. * Returns the number of elements found in the document or -1 in case
  2555. * of error.
  2556. */
  2557. long
  2558. xmlXPathOrderDocElems(xmlDocPtr doc) {
  2559. long count = 0;
  2560. xmlNodePtr cur;
  2561. if (doc == NULL)
  2562. return(-1);
  2563. cur = doc->children;
  2564. while (cur != NULL) {
  2565. if (cur->type == XML_ELEMENT_NODE) {
  2566. cur->content = (void *) (-(++count));
  2567. if (cur->children != NULL) {
  2568. cur = cur->children;
  2569. continue;
  2570. }
  2571. }
  2572. if (cur->next != NULL) {
  2573. cur = cur->next;
  2574. continue;
  2575. }
  2576. do {
  2577. cur = cur->parent;
  2578. if (cur == NULL)
  2579. break;
  2580. if (cur == (xmlNodePtr) doc) {
  2581. cur = NULL;
  2582. break;
  2583. }
  2584. if (cur->next != NULL) {
  2585. cur = cur->next;
  2586. break;
  2587. }
  2588. } while (cur != NULL);
  2589. }
  2590. return(count);
  2591. }
  2592. /**
  2593. * xmlXPathCmpNodes:
  2594. * @node1: the first node
  2595. * @node2: the second node
  2596. *
  2597. * Compare two nodes w.r.t document order
  2598. *
  2599. * Returns -2 in case of error 1 if first point < second point, 0 if
  2600. * it's the same node, -1 otherwise
  2601. */
  2602. int
  2603. xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
  2604. int depth1, depth2;
  2605. int attr1 = 0, attr2 = 0;
  2606. xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
  2607. xmlNodePtr cur, root;
  2608. if ((node1 == NULL) || (node2 == NULL))
  2609. return(-2);
  2610. /*
  2611. * a couple of optimizations which will avoid computations in most cases
  2612. */
  2613. if (node1 == node2) /* trivial case */
  2614. return(0);
  2615. if (node1->type == XML_ATTRIBUTE_NODE) {
  2616. attr1 = 1;
  2617. attrNode1 = node1;
  2618. node1 = node1->parent;
  2619. }
  2620. if (node2->type == XML_ATTRIBUTE_NODE) {
  2621. attr2 = 1;
  2622. attrNode2 = node2;
  2623. node2 = node2->parent;
  2624. }
  2625. if (node1 == node2) {
  2626. if (attr1 == attr2) {
  2627. /* not required, but we keep attributes in order */
  2628. if (attr1 != 0) {
  2629. cur = attrNode2->prev;
  2630. while (cur != NULL) {
  2631. if (cur == attrNode1)
  2632. return (1);
  2633. cur = cur->prev;
  2634. }
  2635. return (-1);
  2636. }
  2637. return(0);
  2638. }
  2639. if (attr2 == 1)
  2640. return(1);
  2641. return(-1);
  2642. }
  2643. if ((node1->type == XML_NAMESPACE_DECL) ||
  2644. (node2->type == XML_NAMESPACE_DECL))
  2645. return(1);
  2646. if (node1 == node2->prev)
  2647. return(1);
  2648. if (node1 == node2->next)
  2649. return(-1);
  2650. /*
  2651. * Speedup using document order if availble.
  2652. */
  2653. if ((node1->type == XML_ELEMENT_NODE) &&
  2654. (node2->type == XML_ELEMENT_NODE) &&
  2655. (0 > (long) node1->content) &&
  2656. (0 > (long) node2->content) &&
  2657. (node1->doc == node2->doc)) {
  2658. long l1, l2;
  2659. l1 = -((long) node1->content);
  2660. l2 = -((long) node2->content);
  2661. if (l1 < l2)
  2662. return(1);
  2663. if (l1 > l2)
  2664. return(-1);
  2665. }
  2666. /*
  2667. * compute depth to root
  2668. */
  2669. for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
  2670. if (cur == node1)
  2671. return(1);
  2672. depth2++;
  2673. }
  2674. root = cur;
  2675. for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
  2676. if (cur == node2)
  2677. return(-1);
  2678. depth1++;
  2679. }
  2680. /*
  2681. * Distinct document (or distinct entities :-( ) case.
  2682. */
  2683. if (root != cur) {
  2684. return(-2);
  2685. }
  2686. /*
  2687. * get the nearest common ancestor.
  2688. */
  2689. while (depth1 > depth2) {
  2690. depth1--;
  2691. node1 = node1->parent;
  2692. }
  2693. while (depth2 > depth1) {
  2694. depth2--;
  2695. node2 = node2->parent;
  2696. }
  2697. while (node1->parent != node2->parent) {
  2698. node1 = node1->parent;
  2699. node2 = node2->parent;
  2700. /* should not happen but just in case ... */
  2701. if ((node1 == NULL) || (node2 == NULL))
  2702. return(-2);
  2703. }
  2704. /*
  2705. * Find who's first.
  2706. */
  2707. if (node1 == node2->prev)
  2708. return(1);
  2709. if (node1 == node2->next)
  2710. return(-1);
  2711. /*
  2712. * Speedup using document order if availble.
  2713. */
  2714. if ((node1->type == XML_ELEMENT_NODE) &&
  2715. (node2->type == XML_ELEMENT_NODE) &&
  2716. (0 > (long) node1->content) &&
  2717. (0 > (long) node2->content) &&
  2718. (node1->doc == node2->doc)) {
  2719. long l1, l2;
  2720. l1 = -((long) node1->content);
  2721. l2 = -((long) node2->content);
  2722. if (l1 < l2)
  2723. return(1);
  2724. if (l1 > l2)
  2725. return(-1);
  2726. }
  2727. for (cur = node1->next;cur != NULL;cur = cur->next)
  2728. if (cur == node2)
  2729. return(1);
  2730. return(-1); /* assume there is no sibling list corruption */
  2731. }
  2732. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  2733. /**
  2734. * xmlXPathCmpNodesExt:
  2735. * @node1: the first node
  2736. * @node2: the second node
  2737. *
  2738. * Compare two nodes w.r.t document order.
  2739. * This one is optimized for handling of non-element nodes.
  2740. *
  2741. * Returns -2 in case of error 1 if first point < second point, 0 if
  2742. * it's the same node, -1 otherwise
  2743. */
  2744. static int
  2745. xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
  2746. int depth1, depth2;
  2747. int misc = 0, precedence1 = 0, precedence2 = 0;
  2748. xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
  2749. xmlNodePtr cur, root;
  2750. long l1, l2;
  2751. if ((node1 == NULL) || (node2 == NULL))
  2752. return(-2);
  2753. if (node1 == node2)
  2754. return(0);
  2755. /*
  2756. * a couple of optimizations which will avoid computations in most cases
  2757. */
  2758. switch (node1->type) {
  2759. case XML_ELEMENT_NODE:
  2760. if (node2->type == XML_ELEMENT_NODE) {
  2761. if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
  2762. (0 > (long) node2->content) &&
  2763. (node1->doc == node2->doc))
  2764. {
  2765. l1 = -((long) node1->content);
  2766. l2 = -((long) node2->content);
  2767. if (l1 < l2)
  2768. return(1);
  2769. if (l1 > l2)
  2770. return(-1);
  2771. } else
  2772. goto turtle_comparison;
  2773. }
  2774. break;
  2775. case XML_ATTRIBUTE_NODE:
  2776. precedence1 = 1; /* element is owner */
  2777. miscNode1 = node1;
  2778. node1 = node1->parent;
  2779. misc = 1;
  2780. break;
  2781. case XML_TEXT_NODE:
  2782. case XML_CDATA_SECTION_NODE:
  2783. case XML_COMMENT_NODE:
  2784. case XML_PI_NODE: {
  2785. miscNode1 = node1;
  2786. /*
  2787. * Find nearest element node.
  2788. */
  2789. if (node1->prev != NULL) {
  2790. do {
  2791. node1 = node1->prev;
  2792. if (node1->type == XML_ELEMENT_NODE) {
  2793. precedence1 = 3; /* element in prev-sibl axis */
  2794. break;
  2795. }
  2796. if (node1->prev == NULL) {
  2797. precedence1 = 2; /* element is parent */
  2798. /*
  2799. * URGENT TODO: Are there any cases, where the
  2800. * parent of such a node is not an element node?
  2801. */
  2802. node1 = node1->parent;
  2803. break;
  2804. }
  2805. } while (1);
  2806. } else {
  2807. precedence1 = 2; /* element is parent */
  2808. node1 = node1->parent;
  2809. }
  2810. if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
  2811. (0 <= (long) node1->content)) {
  2812. /*
  2813. * Fallback for whatever case.
  2814. */
  2815. node1 = miscNode1;
  2816. precedence1 = 0;
  2817. } else
  2818. misc = 1;
  2819. }
  2820. break;
  2821. case XML_NAMESPACE_DECL:
  2822. /*
  2823. * TODO: why do we return 1 for namespace nodes?
  2824. */
  2825. return(1);
  2826. default:
  2827. break;
  2828. }
  2829. switch (node2->type) {
  2830. case XML_ELEMENT_NODE:
  2831. break;
  2832. case XML_ATTRIBUTE_NODE:
  2833. precedence2 = 1; /* element is owner */
  2834. miscNode2 = node2;
  2835. node2 = node2->parent;
  2836. misc = 1;
  2837. break;
  2838. case XML_TEXT_NODE:
  2839. case XML_CDATA_SECTION_NODE:
  2840. case XML_COMMENT_NODE:
  2841. case XML_PI_NODE: {
  2842. miscNode2 = node2;
  2843. if (node2->prev != NULL) {
  2844. do {
  2845. node2 = node2->prev;
  2846. if (node2->type == XML_ELEMENT_NODE) {
  2847. precedence2 = 3; /* element in prev-sibl axis */
  2848. break;
  2849. }
  2850. if (node2->prev == NULL) {
  2851. precedence2 = 2; /* element is parent */
  2852. node2 = node2->parent;
  2853. break;
  2854. }
  2855. } while (1);
  2856. } else {
  2857. precedence2 = 2; /* element is parent */
  2858. node2 = node2->parent;
  2859. }
  2860. if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
  2861. (0 <= (long) node1->content))
  2862. {
  2863. node2 = miscNode2;
  2864. precedence2 = 0;
  2865. } else
  2866. misc = 1;
  2867. }
  2868. break;
  2869. case XML_NAMESPACE_DECL:
  2870. return(1);
  2871. default:
  2872. break;
  2873. }
  2874. if (misc) {
  2875. if (node1 == node2) {
  2876. if (precedence1 == precedence2) {
  2877. /*
  2878. * The ugly case; but normally there aren't many
  2879. * adjacent non-element nodes around.
  2880. */
  2881. cur = miscNode2->prev;
  2882. while (cur != NULL) {
  2883. if (cur == miscNode1)
  2884. return(1);
  2885. if (cur->type == XML_ELEMENT_NODE)
  2886. return(-1);
  2887. cur = cur->prev;
  2888. }
  2889. return (-1);
  2890. } else {
  2891. /*
  2892. * Evaluate based on higher precedence wrt to the element.
  2893. * TODO: This assumes attributes are sorted before content.
  2894. * Is this 100% correct?
  2895. */
  2896. if (precedence1 < precedence2)
  2897. return(1);
  2898. else
  2899. return(-1);
  2900. }
  2901. }
  2902. /*
  2903. * Special case: One of the helper-elements is contained by the other.
  2904. * <foo>
  2905. * <node2>
  2906. * <node1>Text-1(precedence1 == 2)</node1>
  2907. * </node2>
  2908. * Text-6(precedence2 == 3)
  2909. * </foo>
  2910. */
  2911. if ((precedence2 == 3) && (precedence1 > 1)) {
  2912. cur = node1->parent;
  2913. while (cur) {
  2914. if (cur == node2)
  2915. return(1);
  2916. cur = cur->parent;
  2917. }
  2918. }
  2919. if ((precedence1 == 3) && (precedence2 > 1)) {
  2920. cur = node2->parent;
  2921. while (cur) {
  2922. if (cur == node1)
  2923. return(-1);
  2924. cur = cur->parent;
  2925. }
  2926. }
  2927. }
  2928. /*
  2929. * Speedup using document order if availble.
  2930. */
  2931. if ((node1->type == XML_ELEMENT_NODE) &&
  2932. (node2->type == XML_ELEMENT_NODE) &&
  2933. (0 > (long) node1->content) &&
  2934. (0 > (long) node2->content) &&
  2935. (node1->doc == node2->doc)) {
  2936. l1 = -((long) node1->content);
  2937. l2 = -((long) node2->content);
  2938. if (l1 < l2)
  2939. return(1);
  2940. if (l1 > l2)
  2941. return(-1);
  2942. }
  2943. turtle_comparison:
  2944. if (node1 == node2->prev)
  2945. return(1);
  2946. if (node1 == node2->next)
  2947. return(-1);
  2948. /*
  2949. * compute depth to root
  2950. */
  2951. for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
  2952. if (cur == node1)
  2953. return(1);
  2954. depth2++;
  2955. }
  2956. root = cur;
  2957. for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
  2958. if (cur == node2)
  2959. return(-1);
  2960. depth1++;
  2961. }
  2962. /*
  2963. * Distinct document (or distinct entities :-( ) case.
  2964. */
  2965. if (root != cur) {
  2966. return(-2);
  2967. }
  2968. /*
  2969. * get the nearest common ancestor.
  2970. */
  2971. while (depth1 > depth2) {
  2972. depth1--;
  2973. node1 = node1->parent;
  2974. }
  2975. while (depth2 > depth1) {
  2976. depth2--;
  2977. node2 = node2->parent;
  2978. }
  2979. while (node1->parent != node2->parent) {
  2980. node1 = node1->parent;
  2981. node2 = node2->parent;
  2982. /* should not happen but just in case ... */
  2983. if ((node1 == NULL) || (node2 == NULL))
  2984. return(-2);
  2985. }
  2986. /*
  2987. * Find who's first.
  2988. */
  2989. if (node1 == node2->prev)
  2990. return(1);
  2991. if (node1 == node2->next)
  2992. return(-1);
  2993. /*
  2994. * Speedup using document order if availble.
  2995. */
  2996. if ((node1->type == XML_ELEMENT_NODE) &&
  2997. (node2->type == XML_ELEMENT_NODE) &&
  2998. (0 > (long) node1->content) &&
  2999. (0 > (long) node2->content) &&
  3000. (node1->doc == node2->doc)) {
  3001. l1 = -((long) node1->content);
  3002. l2 = -((long) node2->content);
  3003. if (l1 < l2)
  3004. return(1);
  3005. if (l1 > l2)
  3006. return(-1);
  3007. }
  3008. for (cur = node1->next;cur != NULL;cur = cur->next)
  3009. if (cur == node2)
  3010. return(1);
  3011. return(-1); /* assume there is no sibling list corruption */
  3012. }
  3013. #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
  3014. /**
  3015. * xmlXPathNodeSetSort:
  3016. * @set: the node set
  3017. *
  3018. * Sort the node set in document order
  3019. */
  3020. void
  3021. xmlXPathNodeSetSort(xmlNodeSetPtr set) {
  3022. int i, j, incr, len;
  3023. xmlNodePtr tmp;
  3024. if (set == NULL)
  3025. return;
  3026. /* Use Shell's sort to sort the node-set */
  3027. len = set->nodeNr;
  3028. for (incr = len / 2; incr > 0; incr /= 2) {
  3029. for (i = incr; i < len; i++) {
  3030. j = i - incr;
  3031. while (j >= 0) {
  3032. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  3033. if (xmlXPathCmpNodesExt(set->nodeTab[j],
  3034. set->nodeTab[j + incr]) == -1)
  3035. #else
  3036. if (xmlXPathCmpNodes(set->nodeTab[j],
  3037. set->nodeTab[j + incr]) == -1)
  3038. #endif
  3039. {
  3040. tmp = set->nodeTab[j];
  3041. set->nodeTab[j] = set->nodeTab[j + incr];
  3042. set->nodeTab[j + incr] = tmp;
  3043. j -= incr;
  3044. } else
  3045. break;
  3046. }
  3047. }
  3048. }
  3049. }
  3050. #define XML_NODESET_DEFAULT 10
  3051. /**
  3052. * xmlXPathNodeSetDupNs:
  3053. * @node: the parent node of the namespace XPath node
  3054. * @ns: the libxml namespace declaration node.
  3055. *
  3056. * Namespace node in libxml don't match the XPath semantic. In a node set
  3057. * the namespace nodes are duplicated and the next pointer is set to the
  3058. * parent node in the XPath semantic.
  3059. *
  3060. * Returns the newly created object.
  3061. */
  3062. static xmlNodePtr
  3063. xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
  3064. xmlNsPtr cur;
  3065. if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
  3066. return(NULL);
  3067. if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
  3068. return((xmlNodePtr) ns);
  3069. /*
  3070. * Allocate a new Namespace and fill the fields.
  3071. */
  3072. cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
  3073. if (cur == NULL) {
  3074. xmlXPathErrMemory(NULL, "duplicating namespace\n");
  3075. return(NULL);
  3076. }
  3077. memset(cur, 0, sizeof(xmlNs));
  3078. cur->type = XML_NAMESPACE_DECL;
  3079. if (ns->href != NULL)
  3080. cur->href = xmlStrdup(ns->href);
  3081. if (ns->prefix != NULL)
  3082. cur->prefix = xmlStrdup(ns->prefix);
  3083. cur->next = (xmlNsPtr) node;
  3084. return((xmlNodePtr) cur);
  3085. }
  3086. /**
  3087. * xmlXPathNodeSetFreeNs:
  3088. * @ns: the XPath namespace node found in a nodeset.
  3089. *
  3090. * Namespace nodes in libxml don't match the XPath semantic. In a node set
  3091. * the namespace nodes are duplicated and the next pointer is set to the
  3092. * parent node in the XPath semantic. Check if such a node needs to be freed
  3093. */
  3094. void
  3095. xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
  3096. if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
  3097. return;
  3098. if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
  3099. if (ns->href != NULL)
  3100. xmlFree((xmlChar *)ns->href);
  3101. if (ns->prefix != NULL)
  3102. xmlFree((xmlChar *)ns->prefix);
  3103. xmlFree(ns);
  3104. }
  3105. }
  3106. /**
  3107. * xmlXPathNodeSetCreate:
  3108. * @val: an initial xmlNodePtr, or NULL
  3109. *
  3110. * Create a new xmlNodeSetPtr of type double and of value @val
  3111. *
  3112. * Returns the newly created object.
  3113. */
  3114. xmlNodeSetPtr
  3115. xmlXPathNodeSetCreate(xmlNodePtr val) {
  3116. xmlNodeSetPtr ret;
  3117. ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
  3118. if (ret == NULL) {
  3119. xmlXPathErrMemory(NULL, "creating nodeset\n");
  3120. return(NULL);
  3121. }
  3122. memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
  3123. if (val != NULL) {
  3124. ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  3125. sizeof(xmlNodePtr));
  3126. if (ret->nodeTab == NULL) {
  3127. xmlXPathErrMemory(NULL, "creating nodeset\n");
  3128. xmlFree(ret);
  3129. return(NULL);
  3130. }
  3131. memset(ret->nodeTab, 0 ,
  3132. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3133. ret->nodeMax = XML_NODESET_DEFAULT;
  3134. if (val->type == XML_NAMESPACE_DECL) {
  3135. xmlNsPtr ns = (xmlNsPtr) val;
  3136. ret->nodeTab[ret->nodeNr++] =
  3137. xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
  3138. } else
  3139. ret->nodeTab[ret->nodeNr++] = val;
  3140. }
  3141. return(ret);
  3142. }
  3143. /**
  3144. * xmlXPathNodeSetCreateSize:
  3145. * @size: the initial size of the set
  3146. *
  3147. * Create a new xmlNodeSetPtr of type double and of value @val
  3148. *
  3149. * Returns the newly created object.
  3150. */
  3151. static xmlNodeSetPtr
  3152. xmlXPathNodeSetCreateSize(int size) {
  3153. xmlNodeSetPtr ret;
  3154. ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
  3155. if (ret == NULL) {
  3156. xmlXPathErrMemory(NULL, "creating nodeset\n");
  3157. return(NULL);
  3158. }
  3159. memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
  3160. if (size < XML_NODESET_DEFAULT)
  3161. size = XML_NODESET_DEFAULT;
  3162. ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
  3163. if (ret->nodeTab == NULL) {
  3164. xmlXPathErrMemory(NULL, "creating nodeset\n");
  3165. xmlFree(ret);
  3166. return(NULL);
  3167. }
  3168. memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
  3169. ret->nodeMax = size;
  3170. return(ret);
  3171. }
  3172. /**
  3173. * xmlXPathNodeSetContains:
  3174. * @cur: the node-set
  3175. * @val: the node
  3176. *
  3177. * checks whether @cur contains @val
  3178. *
  3179. * Returns true (1) if @cur contains @val, false (0) otherwise
  3180. */
  3181. int
  3182. xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
  3183. int i;
  3184. if ((cur == NULL) || (val == NULL)) return(0);
  3185. if (val->type == XML_NAMESPACE_DECL) {
  3186. for (i = 0; i < cur->nodeNr; i++) {
  3187. if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
  3188. xmlNsPtr ns1, ns2;
  3189. ns1 = (xmlNsPtr) val;
  3190. ns2 = (xmlNsPtr) cur->nodeTab[i];
  3191. if (ns1 == ns2)
  3192. return(1);
  3193. if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
  3194. (xmlStrEqual(ns1->prefix, ns2->prefix)))
  3195. return(1);
  3196. }
  3197. }
  3198. } else {
  3199. for (i = 0; i < cur->nodeNr; i++) {
  3200. if (cur->nodeTab[i] == val)
  3201. return(1);
  3202. }
  3203. }
  3204. return(0);
  3205. }
  3206. /**
  3207. * xmlXPathNodeSetAddNs:
  3208. * @cur: the initial node set
  3209. * @node: the hosting node
  3210. * @ns: a the namespace node
  3211. *
  3212. * add a new namespace node to an existing NodeSet
  3213. */
  3214. void
  3215. xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
  3216. int i;
  3217. if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
  3218. (ns->type != XML_NAMESPACE_DECL) ||
  3219. (node->type != XML_ELEMENT_NODE))
  3220. return;
  3221. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3222. /*
  3223. * prevent duplicates
  3224. */
  3225. for (i = 0;i < cur->nodeNr;i++) {
  3226. if ((cur->nodeTab[i] != NULL) &&
  3227. (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
  3228. (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
  3229. (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
  3230. return;
  3231. }
  3232. /*
  3233. * grow the nodeTab if needed
  3234. */
  3235. if (cur->nodeMax == 0) {
  3236. cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  3237. sizeof(xmlNodePtr));
  3238. if (cur->nodeTab == NULL) {
  3239. xmlXPathErrMemory(NULL, "growing nodeset\n");
  3240. return;
  3241. }
  3242. memset(cur->nodeTab, 0 ,
  3243. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3244. cur->nodeMax = XML_NODESET_DEFAULT;
  3245. } else if (cur->nodeNr == cur->nodeMax) {
  3246. xmlNodePtr *temp;
  3247. cur->nodeMax *= 2;
  3248. temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
  3249. sizeof(xmlNodePtr));
  3250. if (temp == NULL) {
  3251. xmlXPathErrMemory(NULL, "growing nodeset\n");
  3252. return;
  3253. }
  3254. cur->nodeTab = temp;
  3255. }
  3256. cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
  3257. }
  3258. /**
  3259. * xmlXPathNodeSetAdd:
  3260. * @cur: the initial node set
  3261. * @val: a new xmlNodePtr
  3262. *
  3263. * add a new xmlNodePtr to an existing NodeSet
  3264. */
  3265. void
  3266. xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
  3267. int i;
  3268. if ((cur == NULL) || (val == NULL)) return;
  3269. #if 0
  3270. if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
  3271. return; /* an XSLT fake node */
  3272. #endif
  3273. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3274. /*
  3275. * prevent duplcates
  3276. */
  3277. for (i = 0;i < cur->nodeNr;i++)
  3278. if (cur->nodeTab[i] == val) return;
  3279. /*
  3280. * grow the nodeTab if needed
  3281. */
  3282. if (cur->nodeMax == 0) {
  3283. cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  3284. sizeof(xmlNodePtr));
  3285. if (cur->nodeTab == NULL) {
  3286. xmlXPathErrMemory(NULL, "growing nodeset\n");
  3287. return;
  3288. }
  3289. memset(cur->nodeTab, 0 ,
  3290. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3291. cur->nodeMax = XML_NODESET_DEFAULT;
  3292. } else if (cur->nodeNr == cur->nodeMax) {
  3293. xmlNodePtr *temp;
  3294. cur->nodeMax *= 2;
  3295. temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
  3296. sizeof(xmlNodePtr));
  3297. if (temp == NULL) {
  3298. xmlXPathErrMemory(NULL, "growing nodeset\n");
  3299. return;
  3300. }
  3301. cur->nodeTab = temp;
  3302. }
  3303. if (val->type == XML_NAMESPACE_DECL) {
  3304. xmlNsPtr ns = (xmlNsPtr) val;
  3305. cur->nodeTab[cur->nodeNr++] =
  3306. xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
  3307. } else
  3308. cur->nodeTab[cur->nodeNr++] = val;
  3309. }
  3310. /**
  3311. * xmlXPathNodeSetAddUnique:
  3312. * @cur: the initial node set
  3313. * @val: a new xmlNodePtr
  3314. *
  3315. * add a new xmlNodePtr to an existing NodeSet, optimized version
  3316. * when we are sure the node is not already in the set.
  3317. */
  3318. void
  3319. xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
  3320. if ((cur == NULL) || (val == NULL)) return;
  3321. #if 0
  3322. if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
  3323. return; /* an XSLT fake node */
  3324. #endif
  3325. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3326. /*
  3327. * grow the nodeTab if needed
  3328. */
  3329. if (cur->nodeMax == 0) {
  3330. cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  3331. sizeof(xmlNodePtr));
  3332. if (cur->nodeTab == NULL) {
  3333. xmlXPathErrMemory(NULL, "growing nodeset\n");
  3334. return;
  3335. }
  3336. memset(cur->nodeTab, 0 ,
  3337. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3338. cur->nodeMax = XML_NODESET_DEFAULT;
  3339. } else if (cur->nodeNr == cur->nodeMax) {
  3340. xmlNodePtr *temp;
  3341. cur->nodeMax *= 2;
  3342. temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
  3343. sizeof(xmlNodePtr));
  3344. if (temp == NULL) {
  3345. xmlXPathErrMemory(NULL, "growing nodeset\n");
  3346. return;
  3347. }
  3348. cur->nodeTab = temp;
  3349. }
  3350. if (val->type == XML_NAMESPACE_DECL) {
  3351. xmlNsPtr ns = (xmlNsPtr) val;
  3352. cur->nodeTab[cur->nodeNr++] =
  3353. xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
  3354. } else
  3355. cur->nodeTab[cur->nodeNr++] = val;
  3356. }
  3357. /**
  3358. * xmlXPathNodeSetMerge:
  3359. * @val1: the first NodeSet or NULL
  3360. * @val2: the second NodeSet
  3361. *
  3362. * Merges two nodesets, all nodes from @val2 are added to @val1
  3363. * if @val1 is NULL, a new set is created and copied from @val2
  3364. *
  3365. * Returns @val1 once extended or NULL in case of error.
  3366. */
  3367. xmlNodeSetPtr
  3368. xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
  3369. int i, j, initNr, skip;
  3370. xmlNodePtr n1, n2;
  3371. if (val2 == NULL) return(val1);
  3372. if (val1 == NULL) {
  3373. val1 = xmlXPathNodeSetCreate(NULL);
  3374. if (val1 == NULL)
  3375. return (NULL);
  3376. #if 0
  3377. /*
  3378. * TODO: The optimization won't work in every case, since
  3379. * those nasty namespace nodes need to be added with
  3380. * xmlXPathNodeSetDupNs() to the set; thus a pure
  3381. * memcpy is not possible.
  3382. * If there was a flag on the nodesetval, indicating that
  3383. * some temporary nodes are in, that would be helpfull.
  3384. */
  3385. /*
  3386. * Optimization: Create an equally sized node-set
  3387. * and memcpy the content.
  3388. */
  3389. val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
  3390. if (val1 == NULL)
  3391. return(NULL);
  3392. if (val2->nodeNr != 0) {
  3393. if (val2->nodeNr == 1)
  3394. *(val1->nodeTab) = *(val2->nodeTab);
  3395. else {
  3396. memcpy(val1->nodeTab, val2->nodeTab,
  3397. val2->nodeNr * sizeof(xmlNodePtr));
  3398. }
  3399. val1->nodeNr = val2->nodeNr;
  3400. }
  3401. return(val1);
  3402. #endif
  3403. }
  3404. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3405. initNr = val1->nodeNr;
  3406. for (i = 0;i < val2->nodeNr;i++) {
  3407. n2 = val2->nodeTab[i];
  3408. /*
  3409. * check against duplicates
  3410. */
  3411. skip = 0;
  3412. for (j = 0; j < initNr; j++) {
  3413. n1 = val1->nodeTab[j];
  3414. if (n1 == n2) {
  3415. skip = 1;
  3416. break;
  3417. } else if ((n1->type == XML_NAMESPACE_DECL) &&
  3418. (n2->type == XML_NAMESPACE_DECL)) {
  3419. if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
  3420. (xmlStrEqual(((xmlNsPtr) n1)->prefix,
  3421. ((xmlNsPtr) n2)->prefix)))
  3422. {
  3423. skip = 1;
  3424. break;
  3425. }
  3426. }
  3427. }
  3428. if (skip)
  3429. continue;
  3430. /*
  3431. * grow the nodeTab if needed
  3432. */
  3433. if (val1->nodeMax == 0) {
  3434. val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  3435. sizeof(xmlNodePtr));
  3436. if (val1->nodeTab == NULL) {
  3437. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3438. return(NULL);
  3439. }
  3440. memset(val1->nodeTab, 0 ,
  3441. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3442. val1->nodeMax = XML_NODESET_DEFAULT;
  3443. } else if (val1->nodeNr == val1->nodeMax) {
  3444. xmlNodePtr *temp;
  3445. val1->nodeMax *= 2;
  3446. temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
  3447. sizeof(xmlNodePtr));
  3448. if (temp == NULL) {
  3449. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3450. return(NULL);
  3451. }
  3452. val1->nodeTab = temp;
  3453. }
  3454. if (n2->type == XML_NAMESPACE_DECL) {
  3455. xmlNsPtr ns = (xmlNsPtr) n2;
  3456. val1->nodeTab[val1->nodeNr++] =
  3457. xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
  3458. } else
  3459. val1->nodeTab[val1->nodeNr++] = n2;
  3460. }
  3461. return(val1);
  3462. }
  3463. #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
  3464. /**
  3465. * xmlXPathNodeSetMergeUnique:
  3466. * @val1: the first NodeSet or NULL
  3467. * @val2: the second NodeSet
  3468. *
  3469. * Merges two nodesets, all nodes from @val2 are added to @val1
  3470. * if @val1 is NULL, a new set is created and copied from @val2
  3471. *
  3472. * Returns @val1 once extended or NULL in case of error.
  3473. */
  3474. static xmlNodeSetPtr
  3475. xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
  3476. int i;
  3477. if (val2 == NULL) return(val1);
  3478. if (val1 == NULL) {
  3479. val1 = xmlXPathNodeSetCreate(NULL);
  3480. }
  3481. if (val1 == NULL)
  3482. return (NULL);
  3483. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3484. for (i = 0;i < val2->nodeNr;i++) {
  3485. /*
  3486. * grow the nodeTab if needed
  3487. */
  3488. if (val1->nodeMax == 0) {
  3489. val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  3490. sizeof(xmlNodePtr));
  3491. if (val1->nodeTab == NULL) {
  3492. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3493. return(NULL);
  3494. }
  3495. memset(val1->nodeTab, 0 ,
  3496. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3497. val1->nodeMax = XML_NODESET_DEFAULT;
  3498. } else if (val1->nodeNr == val1->nodeMax) {
  3499. xmlNodePtr *temp;
  3500. val1->nodeMax *= 2;
  3501. temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
  3502. sizeof(xmlNodePtr));
  3503. if (temp == NULL) {
  3504. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3505. return(NULL);
  3506. }
  3507. val1->nodeTab = temp;
  3508. }
  3509. if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
  3510. xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
  3511. val1->nodeTab[val1->nodeNr++] =
  3512. xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
  3513. } else
  3514. val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
  3515. }
  3516. return(val1);
  3517. }
  3518. #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
  3519. /**
  3520. * xmlXPathNodeSetMergeAndClear:
  3521. * @set1: the first NodeSet or NULL
  3522. * @set2: the second NodeSet
  3523. * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
  3524. *
  3525. * Merges two nodesets, all nodes from @set2 are added to @set1
  3526. * if @set1 is NULL, a new set is created and copied from @set2.
  3527. * Checks for duplicate nodes. Clears set2.
  3528. *
  3529. * Returns @set1 once extended or NULL in case of error.
  3530. */
  3531. static xmlNodeSetPtr
  3532. xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
  3533. int hasNullEntries)
  3534. {
  3535. if ((set1 == NULL) && (hasNullEntries == 0)) {
  3536. /*
  3537. * Note that doing a memcpy of the list, namespace nodes are
  3538. * just assigned to set1, since set2 is cleared anyway.
  3539. */
  3540. set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
  3541. if (set1 == NULL)
  3542. return(NULL);
  3543. if (set2->nodeNr != 0) {
  3544. memcpy(set1->nodeTab, set2->nodeTab,
  3545. set2->nodeNr * sizeof(xmlNodePtr));
  3546. set1->nodeNr = set2->nodeNr;
  3547. }
  3548. } else {
  3549. int i, j, initNbSet1;
  3550. xmlNodePtr n1, n2;
  3551. if (set1 == NULL)
  3552. set1 = xmlXPathNodeSetCreate(NULL);
  3553. if (set1 == NULL)
  3554. return (NULL);
  3555. initNbSet1 = set1->nodeNr;
  3556. for (i = 0;i < set2->nodeNr;i++) {
  3557. n2 = set2->nodeTab[i];
  3558. /*
  3559. * Skip NULLed entries.
  3560. */
  3561. if (n2 == NULL)
  3562. continue;
  3563. /*
  3564. * Skip duplicates.
  3565. */
  3566. for (j = 0; j < initNbSet1; j++) {
  3567. n1 = set1->nodeTab[j];
  3568. if (n1 == n2) {
  3569. goto skip_node;
  3570. } else if ((n1->type == XML_NAMESPACE_DECL) &&
  3571. (n2->type == XML_NAMESPACE_DECL))
  3572. {
  3573. if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
  3574. (xmlStrEqual(((xmlNsPtr) n1)->prefix,
  3575. ((xmlNsPtr) n2)->prefix)))
  3576. {
  3577. /*
  3578. * Free the namespace node.
  3579. */
  3580. set2->nodeTab[i] = NULL;
  3581. xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
  3582. goto skip_node;
  3583. }
  3584. }
  3585. }
  3586. /*
  3587. * grow the nodeTab if needed
  3588. */
  3589. if (set1->nodeMax == 0) {
  3590. set1->nodeTab = (xmlNodePtr *) xmlMalloc(
  3591. XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
  3592. if (set1->nodeTab == NULL) {
  3593. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3594. return(NULL);
  3595. }
  3596. memset(set1->nodeTab, 0,
  3597. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3598. set1->nodeMax = XML_NODESET_DEFAULT;
  3599. } else if (set1->nodeNr >= set1->nodeMax) {
  3600. xmlNodePtr *temp;
  3601. set1->nodeMax *= 2;
  3602. temp = (xmlNodePtr *) xmlRealloc(
  3603. set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
  3604. if (temp == NULL) {
  3605. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3606. return(NULL);
  3607. }
  3608. set1->nodeTab = temp;
  3609. }
  3610. if (n2->type == XML_NAMESPACE_DECL) {
  3611. xmlNsPtr ns = (xmlNsPtr) n2;
  3612. set1->nodeTab[set1->nodeNr++] =
  3613. xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
  3614. } else
  3615. set1->nodeTab[set1->nodeNr++] = n2;
  3616. skip_node:
  3617. {}
  3618. }
  3619. }
  3620. set2->nodeNr = 0;
  3621. return(set1);
  3622. }
  3623. /**
  3624. * xmlXPathNodeSetMergeAndClearNoDupls:
  3625. * @set1: the first NodeSet or NULL
  3626. * @set2: the second NodeSet
  3627. * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
  3628. *
  3629. * Merges two nodesets, all nodes from @set2 are added to @set1
  3630. * if @set1 is NULL, a new set is created and copied from @set2.
  3631. * Doesn't chack for duplicate nodes. Clears set2.
  3632. *
  3633. * Returns @set1 once extended or NULL in case of error.
  3634. */
  3635. static xmlNodeSetPtr
  3636. xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
  3637. int hasNullEntries)
  3638. {
  3639. if (set2 == NULL)
  3640. return(set1);
  3641. if ((set1 == NULL) && (hasNullEntries == 0)) {
  3642. /*
  3643. * Note that doing a memcpy of the list, namespace nodes are
  3644. * just assigned to set1, since set2 is cleared anyway.
  3645. */
  3646. set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
  3647. if (set1 == NULL)
  3648. return(NULL);
  3649. if (set2->nodeNr != 0) {
  3650. memcpy(set1->nodeTab, set2->nodeTab,
  3651. set2->nodeNr * sizeof(xmlNodePtr));
  3652. set1->nodeNr = set2->nodeNr;
  3653. }
  3654. } else {
  3655. int i;
  3656. xmlNodePtr n2;
  3657. if (set1 == NULL)
  3658. set1 = xmlXPathNodeSetCreate(NULL);
  3659. if (set1 == NULL)
  3660. return (NULL);
  3661. for (i = 0;i < set2->nodeNr;i++) {
  3662. n2 = set2->nodeTab[i];
  3663. /*
  3664. * Skip NULLed entries.
  3665. */
  3666. if (n2 == NULL)
  3667. continue;
  3668. if (set1->nodeMax == 0) {
  3669. set1->nodeTab = (xmlNodePtr *) xmlMalloc(
  3670. XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
  3671. if (set1->nodeTab == NULL) {
  3672. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3673. return(NULL);
  3674. }
  3675. memset(set1->nodeTab, 0,
  3676. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3677. set1->nodeMax = XML_NODESET_DEFAULT;
  3678. } else if (set1->nodeNr >= set1->nodeMax) {
  3679. xmlNodePtr *temp;
  3680. set1->nodeMax *= 2;
  3681. temp = (xmlNodePtr *) xmlRealloc(
  3682. set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
  3683. if (temp == NULL) {
  3684. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3685. return(NULL);
  3686. }
  3687. set1->nodeTab = temp;
  3688. }
  3689. set1->nodeTab[set1->nodeNr++] = n2;
  3690. }
  3691. }
  3692. set2->nodeNr = 0;
  3693. return(set1);
  3694. }
  3695. /**
  3696. * xmlXPathNodeSetDel:
  3697. * @cur: the initial node set
  3698. * @val: an xmlNodePtr
  3699. *
  3700. * Removes an xmlNodePtr from an existing NodeSet
  3701. */
  3702. void
  3703. xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
  3704. int i;
  3705. if (cur == NULL) return;
  3706. if (val == NULL) return;
  3707. /*
  3708. * find node in nodeTab
  3709. */
  3710. for (i = 0;i < cur->nodeNr;i++)
  3711. if (cur->nodeTab[i] == val) break;
  3712. if (i >= cur->nodeNr) { /* not found */
  3713. #ifdef DEBUG
  3714. xmlGenericError(xmlGenericErrorContext,
  3715. "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
  3716. val->name);
  3717. #endif
  3718. return;
  3719. }
  3720. if ((cur->nodeTab[i] != NULL) &&
  3721. (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
  3722. xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
  3723. cur->nodeNr--;
  3724. for (;i < cur->nodeNr;i++)
  3725. cur->nodeTab[i] = cur->nodeTab[i + 1];
  3726. cur->nodeTab[cur->nodeNr] = NULL;
  3727. }
  3728. /**
  3729. * xmlXPathNodeSetRemove:
  3730. * @cur: the initial node set
  3731. * @val: the index to remove
  3732. *
  3733. * Removes an entry from an existing NodeSet list.
  3734. */
  3735. void
  3736. xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
  3737. if (cur == NULL) return;
  3738. if (val >= cur->nodeNr) return;
  3739. if ((cur->nodeTab[val] != NULL) &&
  3740. (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
  3741. xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
  3742. cur->nodeNr--;
  3743. for (;val < cur->nodeNr;val++)
  3744. cur->nodeTab[val] = cur->nodeTab[val + 1];
  3745. cur->nodeTab[cur->nodeNr] = NULL;
  3746. }
  3747. /**
  3748. * xmlXPathFreeNodeSet:
  3749. * @obj: the xmlNodeSetPtr to free
  3750. *
  3751. * Free the NodeSet compound (not the actual nodes !).
  3752. */
  3753. void
  3754. xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
  3755. if (obj == NULL) return;
  3756. if (obj->nodeTab != NULL) {
  3757. int i;
  3758. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3759. for (i = 0;i < obj->nodeNr;i++)
  3760. if ((obj->nodeTab[i] != NULL) &&
  3761. (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
  3762. xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
  3763. xmlFree(obj->nodeTab);
  3764. }
  3765. xmlFree(obj);
  3766. }
  3767. /**
  3768. * xmlXPathNodeSetClear:
  3769. * @set: the node set to clear
  3770. *
  3771. * Clears the list from all temporary XPath objects (e.g. namespace nodes
  3772. * are feed), but does *not* free the list itself. Sets the length of the
  3773. * list to 0.
  3774. */
  3775. static void
  3776. xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
  3777. {
  3778. if ((set == NULL) || (set->nodeNr <= 0))
  3779. return;
  3780. else if (hasNsNodes) {
  3781. int i;
  3782. xmlNodePtr node;
  3783. for (i = 0; i < set->nodeNr; i++) {
  3784. node = set->nodeTab[i];
  3785. if ((node != NULL) &&
  3786. (node->type == XML_NAMESPACE_DECL))
  3787. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  3788. }
  3789. }
  3790. set->nodeNr = 0;
  3791. }
  3792. /**
  3793. * xmlXPathNodeSetClearFromPos:
  3794. * @set: the node set to be cleared
  3795. * @pos: the start position to clear from
  3796. *
  3797. * Clears the list from temporary XPath objects (e.g. namespace nodes
  3798. * are feed) starting with the entry at @pos, but does *not* free the list
  3799. * itself. Sets the length of the list to @pos.
  3800. */
  3801. static void
  3802. xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
  3803. {
  3804. if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
  3805. return;
  3806. else if ((hasNsNodes)) {
  3807. int i;
  3808. xmlNodePtr node;
  3809. for (i = pos; i < set->nodeNr; i++) {
  3810. node = set->nodeTab[i];
  3811. if ((node != NULL) &&
  3812. (node->type == XML_NAMESPACE_DECL))
  3813. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  3814. }
  3815. }
  3816. set->nodeNr = pos;
  3817. }
  3818. /**
  3819. * xmlXPathFreeValueTree:
  3820. * @obj: the xmlNodeSetPtr to free
  3821. *
  3822. * Free the NodeSet compound and the actual tree, this is different
  3823. * from xmlXPathFreeNodeSet()
  3824. */
  3825. static void
  3826. xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
  3827. int i;
  3828. if (obj == NULL) return;
  3829. if (obj->nodeTab != NULL) {
  3830. for (i = 0;i < obj->nodeNr;i++) {
  3831. if (obj->nodeTab[i] != NULL) {
  3832. if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
  3833. xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
  3834. } else {
  3835. xmlFreeNodeList(obj->nodeTab[i]);
  3836. }
  3837. }
  3838. }
  3839. xmlFree(obj->nodeTab);
  3840. }
  3841. xmlFree(obj);
  3842. }
  3843. #if defined(DEBUG) || defined(DEBUG_STEP)
  3844. /**
  3845. * xmlGenericErrorContextNodeSet:
  3846. * @output: a FILE * for the output
  3847. * @obj: the xmlNodeSetPtr to display
  3848. *
  3849. * Quick display of a NodeSet
  3850. */
  3851. void
  3852. xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
  3853. int i;
  3854. if (output == NULL) output = xmlGenericErrorContext;
  3855. if (obj == NULL) {
  3856. fprintf(output, "NodeSet == NULL !\n");
  3857. return;
  3858. }
  3859. if (obj->nodeNr == 0) {
  3860. fprintf(output, "NodeSet is empty\n");
  3861. return;
  3862. }
  3863. if (obj->nodeTab == NULL) {
  3864. fprintf(output, " nodeTab == NULL !\n");
  3865. return;
  3866. }
  3867. for (i = 0; i < obj->nodeNr; i++) {
  3868. if (obj->nodeTab[i] == NULL) {
  3869. fprintf(output, " NULL !\n");
  3870. return;
  3871. }
  3872. if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
  3873. (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
  3874. fprintf(output, " /");
  3875. else if (obj->nodeTab[i]->name == NULL)
  3876. fprintf(output, " noname!");
  3877. else fprintf(output, " %s", obj->nodeTab[i]->name);
  3878. }
  3879. fprintf(output, "\n");
  3880. }
  3881. #endif
  3882. /**
  3883. * xmlXPathNewNodeSet:
  3884. * @val: the NodePtr value
  3885. *
  3886. * Create a new xmlXPathObjectPtr of type NodeSet and initialize
  3887. * it with the single Node @val
  3888. *
  3889. * Returns the newly created object.
  3890. */
  3891. xmlXPathObjectPtr
  3892. xmlXPathNewNodeSet(xmlNodePtr val) {
  3893. xmlXPathObjectPtr ret;
  3894. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  3895. if (ret == NULL) {
  3896. xmlXPathErrMemory(NULL, "creating nodeset\n");
  3897. return(NULL);
  3898. }
  3899. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  3900. ret->type = XPATH_NODESET;
  3901. ret->boolval = 0;
  3902. ret->nodesetval = xmlXPathNodeSetCreate(val);
  3903. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3904. #ifdef XP_DEBUG_OBJ_USAGE
  3905. xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
  3906. #endif
  3907. return(ret);
  3908. }
  3909. /**
  3910. * xmlXPathNewValueTree:
  3911. * @val: the NodePtr value
  3912. *
  3913. * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
  3914. * it with the tree root @val
  3915. *
  3916. * Returns the newly created object.
  3917. */
  3918. xmlXPathObjectPtr
  3919. xmlXPathNewValueTree(xmlNodePtr val) {
  3920. xmlXPathObjectPtr ret;
  3921. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  3922. if (ret == NULL) {
  3923. xmlXPathErrMemory(NULL, "creating result value tree\n");
  3924. return(NULL);
  3925. }
  3926. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  3927. ret->type = XPATH_XSLT_TREE;
  3928. ret->boolval = 1;
  3929. ret->user = (void *) val;
  3930. ret->nodesetval = xmlXPathNodeSetCreate(val);
  3931. #ifdef XP_DEBUG_OBJ_USAGE
  3932. xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
  3933. #endif
  3934. return(ret);
  3935. }
  3936. /**
  3937. * xmlXPathNewNodeSetList:
  3938. * @val: an existing NodeSet
  3939. *
  3940. * Create a new xmlXPathObjectPtr of type NodeSet and initialize
  3941. * it with the Nodeset @val
  3942. *
  3943. * Returns the newly created object.
  3944. */
  3945. xmlXPathObjectPtr
  3946. xmlXPathNewNodeSetList(xmlNodeSetPtr val)
  3947. {
  3948. xmlXPathObjectPtr ret;
  3949. int i;
  3950. if (val == NULL)
  3951. ret = NULL;
  3952. else if (val->nodeTab == NULL)
  3953. ret = xmlXPathNewNodeSet(NULL);
  3954. else {
  3955. ret = xmlXPathNewNodeSet(val->nodeTab[0]);
  3956. if (ret)
  3957. for (i = 1; i < val->nodeNr; ++i)
  3958. xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
  3959. }
  3960. return (ret);
  3961. }
  3962. /**
  3963. * xmlXPathWrapNodeSet:
  3964. * @val: the NodePtr value
  3965. *
  3966. * Wrap the Nodeset @val in a new xmlXPathObjectPtr
  3967. *
  3968. * Returns the newly created object.
  3969. */
  3970. xmlXPathObjectPtr
  3971. xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
  3972. xmlXPathObjectPtr ret;
  3973. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  3974. if (ret == NULL) {
  3975. xmlXPathErrMemory(NULL, "creating node set object\n");
  3976. return(NULL);
  3977. }
  3978. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  3979. ret->type = XPATH_NODESET;
  3980. ret->nodesetval = val;
  3981. #ifdef XP_DEBUG_OBJ_USAGE
  3982. xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
  3983. #endif
  3984. return(ret);
  3985. }
  3986. /**
  3987. * xmlXPathFreeNodeSetList:
  3988. * @obj: an existing NodeSetList object
  3989. *
  3990. * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
  3991. * the list contrary to xmlXPathFreeObject().
  3992. */
  3993. void
  3994. xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
  3995. if (obj == NULL) return;
  3996. #ifdef XP_DEBUG_OBJ_USAGE
  3997. xmlXPathDebugObjUsageReleased(NULL, obj->type);
  3998. #endif
  3999. xmlFree(obj);
  4000. }
  4001. /**
  4002. * xmlXPathDifference:
  4003. * @nodes1: a node-set
  4004. * @nodes2: a node-set
  4005. *
  4006. * Implements the EXSLT - Sets difference() function:
  4007. * node-set set:difference (node-set, node-set)
  4008. *
  4009. * Returns the difference between the two node sets, or nodes1 if
  4010. * nodes2 is empty
  4011. */
  4012. xmlNodeSetPtr
  4013. xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4014. xmlNodeSetPtr ret;
  4015. int i, l1;
  4016. xmlNodePtr cur;
  4017. if (xmlXPathNodeSetIsEmpty(nodes2))
  4018. return(nodes1);
  4019. ret = xmlXPathNodeSetCreate(NULL);
  4020. if (xmlXPathNodeSetIsEmpty(nodes1))
  4021. return(ret);
  4022. l1 = xmlXPathNodeSetGetLength(nodes1);
  4023. for (i = 0; i < l1; i++) {
  4024. cur = xmlXPathNodeSetItem(nodes1, i);
  4025. if (!xmlXPathNodeSetContains(nodes2, cur))
  4026. xmlXPathNodeSetAddUnique(ret, cur);
  4027. }
  4028. return(ret);
  4029. }
  4030. /**
  4031. * xmlXPathIntersection:
  4032. * @nodes1: a node-set
  4033. * @nodes2: a node-set
  4034. *
  4035. * Implements the EXSLT - Sets intersection() function:
  4036. * node-set set:intersection (node-set, node-set)
  4037. *
  4038. * Returns a node set comprising the nodes that are within both the
  4039. * node sets passed as arguments
  4040. */
  4041. xmlNodeSetPtr
  4042. xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4043. xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
  4044. int i, l1;
  4045. xmlNodePtr cur;
  4046. if (ret == NULL)
  4047. return(ret);
  4048. if (xmlXPathNodeSetIsEmpty(nodes1))
  4049. return(ret);
  4050. if (xmlXPathNodeSetIsEmpty(nodes2))
  4051. return(ret);
  4052. l1 = xmlXPathNodeSetGetLength(nodes1);
  4053. for (i = 0; i < l1; i++) {
  4054. cur = xmlXPathNodeSetItem(nodes1, i);
  4055. if (xmlXPathNodeSetContains(nodes2, cur))
  4056. xmlXPathNodeSetAddUnique(ret, cur);
  4057. }
  4058. return(ret);
  4059. }
  4060. /**
  4061. * xmlXPathDistinctSorted:
  4062. * @nodes: a node-set, sorted by document order
  4063. *
  4064. * Implements the EXSLT - Sets distinct() function:
  4065. * node-set set:distinct (node-set)
  4066. *
  4067. * Returns a subset of the nodes contained in @nodes, or @nodes if
  4068. * it is empty
  4069. */
  4070. xmlNodeSetPtr
  4071. xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
  4072. xmlNodeSetPtr ret;
  4073. xmlHashTablePtr hash;
  4074. int i, l;
  4075. xmlChar * strval;
  4076. xmlNodePtr cur;
  4077. if (xmlXPathNodeSetIsEmpty(nodes))
  4078. return(nodes);
  4079. ret = xmlXPathNodeSetCreate(NULL);
  4080. if (ret == NULL)
  4081. return(ret);
  4082. l = xmlXPathNodeSetGetLength(nodes);
  4083. hash = xmlHashCreate (l);
  4084. for (i = 0; i < l; i++) {
  4085. cur = xmlXPathNodeSetItem(nodes, i);
  4086. strval = xmlXPathCastNodeToString(cur);
  4087. if (xmlHashLookup(hash, strval) == NULL) {
  4088. xmlHashAddEntry(hash, strval, strval);
  4089. xmlXPathNodeSetAddUnique(ret, cur);
  4090. } else {
  4091. xmlFree(strval);
  4092. }
  4093. }
  4094. xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
  4095. return(ret);
  4096. }
  4097. /**
  4098. * xmlXPathDistinct:
  4099. * @nodes: a node-set
  4100. *
  4101. * Implements the EXSLT - Sets distinct() function:
  4102. * node-set set:distinct (node-set)
  4103. * @nodes is sorted by document order, then #exslSetsDistinctSorted
  4104. * is called with the sorted node-set
  4105. *
  4106. * Returns a subset of the nodes contained in @nodes, or @nodes if
  4107. * it is empty
  4108. */
  4109. xmlNodeSetPtr
  4110. xmlXPathDistinct (xmlNodeSetPtr nodes) {
  4111. if (xmlXPathNodeSetIsEmpty(nodes))
  4112. return(nodes);
  4113. xmlXPathNodeSetSort(nodes);
  4114. return(xmlXPathDistinctSorted(nodes));
  4115. }
  4116. /**
  4117. * xmlXPathHasSameNodes:
  4118. * @nodes1: a node-set
  4119. * @nodes2: a node-set
  4120. *
  4121. * Implements the EXSLT - Sets has-same-nodes function:
  4122. * boolean set:has-same-node(node-set, node-set)
  4123. *
  4124. * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
  4125. * otherwise
  4126. */
  4127. int
  4128. xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4129. int i, l;
  4130. xmlNodePtr cur;
  4131. if (xmlXPathNodeSetIsEmpty(nodes1) ||
  4132. xmlXPathNodeSetIsEmpty(nodes2))
  4133. return(0);
  4134. l = xmlXPathNodeSetGetLength(nodes1);
  4135. for (i = 0; i < l; i++) {
  4136. cur = xmlXPathNodeSetItem(nodes1, i);
  4137. if (xmlXPathNodeSetContains(nodes2, cur))
  4138. return(1);
  4139. }
  4140. return(0);
  4141. }
  4142. /**
  4143. * xmlXPathNodeLeadingSorted:
  4144. * @nodes: a node-set, sorted by document order
  4145. * @node: a node
  4146. *
  4147. * Implements the EXSLT - Sets leading() function:
  4148. * node-set set:leading (node-set, node-set)
  4149. *
  4150. * Returns the nodes in @nodes that precede @node in document order,
  4151. * @nodes if @node is NULL or an empty node-set if @nodes
  4152. * doesn't contain @node
  4153. */
  4154. xmlNodeSetPtr
  4155. xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
  4156. int i, l;
  4157. xmlNodePtr cur;
  4158. xmlNodeSetPtr ret;
  4159. if (node == NULL)
  4160. return(nodes);
  4161. ret = xmlXPathNodeSetCreate(NULL);
  4162. if (ret == NULL)
  4163. return(ret);
  4164. if (xmlXPathNodeSetIsEmpty(nodes) ||
  4165. (!xmlXPathNodeSetContains(nodes, node)))
  4166. return(ret);
  4167. l = xmlXPathNodeSetGetLength(nodes);
  4168. for (i = 0; i < l; i++) {
  4169. cur = xmlXPathNodeSetItem(nodes, i);
  4170. if (cur == node)
  4171. break;
  4172. xmlXPathNodeSetAddUnique(ret, cur);
  4173. }
  4174. return(ret);
  4175. }
  4176. /**
  4177. * xmlXPathNodeLeading:
  4178. * @nodes: a node-set
  4179. * @node: a node
  4180. *
  4181. * Implements the EXSLT - Sets leading() function:
  4182. * node-set set:leading (node-set, node-set)
  4183. * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
  4184. * is called.
  4185. *
  4186. * Returns the nodes in @nodes that precede @node in document order,
  4187. * @nodes if @node is NULL or an empty node-set if @nodes
  4188. * doesn't contain @node
  4189. */
  4190. xmlNodeSetPtr
  4191. xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
  4192. xmlXPathNodeSetSort(nodes);
  4193. return(xmlXPathNodeLeadingSorted(nodes, node));
  4194. }
  4195. /**
  4196. * xmlXPathLeadingSorted:
  4197. * @nodes1: a node-set, sorted by document order
  4198. * @nodes2: a node-set, sorted by document order
  4199. *
  4200. * Implements the EXSLT - Sets leading() function:
  4201. * node-set set:leading (node-set, node-set)
  4202. *
  4203. * Returns the nodes in @nodes1 that precede the first node in @nodes2
  4204. * in document order, @nodes1 if @nodes2 is NULL or empty or
  4205. * an empty node-set if @nodes1 doesn't contain @nodes2
  4206. */
  4207. xmlNodeSetPtr
  4208. xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4209. if (xmlXPathNodeSetIsEmpty(nodes2))
  4210. return(nodes1);
  4211. return(xmlXPathNodeLeadingSorted(nodes1,
  4212. xmlXPathNodeSetItem(nodes2, 1)));
  4213. }
  4214. /**
  4215. * xmlXPathLeading:
  4216. * @nodes1: a node-set
  4217. * @nodes2: a node-set
  4218. *
  4219. * Implements the EXSLT - Sets leading() function:
  4220. * node-set set:leading (node-set, node-set)
  4221. * @nodes1 and @nodes2 are sorted by document order, then
  4222. * #exslSetsLeadingSorted is called.
  4223. *
  4224. * Returns the nodes in @nodes1 that precede the first node in @nodes2
  4225. * in document order, @nodes1 if @nodes2 is NULL or empty or
  4226. * an empty node-set if @nodes1 doesn't contain @nodes2
  4227. */
  4228. xmlNodeSetPtr
  4229. xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4230. if (xmlXPathNodeSetIsEmpty(nodes2))
  4231. return(nodes1);
  4232. if (xmlXPathNodeSetIsEmpty(nodes1))
  4233. return(xmlXPathNodeSetCreate(NULL));
  4234. xmlXPathNodeSetSort(nodes1);
  4235. xmlXPathNodeSetSort(nodes2);
  4236. return(xmlXPathNodeLeadingSorted(nodes1,
  4237. xmlXPathNodeSetItem(nodes2, 1)));
  4238. }
  4239. /**
  4240. * xmlXPathNodeTrailingSorted:
  4241. * @nodes: a node-set, sorted by document order
  4242. * @node: a node
  4243. *
  4244. * Implements the EXSLT - Sets trailing() function:
  4245. * node-set set:trailing (node-set, node-set)
  4246. *
  4247. * Returns the nodes in @nodes that follow @node in document order,
  4248. * @nodes if @node is NULL or an empty node-set if @nodes
  4249. * doesn't contain @node
  4250. */
  4251. xmlNodeSetPtr
  4252. xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
  4253. int i, l;
  4254. xmlNodePtr cur;
  4255. xmlNodeSetPtr ret;
  4256. if (node == NULL)
  4257. return(nodes);
  4258. ret = xmlXPathNodeSetCreate(NULL);
  4259. if (ret == NULL)
  4260. return(ret);
  4261. if (xmlXPathNodeSetIsEmpty(nodes) ||
  4262. (!xmlXPathNodeSetContains(nodes, node)))
  4263. return(ret);
  4264. l = xmlXPathNodeSetGetLength(nodes);
  4265. for (i = l - 1; i >= 0; i--) {
  4266. cur = xmlXPathNodeSetItem(nodes, i);
  4267. if (cur == node)
  4268. break;
  4269. xmlXPathNodeSetAddUnique(ret, cur);
  4270. }
  4271. xmlXPathNodeSetSort(ret); /* bug 413451 */
  4272. return(ret);
  4273. }
  4274. /**
  4275. * xmlXPathNodeTrailing:
  4276. * @nodes: a node-set
  4277. * @node: a node
  4278. *
  4279. * Implements the EXSLT - Sets trailing() function:
  4280. * node-set set:trailing (node-set, node-set)
  4281. * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
  4282. * is called.
  4283. *
  4284. * Returns the nodes in @nodes that follow @node in document order,
  4285. * @nodes if @node is NULL or an empty node-set if @nodes
  4286. * doesn't contain @node
  4287. */
  4288. xmlNodeSetPtr
  4289. xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
  4290. xmlXPathNodeSetSort(nodes);
  4291. return(xmlXPathNodeTrailingSorted(nodes, node));
  4292. }
  4293. /**
  4294. * xmlXPathTrailingSorted:
  4295. * @nodes1: a node-set, sorted by document order
  4296. * @nodes2: a node-set, sorted by document order
  4297. *
  4298. * Implements the EXSLT - Sets trailing() function:
  4299. * node-set set:trailing (node-set, node-set)
  4300. *
  4301. * Returns the nodes in @nodes1 that follow the first node in @nodes2
  4302. * in document order, @nodes1 if @nodes2 is NULL or empty or
  4303. * an empty node-set if @nodes1 doesn't contain @nodes2
  4304. */
  4305. xmlNodeSetPtr
  4306. xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4307. if (xmlXPathNodeSetIsEmpty(nodes2))
  4308. return(nodes1);
  4309. return(xmlXPathNodeTrailingSorted(nodes1,
  4310. xmlXPathNodeSetItem(nodes2, 0)));
  4311. }
  4312. /**
  4313. * xmlXPathTrailing:
  4314. * @nodes1: a node-set
  4315. * @nodes2: a node-set
  4316. *
  4317. * Implements the EXSLT - Sets trailing() function:
  4318. * node-set set:trailing (node-set, node-set)
  4319. * @nodes1 and @nodes2 are sorted by document order, then
  4320. * #xmlXPathTrailingSorted is called.
  4321. *
  4322. * Returns the nodes in @nodes1 that follow the first node in @nodes2
  4323. * in document order, @nodes1 if @nodes2 is NULL or empty or
  4324. * an empty node-set if @nodes1 doesn't contain @nodes2
  4325. */
  4326. xmlNodeSetPtr
  4327. xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4328. if (xmlXPathNodeSetIsEmpty(nodes2))
  4329. return(nodes1);
  4330. if (xmlXPathNodeSetIsEmpty(nodes1))
  4331. return(xmlXPathNodeSetCreate(NULL));
  4332. xmlXPathNodeSetSort(nodes1);
  4333. xmlXPathNodeSetSort(nodes2);
  4334. return(xmlXPathNodeTrailingSorted(nodes1,
  4335. xmlXPathNodeSetItem(nodes2, 0)));
  4336. }
  4337. /************************************************************************
  4338. * *
  4339. * Routines to handle extra functions *
  4340. * *
  4341. ************************************************************************/
  4342. /**
  4343. * xmlXPathRegisterFunc:
  4344. * @ctxt: the XPath context
  4345. * @name: the function name
  4346. * @f: the function implementation or NULL
  4347. *
  4348. * Register a new function. If @f is NULL it unregisters the function
  4349. *
  4350. * Returns 0 in case of success, -1 in case of error
  4351. */
  4352. int
  4353. xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
  4354. xmlXPathFunction f) {
  4355. return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
  4356. }
  4357. /**
  4358. * xmlXPathRegisterFuncNS:
  4359. * @ctxt: the XPath context
  4360. * @name: the function name
  4361. * @ns_uri: the function namespace URI
  4362. * @f: the function implementation or NULL
  4363. *
  4364. * Register a new function. If @f is NULL it unregisters the function
  4365. *
  4366. * Returns 0 in case of success, -1 in case of error
  4367. */
  4368. int
  4369. xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
  4370. const xmlChar *ns_uri, xmlXPathFunction f) {
  4371. if (ctxt == NULL)
  4372. return(-1);
  4373. if (name == NULL)
  4374. return(-1);
  4375. if (ctxt->funcHash == NULL)
  4376. ctxt->funcHash = xmlHashCreate(0);
  4377. if (ctxt->funcHash == NULL)
  4378. return(-1);
  4379. if (f == NULL)
  4380. return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
  4381. return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
  4382. }
  4383. /**
  4384. * xmlXPathRegisterFuncLookup:
  4385. * @ctxt: the XPath context
  4386. * @f: the lookup function
  4387. * @funcCtxt: the lookup data
  4388. *
  4389. * Registers an external mechanism to do function lookup.
  4390. */
  4391. void
  4392. xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
  4393. xmlXPathFuncLookupFunc f,
  4394. void *funcCtxt) {
  4395. if (ctxt == NULL)
  4396. return;
  4397. ctxt->funcLookupFunc = f;
  4398. ctxt->funcLookupData = funcCtxt;
  4399. }
  4400. /**
  4401. * xmlXPathFunctionLookup:
  4402. * @ctxt: the XPath context
  4403. * @name: the function name
  4404. *
  4405. * Search in the Function array of the context for the given
  4406. * function.
  4407. *
  4408. * Returns the xmlXPathFunction or NULL if not found
  4409. */
  4410. xmlXPathFunction
  4411. xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
  4412. if (ctxt == NULL)
  4413. return (NULL);
  4414. if (ctxt->funcLookupFunc != NULL) {
  4415. xmlXPathFunction ret;
  4416. xmlXPathFuncLookupFunc f;
  4417. f = ctxt->funcLookupFunc;
  4418. ret = f(ctxt->funcLookupData, name, NULL);
  4419. if (ret != NULL)
  4420. return(ret);
  4421. }
  4422. return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
  4423. }
  4424. /**
  4425. * xmlXPathFunctionLookupNS:
  4426. * @ctxt: the XPath context
  4427. * @name: the function name
  4428. * @ns_uri: the function namespace URI
  4429. *
  4430. * Search in the Function array of the context for the given
  4431. * function.
  4432. *
  4433. * Returns the xmlXPathFunction or NULL if not found
  4434. */
  4435. xmlXPathFunction
  4436. xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
  4437. const xmlChar *ns_uri) {
  4438. xmlXPathFunction ret;
  4439. if (ctxt == NULL)
  4440. return(NULL);
  4441. if (name == NULL)
  4442. return(NULL);
  4443. if (ctxt->funcLookupFunc != NULL) {
  4444. xmlXPathFuncLookupFunc f;
  4445. f = ctxt->funcLookupFunc;
  4446. ret = f(ctxt->funcLookupData, name, ns_uri);
  4447. if (ret != NULL)
  4448. return(ret);
  4449. }
  4450. if (ctxt->funcHash == NULL)
  4451. return(NULL);
  4452. XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
  4453. return(ret);
  4454. }
  4455. /**
  4456. * xmlXPathRegisteredFuncsCleanup:
  4457. * @ctxt: the XPath context
  4458. *
  4459. * Cleanup the XPath context data associated to registered functions
  4460. */
  4461. void
  4462. xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
  4463. if (ctxt == NULL)
  4464. return;
  4465. xmlHashFree(ctxt->funcHash, NULL);
  4466. ctxt->funcHash = NULL;
  4467. }
  4468. /************************************************************************
  4469. * *
  4470. * Routines to handle Variables *
  4471. * *
  4472. ************************************************************************/
  4473. /**
  4474. * xmlXPathRegisterVariable:
  4475. * @ctxt: the XPath context
  4476. * @name: the variable name
  4477. * @value: the variable value or NULL
  4478. *
  4479. * Register a new variable value. If @value is NULL it unregisters
  4480. * the variable
  4481. *
  4482. * Returns 0 in case of success, -1 in case of error
  4483. */
  4484. int
  4485. xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
  4486. xmlXPathObjectPtr value) {
  4487. return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
  4488. }
  4489. /**
  4490. * xmlXPathRegisterVariableNS:
  4491. * @ctxt: the XPath context
  4492. * @name: the variable name
  4493. * @ns_uri: the variable namespace URI
  4494. * @value: the variable value or NULL
  4495. *
  4496. * Register a new variable value. If @value is NULL it unregisters
  4497. * the variable
  4498. *
  4499. * Returns 0 in case of success, -1 in case of error
  4500. */
  4501. int
  4502. xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
  4503. const xmlChar *ns_uri,
  4504. xmlXPathObjectPtr value) {
  4505. if (ctxt == NULL)
  4506. return(-1);
  4507. if (name == NULL)
  4508. return(-1);
  4509. if (ctxt->varHash == NULL)
  4510. ctxt->varHash = xmlHashCreate(0);
  4511. if (ctxt->varHash == NULL)
  4512. return(-1);
  4513. if (value == NULL)
  4514. return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
  4515. (xmlHashDeallocator)xmlXPathFreeObject));
  4516. return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
  4517. (void *) value,
  4518. (xmlHashDeallocator)xmlXPathFreeObject));
  4519. }
  4520. /**
  4521. * xmlXPathRegisterVariableLookup:
  4522. * @ctxt: the XPath context
  4523. * @f: the lookup function
  4524. * @data: the lookup data
  4525. *
  4526. * register an external mechanism to do variable lookup
  4527. */
  4528. void
  4529. xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
  4530. xmlXPathVariableLookupFunc f, void *data) {
  4531. if (ctxt == NULL)
  4532. return;
  4533. ctxt->varLookupFunc = f;
  4534. ctxt->varLookupData = data;
  4535. }
  4536. /**
  4537. * xmlXPathVariableLookup:
  4538. * @ctxt: the XPath context
  4539. * @name: the variable name
  4540. *
  4541. * Search in the Variable array of the context for the given
  4542. * variable value.
  4543. *
  4544. * Returns a copy of the value or NULL if not found
  4545. */
  4546. xmlXPathObjectPtr
  4547. xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
  4548. if (ctxt == NULL)
  4549. return(NULL);
  4550. if (ctxt->varLookupFunc != NULL) {
  4551. xmlXPathObjectPtr ret;
  4552. ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
  4553. (ctxt->varLookupData, name, NULL);
  4554. return(ret);
  4555. }
  4556. return(xmlXPathVariableLookupNS(ctxt, name, NULL));
  4557. }
  4558. /**
  4559. * xmlXPathVariableLookupNS:
  4560. * @ctxt: the XPath context
  4561. * @name: the variable name
  4562. * @ns_uri: the variable namespace URI
  4563. *
  4564. * Search in the Variable array of the context for the given
  4565. * variable value.
  4566. *
  4567. * Returns the a copy of the value or NULL if not found
  4568. */
  4569. xmlXPathObjectPtr
  4570. xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
  4571. const xmlChar *ns_uri) {
  4572. if (ctxt == NULL)
  4573. return(NULL);
  4574. if (ctxt->varLookupFunc != NULL) {
  4575. xmlXPathObjectPtr ret;
  4576. ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
  4577. (ctxt->varLookupData, name, ns_uri);
  4578. if (ret != NULL) return(ret);
  4579. }
  4580. if (ctxt->varHash == NULL)
  4581. return(NULL);
  4582. if (name == NULL)
  4583. return(NULL);
  4584. return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
  4585. xmlHashLookup2(ctxt->varHash, name, ns_uri)));
  4586. }
  4587. /**
  4588. * xmlXPathRegisteredVariablesCleanup:
  4589. * @ctxt: the XPath context
  4590. *
  4591. * Cleanup the XPath context data associated to registered variables
  4592. */
  4593. void
  4594. xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
  4595. if (ctxt == NULL)
  4596. return;
  4597. xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
  4598. ctxt->varHash = NULL;
  4599. }
  4600. /**
  4601. * xmlXPathRegisterNs:
  4602. * @ctxt: the XPath context
  4603. * @prefix: the namespace prefix cannot be NULL or empty string
  4604. * @ns_uri: the namespace name
  4605. *
  4606. * Register a new namespace. If @ns_uri is NULL it unregisters
  4607. * the namespace
  4608. *
  4609. * Returns 0 in case of success, -1 in case of error
  4610. */
  4611. int
  4612. xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
  4613. const xmlChar *ns_uri) {
  4614. if (ctxt == NULL)
  4615. return(-1);
  4616. if (prefix == NULL)
  4617. return(-1);
  4618. if (prefix[0] == 0)
  4619. return(-1);
  4620. if (ctxt->nsHash == NULL)
  4621. ctxt->nsHash = xmlHashCreate(10);
  4622. if (ctxt->nsHash == NULL)
  4623. return(-1);
  4624. if (ns_uri == NULL)
  4625. return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
  4626. (xmlHashDeallocator)xmlFree));
  4627. return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
  4628. (xmlHashDeallocator)xmlFree));
  4629. }
  4630. /**
  4631. * xmlXPathNsLookup:
  4632. * @ctxt: the XPath context
  4633. * @prefix: the namespace prefix value
  4634. *
  4635. * Search in the namespace declaration array of the context for the given
  4636. * namespace name associated to the given prefix
  4637. *
  4638. * Returns the value or NULL if not found
  4639. */
  4640. const xmlChar *
  4641. xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
  4642. if (ctxt == NULL)
  4643. return(NULL);
  4644. if (prefix == NULL)
  4645. return(NULL);
  4646. #ifdef XML_XML_NAMESPACE
  4647. if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
  4648. return(XML_XML_NAMESPACE);
  4649. #endif
  4650. if (ctxt->namespaces != NULL) {
  4651. int i;
  4652. for (i = 0;i < ctxt->nsNr;i++) {
  4653. if ((ctxt->namespaces[i] != NULL) &&
  4654. (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
  4655. return(ctxt->namespaces[i]->href);
  4656. }
  4657. }
  4658. return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
  4659. }
  4660. /**
  4661. * xmlXPathRegisteredNsCleanup:
  4662. * @ctxt: the XPath context
  4663. *
  4664. * Cleanup the XPath context data associated to registered variables
  4665. */
  4666. void
  4667. xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
  4668. if (ctxt == NULL)
  4669. return;
  4670. xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
  4671. ctxt->nsHash = NULL;
  4672. }
  4673. /************************************************************************
  4674. * *
  4675. * Routines to handle Values *
  4676. * *
  4677. ************************************************************************/
  4678. /* Allocations are terrible, one needs to optimize all this !!! */
  4679. /**
  4680. * xmlXPathNewFloat:
  4681. * @val: the double value
  4682. *
  4683. * Create a new xmlXPathObjectPtr of type double and of value @val
  4684. *
  4685. * Returns the newly created object.
  4686. */
  4687. xmlXPathObjectPtr
  4688. xmlXPathNewFloat(double val) {
  4689. xmlXPathObjectPtr ret;
  4690. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4691. if (ret == NULL) {
  4692. xmlXPathErrMemory(NULL, "creating float object\n");
  4693. return(NULL);
  4694. }
  4695. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4696. ret->type = XPATH_NUMBER;
  4697. ret->floatval = val;
  4698. #ifdef XP_DEBUG_OBJ_USAGE
  4699. xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
  4700. #endif
  4701. return(ret);
  4702. }
  4703. /**
  4704. * xmlXPathNewBoolean:
  4705. * @val: the boolean value
  4706. *
  4707. * Create a new xmlXPathObjectPtr of type boolean and of value @val
  4708. *
  4709. * Returns the newly created object.
  4710. */
  4711. xmlXPathObjectPtr
  4712. xmlXPathNewBoolean(int val) {
  4713. xmlXPathObjectPtr ret;
  4714. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4715. if (ret == NULL) {
  4716. xmlXPathErrMemory(NULL, "creating boolean object\n");
  4717. return(NULL);
  4718. }
  4719. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4720. ret->type = XPATH_BOOLEAN;
  4721. ret->boolval = (val != 0);
  4722. #ifdef XP_DEBUG_OBJ_USAGE
  4723. xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
  4724. #endif
  4725. return(ret);
  4726. }
  4727. /**
  4728. * xmlXPathNewString:
  4729. * @val: the xmlChar * value
  4730. *
  4731. * Create a new xmlXPathObjectPtr of type string and of value @val
  4732. *
  4733. * Returns the newly created object.
  4734. */
  4735. xmlXPathObjectPtr
  4736. xmlXPathNewString(const xmlChar *val) {
  4737. xmlXPathObjectPtr ret;
  4738. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4739. if (ret == NULL) {
  4740. xmlXPathErrMemory(NULL, "creating string object\n");
  4741. return(NULL);
  4742. }
  4743. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4744. ret->type = XPATH_STRING;
  4745. if (val != NULL)
  4746. ret->stringval = xmlStrdup(val);
  4747. else
  4748. ret->stringval = xmlStrdup((const xmlChar *)"");
  4749. #ifdef XP_DEBUG_OBJ_USAGE
  4750. xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
  4751. #endif
  4752. return(ret);
  4753. }
  4754. /**
  4755. * xmlXPathWrapString:
  4756. * @val: the xmlChar * value
  4757. *
  4758. * Wraps the @val string into an XPath object.
  4759. *
  4760. * Returns the newly created object.
  4761. */
  4762. xmlXPathObjectPtr
  4763. xmlXPathWrapString (xmlChar *val) {
  4764. xmlXPathObjectPtr ret;
  4765. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4766. if (ret == NULL) {
  4767. xmlXPathErrMemory(NULL, "creating string object\n");
  4768. return(NULL);
  4769. }
  4770. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4771. ret->type = XPATH_STRING;
  4772. ret->stringval = val;
  4773. #ifdef XP_DEBUG_OBJ_USAGE
  4774. xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
  4775. #endif
  4776. return(ret);
  4777. }
  4778. /**
  4779. * xmlXPathNewCString:
  4780. * @val: the char * value
  4781. *
  4782. * Create a new xmlXPathObjectPtr of type string and of value @val
  4783. *
  4784. * Returns the newly created object.
  4785. */
  4786. xmlXPathObjectPtr
  4787. xmlXPathNewCString(const char *val) {
  4788. xmlXPathObjectPtr ret;
  4789. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4790. if (ret == NULL) {
  4791. xmlXPathErrMemory(NULL, "creating string object\n");
  4792. return(NULL);
  4793. }
  4794. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4795. ret->type = XPATH_STRING;
  4796. ret->stringval = xmlStrdup(BAD_CAST val);
  4797. #ifdef XP_DEBUG_OBJ_USAGE
  4798. xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
  4799. #endif
  4800. return(ret);
  4801. }
  4802. /**
  4803. * xmlXPathWrapCString:
  4804. * @val: the char * value
  4805. *
  4806. * Wraps a string into an XPath object.
  4807. *
  4808. * Returns the newly created object.
  4809. */
  4810. xmlXPathObjectPtr
  4811. xmlXPathWrapCString (char * val) {
  4812. return(xmlXPathWrapString((xmlChar *)(val)));
  4813. }
  4814. /**
  4815. * xmlXPathWrapExternal:
  4816. * @val: the user data
  4817. *
  4818. * Wraps the @val data into an XPath object.
  4819. *
  4820. * Returns the newly created object.
  4821. */
  4822. xmlXPathObjectPtr
  4823. xmlXPathWrapExternal (void *val) {
  4824. xmlXPathObjectPtr ret;
  4825. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4826. if (ret == NULL) {
  4827. xmlXPathErrMemory(NULL, "creating user object\n");
  4828. return(NULL);
  4829. }
  4830. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4831. ret->type = XPATH_USERS;
  4832. ret->user = val;
  4833. #ifdef XP_DEBUG_OBJ_USAGE
  4834. xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
  4835. #endif
  4836. return(ret);
  4837. }
  4838. /**
  4839. * xmlXPathObjectCopy:
  4840. * @val: the original object
  4841. *
  4842. * allocate a new copy of a given object
  4843. *
  4844. * Returns the newly created object.
  4845. */
  4846. xmlXPathObjectPtr
  4847. xmlXPathObjectCopy(xmlXPathObjectPtr val) {
  4848. xmlXPathObjectPtr ret;
  4849. if (val == NULL)
  4850. return(NULL);
  4851. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4852. if (ret == NULL) {
  4853. xmlXPathErrMemory(NULL, "copying object\n");
  4854. return(NULL);
  4855. }
  4856. memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
  4857. #ifdef XP_DEBUG_OBJ_USAGE
  4858. xmlXPathDebugObjUsageRequested(NULL, val->type);
  4859. #endif
  4860. switch (val->type) {
  4861. case XPATH_BOOLEAN:
  4862. case XPATH_NUMBER:
  4863. case XPATH_POINT:
  4864. case XPATH_RANGE:
  4865. break;
  4866. case XPATH_STRING:
  4867. ret->stringval = xmlStrdup(val->stringval);
  4868. break;
  4869. case XPATH_XSLT_TREE:
  4870. #if 0
  4871. /*
  4872. Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
  4873. this previous handling is no longer correct, and can cause some serious
  4874. problems (ref. bug 145547)
  4875. */
  4876. if ((val->nodesetval != NULL) &&
  4877. (val->nodesetval->nodeTab != NULL)) {
  4878. xmlNodePtr cur, tmp;
  4879. xmlDocPtr top;
  4880. ret->boolval = 1;
  4881. top = xmlNewDoc(NULL);
  4882. top->name = (char *)
  4883. xmlStrdup(val->nodesetval->nodeTab[0]->name);
  4884. ret->user = top;
  4885. if (top != NULL) {
  4886. top->doc = top;
  4887. cur = val->nodesetval->nodeTab[0]->children;
  4888. while (cur != NULL) {
  4889. tmp = xmlDocCopyNode(cur, top, 1);
  4890. xmlAddChild((xmlNodePtr) top, tmp);
  4891. cur = cur->next;
  4892. }
  4893. }
  4894. ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
  4895. } else
  4896. ret->nodesetval = xmlXPathNodeSetCreate(NULL);
  4897. /* Deallocate the copied tree value */
  4898. break;
  4899. #endif
  4900. case XPATH_NODESET:
  4901. ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
  4902. /* Do not deallocate the copied tree value */
  4903. ret->boolval = 0;
  4904. break;
  4905. case XPATH_LOCATIONSET:
  4906. #ifdef LIBXML_XPTR_ENABLED
  4907. {
  4908. xmlLocationSetPtr loc = val->user;
  4909. ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
  4910. break;
  4911. }
  4912. #endif
  4913. case XPATH_USERS:
  4914. ret->user = val->user;
  4915. break;
  4916. case XPATH_UNDEFINED:
  4917. xmlGenericError(xmlGenericErrorContext,
  4918. "xmlXPathObjectCopy: unsupported type %d\n",
  4919. val->type);
  4920. break;
  4921. }
  4922. return(ret);
  4923. }
  4924. /**
  4925. * xmlXPathFreeObject:
  4926. * @obj: the object to free
  4927. *
  4928. * Free up an xmlXPathObjectPtr object.
  4929. */
  4930. void
  4931. xmlXPathFreeObject(xmlXPathObjectPtr obj) {
  4932. if (obj == NULL) return;
  4933. if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
  4934. if (obj->boolval) {
  4935. #if 0
  4936. if (obj->user != NULL) {
  4937. xmlXPathFreeNodeSet(obj->nodesetval);
  4938. xmlFreeNodeList((xmlNodePtr) obj->user);
  4939. } else
  4940. #endif
  4941. obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
  4942. if (obj->nodesetval != NULL)
  4943. xmlXPathFreeValueTree(obj->nodesetval);
  4944. } else {
  4945. if (obj->nodesetval != NULL)
  4946. xmlXPathFreeNodeSet(obj->nodesetval);
  4947. }
  4948. #ifdef LIBXML_XPTR_ENABLED
  4949. } else if (obj->type == XPATH_LOCATIONSET) {
  4950. if (obj->user != NULL)
  4951. xmlXPtrFreeLocationSet(obj->user);
  4952. #endif
  4953. } else if (obj->type == XPATH_STRING) {
  4954. if (obj->stringval != NULL)
  4955. xmlFree(obj->stringval);
  4956. }
  4957. #ifdef XP_DEBUG_OBJ_USAGE
  4958. xmlXPathDebugObjUsageReleased(NULL, obj->type);
  4959. #endif
  4960. xmlFree(obj);
  4961. }
  4962. /**
  4963. * xmlXPathReleaseObject:
  4964. * @obj: the xmlXPathObjectPtr to free or to cache
  4965. *
  4966. * Depending on the state of the cache this frees the given
  4967. * XPath object or stores it in the cache.
  4968. */
  4969. static void
  4970. xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
  4971. {
  4972. #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
  4973. sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
  4974. if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
  4975. #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
  4976. if (obj == NULL)
  4977. return;
  4978. if ((ctxt == NULL) || (ctxt->cache == NULL)) {
  4979. xmlXPathFreeObject(obj);
  4980. } else {
  4981. xmlXPathContextCachePtr cache =
  4982. (xmlXPathContextCachePtr) ctxt->cache;
  4983. switch (obj->type) {
  4984. case XPATH_NODESET:
  4985. case XPATH_XSLT_TREE:
  4986. if (obj->nodesetval != NULL) {
  4987. if (obj->boolval) {
  4988. /*
  4989. * It looks like the @boolval is used for
  4990. * evaluation if this an XSLT Result Tree Fragment.
  4991. * TODO: Check if this assumption is correct.
  4992. */
  4993. obj->type = XPATH_XSLT_TREE; /* just for debugging */
  4994. xmlXPathFreeValueTree(obj->nodesetval);
  4995. obj->nodesetval = NULL;
  4996. } else if ((obj->nodesetval->nodeMax <= 40) &&
  4997. (XP_CACHE_WANTS(cache->nodesetObjs,
  4998. cache->maxNodeset)))
  4999. {
  5000. XP_CACHE_ADD(cache->nodesetObjs, obj);
  5001. goto obj_cached;
  5002. } else {
  5003. xmlXPathFreeNodeSet(obj->nodesetval);
  5004. obj->nodesetval = NULL;
  5005. }
  5006. }
  5007. break;
  5008. case XPATH_STRING:
  5009. if (obj->stringval != NULL)
  5010. xmlFree(obj->stringval);
  5011. if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
  5012. XP_CACHE_ADD(cache->stringObjs, obj);
  5013. goto obj_cached;
  5014. }
  5015. break;
  5016. case XPATH_BOOLEAN:
  5017. if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
  5018. XP_CACHE_ADD(cache->booleanObjs, obj);
  5019. goto obj_cached;
  5020. }
  5021. break;
  5022. case XPATH_NUMBER:
  5023. if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
  5024. XP_CACHE_ADD(cache->numberObjs, obj);
  5025. goto obj_cached;
  5026. }
  5027. break;
  5028. #ifdef LIBXML_XPTR_ENABLED
  5029. case XPATH_LOCATIONSET:
  5030. if (obj->user != NULL) {
  5031. xmlXPtrFreeLocationSet(obj->user);
  5032. }
  5033. goto free_obj;
  5034. #endif
  5035. default:
  5036. goto free_obj;
  5037. }
  5038. /*
  5039. * Fallback to adding to the misc-objects slot.
  5040. */
  5041. if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
  5042. XP_CACHE_ADD(cache->miscObjs, obj);
  5043. } else
  5044. goto free_obj;
  5045. obj_cached:
  5046. #ifdef XP_DEBUG_OBJ_USAGE
  5047. xmlXPathDebugObjUsageReleased(ctxt, obj->type);
  5048. #endif
  5049. if (obj->nodesetval != NULL) {
  5050. xmlNodeSetPtr tmpset = obj->nodesetval;
  5051. /*
  5052. * TODO: Due to those nasty ns-nodes, we need to traverse
  5053. * the list and free the ns-nodes.
  5054. * URGENT TODO: Check if it's actually slowing things down.
  5055. * Maybe we shouldn't try to preserve the list.
  5056. */
  5057. if (tmpset->nodeNr > 1) {
  5058. int i;
  5059. xmlNodePtr node;
  5060. for (i = 0; i < tmpset->nodeNr; i++) {
  5061. node = tmpset->nodeTab[i];
  5062. if ((node != NULL) &&
  5063. (node->type == XML_NAMESPACE_DECL))
  5064. {
  5065. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  5066. }
  5067. }
  5068. } else if (tmpset->nodeNr == 1) {
  5069. if ((tmpset->nodeTab[0] != NULL) &&
  5070. (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
  5071. xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
  5072. }
  5073. tmpset->nodeNr = 0;
  5074. memset(obj, 0, sizeof(xmlXPathObject));
  5075. obj->nodesetval = tmpset;
  5076. } else
  5077. memset(obj, 0, sizeof(xmlXPathObject));
  5078. return;
  5079. free_obj:
  5080. /*
  5081. * Cache is full; free the object.
  5082. */
  5083. if (obj->nodesetval != NULL)
  5084. xmlXPathFreeNodeSet(obj->nodesetval);
  5085. #ifdef XP_DEBUG_OBJ_USAGE
  5086. xmlXPathDebugObjUsageReleased(NULL, obj->type);
  5087. #endif
  5088. xmlFree(obj);
  5089. }
  5090. return;
  5091. }
  5092. /************************************************************************
  5093. * *
  5094. * Type Casting Routines *
  5095. * *
  5096. ************************************************************************/
  5097. /**
  5098. * xmlXPathCastBooleanToString:
  5099. * @val: a boolean
  5100. *
  5101. * Converts a boolean to its string value.
  5102. *
  5103. * Returns a newly allocated string.
  5104. */
  5105. xmlChar *
  5106. xmlXPathCastBooleanToString (int val) {
  5107. xmlChar *ret;
  5108. if (val)
  5109. ret = xmlStrdup((const xmlChar *) "true");
  5110. else
  5111. ret = xmlStrdup((const xmlChar *) "false");
  5112. return(ret);
  5113. }
  5114. /**
  5115. * xmlXPathCastNumberToString:
  5116. * @val: a number
  5117. *
  5118. * Converts a number to its string value.
  5119. *
  5120. * Returns a newly allocated string.
  5121. */
  5122. xmlChar *
  5123. xmlXPathCastNumberToString (double val) {
  5124. xmlChar *ret;
  5125. switch (xmlXPathIsInf(val)) {
  5126. case 1:
  5127. ret = xmlStrdup((const xmlChar *) "Infinity");
  5128. break;
  5129. case -1:
  5130. ret = xmlStrdup((const xmlChar *) "-Infinity");
  5131. break;
  5132. default:
  5133. if (xmlXPathIsNaN(val)) {
  5134. ret = xmlStrdup((const xmlChar *) "NaN");
  5135. } else if (val == 0 && xmlXPathGetSign(val) != 0) {
  5136. ret = xmlStrdup((const xmlChar *) "0");
  5137. } else {
  5138. /* could be improved */
  5139. char buf[100];
  5140. xmlXPathFormatNumber(val, buf, 99);
  5141. buf[99] = 0;
  5142. ret = xmlStrdup((const xmlChar *) buf);
  5143. }
  5144. }
  5145. return(ret);
  5146. }
  5147. /**
  5148. * xmlXPathCastNodeToString:
  5149. * @node: a node
  5150. *
  5151. * Converts a node to its string value.
  5152. *
  5153. * Returns a newly allocated string.
  5154. */
  5155. xmlChar *
  5156. xmlXPathCastNodeToString (xmlNodePtr node) {
  5157. xmlChar *ret;
  5158. if ((ret = xmlNodeGetContent(node)) == NULL)
  5159. ret = xmlStrdup((const xmlChar *) "");
  5160. return(ret);
  5161. }
  5162. /**
  5163. * xmlXPathCastNodeSetToString:
  5164. * @ns: a node-set
  5165. *
  5166. * Converts a node-set to its string value.
  5167. *
  5168. * Returns a newly allocated string.
  5169. */
  5170. xmlChar *
  5171. xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
  5172. if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
  5173. return(xmlStrdup((const xmlChar *) ""));
  5174. if (ns->nodeNr > 1)
  5175. xmlXPathNodeSetSort(ns);
  5176. return(xmlXPathCastNodeToString(ns->nodeTab[0]));
  5177. }
  5178. /**
  5179. * xmlXPathCastToString:
  5180. * @val: an XPath object
  5181. *
  5182. * Converts an existing object to its string() equivalent
  5183. *
  5184. * Returns the allocated string value of the object, NULL in case of error.
  5185. * It's up to the caller to free the string memory with xmlFree().
  5186. */
  5187. xmlChar *
  5188. xmlXPathCastToString(xmlXPathObjectPtr val) {
  5189. xmlChar *ret = NULL;
  5190. if (val == NULL)
  5191. return(xmlStrdup((const xmlChar *) ""));
  5192. switch (val->type) {
  5193. case XPATH_UNDEFINED:
  5194. #ifdef DEBUG_EXPR
  5195. xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
  5196. #endif
  5197. ret = xmlStrdup((const xmlChar *) "");
  5198. break;
  5199. case XPATH_NODESET:
  5200. case XPATH_XSLT_TREE:
  5201. ret = xmlXPathCastNodeSetToString(val->nodesetval);
  5202. break;
  5203. case XPATH_STRING:
  5204. return(xmlStrdup(val->stringval));
  5205. case XPATH_BOOLEAN:
  5206. ret = xmlXPathCastBooleanToString(val->boolval);
  5207. break;
  5208. case XPATH_NUMBER: {
  5209. ret = xmlXPathCastNumberToString(val->floatval);
  5210. break;
  5211. }
  5212. case XPATH_USERS:
  5213. case XPATH_POINT:
  5214. case XPATH_RANGE:
  5215. case XPATH_LOCATIONSET:
  5216. TODO
  5217. ret = xmlStrdup((const xmlChar *) "");
  5218. break;
  5219. }
  5220. return(ret);
  5221. }
  5222. /**
  5223. * xmlXPathConvertString:
  5224. * @val: an XPath object
  5225. *
  5226. * Converts an existing object to its string() equivalent
  5227. *
  5228. * Returns the new object, the old one is freed (or the operation
  5229. * is done directly on @val)
  5230. */
  5231. xmlXPathObjectPtr
  5232. xmlXPathConvertString(xmlXPathObjectPtr val) {
  5233. xmlChar *res = NULL;
  5234. if (val == NULL)
  5235. return(xmlXPathNewCString(""));
  5236. switch (val->type) {
  5237. case XPATH_UNDEFINED:
  5238. #ifdef DEBUG_EXPR
  5239. xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
  5240. #endif
  5241. break;
  5242. case XPATH_NODESET:
  5243. case XPATH_XSLT_TREE:
  5244. res = xmlXPathCastNodeSetToString(val->nodesetval);
  5245. break;
  5246. case XPATH_STRING:
  5247. return(val);
  5248. case XPATH_BOOLEAN:
  5249. res = xmlXPathCastBooleanToString(val->boolval);
  5250. break;
  5251. case XPATH_NUMBER:
  5252. res = xmlXPathCastNumberToString(val->floatval);
  5253. break;
  5254. case XPATH_USERS:
  5255. case XPATH_POINT:
  5256. case XPATH_RANGE:
  5257. case XPATH_LOCATIONSET:
  5258. TODO;
  5259. break;
  5260. }
  5261. xmlXPathFreeObject(val);
  5262. if (res == NULL)
  5263. return(xmlXPathNewCString(""));
  5264. return(xmlXPathWrapString(res));
  5265. }
  5266. /**
  5267. * xmlXPathCastBooleanToNumber:
  5268. * @val: a boolean
  5269. *
  5270. * Converts a boolean to its number value
  5271. *
  5272. * Returns the number value
  5273. */
  5274. double
  5275. xmlXPathCastBooleanToNumber(int val) {
  5276. if (val)
  5277. return(1.0);
  5278. return(0.0);
  5279. }
  5280. /**
  5281. * xmlXPathCastStringToNumber:
  5282. * @val: a string
  5283. *
  5284. * Converts a string to its number value
  5285. *
  5286. * Returns the number value
  5287. */
  5288. double
  5289. xmlXPathCastStringToNumber(const xmlChar * val) {
  5290. return(xmlXPathStringEvalNumber(val));
  5291. }
  5292. /**
  5293. * xmlXPathCastNodeToNumber:
  5294. * @node: a node
  5295. *
  5296. * Converts a node to its number value
  5297. *
  5298. * Returns the number value
  5299. */
  5300. double
  5301. xmlXPathCastNodeToNumber (xmlNodePtr node) {
  5302. xmlChar *strval;
  5303. double ret;
  5304. if (node == NULL)
  5305. return(xmlXPathNAN);
  5306. strval = xmlXPathCastNodeToString(node);
  5307. if (strval == NULL)
  5308. return(xmlXPathNAN);
  5309. ret = xmlXPathCastStringToNumber(strval);
  5310. xmlFree(strval);
  5311. return(ret);
  5312. }
  5313. /**
  5314. * xmlXPathCastNodeSetToNumber:
  5315. * @ns: a node-set
  5316. *
  5317. * Converts a node-set to its number value
  5318. *
  5319. * Returns the number value
  5320. */
  5321. double
  5322. xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
  5323. xmlChar *str;
  5324. double ret;
  5325. if (ns == NULL)
  5326. return(xmlXPathNAN);
  5327. str = xmlXPathCastNodeSetToString(ns);
  5328. ret = xmlXPathCastStringToNumber(str);
  5329. xmlFree(str);
  5330. return(ret);
  5331. }
  5332. /**
  5333. * xmlXPathCastToNumber:
  5334. * @val: an XPath object
  5335. *
  5336. * Converts an XPath object to its number value
  5337. *
  5338. * Returns the number value
  5339. */
  5340. double
  5341. xmlXPathCastToNumber(xmlXPathObjectPtr val) {
  5342. double ret = 0.0;
  5343. if (val == NULL)
  5344. return(xmlXPathNAN);
  5345. switch (val->type) {
  5346. case XPATH_UNDEFINED:
  5347. #ifdef DEGUB_EXPR
  5348. xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
  5349. #endif
  5350. ret = xmlXPathNAN;
  5351. break;
  5352. case XPATH_NODESET:
  5353. case XPATH_XSLT_TREE:
  5354. ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
  5355. break;
  5356. case XPATH_STRING:
  5357. ret = xmlXPathCastStringToNumber(val->stringval);
  5358. break;
  5359. case XPATH_NUMBER:
  5360. ret = val->floatval;
  5361. break;
  5362. case XPATH_BOOLEAN:
  5363. ret = xmlXPathCastBooleanToNumber(val->boolval);
  5364. break;
  5365. case XPATH_USERS:
  5366. case XPATH_POINT:
  5367. case XPATH_RANGE:
  5368. case XPATH_LOCATIONSET:
  5369. TODO;
  5370. ret = xmlXPathNAN;
  5371. break;
  5372. }
  5373. return(ret);
  5374. }
  5375. /**
  5376. * xmlXPathConvertNumber:
  5377. * @val: an XPath object
  5378. *
  5379. * Converts an existing object to its number() equivalent
  5380. *
  5381. * Returns the new object, the old one is freed (or the operation
  5382. * is done directly on @val)
  5383. */
  5384. xmlXPathObjectPtr
  5385. xmlXPathConvertNumber(xmlXPathObjectPtr val) {
  5386. xmlXPathObjectPtr ret;
  5387. if (val == NULL)
  5388. return(xmlXPathNewFloat(0.0));
  5389. if (val->type == XPATH_NUMBER)
  5390. return(val);
  5391. ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
  5392. xmlXPathFreeObject(val);
  5393. return(ret);
  5394. }
  5395. /**
  5396. * xmlXPathCastNumberToBoolean:
  5397. * @val: a number
  5398. *
  5399. * Converts a number to its boolean value
  5400. *
  5401. * Returns the boolean value
  5402. */
  5403. int
  5404. xmlXPathCastNumberToBoolean (double val) {
  5405. if (xmlXPathIsNaN(val) || (val == 0.0))
  5406. return(0);
  5407. return(1);
  5408. }
  5409. /**
  5410. * xmlXPathCastStringToBoolean:
  5411. * @val: a string
  5412. *
  5413. * Converts a string to its boolean value
  5414. *
  5415. * Returns the boolean value
  5416. */
  5417. int
  5418. xmlXPathCastStringToBoolean (const xmlChar *val) {
  5419. if ((val == NULL) || (xmlStrlen(val) == 0))
  5420. return(0);
  5421. return(1);
  5422. }
  5423. /**
  5424. * xmlXPathCastNodeSetToBoolean:
  5425. * @ns: a node-set
  5426. *
  5427. * Converts a node-set to its boolean value
  5428. *
  5429. * Returns the boolean value
  5430. */
  5431. int
  5432. xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
  5433. if ((ns == NULL) || (ns->nodeNr == 0))
  5434. return(0);
  5435. return(1);
  5436. }
  5437. /**
  5438. * xmlXPathCastToBoolean:
  5439. * @val: an XPath object
  5440. *
  5441. * Converts an XPath object to its boolean value
  5442. *
  5443. * Returns the boolean value
  5444. */
  5445. int
  5446. xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
  5447. int ret = 0;
  5448. if (val == NULL)
  5449. return(0);
  5450. switch (val->type) {
  5451. case XPATH_UNDEFINED:
  5452. #ifdef DEBUG_EXPR
  5453. xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
  5454. #endif
  5455. ret = 0;
  5456. break;
  5457. case XPATH_NODESET:
  5458. case XPATH_XSLT_TREE:
  5459. ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
  5460. break;
  5461. case XPATH_STRING:
  5462. ret = xmlXPathCastStringToBoolean(val->stringval);
  5463. break;
  5464. case XPATH_NUMBER:
  5465. ret = xmlXPathCastNumberToBoolean(val->floatval);
  5466. break;
  5467. case XPATH_BOOLEAN:
  5468. ret = val->boolval;
  5469. break;
  5470. case XPATH_USERS:
  5471. case XPATH_POINT:
  5472. case XPATH_RANGE:
  5473. case XPATH_LOCATIONSET:
  5474. TODO;
  5475. ret = 0;
  5476. break;
  5477. }
  5478. return(ret);
  5479. }
  5480. /**
  5481. * xmlXPathConvertBoolean:
  5482. * @val: an XPath object
  5483. *
  5484. * Converts an existing object to its boolean() equivalent
  5485. *
  5486. * Returns the new object, the old one is freed (or the operation
  5487. * is done directly on @val)
  5488. */
  5489. xmlXPathObjectPtr
  5490. xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
  5491. xmlXPathObjectPtr ret;
  5492. if (val == NULL)
  5493. return(xmlXPathNewBoolean(0));
  5494. if (val->type == XPATH_BOOLEAN)
  5495. return(val);
  5496. ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
  5497. xmlXPathFreeObject(val);
  5498. return(ret);
  5499. }
  5500. /************************************************************************
  5501. * *
  5502. * Routines to handle XPath contexts *
  5503. * *
  5504. ************************************************************************/
  5505. /**
  5506. * xmlXPathNewContext:
  5507. * @doc: the XML document
  5508. *
  5509. * Create a new xmlXPathContext
  5510. *
  5511. * Returns the xmlXPathContext just allocated. The caller will need to free it.
  5512. */
  5513. xmlXPathContextPtr
  5514. xmlXPathNewContext(xmlDocPtr doc) {
  5515. xmlXPathContextPtr ret;
  5516. ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
  5517. if (ret == NULL) {
  5518. xmlXPathErrMemory(NULL, "creating context\n");
  5519. return(NULL);
  5520. }
  5521. memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
  5522. ret->doc = doc;
  5523. ret->node = NULL;
  5524. ret->varHash = NULL;
  5525. ret->nb_types = 0;
  5526. ret->max_types = 0;
  5527. ret->types = NULL;
  5528. ret->funcHash = xmlHashCreate(0);
  5529. ret->nb_axis = 0;
  5530. ret->max_axis = 0;
  5531. ret->axis = NULL;
  5532. ret->nsHash = NULL;
  5533. ret->user = NULL;
  5534. ret->contextSize = -1;
  5535. ret->proximityPosition = -1;
  5536. #ifdef XP_DEFAULT_CACHE_ON
  5537. if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
  5538. xmlXPathFreeContext(ret);
  5539. return(NULL);
  5540. }
  5541. #endif
  5542. xmlXPathRegisterAllFunctions(ret);
  5543. return(ret);
  5544. }
  5545. /**
  5546. * xmlXPathFreeContext:
  5547. * @ctxt: the context to free
  5548. *
  5549. * Free up an xmlXPathContext
  5550. */
  5551. void
  5552. xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
  5553. if (ctxt == NULL) return;
  5554. if (ctxt->cache != NULL)
  5555. xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
  5556. xmlXPathRegisteredNsCleanup(ctxt);
  5557. xmlXPathRegisteredFuncsCleanup(ctxt);
  5558. xmlXPathRegisteredVariablesCleanup(ctxt);
  5559. xmlResetError(&ctxt->lastError);
  5560. xmlFree(ctxt);
  5561. }
  5562. /************************************************************************
  5563. * *
  5564. * Routines to handle XPath parser contexts *
  5565. * *
  5566. ************************************************************************/
  5567. #define CHECK_CTXT(ctxt) \
  5568. if (ctxt == NULL) { \
  5569. __xmlRaiseError(NULL, NULL, NULL, \
  5570. NULL, NULL, XML_FROM_XPATH, \
  5571. XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
  5572. __FILE__, __LINE__, \
  5573. NULL, NULL, NULL, 0, 0, \
  5574. "NULL context pointer\n"); \
  5575. return(NULL); \
  5576. } \
  5577. #define CHECK_CTXT_NEG(ctxt) \
  5578. if (ctxt == NULL) { \
  5579. __xmlRaiseError(NULL, NULL, NULL, \
  5580. NULL, NULL, XML_FROM_XPATH, \
  5581. XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
  5582. __FILE__, __LINE__, \
  5583. NULL, NULL, NULL, 0, 0, \
  5584. "NULL context pointer\n"); \
  5585. return(-1); \
  5586. } \
  5587. #define CHECK_CONTEXT(ctxt) \
  5588. if ((ctxt == NULL) || (ctxt->doc == NULL) || \
  5589. (ctxt->doc->children == NULL)) { \
  5590. xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
  5591. return(NULL); \
  5592. }
  5593. /**
  5594. * xmlXPathNewParserContext:
  5595. * @str: the XPath expression
  5596. * @ctxt: the XPath context
  5597. *
  5598. * Create a new xmlXPathParserContext
  5599. *
  5600. * Returns the xmlXPathParserContext just allocated.
  5601. */
  5602. xmlXPathParserContextPtr
  5603. xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
  5604. xmlXPathParserContextPtr ret;
  5605. ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
  5606. if (ret == NULL) {
  5607. xmlXPathErrMemory(ctxt, "creating parser context\n");
  5608. return(NULL);
  5609. }
  5610. memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
  5611. ret->cur = ret->base = str;
  5612. ret->context = ctxt;
  5613. ret->comp = xmlXPathNewCompExpr();
  5614. if (ret->comp == NULL) {
  5615. xmlFree(ret->valueTab);
  5616. xmlFree(ret);
  5617. return(NULL);
  5618. }
  5619. if ((ctxt != NULL) && (ctxt->dict != NULL)) {
  5620. ret->comp->dict = ctxt->dict;
  5621. xmlDictReference(ret->comp->dict);
  5622. }
  5623. return(ret);
  5624. }
  5625. /**
  5626. * xmlXPathCompParserContext:
  5627. * @comp: the XPath compiled expression
  5628. * @ctxt: the XPath context
  5629. *
  5630. * Create a new xmlXPathParserContext when processing a compiled expression
  5631. *
  5632. * Returns the xmlXPathParserContext just allocated.
  5633. */
  5634. static xmlXPathParserContextPtr
  5635. xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
  5636. xmlXPathParserContextPtr ret;
  5637. ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
  5638. if (ret == NULL) {
  5639. xmlXPathErrMemory(ctxt, "creating evaluation context\n");
  5640. return(NULL);
  5641. }
  5642. memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
  5643. /* Allocate the value stack */
  5644. ret->valueTab = (xmlXPathObjectPtr *)
  5645. xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
  5646. if (ret->valueTab == NULL) {
  5647. xmlFree(ret);
  5648. xmlXPathErrMemory(ctxt, "creating evaluation context\n");
  5649. return(NULL);
  5650. }
  5651. ret->valueNr = 0;
  5652. ret->valueMax = 10;
  5653. ret->value = NULL;
  5654. ret->context = ctxt;
  5655. ret->comp = comp;
  5656. return(ret);
  5657. }
  5658. /**
  5659. * xmlXPathFreeParserContext:
  5660. * @ctxt: the context to free
  5661. *
  5662. * Free up an xmlXPathParserContext
  5663. */
  5664. void
  5665. xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
  5666. if (ctxt->valueTab != NULL) {
  5667. xmlFree(ctxt->valueTab);
  5668. }
  5669. if (ctxt->comp != NULL) {
  5670. #ifdef XPATH_STREAMING
  5671. if (ctxt->comp->stream != NULL) {
  5672. xmlFreePatternList(ctxt->comp->stream);
  5673. ctxt->comp->stream = NULL;
  5674. }
  5675. #endif
  5676. xmlXPathFreeCompExpr(ctxt->comp);
  5677. }
  5678. xmlFree(ctxt);
  5679. }
  5680. /************************************************************************
  5681. * *
  5682. * The implicit core function library *
  5683. * *
  5684. ************************************************************************/
  5685. /**
  5686. * xmlXPathNodeValHash:
  5687. * @node: a node pointer
  5688. *
  5689. * Function computing the beginning of the string value of the node,
  5690. * used to speed up comparisons
  5691. *
  5692. * Returns an int usable as a hash
  5693. */
  5694. static unsigned int
  5695. xmlXPathNodeValHash(xmlNodePtr node) {
  5696. int len = 2;
  5697. const xmlChar * string = NULL;
  5698. xmlNodePtr tmp = NULL;
  5699. unsigned int ret = 0;
  5700. if (node == NULL)
  5701. return(0);
  5702. if (node->type == XML_DOCUMENT_NODE) {
  5703. tmp = xmlDocGetRootElement((xmlDocPtr) node);
  5704. if (tmp == NULL)
  5705. node = node->children;
  5706. else
  5707. node = tmp;
  5708. if (node == NULL)
  5709. return(0);
  5710. }
  5711. switch (node->type) {
  5712. case XML_COMMENT_NODE:
  5713. case XML_PI_NODE:
  5714. case XML_CDATA_SECTION_NODE:
  5715. case XML_TEXT_NODE:
  5716. string = node->content;
  5717. if (string == NULL)
  5718. return(0);
  5719. if (string[0] == 0)
  5720. return(0);
  5721. return(((unsigned int) string[0]) +
  5722. (((unsigned int) string[1]) << 8));
  5723. case XML_NAMESPACE_DECL:
  5724. string = ((xmlNsPtr)node)->href;
  5725. if (string == NULL)
  5726. return(0);
  5727. if (string[0] == 0)
  5728. return(0);
  5729. return(((unsigned int) string[0]) +
  5730. (((unsigned int) string[1]) << 8));
  5731. case XML_ATTRIBUTE_NODE:
  5732. tmp = ((xmlAttrPtr) node)->children;
  5733. break;
  5734. case XML_ELEMENT_NODE:
  5735. tmp = node->children;
  5736. break;
  5737. default:
  5738. return(0);
  5739. }
  5740. while (tmp != NULL) {
  5741. switch (tmp->type) {
  5742. case XML_COMMENT_NODE:
  5743. case XML_PI_NODE:
  5744. case XML_CDATA_SECTION_NODE:
  5745. case XML_TEXT_NODE:
  5746. string = tmp->content;
  5747. break;
  5748. case XML_NAMESPACE_DECL:
  5749. string = ((xmlNsPtr)tmp)->href;
  5750. break;
  5751. default:
  5752. break;
  5753. }
  5754. if ((string != NULL) && (string[0] != 0)) {
  5755. if (len == 1) {
  5756. return(ret + (((unsigned int) string[0]) << 8));
  5757. }
  5758. if (string[1] == 0) {
  5759. len = 1;
  5760. ret = (unsigned int) string[0];
  5761. } else {
  5762. return(((unsigned int) string[0]) +
  5763. (((unsigned int) string[1]) << 8));
  5764. }
  5765. }
  5766. /*
  5767. * Skip to next node
  5768. */
  5769. if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
  5770. if (tmp->children->type != XML_ENTITY_DECL) {
  5771. tmp = tmp->children;
  5772. continue;
  5773. }
  5774. }
  5775. if (tmp == node)
  5776. break;
  5777. if (tmp->next != NULL) {
  5778. tmp = tmp->next;
  5779. continue;
  5780. }
  5781. do {
  5782. tmp = tmp->parent;
  5783. if (tmp == NULL)
  5784. break;
  5785. if (tmp == node) {
  5786. tmp = NULL;
  5787. break;
  5788. }
  5789. if (tmp->next != NULL) {
  5790. tmp = tmp->next;
  5791. break;
  5792. }
  5793. } while (tmp != NULL);
  5794. }
  5795. return(ret);
  5796. }
  5797. /**
  5798. * xmlXPathStringHash:
  5799. * @string: a string
  5800. *
  5801. * Function computing the beginning of the string value of the node,
  5802. * used to speed up comparisons
  5803. *
  5804. * Returns an int usable as a hash
  5805. */
  5806. static unsigned int
  5807. xmlXPathStringHash(const xmlChar * string) {
  5808. if (string == NULL)
  5809. return((unsigned int) 0);
  5810. if (string[0] == 0)
  5811. return(0);
  5812. return(((unsigned int) string[0]) +
  5813. (((unsigned int) string[1]) << 8));
  5814. }
  5815. /**
  5816. * xmlXPathCompareNodeSetFloat:
  5817. * @ctxt: the XPath Parser context
  5818. * @inf: less than (1) or greater than (0)
  5819. * @strict: is the comparison strict
  5820. * @arg: the node set
  5821. * @f: the value
  5822. *
  5823. * Implement the compare operation between a nodeset and a number
  5824. * @ns < @val (1, 1, ...
  5825. * @ns <= @val (1, 0, ...
  5826. * @ns > @val (0, 1, ...
  5827. * @ns >= @val (0, 0, ...
  5828. *
  5829. * If one object to be compared is a node-set and the other is a number,
  5830. * then the comparison will be true if and only if there is a node in the
  5831. * node-set such that the result of performing the comparison on the number
  5832. * to be compared and on the result of converting the string-value of that
  5833. * node to a number using the number function is true.
  5834. *
  5835. * Returns 0 or 1 depending on the results of the test.
  5836. */
  5837. static int
  5838. xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
  5839. xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
  5840. int i, ret = 0;
  5841. xmlNodeSetPtr ns;
  5842. xmlChar *str2;
  5843. if ((f == NULL) || (arg == NULL) ||
  5844. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
  5845. xmlXPathReleaseObject(ctxt->context, arg);
  5846. xmlXPathReleaseObject(ctxt->context, f);
  5847. return(0);
  5848. }
  5849. ns = arg->nodesetval;
  5850. if (ns != NULL) {
  5851. for (i = 0;i < ns->nodeNr;i++) {
  5852. str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
  5853. if (str2 != NULL) {
  5854. valuePush(ctxt,
  5855. xmlXPathCacheNewString(ctxt->context, str2));
  5856. xmlFree(str2);
  5857. xmlXPathNumberFunction(ctxt, 1);
  5858. valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
  5859. ret = xmlXPathCompareValues(ctxt, inf, strict);
  5860. if (ret)
  5861. break;
  5862. }
  5863. }
  5864. }
  5865. xmlXPathReleaseObject(ctxt->context, arg);
  5866. xmlXPathReleaseObject(ctxt->context, f);
  5867. return(ret);
  5868. }
  5869. /**
  5870. * xmlXPathCompareNodeSetString:
  5871. * @ctxt: the XPath Parser context
  5872. * @inf: less than (1) or greater than (0)
  5873. * @strict: is the comparison strict
  5874. * @arg: the node set
  5875. * @s: the value
  5876. *
  5877. * Implement the compare operation between a nodeset and a string
  5878. * @ns < @val (1, 1, ...
  5879. * @ns <= @val (1, 0, ...
  5880. * @ns > @val (0, 1, ...
  5881. * @ns >= @val (0, 0, ...
  5882. *
  5883. * If one object to be compared is a node-set and the other is a string,
  5884. * then the comparison will be true if and only if there is a node in
  5885. * the node-set such that the result of performing the comparison on the
  5886. * string-value of the node and the other string is true.
  5887. *
  5888. * Returns 0 or 1 depending on the results of the test.
  5889. */
  5890. static int
  5891. xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
  5892. xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
  5893. int i, ret = 0;
  5894. xmlNodeSetPtr ns;
  5895. xmlChar *str2;
  5896. if ((s == NULL) || (arg == NULL) ||
  5897. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
  5898. xmlXPathReleaseObject(ctxt->context, arg);
  5899. xmlXPathReleaseObject(ctxt->context, s);
  5900. return(0);
  5901. }
  5902. ns = arg->nodesetval;
  5903. if (ns != NULL) {
  5904. for (i = 0;i < ns->nodeNr;i++) {
  5905. str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
  5906. if (str2 != NULL) {
  5907. valuePush(ctxt,
  5908. xmlXPathCacheNewString(ctxt->context, str2));
  5909. xmlFree(str2);
  5910. valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
  5911. ret = xmlXPathCompareValues(ctxt, inf, strict);
  5912. if (ret)
  5913. break;
  5914. }
  5915. }
  5916. }
  5917. xmlXPathReleaseObject(ctxt->context, arg);
  5918. xmlXPathReleaseObject(ctxt->context, s);
  5919. return(ret);
  5920. }
  5921. /**
  5922. * xmlXPathCompareNodeSets:
  5923. * @inf: less than (1) or greater than (0)
  5924. * @strict: is the comparison strict
  5925. * @arg1: the first node set object
  5926. * @arg2: the second node set object
  5927. *
  5928. * Implement the compare operation on nodesets:
  5929. *
  5930. * If both objects to be compared are node-sets, then the comparison
  5931. * will be true if and only if there is a node in the first node-set
  5932. * and a node in the second node-set such that the result of performing
  5933. * the comparison on the string-values of the two nodes is true.
  5934. * ....
  5935. * When neither object to be compared is a node-set and the operator
  5936. * is <=, <, >= or >, then the objects are compared by converting both
  5937. * objects to numbers and comparing the numbers according to IEEE 754.
  5938. * ....
  5939. * The number function converts its argument to a number as follows:
  5940. * - a string that consists of optional whitespace followed by an
  5941. * optional minus sign followed by a Number followed by whitespace
  5942. * is converted to the IEEE 754 number that is nearest (according
  5943. * to the IEEE 754 round-to-nearest rule) to the mathematical value
  5944. * represented by the string; any other string is converted to NaN
  5945. *
  5946. * Conclusion all nodes need to be converted first to their string value
  5947. * and then the comparison must be done when possible
  5948. */
  5949. static int
  5950. xmlXPathCompareNodeSets(int inf, int strict,
  5951. xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
  5952. int i, j, init = 0;
  5953. double val1;
  5954. double *values2;
  5955. int ret = 0;
  5956. xmlNodeSetPtr ns1;
  5957. xmlNodeSetPtr ns2;
  5958. if ((arg1 == NULL) ||
  5959. ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
  5960. xmlXPathFreeObject(arg2);
  5961. return(0);
  5962. }
  5963. if ((arg2 == NULL) ||
  5964. ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
  5965. xmlXPathFreeObject(arg1);
  5966. xmlXPathFreeObject(arg2);
  5967. return(0);
  5968. }
  5969. ns1 = arg1->nodesetval;
  5970. ns2 = arg2->nodesetval;
  5971. if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
  5972. xmlXPathFreeObject(arg1);
  5973. xmlXPathFreeObject(arg2);
  5974. return(0);
  5975. }
  5976. if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
  5977. xmlXPathFreeObject(arg1);
  5978. xmlXPathFreeObject(arg2);
  5979. return(0);
  5980. }
  5981. values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
  5982. if (values2 == NULL) {
  5983. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  5984. xmlXPathFreeObject(arg1);
  5985. xmlXPathFreeObject(arg2);
  5986. return(0);
  5987. }
  5988. for (i = 0;i < ns1->nodeNr;i++) {
  5989. val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
  5990. if (xmlXPathIsNaN(val1))
  5991. continue;
  5992. for (j = 0;j < ns2->nodeNr;j++) {
  5993. if (init == 0) {
  5994. values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
  5995. }
  5996. if (xmlXPathIsNaN(values2[j]))
  5997. continue;
  5998. if (inf && strict)
  5999. ret = (val1 < values2[j]);
  6000. else if (inf && !strict)
  6001. ret = (val1 <= values2[j]);
  6002. else if (!inf && strict)
  6003. ret = (val1 > values2[j]);
  6004. else if (!inf && !strict)
  6005. ret = (val1 >= values2[j]);
  6006. if (ret)
  6007. break;
  6008. }
  6009. if (ret)
  6010. break;
  6011. init = 1;
  6012. }
  6013. xmlFree(values2);
  6014. xmlXPathFreeObject(arg1);
  6015. xmlXPathFreeObject(arg2);
  6016. return(ret);
  6017. }
  6018. /**
  6019. * xmlXPathCompareNodeSetValue:
  6020. * @ctxt: the XPath Parser context
  6021. * @inf: less than (1) or greater than (0)
  6022. * @strict: is the comparison strict
  6023. * @arg: the node set
  6024. * @val: the value
  6025. *
  6026. * Implement the compare operation between a nodeset and a value
  6027. * @ns < @val (1, 1, ...
  6028. * @ns <= @val (1, 0, ...
  6029. * @ns > @val (0, 1, ...
  6030. * @ns >= @val (0, 0, ...
  6031. *
  6032. * If one object to be compared is a node-set and the other is a boolean,
  6033. * then the comparison will be true if and only if the result of performing
  6034. * the comparison on the boolean and on the result of converting
  6035. * the node-set to a boolean using the boolean function is true.
  6036. *
  6037. * Returns 0 or 1 depending on the results of the test.
  6038. */
  6039. static int
  6040. xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
  6041. xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
  6042. if ((val == NULL) || (arg == NULL) ||
  6043. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
  6044. return(0);
  6045. switch(val->type) {
  6046. case XPATH_NUMBER:
  6047. return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
  6048. case XPATH_NODESET:
  6049. case XPATH_XSLT_TREE:
  6050. return(xmlXPathCompareNodeSets(inf, strict, arg, val));
  6051. case XPATH_STRING:
  6052. return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
  6053. case XPATH_BOOLEAN:
  6054. valuePush(ctxt, arg);
  6055. xmlXPathBooleanFunction(ctxt, 1);
  6056. valuePush(ctxt, val);
  6057. return(xmlXPathCompareValues(ctxt, inf, strict));
  6058. default:
  6059. TODO
  6060. }
  6061. return(0);
  6062. }
  6063. /**
  6064. * xmlXPathEqualNodeSetString:
  6065. * @arg: the nodeset object argument
  6066. * @str: the string to compare to.
  6067. * @neq: flag to show whether for '=' (0) or '!=' (1)
  6068. *
  6069. * Implement the equal operation on XPath objects content: @arg1 == @arg2
  6070. * If one object to be compared is a node-set and the other is a string,
  6071. * then the comparison will be true if and only if there is a node in
  6072. * the node-set such that the result of performing the comparison on the
  6073. * string-value of the node and the other string is true.
  6074. *
  6075. * Returns 0 or 1 depending on the results of the test.
  6076. */
  6077. static int
  6078. xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
  6079. {
  6080. int i;
  6081. xmlNodeSetPtr ns;
  6082. xmlChar *str2;
  6083. unsigned int hash;
  6084. if ((str == NULL) || (arg == NULL) ||
  6085. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
  6086. return (0);
  6087. ns = arg->nodesetval;
  6088. /*
  6089. * A NULL nodeset compared with a string is always false
  6090. * (since there is no node equal, and no node not equal)
  6091. */
  6092. if ((ns == NULL) || (ns->nodeNr <= 0) )
  6093. return (0);
  6094. hash = xmlXPathStringHash(str);
  6095. for (i = 0; i < ns->nodeNr; i++) {
  6096. if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
  6097. str2 = xmlNodeGetContent(ns->nodeTab[i]);
  6098. if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
  6099. xmlFree(str2);
  6100. if (neq)
  6101. continue;
  6102. return (1);
  6103. } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
  6104. if (neq)
  6105. continue;
  6106. return (1);
  6107. } else if (neq) {
  6108. if (str2 != NULL)
  6109. xmlFree(str2);
  6110. return (1);
  6111. }
  6112. if (str2 != NULL)
  6113. xmlFree(str2);
  6114. } else if (neq)
  6115. return (1);
  6116. }
  6117. return (0);
  6118. }
  6119. /**
  6120. * xmlXPathEqualNodeSetFloat:
  6121. * @arg: the nodeset object argument
  6122. * @f: the float to compare to
  6123. * @neq: flag to show whether to compare '=' (0) or '!=' (1)
  6124. *
  6125. * Implement the equal operation on XPath objects content: @arg1 == @arg2
  6126. * If one object to be compared is a node-set and the other is a number,
  6127. * then the comparison will be true if and only if there is a node in
  6128. * the node-set such that the result of performing the comparison on the
  6129. * number to be compared and on the result of converting the string-value
  6130. * of that node to a number using the number function is true.
  6131. *
  6132. * Returns 0 or 1 depending on the results of the test.
  6133. */
  6134. static int
  6135. xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
  6136. xmlXPathObjectPtr arg, double f, int neq) {
  6137. int i, ret=0;
  6138. xmlNodeSetPtr ns;
  6139. xmlChar *str2;
  6140. xmlXPathObjectPtr val;
  6141. double v;
  6142. if ((arg == NULL) ||
  6143. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
  6144. return(0);
  6145. ns = arg->nodesetval;
  6146. if (ns != NULL) {
  6147. for (i=0;i<ns->nodeNr;i++) {
  6148. str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
  6149. if (str2 != NULL) {
  6150. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
  6151. xmlFree(str2);
  6152. xmlXPathNumberFunction(ctxt, 1);
  6153. val = valuePop(ctxt);
  6154. v = val->floatval;
  6155. xmlXPathReleaseObject(ctxt->context, val);
  6156. if (!xmlXPathIsNaN(v)) {
  6157. if ((!neq) && (v==f)) {
  6158. ret = 1;
  6159. break;
  6160. } else if ((neq) && (v!=f)) {
  6161. ret = 1;
  6162. break;
  6163. }
  6164. } else { /* NaN is unequal to any value */
  6165. if (neq)
  6166. ret = 1;
  6167. }
  6168. }
  6169. }
  6170. }
  6171. return(ret);
  6172. }
  6173. /**
  6174. * xmlXPathEqualNodeSets:
  6175. * @arg1: first nodeset object argument
  6176. * @arg2: second nodeset object argument
  6177. * @neq: flag to show whether to test '=' (0) or '!=' (1)
  6178. *
  6179. * Implement the equal / not equal operation on XPath nodesets:
  6180. * @arg1 == @arg2 or @arg1 != @arg2
  6181. * If both objects to be compared are node-sets, then the comparison
  6182. * will be true if and only if there is a node in the first node-set and
  6183. * a node in the second node-set such that the result of performing the
  6184. * comparison on the string-values of the two nodes is true.
  6185. *
  6186. * (needless to say, this is a costly operation)
  6187. *
  6188. * Returns 0 or 1 depending on the results of the test.
  6189. */
  6190. static int
  6191. xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
  6192. int i, j;
  6193. unsigned int *hashs1;
  6194. unsigned int *hashs2;
  6195. xmlChar **values1;
  6196. xmlChar **values2;
  6197. int ret = 0;
  6198. xmlNodeSetPtr ns1;
  6199. xmlNodeSetPtr ns2;
  6200. if ((arg1 == NULL) ||
  6201. ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
  6202. return(0);
  6203. if ((arg2 == NULL) ||
  6204. ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
  6205. return(0);
  6206. ns1 = arg1->nodesetval;
  6207. ns2 = arg2->nodesetval;
  6208. if ((ns1 == NULL) || (ns1->nodeNr <= 0))
  6209. return(0);
  6210. if ((ns2 == NULL) || (ns2->nodeNr <= 0))
  6211. return(0);
  6212. /*
  6213. * for equal, check if there is a node pertaining to both sets
  6214. */
  6215. if (neq == 0)
  6216. for (i = 0;i < ns1->nodeNr;i++)
  6217. for (j = 0;j < ns2->nodeNr;j++)
  6218. if (ns1->nodeTab[i] == ns2->nodeTab[j])
  6219. return(1);
  6220. values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
  6221. if (values1 == NULL) {
  6222. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  6223. return(0);
  6224. }
  6225. hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
  6226. if (hashs1 == NULL) {
  6227. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  6228. xmlFree(values1);
  6229. return(0);
  6230. }
  6231. memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
  6232. values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
  6233. if (values2 == NULL) {
  6234. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  6235. xmlFree(hashs1);
  6236. xmlFree(values1);
  6237. return(0);
  6238. }
  6239. hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
  6240. if (hashs2 == NULL) {
  6241. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  6242. xmlFree(hashs1);
  6243. xmlFree(values1);
  6244. xmlFree(values2);
  6245. return(0);
  6246. }
  6247. memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
  6248. for (i = 0;i < ns1->nodeNr;i++) {
  6249. hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
  6250. for (j = 0;j < ns2->nodeNr;j++) {
  6251. if (i == 0)
  6252. hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
  6253. if (hashs1[i] != hashs2[j]) {
  6254. if (neq) {
  6255. ret = 1;
  6256. break;
  6257. }
  6258. }
  6259. else {
  6260. if (values1[i] == NULL)
  6261. values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
  6262. if (values2[j] == NULL)
  6263. values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
  6264. ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
  6265. if (ret)
  6266. break;
  6267. }
  6268. }
  6269. if (ret)
  6270. break;
  6271. }
  6272. for (i = 0;i < ns1->nodeNr;i++)
  6273. if (values1[i] != NULL)
  6274. xmlFree(values1[i]);
  6275. for (j = 0;j < ns2->nodeNr;j++)
  6276. if (values2[j] != NULL)
  6277. xmlFree(values2[j]);
  6278. xmlFree(values1);
  6279. xmlFree(values2);
  6280. xmlFree(hashs1);
  6281. xmlFree(hashs2);
  6282. return(ret);
  6283. }
  6284. static int
  6285. xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
  6286. xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
  6287. int ret = 0;
  6288. /*
  6289. *At this point we are assured neither arg1 nor arg2
  6290. *is a nodeset, so we can just pick the appropriate routine.
  6291. */
  6292. switch (arg1->type) {
  6293. case XPATH_UNDEFINED:
  6294. #ifdef DEBUG_EXPR
  6295. xmlGenericError(xmlGenericErrorContext,
  6296. "Equal: undefined\n");
  6297. #endif
  6298. break;
  6299. case XPATH_BOOLEAN:
  6300. switch (arg2->type) {
  6301. case XPATH_UNDEFINED:
  6302. #ifdef DEBUG_EXPR
  6303. xmlGenericError(xmlGenericErrorContext,
  6304. "Equal: undefined\n");
  6305. #endif
  6306. break;
  6307. case XPATH_BOOLEAN:
  6308. #ifdef DEBUG_EXPR
  6309. xmlGenericError(xmlGenericErrorContext,
  6310. "Equal: %d boolean %d \n",
  6311. arg1->boolval, arg2->boolval);
  6312. #endif
  6313. ret = (arg1->boolval == arg2->boolval);
  6314. break;
  6315. case XPATH_NUMBER:
  6316. ret = (arg1->boolval ==
  6317. xmlXPathCastNumberToBoolean(arg2->floatval));
  6318. break;
  6319. case XPATH_STRING:
  6320. if ((arg2->stringval == NULL) ||
  6321. (arg2->stringval[0] == 0)) ret = 0;
  6322. else
  6323. ret = 1;
  6324. ret = (arg1->boolval == ret);
  6325. break;
  6326. case XPATH_USERS:
  6327. case XPATH_POINT:
  6328. case XPATH_RANGE:
  6329. case XPATH_LOCATIONSET:
  6330. TODO
  6331. break;
  6332. case XPATH_NODESET:
  6333. case XPATH_XSLT_TREE:
  6334. break;
  6335. }
  6336. break;
  6337. case XPATH_NUMBER:
  6338. switch (arg2->type) {
  6339. case XPATH_UNDEFINED:
  6340. #ifdef DEBUG_EXPR
  6341. xmlGenericError(xmlGenericErrorContext,
  6342. "Equal: undefined\n");
  6343. #endif
  6344. break;
  6345. case XPATH_BOOLEAN:
  6346. ret = (arg2->boolval==
  6347. xmlXPathCastNumberToBoolean(arg1->floatval));
  6348. break;
  6349. case XPATH_STRING:
  6350. valuePush(ctxt, arg2);
  6351. xmlXPathNumberFunction(ctxt, 1);
  6352. arg2 = valuePop(ctxt);
  6353. /* no break on purpose */
  6354. case XPATH_NUMBER:
  6355. /* Hand check NaN and Infinity equalities */
  6356. if (xmlXPathIsNaN(arg1->floatval) ||
  6357. xmlXPathIsNaN(arg2->floatval)) {
  6358. ret = 0;
  6359. } else if (xmlXPathIsInf(arg1->floatval) == 1) {
  6360. if (xmlXPathIsInf(arg2->floatval) == 1)
  6361. ret = 1;
  6362. else
  6363. ret = 0;
  6364. } else if (xmlXPathIsInf(arg1->floatval) == -1) {
  6365. if (xmlXPathIsInf(arg2->floatval) == -1)
  6366. ret = 1;
  6367. else
  6368. ret = 0;
  6369. } else if (xmlXPathIsInf(arg2->floatval) == 1) {
  6370. if (xmlXPathIsInf(arg1->floatval) == 1)
  6371. ret = 1;
  6372. else
  6373. ret = 0;
  6374. } else if (xmlXPathIsInf(arg2->floatval) == -1) {
  6375. if (xmlXPathIsInf(arg1->floatval) == -1)
  6376. ret = 1;
  6377. else
  6378. ret = 0;
  6379. } else {
  6380. ret = (arg1->floatval == arg2->floatval);
  6381. }
  6382. break;
  6383. case XPATH_USERS:
  6384. case XPATH_POINT:
  6385. case XPATH_RANGE:
  6386. case XPATH_LOCATIONSET:
  6387. TODO
  6388. break;
  6389. case XPATH_NODESET:
  6390. case XPATH_XSLT_TREE:
  6391. break;
  6392. }
  6393. break;
  6394. case XPATH_STRING:
  6395. switch (arg2->type) {
  6396. case XPATH_UNDEFINED:
  6397. #ifdef DEBUG_EXPR
  6398. xmlGenericError(xmlGenericErrorContext,
  6399. "Equal: undefined\n");
  6400. #endif
  6401. break;
  6402. case XPATH_BOOLEAN:
  6403. if ((arg1->stringval == NULL) ||
  6404. (arg1->stringval[0] == 0)) ret = 0;
  6405. else
  6406. ret = 1;
  6407. ret = (arg2->boolval == ret);
  6408. break;
  6409. case XPATH_STRING:
  6410. ret = xmlStrEqual(arg1->stringval, arg2->stringval);
  6411. break;
  6412. case XPATH_NUMBER:
  6413. valuePush(ctxt, arg1);
  6414. xmlXPathNumberFunction(ctxt, 1);
  6415. arg1 = valuePop(ctxt);
  6416. /* Hand check NaN and Infinity equalities */
  6417. if (xmlXPathIsNaN(arg1->floatval) ||
  6418. xmlXPathIsNaN(arg2->floatval)) {
  6419. ret = 0;
  6420. } else if (xmlXPathIsInf(arg1->floatval) == 1) {
  6421. if (xmlXPathIsInf(arg2->floatval) == 1)
  6422. ret = 1;
  6423. else
  6424. ret = 0;
  6425. } else if (xmlXPathIsInf(arg1->floatval) == -1) {
  6426. if (xmlXPathIsInf(arg2->floatval) == -1)
  6427. ret = 1;
  6428. else
  6429. ret = 0;
  6430. } else if (xmlXPathIsInf(arg2->floatval) == 1) {
  6431. if (xmlXPathIsInf(arg1->floatval) == 1)
  6432. ret = 1;
  6433. else
  6434. ret = 0;
  6435. } else if (xmlXPathIsInf(arg2->floatval) == -1) {
  6436. if (xmlXPathIsInf(arg1->floatval) == -1)
  6437. ret = 1;
  6438. else
  6439. ret = 0;
  6440. } else {
  6441. ret = (arg1->floatval == arg2->floatval);
  6442. }
  6443. break;
  6444. case XPATH_USERS:
  6445. case XPATH_POINT:
  6446. case XPATH_RANGE:
  6447. case XPATH_LOCATIONSET:
  6448. TODO
  6449. break;
  6450. case XPATH_NODESET:
  6451. case XPATH_XSLT_TREE:
  6452. break;
  6453. }
  6454. break;
  6455. case XPATH_USERS:
  6456. case XPATH_POINT:
  6457. case XPATH_RANGE:
  6458. case XPATH_LOCATIONSET:
  6459. TODO
  6460. break;
  6461. case XPATH_NODESET:
  6462. case XPATH_XSLT_TREE:
  6463. break;
  6464. }
  6465. xmlXPathReleaseObject(ctxt->context, arg1);
  6466. xmlXPathReleaseObject(ctxt->context, arg2);
  6467. return(ret);
  6468. }
  6469. /**
  6470. * xmlXPathEqualValues:
  6471. * @ctxt: the XPath Parser context
  6472. *
  6473. * Implement the equal operation on XPath objects content: @arg1 == @arg2
  6474. *
  6475. * Returns 0 or 1 depending on the results of the test.
  6476. */
  6477. int
  6478. xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
  6479. xmlXPathObjectPtr arg1, arg2, argtmp;
  6480. int ret = 0;
  6481. if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
  6482. arg2 = valuePop(ctxt);
  6483. arg1 = valuePop(ctxt);
  6484. if ((arg1 == NULL) || (arg2 == NULL)) {
  6485. if (arg1 != NULL)
  6486. xmlXPathReleaseObject(ctxt->context, arg1);
  6487. else
  6488. xmlXPathReleaseObject(ctxt->context, arg2);
  6489. XP_ERROR0(XPATH_INVALID_OPERAND);
  6490. }
  6491. if (arg1 == arg2) {
  6492. #ifdef DEBUG_EXPR
  6493. xmlGenericError(xmlGenericErrorContext,
  6494. "Equal: by pointer\n");
  6495. #endif
  6496. xmlXPathFreeObject(arg1);
  6497. return(1);
  6498. }
  6499. /*
  6500. *If either argument is a nodeset, it's a 'special case'
  6501. */
  6502. if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
  6503. (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
  6504. /*
  6505. *Hack it to assure arg1 is the nodeset
  6506. */
  6507. if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
  6508. argtmp = arg2;
  6509. arg2 = arg1;
  6510. arg1 = argtmp;
  6511. }
  6512. switch (arg2->type) {
  6513. case XPATH_UNDEFINED:
  6514. #ifdef DEBUG_EXPR
  6515. xmlGenericError(xmlGenericErrorContext,
  6516. "Equal: undefined\n");
  6517. #endif
  6518. break;
  6519. case XPATH_NODESET:
  6520. case XPATH_XSLT_TREE:
  6521. ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
  6522. break;
  6523. case XPATH_BOOLEAN:
  6524. if ((arg1->nodesetval == NULL) ||
  6525. (arg1->nodesetval->nodeNr == 0)) ret = 0;
  6526. else
  6527. ret = 1;
  6528. ret = (ret == arg2->boolval);
  6529. break;
  6530. case XPATH_NUMBER:
  6531. ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
  6532. break;
  6533. case XPATH_STRING:
  6534. ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
  6535. break;
  6536. case XPATH_USERS:
  6537. case XPATH_POINT:
  6538. case XPATH_RANGE:
  6539. case XPATH_LOCATIONSET:
  6540. TODO
  6541. break;
  6542. }
  6543. xmlXPathReleaseObject(ctxt->context, arg1);
  6544. xmlXPathReleaseObject(ctxt->context, arg2);
  6545. return(ret);
  6546. }
  6547. return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
  6548. }
  6549. /**
  6550. * xmlXPathNotEqualValues:
  6551. * @ctxt: the XPath Parser context
  6552. *
  6553. * Implement the equal operation on XPath objects content: @arg1 == @arg2
  6554. *
  6555. * Returns 0 or 1 depending on the results of the test.
  6556. */
  6557. int
  6558. xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
  6559. xmlXPathObjectPtr arg1, arg2, argtmp;
  6560. int ret = 0;
  6561. if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
  6562. arg2 = valuePop(ctxt);
  6563. arg1 = valuePop(ctxt);
  6564. if ((arg1 == NULL) || (arg2 == NULL)) {
  6565. if (arg1 != NULL)
  6566. xmlXPathReleaseObject(ctxt->context, arg1);
  6567. else
  6568. xmlXPathReleaseObject(ctxt->context, arg2);
  6569. XP_ERROR0(XPATH_INVALID_OPERAND);
  6570. }
  6571. if (arg1 == arg2) {
  6572. #ifdef DEBUG_EXPR
  6573. xmlGenericError(xmlGenericErrorContext,
  6574. "NotEqual: by pointer\n");
  6575. #endif
  6576. xmlXPathReleaseObject(ctxt->context, arg1);
  6577. return(0);
  6578. }
  6579. /*
  6580. *If either argument is a nodeset, it's a 'special case'
  6581. */
  6582. if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
  6583. (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
  6584. /*
  6585. *Hack it to assure arg1 is the nodeset
  6586. */
  6587. if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
  6588. argtmp = arg2;
  6589. arg2 = arg1;
  6590. arg1 = argtmp;
  6591. }
  6592. switch (arg2->type) {
  6593. case XPATH_UNDEFINED:
  6594. #ifdef DEBUG_EXPR
  6595. xmlGenericError(xmlGenericErrorContext,
  6596. "NotEqual: undefined\n");
  6597. #endif
  6598. break;
  6599. case XPATH_NODESET:
  6600. case XPATH_XSLT_TREE:
  6601. ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
  6602. break;
  6603. case XPATH_BOOLEAN:
  6604. if ((arg1->nodesetval == NULL) ||
  6605. (arg1->nodesetval->nodeNr == 0)) ret = 0;
  6606. else
  6607. ret = 1;
  6608. ret = (ret != arg2->boolval);
  6609. break;
  6610. case XPATH_NUMBER:
  6611. ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
  6612. break;
  6613. case XPATH_STRING:
  6614. ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
  6615. break;
  6616. case XPATH_USERS:
  6617. case XPATH_POINT:
  6618. case XPATH_RANGE:
  6619. case XPATH_LOCATIONSET:
  6620. TODO
  6621. break;
  6622. }
  6623. xmlXPathReleaseObject(ctxt->context, arg1);
  6624. xmlXPathReleaseObject(ctxt->context, arg2);
  6625. return(ret);
  6626. }
  6627. return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
  6628. }
  6629. /**
  6630. * xmlXPathCompareValues:
  6631. * @ctxt: the XPath Parser context
  6632. * @inf: less than (1) or greater than (0)
  6633. * @strict: is the comparison strict
  6634. *
  6635. * Implement the compare operation on XPath objects:
  6636. * @arg1 < @arg2 (1, 1, ...
  6637. * @arg1 <= @arg2 (1, 0, ...
  6638. * @arg1 > @arg2 (0, 1, ...
  6639. * @arg1 >= @arg2 (0, 0, ...
  6640. *
  6641. * When neither object to be compared is a node-set and the operator is
  6642. * <=, <, >=, >, then the objects are compared by converted both objects
  6643. * to numbers and comparing the numbers according to IEEE 754. The <
  6644. * comparison will be true if and only if the first number is less than the
  6645. * second number. The <= comparison will be true if and only if the first
  6646. * number is less than or equal to the second number. The > comparison
  6647. * will be true if and only if the first number is greater than the second
  6648. * number. The >= comparison will be true if and only if the first number
  6649. * is greater than or equal to the second number.
  6650. *
  6651. * Returns 1 if the comparison succeeded, 0 if it failed
  6652. */
  6653. int
  6654. xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
  6655. int ret = 0, arg1i = 0, arg2i = 0;
  6656. xmlXPathObjectPtr arg1, arg2;
  6657. if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
  6658. arg2 = valuePop(ctxt);
  6659. arg1 = valuePop(ctxt);
  6660. if ((arg1 == NULL) || (arg2 == NULL)) {
  6661. if (arg1 != NULL)
  6662. xmlXPathReleaseObject(ctxt->context, arg1);
  6663. else
  6664. xmlXPathReleaseObject(ctxt->context, arg2);
  6665. XP_ERROR0(XPATH_INVALID_OPERAND);
  6666. }
  6667. if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
  6668. (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
  6669. /*
  6670. * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
  6671. * are not freed from within this routine; they will be freed from the
  6672. * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
  6673. */
  6674. if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
  6675. ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
  6676. ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
  6677. } else {
  6678. if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
  6679. ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
  6680. arg1, arg2);
  6681. } else {
  6682. ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
  6683. arg2, arg1);
  6684. }
  6685. }
  6686. return(ret);
  6687. }
  6688. if (arg1->type != XPATH_NUMBER) {
  6689. valuePush(ctxt, arg1);
  6690. xmlXPathNumberFunction(ctxt, 1);
  6691. arg1 = valuePop(ctxt);
  6692. }
  6693. if (arg1->type != XPATH_NUMBER) {
  6694. xmlXPathFreeObject(arg1);
  6695. xmlXPathFreeObject(arg2);
  6696. XP_ERROR0(XPATH_INVALID_OPERAND);
  6697. }
  6698. if (arg2->type != XPATH_NUMBER) {
  6699. valuePush(ctxt, arg2);
  6700. xmlXPathNumberFunction(ctxt, 1);
  6701. arg2 = valuePop(ctxt);
  6702. }
  6703. if (arg2->type != XPATH_NUMBER) {
  6704. xmlXPathReleaseObject(ctxt->context, arg1);
  6705. xmlXPathReleaseObject(ctxt->context, arg2);
  6706. XP_ERROR0(XPATH_INVALID_OPERAND);
  6707. }
  6708. /*
  6709. * Add tests for infinity and nan
  6710. * => feedback on 3.4 for Inf and NaN
  6711. */
  6712. /* Hand check NaN and Infinity comparisons */
  6713. if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
  6714. ret=0;
  6715. } else {
  6716. arg1i=xmlXPathIsInf(arg1->floatval);
  6717. arg2i=xmlXPathIsInf(arg2->floatval);
  6718. if (inf && strict) {
  6719. if ((arg1i == -1 && arg2i != -1) ||
  6720. (arg2i == 1 && arg1i != 1)) {
  6721. ret = 1;
  6722. } else if (arg1i == 0 && arg2i == 0) {
  6723. ret = (arg1->floatval < arg2->floatval);
  6724. } else {
  6725. ret = 0;
  6726. }
  6727. }
  6728. else if (inf && !strict) {
  6729. if (arg1i == -1 || arg2i == 1) {
  6730. ret = 1;
  6731. } else if (arg1i == 0 && arg2i == 0) {
  6732. ret = (arg1->floatval <= arg2->floatval);
  6733. } else {
  6734. ret = 0;
  6735. }
  6736. }
  6737. else if (!inf && strict) {
  6738. if ((arg1i == 1 && arg2i != 1) ||
  6739. (arg2i == -1 && arg1i != -1)) {
  6740. ret = 1;
  6741. } else if (arg1i == 0 && arg2i == 0) {
  6742. ret = (arg1->floatval > arg2->floatval);
  6743. } else {
  6744. ret = 0;
  6745. }
  6746. }
  6747. else if (!inf && !strict) {
  6748. if (arg1i == 1 || arg2i == -1) {
  6749. ret = 1;
  6750. } else if (arg1i == 0 && arg2i == 0) {
  6751. ret = (arg1->floatval >= arg2->floatval);
  6752. } else {
  6753. ret = 0;
  6754. }
  6755. }
  6756. }
  6757. xmlXPathReleaseObject(ctxt->context, arg1);
  6758. xmlXPathReleaseObject(ctxt->context, arg2);
  6759. return(ret);
  6760. }
  6761. /**
  6762. * xmlXPathValueFlipSign:
  6763. * @ctxt: the XPath Parser context
  6764. *
  6765. * Implement the unary - operation on an XPath object
  6766. * The numeric operators convert their operands to numbers as if
  6767. * by calling the number function.
  6768. */
  6769. void
  6770. xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
  6771. if ((ctxt == NULL) || (ctxt->context == NULL)) return;
  6772. CAST_TO_NUMBER;
  6773. CHECK_TYPE(XPATH_NUMBER);
  6774. if (xmlXPathIsNaN(ctxt->value->floatval))
  6775. ctxt->value->floatval=xmlXPathNAN;
  6776. else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
  6777. ctxt->value->floatval=xmlXPathNINF;
  6778. else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
  6779. ctxt->value->floatval=xmlXPathPINF;
  6780. else if (ctxt->value->floatval == 0) {
  6781. if (xmlXPathGetSign(ctxt->value->floatval) == 0)
  6782. ctxt->value->floatval = xmlXPathNZERO;
  6783. else
  6784. ctxt->value->floatval = 0;
  6785. }
  6786. else
  6787. ctxt->value->floatval = - ctxt->value->floatval;
  6788. }
  6789. /**
  6790. * xmlXPathAddValues:
  6791. * @ctxt: the XPath Parser context
  6792. *
  6793. * Implement the add operation on XPath objects:
  6794. * The numeric operators convert their operands to numbers as if
  6795. * by calling the number function.
  6796. */
  6797. void
  6798. xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
  6799. xmlXPathObjectPtr arg;
  6800. double val;
  6801. arg = valuePop(ctxt);
  6802. if (arg == NULL)
  6803. XP_ERROR(XPATH_INVALID_OPERAND);
  6804. val = xmlXPathCastToNumber(arg);
  6805. xmlXPathReleaseObject(ctxt->context, arg);
  6806. CAST_TO_NUMBER;
  6807. CHECK_TYPE(XPATH_NUMBER);
  6808. ctxt->value->floatval += val;
  6809. }
  6810. /**
  6811. * xmlXPathSubValues:
  6812. * @ctxt: the XPath Parser context
  6813. *
  6814. * Implement the subtraction operation on XPath objects:
  6815. * The numeric operators convert their operands to numbers as if
  6816. * by calling the number function.
  6817. */
  6818. void
  6819. xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
  6820. xmlXPathObjectPtr arg;
  6821. double val;
  6822. arg = valuePop(ctxt);
  6823. if (arg == NULL)
  6824. XP_ERROR(XPATH_INVALID_OPERAND);
  6825. val = xmlXPathCastToNumber(arg);
  6826. xmlXPathReleaseObject(ctxt->context, arg);
  6827. CAST_TO_NUMBER;
  6828. CHECK_TYPE(XPATH_NUMBER);
  6829. ctxt->value->floatval -= val;
  6830. }
  6831. /**
  6832. * xmlXPathMultValues:
  6833. * @ctxt: the XPath Parser context
  6834. *
  6835. * Implement the multiply operation on XPath objects:
  6836. * The numeric operators convert their operands to numbers as if
  6837. * by calling the number function.
  6838. */
  6839. void
  6840. xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
  6841. xmlXPathObjectPtr arg;
  6842. double val;
  6843. arg = valuePop(ctxt);
  6844. if (arg == NULL)
  6845. XP_ERROR(XPATH_INVALID_OPERAND);
  6846. val = xmlXPathCastToNumber(arg);
  6847. xmlXPathReleaseObject(ctxt->context, arg);
  6848. CAST_TO_NUMBER;
  6849. CHECK_TYPE(XPATH_NUMBER);
  6850. ctxt->value->floatval *= val;
  6851. }
  6852. /**
  6853. * xmlXPathDivValues:
  6854. * @ctxt: the XPath Parser context
  6855. *
  6856. * Implement the div operation on XPath objects @arg1 / @arg2:
  6857. * The numeric operators convert their operands to numbers as if
  6858. * by calling the number function.
  6859. */
  6860. void
  6861. xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
  6862. xmlXPathObjectPtr arg;
  6863. double val;
  6864. arg = valuePop(ctxt);
  6865. if (arg == NULL)
  6866. XP_ERROR(XPATH_INVALID_OPERAND);
  6867. val = xmlXPathCastToNumber(arg);
  6868. xmlXPathReleaseObject(ctxt->context, arg);
  6869. CAST_TO_NUMBER;
  6870. CHECK_TYPE(XPATH_NUMBER);
  6871. if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
  6872. ctxt->value->floatval = xmlXPathNAN;
  6873. else if (val == 0 && xmlXPathGetSign(val) != 0) {
  6874. if (ctxt->value->floatval == 0)
  6875. ctxt->value->floatval = xmlXPathNAN;
  6876. else if (ctxt->value->floatval > 0)
  6877. ctxt->value->floatval = xmlXPathNINF;
  6878. else if (ctxt->value->floatval < 0)
  6879. ctxt->value->floatval = xmlXPathPINF;
  6880. }
  6881. else if (val == 0) {
  6882. if (ctxt->value->floatval == 0)
  6883. ctxt->value->floatval = xmlXPathNAN;
  6884. else if (ctxt->value->floatval > 0)
  6885. ctxt->value->floatval = xmlXPathPINF;
  6886. else if (ctxt->value->floatval < 0)
  6887. ctxt->value->floatval = xmlXPathNINF;
  6888. } else
  6889. ctxt->value->floatval /= val;
  6890. }
  6891. /**
  6892. * xmlXPathModValues:
  6893. * @ctxt: the XPath Parser context
  6894. *
  6895. * Implement the mod operation on XPath objects: @arg1 / @arg2
  6896. * The numeric operators convert their operands to numbers as if
  6897. * by calling the number function.
  6898. */
  6899. void
  6900. xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
  6901. xmlXPathObjectPtr arg;
  6902. double arg1, arg2;
  6903. arg = valuePop(ctxt);
  6904. if (arg == NULL)
  6905. XP_ERROR(XPATH_INVALID_OPERAND);
  6906. arg2 = xmlXPathCastToNumber(arg);
  6907. xmlXPathReleaseObject(ctxt->context, arg);
  6908. CAST_TO_NUMBER;
  6909. CHECK_TYPE(XPATH_NUMBER);
  6910. arg1 = ctxt->value->floatval;
  6911. if (arg2 == 0)
  6912. ctxt->value->floatval = xmlXPathNAN;
  6913. else {
  6914. ctxt->value->floatval = fmod(arg1, arg2);
  6915. }
  6916. }
  6917. /************************************************************************
  6918. * *
  6919. * The traversal functions *
  6920. * *
  6921. ************************************************************************/
  6922. /*
  6923. * A traversal function enumerates nodes along an axis.
  6924. * Initially it must be called with NULL, and it indicates
  6925. * termination on the axis by returning NULL.
  6926. */
  6927. typedef xmlNodePtr (*xmlXPathTraversalFunction)
  6928. (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
  6929. /*
  6930. * xmlXPathTraversalFunctionExt:
  6931. * A traversal function enumerates nodes along an axis.
  6932. * Initially it must be called with NULL, and it indicates
  6933. * termination on the axis by returning NULL.
  6934. * The context node of the traversal is specified via @contextNode.
  6935. */
  6936. typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
  6937. (xmlNodePtr cur, xmlNodePtr contextNode);
  6938. /*
  6939. * xmlXPathNodeSetMergeFunction:
  6940. * Used for merging node sets in xmlXPathCollectAndTest().
  6941. */
  6942. typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
  6943. (xmlNodeSetPtr, xmlNodeSetPtr, int);
  6944. /**
  6945. * xmlXPathNextSelf:
  6946. * @ctxt: the XPath Parser context
  6947. * @cur: the current node in the traversal
  6948. *
  6949. * Traversal function for the "self" direction
  6950. * The self axis contains just the context node itself
  6951. *
  6952. * Returns the next element following that axis
  6953. */
  6954. xmlNodePtr
  6955. xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  6956. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  6957. if (cur == NULL)
  6958. return(ctxt->context->node);
  6959. return(NULL);
  6960. }
  6961. /**
  6962. * xmlXPathNextChild:
  6963. * @ctxt: the XPath Parser context
  6964. * @cur: the current node in the traversal
  6965. *
  6966. * Traversal function for the "child" direction
  6967. * The child axis contains the children of the context node in document order.
  6968. *
  6969. * Returns the next element following that axis
  6970. */
  6971. xmlNodePtr
  6972. xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  6973. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  6974. if (cur == NULL) {
  6975. if (ctxt->context->node == NULL) return(NULL);
  6976. switch (ctxt->context->node->type) {
  6977. case XML_ELEMENT_NODE:
  6978. case XML_TEXT_NODE:
  6979. case XML_CDATA_SECTION_NODE:
  6980. case XML_ENTITY_REF_NODE:
  6981. case XML_ENTITY_NODE:
  6982. case XML_PI_NODE:
  6983. case XML_COMMENT_NODE:
  6984. case XML_NOTATION_NODE:
  6985. case XML_DTD_NODE:
  6986. return(ctxt->context->node->children);
  6987. case XML_DOCUMENT_NODE:
  6988. case XML_DOCUMENT_TYPE_NODE:
  6989. case XML_DOCUMENT_FRAG_NODE:
  6990. case XML_HTML_DOCUMENT_NODE:
  6991. #ifdef LIBXML_DOCB_ENABLED
  6992. case XML_DOCB_DOCUMENT_NODE:
  6993. #endif
  6994. return(((xmlDocPtr) ctxt->context->node)->children);
  6995. case XML_ELEMENT_DECL:
  6996. case XML_ATTRIBUTE_DECL:
  6997. case XML_ENTITY_DECL:
  6998. case XML_ATTRIBUTE_NODE:
  6999. case XML_NAMESPACE_DECL:
  7000. case XML_XINCLUDE_START:
  7001. case XML_XINCLUDE_END:
  7002. return(NULL);
  7003. }
  7004. return(NULL);
  7005. }
  7006. if ((cur->type == XML_DOCUMENT_NODE) ||
  7007. (cur->type == XML_HTML_DOCUMENT_NODE))
  7008. return(NULL);
  7009. return(cur->next);
  7010. }
  7011. /**
  7012. * xmlXPathNextChildElement:
  7013. * @ctxt: the XPath Parser context
  7014. * @cur: the current node in the traversal
  7015. *
  7016. * Traversal function for the "child" direction and nodes of type element.
  7017. * The child axis contains the children of the context node in document order.
  7018. *
  7019. * Returns the next element following that axis
  7020. */
  7021. static xmlNodePtr
  7022. xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7023. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7024. if (cur == NULL) {
  7025. cur = ctxt->context->node;
  7026. if (cur == NULL) return(NULL);
  7027. /*
  7028. * Get the first element child.
  7029. */
  7030. switch (cur->type) {
  7031. case XML_ELEMENT_NODE:
  7032. case XML_DOCUMENT_FRAG_NODE:
  7033. case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
  7034. case XML_ENTITY_NODE:
  7035. cur = cur->children;
  7036. if (cur != NULL) {
  7037. if (cur->type == XML_ELEMENT_NODE)
  7038. return(cur);
  7039. do {
  7040. cur = cur->next;
  7041. } while ((cur != NULL) &&
  7042. (cur->type != XML_ELEMENT_NODE));
  7043. return(cur);
  7044. }
  7045. return(NULL);
  7046. case XML_DOCUMENT_NODE:
  7047. case XML_HTML_DOCUMENT_NODE:
  7048. #ifdef LIBXML_DOCB_ENABLED
  7049. case XML_DOCB_DOCUMENT_NODE:
  7050. #endif
  7051. return(xmlDocGetRootElement((xmlDocPtr) cur));
  7052. default:
  7053. return(NULL);
  7054. }
  7055. return(NULL);
  7056. }
  7057. /*
  7058. * Get the next sibling element node.
  7059. */
  7060. switch (cur->type) {
  7061. case XML_ELEMENT_NODE:
  7062. case XML_TEXT_NODE:
  7063. case XML_ENTITY_REF_NODE:
  7064. case XML_ENTITY_NODE:
  7065. case XML_CDATA_SECTION_NODE:
  7066. case XML_PI_NODE:
  7067. case XML_COMMENT_NODE:
  7068. case XML_XINCLUDE_END:
  7069. break;
  7070. /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
  7071. default:
  7072. return(NULL);
  7073. }
  7074. if (cur->next != NULL) {
  7075. if (cur->next->type == XML_ELEMENT_NODE)
  7076. return(cur->next);
  7077. cur = cur->next;
  7078. do {
  7079. cur = cur->next;
  7080. } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
  7081. return(cur);
  7082. }
  7083. return(NULL);
  7084. }
  7085. /**
  7086. * xmlXPathNextDescendantOrSelfElemParent:
  7087. * @ctxt: the XPath Parser context
  7088. * @cur: the current node in the traversal
  7089. *
  7090. * Traversal function for the "descendant-or-self" axis.
  7091. * Additionally it returns only nodes which can be parents of
  7092. * element nodes.
  7093. *
  7094. *
  7095. * Returns the next element following that axis
  7096. */
  7097. static xmlNodePtr
  7098. xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
  7099. xmlNodePtr contextNode)
  7100. {
  7101. if (cur == NULL) {
  7102. if (contextNode == NULL)
  7103. return(NULL);
  7104. switch (contextNode->type) {
  7105. case XML_ELEMENT_NODE:
  7106. case XML_XINCLUDE_START:
  7107. case XML_DOCUMENT_FRAG_NODE:
  7108. case XML_DOCUMENT_NODE:
  7109. #ifdef LIBXML_DOCB_ENABLED
  7110. case XML_DOCB_DOCUMENT_NODE:
  7111. #endif
  7112. case XML_HTML_DOCUMENT_NODE:
  7113. return(contextNode);
  7114. default:
  7115. return(NULL);
  7116. }
  7117. return(NULL);
  7118. } else {
  7119. xmlNodePtr start = cur;
  7120. while (cur != NULL) {
  7121. switch (cur->type) {
  7122. case XML_ELEMENT_NODE:
  7123. /* TODO: OK to have XInclude here? */
  7124. case XML_XINCLUDE_START:
  7125. case XML_DOCUMENT_FRAG_NODE:
  7126. if (cur != start)
  7127. return(cur);
  7128. if (cur->children != NULL) {
  7129. cur = cur->children;
  7130. continue;
  7131. }
  7132. break;
  7133. /* Not sure if we need those here. */
  7134. case XML_DOCUMENT_NODE:
  7135. #ifdef LIBXML_DOCB_ENABLED
  7136. case XML_DOCB_DOCUMENT_NODE:
  7137. #endif
  7138. case XML_HTML_DOCUMENT_NODE:
  7139. if (cur != start)
  7140. return(cur);
  7141. return(xmlDocGetRootElement((xmlDocPtr) cur));
  7142. default:
  7143. break;
  7144. }
  7145. next_sibling:
  7146. if ((cur == NULL) || (cur == contextNode))
  7147. return(NULL);
  7148. if (cur->next != NULL) {
  7149. cur = cur->next;
  7150. } else {
  7151. cur = cur->parent;
  7152. goto next_sibling;
  7153. }
  7154. }
  7155. }
  7156. return(NULL);
  7157. }
  7158. /**
  7159. * xmlXPathNextDescendant:
  7160. * @ctxt: the XPath Parser context
  7161. * @cur: the current node in the traversal
  7162. *
  7163. * Traversal function for the "descendant" direction
  7164. * the descendant axis contains the descendants of the context node in document
  7165. * order; a descendant is a child or a child of a child and so on.
  7166. *
  7167. * Returns the next element following that axis
  7168. */
  7169. xmlNodePtr
  7170. xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7171. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7172. if (cur == NULL) {
  7173. if (ctxt->context->node == NULL)
  7174. return(NULL);
  7175. if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
  7176. (ctxt->context->node->type == XML_NAMESPACE_DECL))
  7177. return(NULL);
  7178. if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
  7179. return(ctxt->context->doc->children);
  7180. return(ctxt->context->node->children);
  7181. }
  7182. if (cur->children != NULL) {
  7183. /*
  7184. * Do not descend on entities declarations
  7185. */
  7186. if (cur->children->type != XML_ENTITY_DECL) {
  7187. cur = cur->children;
  7188. /*
  7189. * Skip DTDs
  7190. */
  7191. if (cur->type != XML_DTD_NODE)
  7192. return(cur);
  7193. }
  7194. }
  7195. if (cur == ctxt->context->node) return(NULL);
  7196. while (cur->next != NULL) {
  7197. cur = cur->next;
  7198. if ((cur->type != XML_ENTITY_DECL) &&
  7199. (cur->type != XML_DTD_NODE))
  7200. return(cur);
  7201. }
  7202. do {
  7203. cur = cur->parent;
  7204. if (cur == NULL) break;
  7205. if (cur == ctxt->context->node) return(NULL);
  7206. if (cur->next != NULL) {
  7207. cur = cur->next;
  7208. return(cur);
  7209. }
  7210. } while (cur != NULL);
  7211. return(cur);
  7212. }
  7213. /**
  7214. * xmlXPathNextDescendantOrSelf:
  7215. * @ctxt: the XPath Parser context
  7216. * @cur: the current node in the traversal
  7217. *
  7218. * Traversal function for the "descendant-or-self" direction
  7219. * the descendant-or-self axis contains the context node and the descendants
  7220. * of the context node in document order; thus the context node is the first
  7221. * node on the axis, and the first child of the context node is the second node
  7222. * on the axis
  7223. *
  7224. * Returns the next element following that axis
  7225. */
  7226. xmlNodePtr
  7227. xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7228. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7229. if (cur == NULL) {
  7230. if (ctxt->context->node == NULL)
  7231. return(NULL);
  7232. if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
  7233. (ctxt->context->node->type == XML_NAMESPACE_DECL))
  7234. return(NULL);
  7235. return(ctxt->context->node);
  7236. }
  7237. return(xmlXPathNextDescendant(ctxt, cur));
  7238. }
  7239. /**
  7240. * xmlXPathNextParent:
  7241. * @ctxt: the XPath Parser context
  7242. * @cur: the current node in the traversal
  7243. *
  7244. * Traversal function for the "parent" direction
  7245. * The parent axis contains the parent of the context node, if there is one.
  7246. *
  7247. * Returns the next element following that axis
  7248. */
  7249. xmlNodePtr
  7250. xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7251. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7252. /*
  7253. * the parent of an attribute or namespace node is the element
  7254. * to which the attribute or namespace node is attached
  7255. * Namespace handling !!!
  7256. */
  7257. if (cur == NULL) {
  7258. if (ctxt->context->node == NULL) return(NULL);
  7259. switch (ctxt->context->node->type) {
  7260. case XML_ELEMENT_NODE:
  7261. case XML_TEXT_NODE:
  7262. case XML_CDATA_SECTION_NODE:
  7263. case XML_ENTITY_REF_NODE:
  7264. case XML_ENTITY_NODE:
  7265. case XML_PI_NODE:
  7266. case XML_COMMENT_NODE:
  7267. case XML_NOTATION_NODE:
  7268. case XML_DTD_NODE:
  7269. case XML_ELEMENT_DECL:
  7270. case XML_ATTRIBUTE_DECL:
  7271. case XML_XINCLUDE_START:
  7272. case XML_XINCLUDE_END:
  7273. case XML_ENTITY_DECL:
  7274. if (ctxt->context->node->parent == NULL)
  7275. return((xmlNodePtr) ctxt->context->doc);
  7276. if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
  7277. ((ctxt->context->node->parent->name[0] == ' ') ||
  7278. (xmlStrEqual(ctxt->context->node->parent->name,
  7279. BAD_CAST "fake node libxslt"))))
  7280. return(NULL);
  7281. return(ctxt->context->node->parent);
  7282. case XML_ATTRIBUTE_NODE: {
  7283. xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
  7284. return(att->parent);
  7285. }
  7286. case XML_DOCUMENT_NODE:
  7287. case XML_DOCUMENT_TYPE_NODE:
  7288. case XML_DOCUMENT_FRAG_NODE:
  7289. case XML_HTML_DOCUMENT_NODE:
  7290. #ifdef LIBXML_DOCB_ENABLED
  7291. case XML_DOCB_DOCUMENT_NODE:
  7292. #endif
  7293. return(NULL);
  7294. case XML_NAMESPACE_DECL: {
  7295. xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
  7296. if ((ns->next != NULL) &&
  7297. (ns->next->type != XML_NAMESPACE_DECL))
  7298. return((xmlNodePtr) ns->next);
  7299. return(NULL);
  7300. }
  7301. }
  7302. }
  7303. return(NULL);
  7304. }
  7305. /**
  7306. * xmlXPathNextAncestor:
  7307. * @ctxt: the XPath Parser context
  7308. * @cur: the current node in the traversal
  7309. *
  7310. * Traversal function for the "ancestor" direction
  7311. * the ancestor axis contains the ancestors of the context node; the ancestors
  7312. * of the context node consist of the parent of context node and the parent's
  7313. * parent and so on; the nodes are ordered in reverse document order; thus the
  7314. * parent is the first node on the axis, and the parent's parent is the second
  7315. * node on the axis
  7316. *
  7317. * Returns the next element following that axis
  7318. */
  7319. xmlNodePtr
  7320. xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7321. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7322. /*
  7323. * the parent of an attribute or namespace node is the element
  7324. * to which the attribute or namespace node is attached
  7325. * !!!!!!!!!!!!!
  7326. */
  7327. if (cur == NULL) {
  7328. if (ctxt->context->node == NULL) return(NULL);
  7329. switch (ctxt->context->node->type) {
  7330. case XML_ELEMENT_NODE:
  7331. case XML_TEXT_NODE:
  7332. case XML_CDATA_SECTION_NODE:
  7333. case XML_ENTITY_REF_NODE:
  7334. case XML_ENTITY_NODE:
  7335. case XML_PI_NODE:
  7336. case XML_COMMENT_NODE:
  7337. case XML_DTD_NODE:
  7338. case XML_ELEMENT_DECL:
  7339. case XML_ATTRIBUTE_DECL:
  7340. case XML_ENTITY_DECL:
  7341. case XML_NOTATION_NODE:
  7342. case XML_XINCLUDE_START:
  7343. case XML_XINCLUDE_END:
  7344. if (ctxt->context->node->parent == NULL)
  7345. return((xmlNodePtr) ctxt->context->doc);
  7346. if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
  7347. ((ctxt->context->node->parent->name[0] == ' ') ||
  7348. (xmlStrEqual(ctxt->context->node->parent->name,
  7349. BAD_CAST "fake node libxslt"))))
  7350. return(NULL);
  7351. return(ctxt->context->node->parent);
  7352. case XML_ATTRIBUTE_NODE: {
  7353. xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
  7354. return(tmp->parent);
  7355. }
  7356. case XML_DOCUMENT_NODE:
  7357. case XML_DOCUMENT_TYPE_NODE:
  7358. case XML_DOCUMENT_FRAG_NODE:
  7359. case XML_HTML_DOCUMENT_NODE:
  7360. #ifdef LIBXML_DOCB_ENABLED
  7361. case XML_DOCB_DOCUMENT_NODE:
  7362. #endif
  7363. return(NULL);
  7364. case XML_NAMESPACE_DECL: {
  7365. xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
  7366. if ((ns->next != NULL) &&
  7367. (ns->next->type != XML_NAMESPACE_DECL))
  7368. return((xmlNodePtr) ns->next);
  7369. /* Bad, how did that namespace end up here ? */
  7370. return(NULL);
  7371. }
  7372. }
  7373. return(NULL);
  7374. }
  7375. if (cur == ctxt->context->doc->children)
  7376. return((xmlNodePtr) ctxt->context->doc);
  7377. if (cur == (xmlNodePtr) ctxt->context->doc)
  7378. return(NULL);
  7379. switch (cur->type) {
  7380. case XML_ELEMENT_NODE:
  7381. case XML_TEXT_NODE:
  7382. case XML_CDATA_SECTION_NODE:
  7383. case XML_ENTITY_REF_NODE:
  7384. case XML_ENTITY_NODE:
  7385. case XML_PI_NODE:
  7386. case XML_COMMENT_NODE:
  7387. case XML_NOTATION_NODE:
  7388. case XML_DTD_NODE:
  7389. case XML_ELEMENT_DECL:
  7390. case XML_ATTRIBUTE_DECL:
  7391. case XML_ENTITY_DECL:
  7392. case XML_XINCLUDE_START:
  7393. case XML_XINCLUDE_END:
  7394. if (cur->parent == NULL)
  7395. return(NULL);
  7396. if ((cur->parent->type == XML_ELEMENT_NODE) &&
  7397. ((cur->parent->name[0] == ' ') ||
  7398. (xmlStrEqual(cur->parent->name,
  7399. BAD_CAST "fake node libxslt"))))
  7400. return(NULL);
  7401. return(cur->parent);
  7402. case XML_ATTRIBUTE_NODE: {
  7403. xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
  7404. return(att->parent);
  7405. }
  7406. case XML_NAMESPACE_DECL: {
  7407. xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
  7408. if ((ns->next != NULL) &&
  7409. (ns->next->type != XML_NAMESPACE_DECL))
  7410. return((xmlNodePtr) ns->next);
  7411. /* Bad, how did that namespace end up here ? */
  7412. return(NULL);
  7413. }
  7414. case XML_DOCUMENT_NODE:
  7415. case XML_DOCUMENT_TYPE_NODE:
  7416. case XML_DOCUMENT_FRAG_NODE:
  7417. case XML_HTML_DOCUMENT_NODE:
  7418. #ifdef LIBXML_DOCB_ENABLED
  7419. case XML_DOCB_DOCUMENT_NODE:
  7420. #endif
  7421. return(NULL);
  7422. }
  7423. return(NULL);
  7424. }
  7425. /**
  7426. * xmlXPathNextAncestorOrSelf:
  7427. * @ctxt: the XPath Parser context
  7428. * @cur: the current node in the traversal
  7429. *
  7430. * Traversal function for the "ancestor-or-self" direction
  7431. * he ancestor-or-self axis contains the context node and ancestors of
  7432. * the context node in reverse document order; thus the context node is
  7433. * the first node on the axis, and the context node's parent the second;
  7434. * parent here is defined the same as with the parent axis.
  7435. *
  7436. * Returns the next element following that axis
  7437. */
  7438. xmlNodePtr
  7439. xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7440. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7441. if (cur == NULL)
  7442. return(ctxt->context->node);
  7443. return(xmlXPathNextAncestor(ctxt, cur));
  7444. }
  7445. /**
  7446. * xmlXPathNextFollowingSibling:
  7447. * @ctxt: the XPath Parser context
  7448. * @cur: the current node in the traversal
  7449. *
  7450. * Traversal function for the "following-sibling" direction
  7451. * The following-sibling axis contains the following siblings of the context
  7452. * node in document order.
  7453. *
  7454. * Returns the next element following that axis
  7455. */
  7456. xmlNodePtr
  7457. xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7458. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7459. if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
  7460. (ctxt->context->node->type == XML_NAMESPACE_DECL))
  7461. return(NULL);
  7462. if (cur == (xmlNodePtr) ctxt->context->doc)
  7463. return(NULL);
  7464. if (cur == NULL)
  7465. return(ctxt->context->node->next);
  7466. return(cur->next);
  7467. }
  7468. /**
  7469. * xmlXPathNextPrecedingSibling:
  7470. * @ctxt: the XPath Parser context
  7471. * @cur: the current node in the traversal
  7472. *
  7473. * Traversal function for the "preceding-sibling" direction
  7474. * The preceding-sibling axis contains the preceding siblings of the context
  7475. * node in reverse document order; the first preceding sibling is first on the
  7476. * axis; the sibling preceding that node is the second on the axis and so on.
  7477. *
  7478. * Returns the next element following that axis
  7479. */
  7480. xmlNodePtr
  7481. xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7482. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7483. if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
  7484. (ctxt->context->node->type == XML_NAMESPACE_DECL))
  7485. return(NULL);
  7486. if (cur == (xmlNodePtr) ctxt->context->doc)
  7487. return(NULL);
  7488. if (cur == NULL)
  7489. return(ctxt->context->node->prev);
  7490. if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
  7491. cur = cur->prev;
  7492. if (cur == NULL)
  7493. return(ctxt->context->node->prev);
  7494. }
  7495. return(cur->prev);
  7496. }
  7497. /**
  7498. * xmlXPathNextFollowing:
  7499. * @ctxt: the XPath Parser context
  7500. * @cur: the current node in the traversal
  7501. *
  7502. * Traversal function for the "following" direction
  7503. * The following axis contains all nodes in the same document as the context
  7504. * node that are after the context node in document order, excluding any
  7505. * descendants and excluding attribute nodes and namespace nodes; the nodes
  7506. * are ordered in document order
  7507. *
  7508. * Returns the next element following that axis
  7509. */
  7510. xmlNodePtr
  7511. xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7512. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7513. if (cur != NULL && cur->children != NULL)
  7514. return cur->children ;
  7515. if (cur == NULL) cur = ctxt->context->node;
  7516. if (cur == NULL) return(NULL) ; /* ERROR */
  7517. if (cur->next != NULL) return(cur->next) ;
  7518. do {
  7519. cur = cur->parent;
  7520. if (cur == NULL) break;
  7521. if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
  7522. if (cur->next != NULL) return(cur->next);
  7523. } while (cur != NULL);
  7524. return(cur);
  7525. }
  7526. /*
  7527. * xmlXPathIsAncestor:
  7528. * @ancestor: the ancestor node
  7529. * @node: the current node
  7530. *
  7531. * Check that @ancestor is a @node's ancestor
  7532. *
  7533. * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
  7534. */
  7535. static int
  7536. xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
  7537. if ((ancestor == NULL) || (node == NULL)) return(0);
  7538. /* nodes need to be in the same document */
  7539. if (ancestor->doc != node->doc) return(0);
  7540. /* avoid searching if ancestor or node is the root node */
  7541. if (ancestor == (xmlNodePtr) node->doc) return(1);
  7542. if (node == (xmlNodePtr) ancestor->doc) return(0);
  7543. while (node->parent != NULL) {
  7544. if (node->parent == ancestor)
  7545. return(1);
  7546. node = node->parent;
  7547. }
  7548. return(0);
  7549. }
  7550. /**
  7551. * xmlXPathNextPreceding:
  7552. * @ctxt: the XPath Parser context
  7553. * @cur: the current node in the traversal
  7554. *
  7555. * Traversal function for the "preceding" direction
  7556. * the preceding axis contains all nodes in the same document as the context
  7557. * node that are before the context node in document order, excluding any
  7558. * ancestors and excluding attribute nodes and namespace nodes; the nodes are
  7559. * ordered in reverse document order
  7560. *
  7561. * Returns the next element following that axis
  7562. */
  7563. xmlNodePtr
  7564. xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
  7565. {
  7566. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7567. if (cur == NULL)
  7568. cur = ctxt->context->node;
  7569. if (cur == NULL)
  7570. return (NULL);
  7571. if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
  7572. cur = cur->prev;
  7573. do {
  7574. if (cur->prev != NULL) {
  7575. for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
  7576. return (cur);
  7577. }
  7578. cur = cur->parent;
  7579. if (cur == NULL)
  7580. return (NULL);
  7581. if (cur == ctxt->context->doc->children)
  7582. return (NULL);
  7583. } while (xmlXPathIsAncestor(cur, ctxt->context->node));
  7584. return (cur);
  7585. }
  7586. /**
  7587. * xmlXPathNextPrecedingInternal:
  7588. * @ctxt: the XPath Parser context
  7589. * @cur: the current node in the traversal
  7590. *
  7591. * Traversal function for the "preceding" direction
  7592. * the preceding axis contains all nodes in the same document as the context
  7593. * node that are before the context node in document order, excluding any
  7594. * ancestors and excluding attribute nodes and namespace nodes; the nodes are
  7595. * ordered in reverse document order
  7596. * This is a faster implementation but internal only since it requires a
  7597. * state kept in the parser context: ctxt->ancestor.
  7598. *
  7599. * Returns the next element following that axis
  7600. */
  7601. static xmlNodePtr
  7602. xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
  7603. xmlNodePtr cur)
  7604. {
  7605. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7606. if (cur == NULL) {
  7607. cur = ctxt->context->node;
  7608. if (cur == NULL)
  7609. return (NULL);
  7610. if (cur->type == XML_NAMESPACE_DECL)
  7611. cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
  7612. ctxt->ancestor = cur->parent;
  7613. }
  7614. if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
  7615. cur = cur->prev;
  7616. while (cur->prev == NULL) {
  7617. cur = cur->parent;
  7618. if (cur == NULL)
  7619. return (NULL);
  7620. if (cur == ctxt->context->doc->children)
  7621. return (NULL);
  7622. if (cur != ctxt->ancestor)
  7623. return (cur);
  7624. ctxt->ancestor = cur->parent;
  7625. }
  7626. cur = cur->prev;
  7627. while (cur->last != NULL)
  7628. cur = cur->last;
  7629. return (cur);
  7630. }
  7631. /**
  7632. * xmlXPathNextNamespace:
  7633. * @ctxt: the XPath Parser context
  7634. * @cur: the current attribute in the traversal
  7635. *
  7636. * Traversal function for the "namespace" direction
  7637. * the namespace axis contains the namespace nodes of the context node;
  7638. * the order of nodes on this axis is implementation-defined; the axis will
  7639. * be empty unless the context node is an element
  7640. *
  7641. * We keep the XML namespace node at the end of the list.
  7642. *
  7643. * Returns the next element following that axis
  7644. */
  7645. xmlNodePtr
  7646. xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7647. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7648. if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
  7649. if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
  7650. if (ctxt->context->tmpNsList != NULL)
  7651. xmlFree(ctxt->context->tmpNsList);
  7652. ctxt->context->tmpNsList =
  7653. xmlGetNsList(ctxt->context->doc, ctxt->context->node);
  7654. ctxt->context->tmpNsNr = 0;
  7655. if (ctxt->context->tmpNsList != NULL) {
  7656. while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
  7657. ctxt->context->tmpNsNr++;
  7658. }
  7659. }
  7660. return((xmlNodePtr) xmlXPathXMLNamespace);
  7661. }
  7662. if (ctxt->context->tmpNsNr > 0) {
  7663. return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
  7664. } else {
  7665. if (ctxt->context->tmpNsList != NULL)
  7666. xmlFree(ctxt->context->tmpNsList);
  7667. ctxt->context->tmpNsList = NULL;
  7668. return(NULL);
  7669. }
  7670. }
  7671. /**
  7672. * xmlXPathNextAttribute:
  7673. * @ctxt: the XPath Parser context
  7674. * @cur: the current attribute in the traversal
  7675. *
  7676. * Traversal function for the "attribute" direction
  7677. * TODO: support DTD inherited default attributes
  7678. *
  7679. * Returns the next element following that axis
  7680. */
  7681. xmlNodePtr
  7682. xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7683. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7684. if (ctxt->context->node == NULL)
  7685. return(NULL);
  7686. if (ctxt->context->node->type != XML_ELEMENT_NODE)
  7687. return(NULL);
  7688. if (cur == NULL) {
  7689. if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
  7690. return(NULL);
  7691. return((xmlNodePtr)ctxt->context->node->properties);
  7692. }
  7693. return((xmlNodePtr)cur->next);
  7694. }
  7695. /************************************************************************
  7696. * *
  7697. * NodeTest Functions *
  7698. * *
  7699. ************************************************************************/
  7700. #define IS_FUNCTION 200
  7701. /************************************************************************
  7702. * *
  7703. * Implicit tree core function library *
  7704. * *
  7705. ************************************************************************/
  7706. /**
  7707. * xmlXPathRoot:
  7708. * @ctxt: the XPath Parser context
  7709. *
  7710. * Initialize the context to the root of the document
  7711. */
  7712. void
  7713. xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
  7714. if ((ctxt == NULL) || (ctxt->context == NULL))
  7715. return;
  7716. ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
  7717. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  7718. ctxt->context->node));
  7719. }
  7720. /************************************************************************
  7721. * *
  7722. * The explicit core function library *
  7723. *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
  7724. * *
  7725. ************************************************************************/
  7726. /**
  7727. * xmlXPathLastFunction:
  7728. * @ctxt: the XPath Parser context
  7729. * @nargs: the number of arguments
  7730. *
  7731. * Implement the last() XPath function
  7732. * number last()
  7733. * The last function returns the number of nodes in the context node list.
  7734. */
  7735. void
  7736. xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7737. CHECK_ARITY(0);
  7738. if (ctxt->context->contextSize >= 0) {
  7739. valuePush(ctxt,
  7740. xmlXPathCacheNewFloat(ctxt->context,
  7741. (double) ctxt->context->contextSize));
  7742. #ifdef DEBUG_EXPR
  7743. xmlGenericError(xmlGenericErrorContext,
  7744. "last() : %d\n", ctxt->context->contextSize);
  7745. #endif
  7746. } else {
  7747. XP_ERROR(XPATH_INVALID_CTXT_SIZE);
  7748. }
  7749. }
  7750. /**
  7751. * xmlXPathPositionFunction:
  7752. * @ctxt: the XPath Parser context
  7753. * @nargs: the number of arguments
  7754. *
  7755. * Implement the position() XPath function
  7756. * number position()
  7757. * The position function returns the position of the context node in the
  7758. * context node list. The first position is 1, and so the last position
  7759. * will be equal to last().
  7760. */
  7761. void
  7762. xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7763. CHECK_ARITY(0);
  7764. if (ctxt->context->proximityPosition >= 0) {
  7765. valuePush(ctxt,
  7766. xmlXPathCacheNewFloat(ctxt->context,
  7767. (double) ctxt->context->proximityPosition));
  7768. #ifdef DEBUG_EXPR
  7769. xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
  7770. ctxt->context->proximityPosition);
  7771. #endif
  7772. } else {
  7773. XP_ERROR(XPATH_INVALID_CTXT_POSITION);
  7774. }
  7775. }
  7776. /**
  7777. * xmlXPathCountFunction:
  7778. * @ctxt: the XPath Parser context
  7779. * @nargs: the number of arguments
  7780. *
  7781. * Implement the count() XPath function
  7782. * number count(node-set)
  7783. */
  7784. void
  7785. xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7786. xmlXPathObjectPtr cur;
  7787. CHECK_ARITY(1);
  7788. if ((ctxt->value == NULL) ||
  7789. ((ctxt->value->type != XPATH_NODESET) &&
  7790. (ctxt->value->type != XPATH_XSLT_TREE)))
  7791. XP_ERROR(XPATH_INVALID_TYPE);
  7792. cur = valuePop(ctxt);
  7793. if ((cur == NULL) || (cur->nodesetval == NULL))
  7794. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
  7795. else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
  7796. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
  7797. (double) cur->nodesetval->nodeNr));
  7798. } else {
  7799. if ((cur->nodesetval->nodeNr != 1) ||
  7800. (cur->nodesetval->nodeTab == NULL)) {
  7801. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
  7802. } else {
  7803. xmlNodePtr tmp;
  7804. int i = 0;
  7805. tmp = cur->nodesetval->nodeTab[0];
  7806. if (tmp != NULL) {
  7807. tmp = tmp->children;
  7808. while (tmp != NULL) {
  7809. tmp = tmp->next;
  7810. i++;
  7811. }
  7812. }
  7813. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
  7814. }
  7815. }
  7816. xmlXPathReleaseObject(ctxt->context, cur);
  7817. }
  7818. /**
  7819. * xmlXPathGetElementsByIds:
  7820. * @doc: the document
  7821. * @ids: a whitespace separated list of IDs
  7822. *
  7823. * Selects elements by their unique ID.
  7824. *
  7825. * Returns a node-set of selected elements.
  7826. */
  7827. static xmlNodeSetPtr
  7828. xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
  7829. xmlNodeSetPtr ret;
  7830. const xmlChar *cur = ids;
  7831. xmlChar *ID;
  7832. xmlAttrPtr attr;
  7833. xmlNodePtr elem = NULL;
  7834. if (ids == NULL) return(NULL);
  7835. ret = xmlXPathNodeSetCreate(NULL);
  7836. if (ret == NULL)
  7837. return(ret);
  7838. while (IS_BLANK_CH(*cur)) cur++;
  7839. while (*cur != 0) {
  7840. while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
  7841. cur++;
  7842. ID = xmlStrndup(ids, cur - ids);
  7843. if (ID != NULL) {
  7844. /*
  7845. * We used to check the fact that the value passed
  7846. * was an NCName, but this generated much troubles for
  7847. * me and Aleksey Sanin, people blatantly violated that
  7848. * constaint, like Visa3D spec.
  7849. * if (xmlValidateNCName(ID, 1) == 0)
  7850. */
  7851. attr = xmlGetID(doc, ID);
  7852. if (attr != NULL) {
  7853. if (attr->type == XML_ATTRIBUTE_NODE)
  7854. elem = attr->parent;
  7855. else if (attr->type == XML_ELEMENT_NODE)
  7856. elem = (xmlNodePtr) attr;
  7857. else
  7858. elem = NULL;
  7859. if (elem != NULL)
  7860. xmlXPathNodeSetAdd(ret, elem);
  7861. }
  7862. xmlFree(ID);
  7863. }
  7864. while (IS_BLANK_CH(*cur)) cur++;
  7865. ids = cur;
  7866. }
  7867. return(ret);
  7868. }
  7869. /**
  7870. * xmlXPathIdFunction:
  7871. * @ctxt: the XPath Parser context
  7872. * @nargs: the number of arguments
  7873. *
  7874. * Implement the id() XPath function
  7875. * node-set id(object)
  7876. * The id function selects elements by their unique ID
  7877. * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
  7878. * then the result is the union of the result of applying id to the
  7879. * string value of each of the nodes in the argument node-set. When the
  7880. * argument to id is of any other type, the argument is converted to a
  7881. * string as if by a call to the string function; the string is split
  7882. * into a whitespace-separated list of tokens (whitespace is any sequence
  7883. * of characters matching the production S); the result is a node-set
  7884. * containing the elements in the same document as the context node that
  7885. * have a unique ID equal to any of the tokens in the list.
  7886. */
  7887. void
  7888. xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7889. xmlChar *tokens;
  7890. xmlNodeSetPtr ret;
  7891. xmlXPathObjectPtr obj;
  7892. CHECK_ARITY(1);
  7893. obj = valuePop(ctxt);
  7894. if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
  7895. if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
  7896. xmlNodeSetPtr ns;
  7897. int i;
  7898. ret = xmlXPathNodeSetCreate(NULL);
  7899. /*
  7900. * FIXME -- in an out-of-memory condition this will behave badly.
  7901. * The solution is not clear -- we already popped an item from
  7902. * ctxt, so the object is in a corrupt state.
  7903. */
  7904. if (obj->nodesetval != NULL) {
  7905. for (i = 0; i < obj->nodesetval->nodeNr; i++) {
  7906. tokens =
  7907. xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
  7908. ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
  7909. ret = xmlXPathNodeSetMerge(ret, ns);
  7910. xmlXPathFreeNodeSet(ns);
  7911. if (tokens != NULL)
  7912. xmlFree(tokens);
  7913. }
  7914. }
  7915. xmlXPathReleaseObject(ctxt->context, obj);
  7916. valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
  7917. return;
  7918. }
  7919. obj = xmlXPathCacheConvertString(ctxt->context, obj);
  7920. ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
  7921. valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
  7922. xmlXPathReleaseObject(ctxt->context, obj);
  7923. return;
  7924. }
  7925. /**
  7926. * xmlXPathLocalNameFunction:
  7927. * @ctxt: the XPath Parser context
  7928. * @nargs: the number of arguments
  7929. *
  7930. * Implement the local-name() XPath function
  7931. * string local-name(node-set?)
  7932. * The local-name function returns a string containing the local part
  7933. * of the name of the node in the argument node-set that is first in
  7934. * document order. If the node-set is empty or the first node has no
  7935. * name, an empty string is returned. If the argument is omitted it
  7936. * defaults to the context node.
  7937. */
  7938. void
  7939. xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7940. xmlXPathObjectPtr cur;
  7941. if (ctxt == NULL) return;
  7942. if (nargs == 0) {
  7943. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  7944. ctxt->context->node));
  7945. nargs = 1;
  7946. }
  7947. CHECK_ARITY(1);
  7948. if ((ctxt->value == NULL) ||
  7949. ((ctxt->value->type != XPATH_NODESET) &&
  7950. (ctxt->value->type != XPATH_XSLT_TREE)))
  7951. XP_ERROR(XPATH_INVALID_TYPE);
  7952. cur = valuePop(ctxt);
  7953. if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
  7954. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  7955. } else {
  7956. int i = 0; /* Should be first in document order !!!!! */
  7957. switch (cur->nodesetval->nodeTab[i]->type) {
  7958. case XML_ELEMENT_NODE:
  7959. case XML_ATTRIBUTE_NODE:
  7960. case XML_PI_NODE:
  7961. if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
  7962. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  7963. else
  7964. valuePush(ctxt,
  7965. xmlXPathCacheNewString(ctxt->context,
  7966. cur->nodesetval->nodeTab[i]->name));
  7967. break;
  7968. case XML_NAMESPACE_DECL:
  7969. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  7970. ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
  7971. break;
  7972. default:
  7973. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  7974. }
  7975. }
  7976. xmlXPathReleaseObject(ctxt->context, cur);
  7977. }
  7978. /**
  7979. * xmlXPathNamespaceURIFunction:
  7980. * @ctxt: the XPath Parser context
  7981. * @nargs: the number of arguments
  7982. *
  7983. * Implement the namespace-uri() XPath function
  7984. * string namespace-uri(node-set?)
  7985. * The namespace-uri function returns a string containing the
  7986. * namespace URI of the expanded name of the node in the argument
  7987. * node-set that is first in document order. If the node-set is empty,
  7988. * the first node has no name, or the expanded name has no namespace
  7989. * URI, an empty string is returned. If the argument is omitted it
  7990. * defaults to the context node.
  7991. */
  7992. void
  7993. xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7994. xmlXPathObjectPtr cur;
  7995. if (ctxt == NULL) return;
  7996. if (nargs == 0) {
  7997. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  7998. ctxt->context->node));
  7999. nargs = 1;
  8000. }
  8001. CHECK_ARITY(1);
  8002. if ((ctxt->value == NULL) ||
  8003. ((ctxt->value->type != XPATH_NODESET) &&
  8004. (ctxt->value->type != XPATH_XSLT_TREE)))
  8005. XP_ERROR(XPATH_INVALID_TYPE);
  8006. cur = valuePop(ctxt);
  8007. if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
  8008. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8009. } else {
  8010. int i = 0; /* Should be first in document order !!!!! */
  8011. switch (cur->nodesetval->nodeTab[i]->type) {
  8012. case XML_ELEMENT_NODE:
  8013. case XML_ATTRIBUTE_NODE:
  8014. if (cur->nodesetval->nodeTab[i]->ns == NULL)
  8015. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8016. else
  8017. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  8018. cur->nodesetval->nodeTab[i]->ns->href));
  8019. break;
  8020. default:
  8021. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8022. }
  8023. }
  8024. xmlXPathReleaseObject(ctxt->context, cur);
  8025. }
  8026. /**
  8027. * xmlXPathNameFunction:
  8028. * @ctxt: the XPath Parser context
  8029. * @nargs: the number of arguments
  8030. *
  8031. * Implement the name() XPath function
  8032. * string name(node-set?)
  8033. * The name function returns a string containing a QName representing
  8034. * the name of the node in the argument node-set that is first in document
  8035. * order. The QName must represent the name with respect to the namespace
  8036. * declarations in effect on the node whose name is being represented.
  8037. * Typically, this will be the form in which the name occurred in the XML
  8038. * source. This need not be the case if there are namespace declarations
  8039. * in effect on the node that associate multiple prefixes with the same
  8040. * namespace. However, an implementation may include information about
  8041. * the original prefix in its representation of nodes; in this case, an
  8042. * implementation can ensure that the returned string is always the same
  8043. * as the QName used in the XML source. If the argument it omitted it
  8044. * defaults to the context node.
  8045. * Libxml keep the original prefix so the "real qualified name" used is
  8046. * returned.
  8047. */
  8048. static void
  8049. xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
  8050. {
  8051. xmlXPathObjectPtr cur;
  8052. if (nargs == 0) {
  8053. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  8054. ctxt->context->node));
  8055. nargs = 1;
  8056. }
  8057. CHECK_ARITY(1);
  8058. if ((ctxt->value == NULL) ||
  8059. ((ctxt->value->type != XPATH_NODESET) &&
  8060. (ctxt->value->type != XPATH_XSLT_TREE)))
  8061. XP_ERROR(XPATH_INVALID_TYPE);
  8062. cur = valuePop(ctxt);
  8063. if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
  8064. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8065. } else {
  8066. int i = 0; /* Should be first in document order !!!!! */
  8067. switch (cur->nodesetval->nodeTab[i]->type) {
  8068. case XML_ELEMENT_NODE:
  8069. case XML_ATTRIBUTE_NODE:
  8070. if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
  8071. valuePush(ctxt,
  8072. xmlXPathCacheNewCString(ctxt->context, ""));
  8073. else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
  8074. (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
  8075. valuePush(ctxt,
  8076. xmlXPathCacheNewString(ctxt->context,
  8077. cur->nodesetval->nodeTab[i]->name));
  8078. } else {
  8079. xmlChar *fullname;
  8080. fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
  8081. cur->nodesetval->nodeTab[i]->ns->prefix,
  8082. NULL, 0);
  8083. if (fullname == cur->nodesetval->nodeTab[i]->name)
  8084. fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
  8085. if (fullname == NULL) {
  8086. XP_ERROR(XPATH_MEMORY_ERROR);
  8087. }
  8088. valuePush(ctxt, xmlXPathCacheWrapString(
  8089. ctxt->context, fullname));
  8090. }
  8091. break;
  8092. default:
  8093. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  8094. cur->nodesetval->nodeTab[i]));
  8095. xmlXPathLocalNameFunction(ctxt, 1);
  8096. }
  8097. }
  8098. xmlXPathReleaseObject(ctxt->context, cur);
  8099. }
  8100. /**
  8101. * xmlXPathStringFunction:
  8102. * @ctxt: the XPath Parser context
  8103. * @nargs: the number of arguments
  8104. *
  8105. * Implement the string() XPath function
  8106. * string string(object?)
  8107. * The string function converts an object to a string as follows:
  8108. * - A node-set is converted to a string by returning the value of
  8109. * the node in the node-set that is first in document order.
  8110. * If the node-set is empty, an empty string is returned.
  8111. * - A number is converted to a string as follows
  8112. * + NaN is converted to the string NaN
  8113. * + positive zero is converted to the string 0
  8114. * + negative zero is converted to the string 0
  8115. * + positive infinity is converted to the string Infinity
  8116. * + negative infinity is converted to the string -Infinity
  8117. * + if the number is an integer, the number is represented in
  8118. * decimal form as a Number with no decimal point and no leading
  8119. * zeros, preceded by a minus sign (-) if the number is negative
  8120. * + otherwise, the number is represented in decimal form as a
  8121. * Number including a decimal point with at least one digit
  8122. * before the decimal point and at least one digit after the
  8123. * decimal point, preceded by a minus sign (-) if the number
  8124. * is negative; there must be no leading zeros before the decimal
  8125. * point apart possibly from the one required digit immediately
  8126. * before the decimal point; beyond the one required digit
  8127. * after the decimal point there must be as many, but only as
  8128. * many, more digits as are needed to uniquely distinguish the
  8129. * number from all other IEEE 754 numeric values.
  8130. * - The boolean false value is converted to the string false.
  8131. * The boolean true value is converted to the string true.
  8132. *
  8133. * If the argument is omitted, it defaults to a node-set with the
  8134. * context node as its only member.
  8135. */
  8136. void
  8137. xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8138. xmlXPathObjectPtr cur;
  8139. if (ctxt == NULL) return;
  8140. if (nargs == 0) {
  8141. valuePush(ctxt,
  8142. xmlXPathCacheWrapString(ctxt->context,
  8143. xmlXPathCastNodeToString(ctxt->context->node)));
  8144. return;
  8145. }
  8146. CHECK_ARITY(1);
  8147. cur = valuePop(ctxt);
  8148. if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
  8149. valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
  8150. }
  8151. /**
  8152. * xmlXPathStringLengthFunction:
  8153. * @ctxt: the XPath Parser context
  8154. * @nargs: the number of arguments
  8155. *
  8156. * Implement the string-length() XPath function
  8157. * number string-length(string?)
  8158. * The string-length returns the number of characters in the string
  8159. * (see [3.6 Strings]). If the argument is omitted, it defaults to
  8160. * the context node converted to a string, in other words the value
  8161. * of the context node.
  8162. */
  8163. void
  8164. xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8165. xmlXPathObjectPtr cur;
  8166. if (nargs == 0) {
  8167. if ((ctxt == NULL) || (ctxt->context == NULL))
  8168. return;
  8169. if (ctxt->context->node == NULL) {
  8170. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
  8171. } else {
  8172. xmlChar *content;
  8173. content = xmlXPathCastNodeToString(ctxt->context->node);
  8174. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
  8175. xmlUTF8Strlen(content)));
  8176. xmlFree(content);
  8177. }
  8178. return;
  8179. }
  8180. CHECK_ARITY(1);
  8181. CAST_TO_STRING;
  8182. CHECK_TYPE(XPATH_STRING);
  8183. cur = valuePop(ctxt);
  8184. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
  8185. xmlUTF8Strlen(cur->stringval)));
  8186. xmlXPathReleaseObject(ctxt->context, cur);
  8187. }
  8188. /**
  8189. * xmlXPathConcatFunction:
  8190. * @ctxt: the XPath Parser context
  8191. * @nargs: the number of arguments
  8192. *
  8193. * Implement the concat() XPath function
  8194. * string concat(string, string, string*)
  8195. * The concat function returns the concatenation of its arguments.
  8196. */
  8197. void
  8198. xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8199. xmlXPathObjectPtr cur, newobj;
  8200. xmlChar *tmp;
  8201. if (ctxt == NULL) return;
  8202. if (nargs < 2) {
  8203. CHECK_ARITY(2);
  8204. }
  8205. CAST_TO_STRING;
  8206. cur = valuePop(ctxt);
  8207. if ((cur == NULL) || (cur->type != XPATH_STRING)) {
  8208. xmlXPathReleaseObject(ctxt->context, cur);
  8209. return;
  8210. }
  8211. nargs--;
  8212. while (nargs > 0) {
  8213. CAST_TO_STRING;
  8214. newobj = valuePop(ctxt);
  8215. if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
  8216. xmlXPathReleaseObject(ctxt->context, newobj);
  8217. xmlXPathReleaseObject(ctxt->context, cur);
  8218. XP_ERROR(XPATH_INVALID_TYPE);
  8219. }
  8220. tmp = xmlStrcat(newobj->stringval, cur->stringval);
  8221. newobj->stringval = cur->stringval;
  8222. cur->stringval = tmp;
  8223. xmlXPathReleaseObject(ctxt->context, newobj);
  8224. nargs--;
  8225. }
  8226. valuePush(ctxt, cur);
  8227. }
  8228. /**
  8229. * xmlXPathContainsFunction:
  8230. * @ctxt: the XPath Parser context
  8231. * @nargs: the number of arguments
  8232. *
  8233. * Implement the contains() XPath function
  8234. * boolean contains(string, string)
  8235. * The contains function returns true if the first argument string
  8236. * contains the second argument string, and otherwise returns false.
  8237. */
  8238. void
  8239. xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8240. xmlXPathObjectPtr hay, needle;
  8241. CHECK_ARITY(2);
  8242. CAST_TO_STRING;
  8243. CHECK_TYPE(XPATH_STRING);
  8244. needle = valuePop(ctxt);
  8245. CAST_TO_STRING;
  8246. hay = valuePop(ctxt);
  8247. if ((hay == NULL) || (hay->type != XPATH_STRING)) {
  8248. xmlXPathReleaseObject(ctxt->context, hay);
  8249. xmlXPathReleaseObject(ctxt->context, needle);
  8250. XP_ERROR(XPATH_INVALID_TYPE);
  8251. }
  8252. if (xmlStrstr(hay->stringval, needle->stringval))
  8253. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
  8254. else
  8255. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
  8256. xmlXPathReleaseObject(ctxt->context, hay);
  8257. xmlXPathReleaseObject(ctxt->context, needle);
  8258. }
  8259. /**
  8260. * xmlXPathStartsWithFunction:
  8261. * @ctxt: the XPath Parser context
  8262. * @nargs: the number of arguments
  8263. *
  8264. * Implement the starts-with() XPath function
  8265. * boolean starts-with(string, string)
  8266. * The starts-with function returns true if the first argument string
  8267. * starts with the second argument string, and otherwise returns false.
  8268. */
  8269. void
  8270. xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8271. xmlXPathObjectPtr hay, needle;
  8272. int n;
  8273. CHECK_ARITY(2);
  8274. CAST_TO_STRING;
  8275. CHECK_TYPE(XPATH_STRING);
  8276. needle = valuePop(ctxt);
  8277. CAST_TO_STRING;
  8278. hay = valuePop(ctxt);
  8279. if ((hay == NULL) || (hay->type != XPATH_STRING)) {
  8280. xmlXPathReleaseObject(ctxt->context, hay);
  8281. xmlXPathReleaseObject(ctxt->context, needle);
  8282. XP_ERROR(XPATH_INVALID_TYPE);
  8283. }
  8284. n = xmlStrlen(needle->stringval);
  8285. if (xmlStrncmp(hay->stringval, needle->stringval, n))
  8286. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
  8287. else
  8288. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
  8289. xmlXPathReleaseObject(ctxt->context, hay);
  8290. xmlXPathReleaseObject(ctxt->context, needle);
  8291. }
  8292. /**
  8293. * xmlXPathSubstringFunction:
  8294. * @ctxt: the XPath Parser context
  8295. * @nargs: the number of arguments
  8296. *
  8297. * Implement the substring() XPath function
  8298. * string substring(string, number, number?)
  8299. * The substring function returns the substring of the first argument
  8300. * starting at the position specified in the second argument with
  8301. * length specified in the third argument. For example,
  8302. * substring("12345",2,3) returns "234". If the third argument is not
  8303. * specified, it returns the substring starting at the position specified
  8304. * in the second argument and continuing to the end of the string. For
  8305. * example, substring("12345",2) returns "2345". More precisely, each
  8306. * character in the string (see [3.6 Strings]) is considered to have a
  8307. * numeric position: the position of the first character is 1, the position
  8308. * of the second character is 2 and so on. The returned substring contains
  8309. * those characters for which the position of the character is greater than
  8310. * or equal to the second argument and, if the third argument is specified,
  8311. * less than the sum of the second and third arguments; the comparisons
  8312. * and addition used for the above follow the standard IEEE 754 rules. Thus:
  8313. * - substring("12345", 1.5, 2.6) returns "234"
  8314. * - substring("12345", 0, 3) returns "12"
  8315. * - substring("12345", 0 div 0, 3) returns ""
  8316. * - substring("12345", 1, 0 div 0) returns ""
  8317. * - substring("12345", -42, 1 div 0) returns "12345"
  8318. * - substring("12345", -1 div 0, 1 div 0) returns ""
  8319. */
  8320. void
  8321. xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8322. xmlXPathObjectPtr str, start, len;
  8323. double le=0, in;
  8324. int i, l, m;
  8325. xmlChar *ret;
  8326. if (nargs < 2) {
  8327. CHECK_ARITY(2);
  8328. }
  8329. if (nargs > 3) {
  8330. CHECK_ARITY(3);
  8331. }
  8332. /*
  8333. * take care of possible last (position) argument
  8334. */
  8335. if (nargs == 3) {
  8336. CAST_TO_NUMBER;
  8337. CHECK_TYPE(XPATH_NUMBER);
  8338. len = valuePop(ctxt);
  8339. le = len->floatval;
  8340. xmlXPathReleaseObject(ctxt->context, len);
  8341. }
  8342. CAST_TO_NUMBER;
  8343. CHECK_TYPE(XPATH_NUMBER);
  8344. start = valuePop(ctxt);
  8345. in = start->floatval;
  8346. xmlXPathReleaseObject(ctxt->context, start);
  8347. CAST_TO_STRING;
  8348. CHECK_TYPE(XPATH_STRING);
  8349. str = valuePop(ctxt);
  8350. m = xmlUTF8Strlen((const unsigned char *)str->stringval);
  8351. /*
  8352. * If last pos not present, calculate last position
  8353. */
  8354. if (nargs != 3) {
  8355. le = (double)m;
  8356. if (in < 1.0)
  8357. in = 1.0;
  8358. }
  8359. /* Need to check for the special cases where either
  8360. * the index is NaN, the length is NaN, or both
  8361. * arguments are infinity (relying on Inf + -Inf = NaN)
  8362. */
  8363. if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
  8364. /*
  8365. * To meet the requirements of the spec, the arguments
  8366. * must be converted to integer format before
  8367. * initial index calculations are done
  8368. *
  8369. * First we go to integer form, rounding up
  8370. * and checking for special cases
  8371. */
  8372. i = (int) in;
  8373. if (((double)i)+0.5 <= in) i++;
  8374. if (xmlXPathIsInf(le) == 1) {
  8375. l = m;
  8376. if (i < 1)
  8377. i = 1;
  8378. }
  8379. else if (xmlXPathIsInf(le) == -1 || le < 0.0)
  8380. l = 0;
  8381. else {
  8382. l = (int) le;
  8383. if (((double)l)+0.5 <= le) l++;
  8384. }
  8385. /* Now we normalize inidices */
  8386. i -= 1;
  8387. l += i;
  8388. if (i < 0)
  8389. i = 0;
  8390. if (l > m)
  8391. l = m;
  8392. /* number of chars to copy */
  8393. l -= i;
  8394. ret = xmlUTF8Strsub(str->stringval, i, l);
  8395. }
  8396. else {
  8397. ret = NULL;
  8398. }
  8399. if (ret == NULL)
  8400. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8401. else {
  8402. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
  8403. xmlFree(ret);
  8404. }
  8405. xmlXPathReleaseObject(ctxt->context, str);
  8406. }
  8407. /**
  8408. * xmlXPathSubstringBeforeFunction:
  8409. * @ctxt: the XPath Parser context
  8410. * @nargs: the number of arguments
  8411. *
  8412. * Implement the substring-before() XPath function
  8413. * string substring-before(string, string)
  8414. * The substring-before function returns the substring of the first
  8415. * argument string that precedes the first occurrence of the second
  8416. * argument string in the first argument string, or the empty string
  8417. * if the first argument string does not contain the second argument
  8418. * string. For example, substring-before("1999/04/01","/") returns 1999.
  8419. */
  8420. void
  8421. xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8422. xmlXPathObjectPtr str;
  8423. xmlXPathObjectPtr find;
  8424. xmlBufferPtr target;
  8425. const xmlChar *point;
  8426. int offset;
  8427. CHECK_ARITY(2);
  8428. CAST_TO_STRING;
  8429. find = valuePop(ctxt);
  8430. CAST_TO_STRING;
  8431. str = valuePop(ctxt);
  8432. target = xmlBufferCreate();
  8433. if (target) {
  8434. point = xmlStrstr(str->stringval, find->stringval);
  8435. if (point) {
  8436. offset = (int)(point - str->stringval);
  8437. xmlBufferAdd(target, str->stringval, offset);
  8438. }
  8439. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  8440. xmlBufferContent(target)));
  8441. xmlBufferFree(target);
  8442. }
  8443. xmlXPathReleaseObject(ctxt->context, str);
  8444. xmlXPathReleaseObject(ctxt->context, find);
  8445. }
  8446. /**
  8447. * xmlXPathSubstringAfterFunction:
  8448. * @ctxt: the XPath Parser context
  8449. * @nargs: the number of arguments
  8450. *
  8451. * Implement the substring-after() XPath function
  8452. * string substring-after(string, string)
  8453. * The substring-after function returns the substring of the first
  8454. * argument string that follows the first occurrence of the second
  8455. * argument string in the first argument string, or the empty stringi
  8456. * if the first argument string does not contain the second argument
  8457. * string. For example, substring-after("1999/04/01","/") returns 04/01,
  8458. * and substring-after("1999/04/01","19") returns 99/04/01.
  8459. */
  8460. void
  8461. xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8462. xmlXPathObjectPtr str;
  8463. xmlXPathObjectPtr find;
  8464. xmlBufferPtr target;
  8465. const xmlChar *point;
  8466. int offset;
  8467. CHECK_ARITY(2);
  8468. CAST_TO_STRING;
  8469. find = valuePop(ctxt);
  8470. CAST_TO_STRING;
  8471. str = valuePop(ctxt);
  8472. target = xmlBufferCreate();
  8473. if (target) {
  8474. point = xmlStrstr(str->stringval, find->stringval);
  8475. if (point) {
  8476. offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
  8477. xmlBufferAdd(target, &str->stringval[offset],
  8478. xmlStrlen(str->stringval) - offset);
  8479. }
  8480. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  8481. xmlBufferContent(target)));
  8482. xmlBufferFree(target);
  8483. }
  8484. xmlXPathReleaseObject(ctxt->context, str);
  8485. xmlXPathReleaseObject(ctxt->context, find);
  8486. }
  8487. /**
  8488. * xmlXPathNormalizeFunction:
  8489. * @ctxt: the XPath Parser context
  8490. * @nargs: the number of arguments
  8491. *
  8492. * Implement the normalize-space() XPath function
  8493. * string normalize-space(string?)
  8494. * The normalize-space function returns the argument string with white
  8495. * space normalized by stripping leading and trailing whitespace
  8496. * and replacing sequences of whitespace characters by a single
  8497. * space. Whitespace characters are the same allowed by the S production
  8498. * in XML. If the argument is omitted, it defaults to the context
  8499. * node converted to a string, in other words the value of the context node.
  8500. */
  8501. void
  8502. xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8503. xmlXPathObjectPtr obj = NULL;
  8504. xmlChar *source = NULL;
  8505. xmlBufferPtr target;
  8506. xmlChar blank;
  8507. if (ctxt == NULL) return;
  8508. if (nargs == 0) {
  8509. /* Use current context node */
  8510. valuePush(ctxt,
  8511. xmlXPathCacheWrapString(ctxt->context,
  8512. xmlXPathCastNodeToString(ctxt->context->node)));
  8513. nargs = 1;
  8514. }
  8515. CHECK_ARITY(1);
  8516. CAST_TO_STRING;
  8517. CHECK_TYPE(XPATH_STRING);
  8518. obj = valuePop(ctxt);
  8519. source = obj->stringval;
  8520. target = xmlBufferCreate();
  8521. if (target && source) {
  8522. /* Skip leading whitespaces */
  8523. while (IS_BLANK_CH(*source))
  8524. source++;
  8525. /* Collapse intermediate whitespaces, and skip trailing whitespaces */
  8526. blank = 0;
  8527. while (*source) {
  8528. if (IS_BLANK_CH(*source)) {
  8529. blank = 0x20;
  8530. } else {
  8531. if (blank) {
  8532. xmlBufferAdd(target, &blank, 1);
  8533. blank = 0;
  8534. }
  8535. xmlBufferAdd(target, source, 1);
  8536. }
  8537. source++;
  8538. }
  8539. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  8540. xmlBufferContent(target)));
  8541. xmlBufferFree(target);
  8542. }
  8543. xmlXPathReleaseObject(ctxt->context, obj);
  8544. }
  8545. /**
  8546. * xmlXPathTranslateFunction:
  8547. * @ctxt: the XPath Parser context
  8548. * @nargs: the number of arguments
  8549. *
  8550. * Implement the translate() XPath function
  8551. * string translate(string, string, string)
  8552. * The translate function returns the first argument string with
  8553. * occurrences of characters in the second argument string replaced
  8554. * by the character at the corresponding position in the third argument
  8555. * string. For example, translate("bar","abc","ABC") returns the string
  8556. * BAr. If there is a character in the second argument string with no
  8557. * character at a corresponding position in the third argument string
  8558. * (because the second argument string is longer than the third argument
  8559. * string), then occurrences of that character in the first argument
  8560. * string are removed. For example, translate("--aaa--","abc-","ABC")
  8561. * returns "AAA". If a character occurs more than once in second
  8562. * argument string, then the first occurrence determines the replacement
  8563. * character. If the third argument string is longer than the second
  8564. * argument string, then excess characters are ignored.
  8565. */
  8566. void
  8567. xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8568. xmlXPathObjectPtr str;
  8569. xmlXPathObjectPtr from;
  8570. xmlXPathObjectPtr to;
  8571. xmlBufferPtr target;
  8572. int offset, max;
  8573. xmlChar ch;
  8574. const xmlChar *point;
  8575. xmlChar *cptr;
  8576. CHECK_ARITY(3);
  8577. CAST_TO_STRING;
  8578. to = valuePop(ctxt);
  8579. CAST_TO_STRING;
  8580. from = valuePop(ctxt);
  8581. CAST_TO_STRING;
  8582. str = valuePop(ctxt);
  8583. target = xmlBufferCreate();
  8584. if (target) {
  8585. max = xmlUTF8Strlen(to->stringval);
  8586. for (cptr = str->stringval; (ch=*cptr); ) {
  8587. offset = xmlUTF8Strloc(from->stringval, cptr);
  8588. if (offset >= 0) {
  8589. if (offset < max) {
  8590. point = xmlUTF8Strpos(to->stringval, offset);
  8591. if (point)
  8592. xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
  8593. }
  8594. } else
  8595. xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
  8596. /* Step to next character in input */
  8597. cptr++;
  8598. if ( ch & 0x80 ) {
  8599. /* if not simple ascii, verify proper format */
  8600. if ( (ch & 0xc0) != 0xc0 ) {
  8601. xmlGenericError(xmlGenericErrorContext,
  8602. "xmlXPathTranslateFunction: Invalid UTF8 string\n");
  8603. break;
  8604. }
  8605. /* then skip over remaining bytes for this char */
  8606. while ( (ch <<= 1) & 0x80 )
  8607. if ( (*cptr++ & 0xc0) != 0x80 ) {
  8608. xmlGenericError(xmlGenericErrorContext,
  8609. "xmlXPathTranslateFunction: Invalid UTF8 string\n");
  8610. break;
  8611. }
  8612. if (ch & 0x80) /* must have had error encountered */
  8613. break;
  8614. }
  8615. }
  8616. }
  8617. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  8618. xmlBufferContent(target)));
  8619. xmlBufferFree(target);
  8620. xmlXPathReleaseObject(ctxt->context, str);
  8621. xmlXPathReleaseObject(ctxt->context, from);
  8622. xmlXPathReleaseObject(ctxt->context, to);
  8623. }
  8624. /**
  8625. * xmlXPathBooleanFunction:
  8626. * @ctxt: the XPath Parser context
  8627. * @nargs: the number of arguments
  8628. *
  8629. * Implement the boolean() XPath function
  8630. * boolean boolean(object)
  8631. * The boolean function converts its argument to a boolean as follows:
  8632. * - a number is true if and only if it is neither positive or
  8633. * negative zero nor NaN
  8634. * - a node-set is true if and only if it is non-empty
  8635. * - a string is true if and only if its length is non-zero
  8636. */
  8637. void
  8638. xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8639. xmlXPathObjectPtr cur;
  8640. CHECK_ARITY(1);
  8641. cur = valuePop(ctxt);
  8642. if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
  8643. cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
  8644. valuePush(ctxt, cur);
  8645. }
  8646. /**
  8647. * xmlXPathNotFunction:
  8648. * @ctxt: the XPath Parser context
  8649. * @nargs: the number of arguments
  8650. *
  8651. * Implement the not() XPath function
  8652. * boolean not(boolean)
  8653. * The not function returns true if its argument is false,
  8654. * and false otherwise.
  8655. */
  8656. void
  8657. xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8658. CHECK_ARITY(1);
  8659. CAST_TO_BOOLEAN;
  8660. CHECK_TYPE(XPATH_BOOLEAN);
  8661. ctxt->value->boolval = ! ctxt->value->boolval;
  8662. }
  8663. /**
  8664. * xmlXPathTrueFunction:
  8665. * @ctxt: the XPath Parser context
  8666. * @nargs: the number of arguments
  8667. *
  8668. * Implement the true() XPath function
  8669. * boolean true()
  8670. */
  8671. void
  8672. xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8673. CHECK_ARITY(0);
  8674. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
  8675. }
  8676. /**
  8677. * xmlXPathFalseFunction:
  8678. * @ctxt: the XPath Parser context
  8679. * @nargs: the number of arguments
  8680. *
  8681. * Implement the false() XPath function
  8682. * boolean false()
  8683. */
  8684. void
  8685. xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8686. CHECK_ARITY(0);
  8687. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
  8688. }
  8689. /**
  8690. * xmlXPathLangFunction:
  8691. * @ctxt: the XPath Parser context
  8692. * @nargs: the number of arguments
  8693. *
  8694. * Implement the lang() XPath function
  8695. * boolean lang(string)
  8696. * The lang function returns true or false depending on whether the
  8697. * language of the context node as specified by xml:lang attributes
  8698. * is the same as or is a sublanguage of the language specified by
  8699. * the argument string. The language of the context node is determined
  8700. * by the value of the xml:lang attribute on the context node, or, if
  8701. * the context node has no xml:lang attribute, by the value of the
  8702. * xml:lang attribute on the nearest ancestor of the context node that
  8703. * has an xml:lang attribute. If there is no such attribute, then lang
  8704. * returns false. If there is such an attribute, then lang returns
  8705. * true if the attribute value is equal to the argument ignoring case,
  8706. * or if there is some suffix starting with - such that the attribute
  8707. * value is equal to the argument ignoring that suffix of the attribute
  8708. * value and ignoring case.
  8709. */
  8710. void
  8711. xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8712. xmlXPathObjectPtr val = NULL;
  8713. const xmlChar *theLang = NULL;
  8714. const xmlChar *lang;
  8715. int ret = 0;
  8716. int i;
  8717. CHECK_ARITY(1);
  8718. CAST_TO_STRING;
  8719. CHECK_TYPE(XPATH_STRING);
  8720. val = valuePop(ctxt);
  8721. lang = val->stringval;
  8722. theLang = xmlNodeGetLang(ctxt->context->node);
  8723. if ((theLang != NULL) && (lang != NULL)) {
  8724. for (i = 0;lang[i] != 0;i++)
  8725. if (toupper(lang[i]) != toupper(theLang[i]))
  8726. goto not_equal;
  8727. if ((theLang[i] == 0) || (theLang[i] == '-'))
  8728. ret = 1;
  8729. }
  8730. not_equal:
  8731. if (theLang != NULL)
  8732. xmlFree((void *)theLang);
  8733. xmlXPathReleaseObject(ctxt->context, val);
  8734. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
  8735. }
  8736. /**
  8737. * xmlXPathNumberFunction:
  8738. * @ctxt: the XPath Parser context
  8739. * @nargs: the number of arguments
  8740. *
  8741. * Implement the number() XPath function
  8742. * number number(object?)
  8743. */
  8744. void
  8745. xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8746. xmlXPathObjectPtr cur;
  8747. double res;
  8748. if (ctxt == NULL) return;
  8749. if (nargs == 0) {
  8750. if (ctxt->context->node == NULL) {
  8751. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
  8752. } else {
  8753. xmlChar* content = xmlNodeGetContent(ctxt->context->node);
  8754. res = xmlXPathStringEvalNumber(content);
  8755. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
  8756. xmlFree(content);
  8757. }
  8758. return;
  8759. }
  8760. CHECK_ARITY(1);
  8761. cur = valuePop(ctxt);
  8762. valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
  8763. }
  8764. /**
  8765. * xmlXPathSumFunction:
  8766. * @ctxt: the XPath Parser context
  8767. * @nargs: the number of arguments
  8768. *
  8769. * Implement the sum() XPath function
  8770. * number sum(node-set)
  8771. * The sum function returns the sum of the values of the nodes in
  8772. * the argument node-set.
  8773. */
  8774. void
  8775. xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8776. xmlXPathObjectPtr cur;
  8777. int i;
  8778. double res = 0.0;
  8779. CHECK_ARITY(1);
  8780. if ((ctxt->value == NULL) ||
  8781. ((ctxt->value->type != XPATH_NODESET) &&
  8782. (ctxt->value->type != XPATH_XSLT_TREE)))
  8783. XP_ERROR(XPATH_INVALID_TYPE);
  8784. cur = valuePop(ctxt);
  8785. if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
  8786. for (i = 0; i < cur->nodesetval->nodeNr; i++) {
  8787. res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
  8788. }
  8789. }
  8790. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
  8791. xmlXPathReleaseObject(ctxt->context, cur);
  8792. }
  8793. /*
  8794. * To assure working code on multiple platforms, we want to only depend
  8795. * upon the characteristic truncation of converting a floating point value
  8796. * to an integer. Unfortunately, because of the different storage sizes
  8797. * of our internal floating point value (double) and integer (int), we
  8798. * can't directly convert (see bug 301162). This macro is a messy
  8799. * 'workaround'
  8800. */
  8801. #define XTRUNC(f, v) \
  8802. f = fmod((v), INT_MAX); \
  8803. f = (v) - (f) + (double)((int)(f));
  8804. /**
  8805. * xmlXPathFloorFunction:
  8806. * @ctxt: the XPath Parser context
  8807. * @nargs: the number of arguments
  8808. *
  8809. * Implement the floor() XPath function
  8810. * number floor(number)
  8811. * The floor function returns the largest (closest to positive infinity)
  8812. * number that is not greater than the argument and that is an integer.
  8813. */
  8814. void
  8815. xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8816. double f;
  8817. CHECK_ARITY(1);
  8818. CAST_TO_NUMBER;
  8819. CHECK_TYPE(XPATH_NUMBER);
  8820. XTRUNC(f, ctxt->value->floatval);
  8821. if (f != ctxt->value->floatval) {
  8822. if (ctxt->value->floatval > 0)
  8823. ctxt->value->floatval = f;
  8824. else
  8825. ctxt->value->floatval = f - 1;
  8826. }
  8827. }
  8828. /**
  8829. * xmlXPathCeilingFunction:
  8830. * @ctxt: the XPath Parser context
  8831. * @nargs: the number of arguments
  8832. *
  8833. * Implement the ceiling() XPath function
  8834. * number ceiling(number)
  8835. * The ceiling function returns the smallest (closest to negative infinity)
  8836. * number that is not less than the argument and that is an integer.
  8837. */
  8838. void
  8839. xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8840. double f;
  8841. CHECK_ARITY(1);
  8842. CAST_TO_NUMBER;
  8843. CHECK_TYPE(XPATH_NUMBER);
  8844. #if 0
  8845. ctxt->value->floatval = ceil(ctxt->value->floatval);
  8846. #else
  8847. XTRUNC(f, ctxt->value->floatval);
  8848. if (f != ctxt->value->floatval) {
  8849. if (ctxt->value->floatval > 0)
  8850. ctxt->value->floatval = f + 1;
  8851. else {
  8852. if (ctxt->value->floatval < 0 && f == 0)
  8853. ctxt->value->floatval = xmlXPathNZERO;
  8854. else
  8855. ctxt->value->floatval = f;
  8856. }
  8857. }
  8858. #endif
  8859. }
  8860. /**
  8861. * xmlXPathRoundFunction:
  8862. * @ctxt: the XPath Parser context
  8863. * @nargs: the number of arguments
  8864. *
  8865. * Implement the round() XPath function
  8866. * number round(number)
  8867. * The round function returns the number that is closest to the
  8868. * argument and that is an integer. If there are two such numbers,
  8869. * then the one that is even is returned.
  8870. */
  8871. void
  8872. xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8873. double f;
  8874. CHECK_ARITY(1);
  8875. CAST_TO_NUMBER;
  8876. CHECK_TYPE(XPATH_NUMBER);
  8877. if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
  8878. (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
  8879. (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
  8880. (ctxt->value->floatval == 0.0))
  8881. return;
  8882. XTRUNC(f, ctxt->value->floatval);
  8883. if (ctxt->value->floatval < 0) {
  8884. if (ctxt->value->floatval < f - 0.5)
  8885. ctxt->value->floatval = f - 1;
  8886. else
  8887. ctxt->value->floatval = f;
  8888. if (ctxt->value->floatval == 0)
  8889. ctxt->value->floatval = xmlXPathNZERO;
  8890. } else {
  8891. if (ctxt->value->floatval < f + 0.5)
  8892. ctxt->value->floatval = f;
  8893. else
  8894. ctxt->value->floatval = f + 1;
  8895. }
  8896. }
  8897. /************************************************************************
  8898. * *
  8899. * The Parser *
  8900. * *
  8901. ************************************************************************/
  8902. /*
  8903. * a few forward declarations since we use a recursive call based
  8904. * implementation.
  8905. */
  8906. static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
  8907. static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
  8908. static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
  8909. static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
  8910. static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
  8911. int qualified);
  8912. /**
  8913. * xmlXPathCurrentChar:
  8914. * @ctxt: the XPath parser context
  8915. * @cur: pointer to the beginning of the char
  8916. * @len: pointer to the length of the char read
  8917. *
  8918. * The current char value, if using UTF-8 this may actually span multiple
  8919. * bytes in the input buffer.
  8920. *
  8921. * Returns the current char value and its length
  8922. */
  8923. static int
  8924. xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
  8925. unsigned char c;
  8926. unsigned int val;
  8927. const xmlChar *cur;
  8928. if (ctxt == NULL)
  8929. return(0);
  8930. cur = ctxt->cur;
  8931. /*
  8932. * We are supposed to handle UTF8, check it's valid
  8933. * From rfc2044: encoding of the Unicode values on UTF-8:
  8934. *
  8935. * UCS-4 range (hex.) UTF-8 octet sequence (binary)
  8936. * 0000 0000-0000 007F 0xxxxxxx
  8937. * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
  8938. * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
  8939. *
  8940. * Check for the 0x110000 limit too
  8941. */
  8942. c = *cur;
  8943. if (c & 0x80) {
  8944. if ((cur[1] & 0xc0) != 0x80)
  8945. goto encoding_error;
  8946. if ((c & 0xe0) == 0xe0) {
  8947. if ((cur[2] & 0xc0) != 0x80)
  8948. goto encoding_error;
  8949. if ((c & 0xf0) == 0xf0) {
  8950. if (((c & 0xf8) != 0xf0) ||
  8951. ((cur[3] & 0xc0) != 0x80))
  8952. goto encoding_error;
  8953. /* 4-byte code */
  8954. *len = 4;
  8955. val = (cur[0] & 0x7) << 18;
  8956. val |= (cur[1] & 0x3f) << 12;
  8957. val |= (cur[2] & 0x3f) << 6;
  8958. val |= cur[3] & 0x3f;
  8959. } else {
  8960. /* 3-byte code */
  8961. *len = 3;
  8962. val = (cur[0] & 0xf) << 12;
  8963. val |= (cur[1] & 0x3f) << 6;
  8964. val |= cur[2] & 0x3f;
  8965. }
  8966. } else {
  8967. /* 2-byte code */
  8968. *len = 2;
  8969. val = (cur[0] & 0x1f) << 6;
  8970. val |= cur[1] & 0x3f;
  8971. }
  8972. if (!IS_CHAR(val)) {
  8973. XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
  8974. }
  8975. return(val);
  8976. } else {
  8977. /* 1-byte code */
  8978. *len = 1;
  8979. return((int) *cur);
  8980. }
  8981. encoding_error:
  8982. /*
  8983. * If we detect an UTF8 error that probably means that the
  8984. * input encoding didn't get properly advertised in the
  8985. * declaration header. Report the error and switch the encoding
  8986. * to ISO-Latin-1 (if you don't like this policy, just declare the
  8987. * encoding !)
  8988. */
  8989. *len = 0;
  8990. XP_ERROR0(XPATH_ENCODING_ERROR);
  8991. }
  8992. /**
  8993. * xmlXPathParseNCName:
  8994. * @ctxt: the XPath Parser context
  8995. *
  8996. * parse an XML namespace non qualified name.
  8997. *
  8998. * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
  8999. *
  9000. * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
  9001. * CombiningChar | Extender
  9002. *
  9003. * Returns the namespace name or NULL
  9004. */
  9005. xmlChar *
  9006. xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
  9007. const xmlChar *in;
  9008. xmlChar *ret;
  9009. int count = 0;
  9010. if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
  9011. /*
  9012. * Accelerator for simple ASCII names
  9013. */
  9014. in = ctxt->cur;
  9015. if (((*in >= 0x61) && (*in <= 0x7A)) ||
  9016. ((*in >= 0x41) && (*in <= 0x5A)) ||
  9017. (*in == '_')) {
  9018. in++;
  9019. while (((*in >= 0x61) && (*in <= 0x7A)) ||
  9020. ((*in >= 0x41) && (*in <= 0x5A)) ||
  9021. ((*in >= 0x30) && (*in <= 0x39)) ||
  9022. (*in == '_') || (*in == '.') ||
  9023. (*in == '-'))
  9024. in++;
  9025. if ((*in == ' ') || (*in == '>') || (*in == '/') ||
  9026. (*in == '[') || (*in == ']') || (*in == ':') ||
  9027. (*in == '@') || (*in == '*')) {
  9028. count = in - ctxt->cur;
  9029. if (count == 0)
  9030. return(NULL);
  9031. ret = xmlStrndup(ctxt->cur, count);
  9032. ctxt->cur = in;
  9033. return(ret);
  9034. }
  9035. }
  9036. return(xmlXPathParseNameComplex(ctxt, 0));
  9037. }
  9038. /**
  9039. * xmlXPathParseQName:
  9040. * @ctxt: the XPath Parser context
  9041. * @prefix: a xmlChar **
  9042. *
  9043. * parse an XML qualified name
  9044. *
  9045. * [NS 5] QName ::= (Prefix ':')? LocalPart
  9046. *
  9047. * [NS 6] Prefix ::= NCName
  9048. *
  9049. * [NS 7] LocalPart ::= NCName
  9050. *
  9051. * Returns the function returns the local part, and prefix is updated
  9052. * to get the Prefix if any.
  9053. */
  9054. static xmlChar *
  9055. xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
  9056. xmlChar *ret = NULL;
  9057. *prefix = NULL;
  9058. ret = xmlXPathParseNCName(ctxt);
  9059. if (ret && CUR == ':') {
  9060. *prefix = ret;
  9061. NEXT;
  9062. ret = xmlXPathParseNCName(ctxt);
  9063. }
  9064. return(ret);
  9065. }
  9066. /**
  9067. * xmlXPathParseName:
  9068. * @ctxt: the XPath Parser context
  9069. *
  9070. * parse an XML name
  9071. *
  9072. * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
  9073. * CombiningChar | Extender
  9074. *
  9075. * [5] Name ::= (Letter | '_' | ':') (NameChar)*
  9076. *
  9077. * Returns the namespace name or NULL
  9078. */
  9079. xmlChar *
  9080. xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
  9081. const xmlChar *in;
  9082. xmlChar *ret;
  9083. int count = 0;
  9084. if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
  9085. /*
  9086. * Accelerator for simple ASCII names
  9087. */
  9088. in = ctxt->cur;
  9089. if (((*in >= 0x61) && (*in <= 0x7A)) ||
  9090. ((*in >= 0x41) && (*in <= 0x5A)) ||
  9091. (*in == '_') || (*in == ':')) {
  9092. in++;
  9093. while (((*in >= 0x61) && (*in <= 0x7A)) ||
  9094. ((*in >= 0x41) && (*in <= 0x5A)) ||
  9095. ((*in >= 0x30) && (*in <= 0x39)) ||
  9096. (*in == '_') || (*in == '-') ||
  9097. (*in == ':') || (*in == '.'))
  9098. in++;
  9099. if ((*in > 0) && (*in < 0x80)) {
  9100. count = in - ctxt->cur;
  9101. ret = xmlStrndup(ctxt->cur, count);
  9102. ctxt->cur = in;
  9103. return(ret);
  9104. }
  9105. }
  9106. return(xmlXPathParseNameComplex(ctxt, 1));
  9107. }
  9108. static xmlChar *
  9109. xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
  9110. xmlChar buf[XML_MAX_NAMELEN + 5];
  9111. int len = 0, l;
  9112. int c;
  9113. /*
  9114. * Handler for more complex cases
  9115. */
  9116. c = CUR_CHAR(l);
  9117. if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
  9118. (c == '[') || (c == ']') || (c == '@') || /* accelerators */
  9119. (c == '*') || /* accelerators */
  9120. (!IS_LETTER(c) && (c != '_') &&
  9121. ((qualified) && (c != ':')))) {
  9122. return(NULL);
  9123. }
  9124. while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
  9125. ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
  9126. (c == '.') || (c == '-') ||
  9127. (c == '_') || ((qualified) && (c == ':')) ||
  9128. (IS_COMBINING(c)) ||
  9129. (IS_EXTENDER(c)))) {
  9130. COPY_BUF(l,buf,len,c);
  9131. NEXTL(l);
  9132. c = CUR_CHAR(l);
  9133. if (len >= XML_MAX_NAMELEN) {
  9134. /*
  9135. * Okay someone managed to make a huge name, so he's ready to pay
  9136. * for the processing speed.
  9137. */
  9138. xmlChar *buffer;
  9139. int max = len * 2;
  9140. buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
  9141. if (buffer == NULL) {
  9142. XP_ERRORNULL(XPATH_MEMORY_ERROR);
  9143. }
  9144. memcpy(buffer, buf, len);
  9145. while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
  9146. (c == '.') || (c == '-') ||
  9147. (c == '_') || ((qualified) && (c == ':')) ||
  9148. (IS_COMBINING(c)) ||
  9149. (IS_EXTENDER(c))) {
  9150. if (len + 10 > max) {
  9151. max *= 2;
  9152. buffer = (xmlChar *) xmlRealloc(buffer,
  9153. max * sizeof(xmlChar));
  9154. if (buffer == NULL) {
  9155. XP_ERRORNULL(XPATH_MEMORY_ERROR);
  9156. }
  9157. }
  9158. COPY_BUF(l,buffer,len,c);
  9159. NEXTL(l);
  9160. c = CUR_CHAR(l);
  9161. }
  9162. buffer[len] = 0;
  9163. return(buffer);
  9164. }
  9165. }
  9166. if (len == 0)
  9167. return(NULL);
  9168. return(xmlStrndup(buf, len));
  9169. }
  9170. #define MAX_FRAC 20
  9171. /*
  9172. * These are used as divisors for the fractional part of a number.
  9173. * Since the table includes 1.0 (representing '0' fractional digits),
  9174. * it must be dimensioned at MAX_FRAC+1 (bug 133921)
  9175. */
  9176. static double my_pow10[MAX_FRAC+1] = {
  9177. 1.0, 10.0, 100.0, 1000.0, 10000.0,
  9178. 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
  9179. 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
  9180. 100000000000000.0,
  9181. 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
  9182. 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
  9183. };
  9184. /**
  9185. * xmlXPathStringEvalNumber:
  9186. * @str: A string to scan
  9187. *
  9188. * [30a] Float ::= Number ('e' Digits?)?
  9189. *
  9190. * [30] Number ::= Digits ('.' Digits?)?
  9191. * | '.' Digits
  9192. * [31] Digits ::= [0-9]+
  9193. *
  9194. * Compile a Number in the string
  9195. * In complement of the Number expression, this function also handles
  9196. * negative values : '-' Number.
  9197. *
  9198. * Returns the double value.
  9199. */
  9200. double
  9201. xmlXPathStringEvalNumber(const xmlChar *str) {
  9202. const xmlChar *cur = str;
  9203. double ret;
  9204. int ok = 0;
  9205. int isneg = 0;
  9206. int exponent = 0;
  9207. int is_exponent_negative = 0;
  9208. #ifdef __GNUC__
  9209. unsigned long tmp = 0;
  9210. double temp;
  9211. #endif
  9212. if (cur == NULL) return(0);
  9213. while (IS_BLANK_CH(*cur)) cur++;
  9214. if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
  9215. return(xmlXPathNAN);
  9216. }
  9217. if (*cur == '-') {
  9218. isneg = 1;
  9219. cur++;
  9220. }
  9221. #ifdef __GNUC__
  9222. /*
  9223. * tmp/temp is a workaround against a gcc compiler bug
  9224. * http://veillard.com/gcc.bug
  9225. */
  9226. ret = 0;
  9227. while ((*cur >= '0') && (*cur <= '9')) {
  9228. ret = ret * 10;
  9229. tmp = (*cur - '0');
  9230. ok = 1;
  9231. cur++;
  9232. temp = (double) tmp;
  9233. ret = ret + temp;
  9234. }
  9235. #else
  9236. ret = 0;
  9237. while ((*cur >= '0') && (*cur <= '9')) {
  9238. ret = ret * 10 + (*cur - '0');
  9239. ok = 1;
  9240. cur++;
  9241. }
  9242. #endif
  9243. if (*cur == '.') {
  9244. int v, frac = 0;
  9245. double fraction = 0;
  9246. cur++;
  9247. if (((*cur < '0') || (*cur > '9')) && (!ok)) {
  9248. return(xmlXPathNAN);
  9249. }
  9250. while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
  9251. v = (*cur - '0');
  9252. fraction = fraction * 10 + v;
  9253. frac = frac + 1;
  9254. cur++;
  9255. }
  9256. fraction /= my_pow10[frac];
  9257. ret = ret + fraction;
  9258. while ((*cur >= '0') && (*cur <= '9'))
  9259. cur++;
  9260. }
  9261. if ((*cur == 'e') || (*cur == 'E')) {
  9262. cur++;
  9263. if (*cur == '-') {
  9264. is_exponent_negative = 1;
  9265. cur++;
  9266. } else if (*cur == '+') {
  9267. cur++;
  9268. }
  9269. while ((*cur >= '0') && (*cur <= '9')) {
  9270. exponent = exponent * 10 + (*cur - '0');
  9271. cur++;
  9272. }
  9273. }
  9274. while (IS_BLANK_CH(*cur)) cur++;
  9275. if (*cur != 0) return(xmlXPathNAN);
  9276. if (isneg) ret = -ret;
  9277. if (is_exponent_negative) exponent = -exponent;
  9278. ret *= pow(10.0, (double)exponent);
  9279. return(ret);
  9280. }
  9281. /**
  9282. * xmlXPathCompNumber:
  9283. * @ctxt: the XPath Parser context
  9284. *
  9285. * [30] Number ::= Digits ('.' Digits?)?
  9286. * | '.' Digits
  9287. * [31] Digits ::= [0-9]+
  9288. *
  9289. * Compile a Number, then push it on the stack
  9290. *
  9291. */
  9292. static void
  9293. xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
  9294. {
  9295. double ret = 0.0;
  9296. double mult = 1;
  9297. int ok = 0;
  9298. int exponent = 0;
  9299. int is_exponent_negative = 0;
  9300. #ifdef __GNUC__
  9301. unsigned long tmp = 0;
  9302. double temp;
  9303. #endif
  9304. CHECK_ERROR;
  9305. if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
  9306. XP_ERROR(XPATH_NUMBER_ERROR);
  9307. }
  9308. #ifdef __GNUC__
  9309. /*
  9310. * tmp/temp is a workaround against a gcc compiler bug
  9311. * http://veillard.com/gcc.bug
  9312. */
  9313. ret = 0;
  9314. while ((CUR >= '0') && (CUR <= '9')) {
  9315. ret = ret * 10;
  9316. tmp = (CUR - '0');
  9317. ok = 1;
  9318. NEXT;
  9319. temp = (double) tmp;
  9320. ret = ret + temp;
  9321. }
  9322. #else
  9323. ret = 0;
  9324. while ((CUR >= '0') && (CUR <= '9')) {
  9325. ret = ret * 10 + (CUR - '0');
  9326. ok = 1;
  9327. NEXT;
  9328. }
  9329. #endif
  9330. if (CUR == '.') {
  9331. NEXT;
  9332. if (((CUR < '0') || (CUR > '9')) && (!ok)) {
  9333. XP_ERROR(XPATH_NUMBER_ERROR);
  9334. }
  9335. while ((CUR >= '0') && (CUR <= '9')) {
  9336. mult /= 10;
  9337. ret = ret + (CUR - '0') * mult;
  9338. NEXT;
  9339. }
  9340. }
  9341. if ((CUR == 'e') || (CUR == 'E')) {
  9342. NEXT;
  9343. if (CUR == '-') {
  9344. is_exponent_negative = 1;
  9345. NEXT;
  9346. } else if (CUR == '+') {
  9347. NEXT;
  9348. }
  9349. while ((CUR >= '0') && (CUR <= '9')) {
  9350. exponent = exponent * 10 + (CUR - '0');
  9351. NEXT;
  9352. }
  9353. if (is_exponent_negative)
  9354. exponent = -exponent;
  9355. ret *= pow(10.0, (double) exponent);
  9356. }
  9357. PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
  9358. xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
  9359. }
  9360. /**
  9361. * xmlXPathParseLiteral:
  9362. * @ctxt: the XPath Parser context
  9363. *
  9364. * Parse a Literal
  9365. *
  9366. * [29] Literal ::= '"' [^"]* '"'
  9367. * | "'" [^']* "'"
  9368. *
  9369. * Returns the value found or NULL in case of error
  9370. */
  9371. static xmlChar *
  9372. xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
  9373. const xmlChar *q;
  9374. xmlChar *ret = NULL;
  9375. if (CUR == '"') {
  9376. NEXT;
  9377. q = CUR_PTR;
  9378. while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
  9379. NEXT;
  9380. if (!IS_CHAR_CH(CUR)) {
  9381. XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
  9382. } else {
  9383. ret = xmlStrndup(q, CUR_PTR - q);
  9384. NEXT;
  9385. }
  9386. } else if (CUR == '\'') {
  9387. NEXT;
  9388. q = CUR_PTR;
  9389. while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
  9390. NEXT;
  9391. if (!IS_CHAR_CH(CUR)) {
  9392. XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
  9393. } else {
  9394. ret = xmlStrndup(q, CUR_PTR - q);
  9395. NEXT;
  9396. }
  9397. } else {
  9398. XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
  9399. }
  9400. return(ret);
  9401. }
  9402. /**
  9403. * xmlXPathCompLiteral:
  9404. * @ctxt: the XPath Parser context
  9405. *
  9406. * Parse a Literal and push it on the stack.
  9407. *
  9408. * [29] Literal ::= '"' [^"]* '"'
  9409. * | "'" [^']* "'"
  9410. *
  9411. * TODO: xmlXPathCompLiteral memory allocation could be improved.
  9412. */
  9413. static void
  9414. xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
  9415. const xmlChar *q;
  9416. xmlChar *ret = NULL;
  9417. if (CUR == '"') {
  9418. NEXT;
  9419. q = CUR_PTR;
  9420. while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
  9421. NEXT;
  9422. if (!IS_CHAR_CH(CUR)) {
  9423. XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
  9424. } else {
  9425. ret = xmlStrndup(q, CUR_PTR - q);
  9426. NEXT;
  9427. }
  9428. } else if (CUR == '\'') {
  9429. NEXT;
  9430. q = CUR_PTR;
  9431. while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
  9432. NEXT;
  9433. if (!IS_CHAR_CH(CUR)) {
  9434. XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
  9435. } else {
  9436. ret = xmlStrndup(q, CUR_PTR - q);
  9437. NEXT;
  9438. }
  9439. } else {
  9440. XP_ERROR(XPATH_START_LITERAL_ERROR);
  9441. }
  9442. if (ret == NULL) return;
  9443. PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
  9444. xmlXPathCacheNewString(ctxt->context, ret), NULL);
  9445. xmlFree(ret);
  9446. }
  9447. /**
  9448. * xmlXPathCompVariableReference:
  9449. * @ctxt: the XPath Parser context
  9450. *
  9451. * Parse a VariableReference, evaluate it and push it on the stack.
  9452. *
  9453. * The variable bindings consist of a mapping from variable names
  9454. * to variable values. The value of a variable is an object, which can be
  9455. * of any of the types that are possible for the value of an expression,
  9456. * and may also be of additional types not specified here.
  9457. *
  9458. * Early evaluation is possible since:
  9459. * The variable bindings [...] used to evaluate a subexpression are
  9460. * always the same as those used to evaluate the containing expression.
  9461. *
  9462. * [36] VariableReference ::= '$' QName
  9463. */
  9464. static void
  9465. xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
  9466. xmlChar *name;
  9467. xmlChar *prefix;
  9468. SKIP_BLANKS;
  9469. if (CUR != '$') {
  9470. XP_ERROR(XPATH_VARIABLE_REF_ERROR);
  9471. }
  9472. NEXT;
  9473. name = xmlXPathParseQName(ctxt, &prefix);
  9474. if (name == NULL) {
  9475. XP_ERROR(XPATH_VARIABLE_REF_ERROR);
  9476. }
  9477. ctxt->comp->last = -1;
  9478. PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
  9479. name, prefix);
  9480. SKIP_BLANKS;
  9481. if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
  9482. XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
  9483. }
  9484. }
  9485. /**
  9486. * xmlXPathIsNodeType:
  9487. * @name: a name string
  9488. *
  9489. * Is the name given a NodeType one.
  9490. *
  9491. * [38] NodeType ::= 'comment'
  9492. * | 'text'
  9493. * | 'processing-instruction'
  9494. * | 'node'
  9495. *
  9496. * Returns 1 if true 0 otherwise
  9497. */
  9498. int
  9499. xmlXPathIsNodeType(const xmlChar *name) {
  9500. if (name == NULL)
  9501. return(0);
  9502. if (xmlStrEqual(name, BAD_CAST "node"))
  9503. return(1);
  9504. if (xmlStrEqual(name, BAD_CAST "text"))
  9505. return(1);
  9506. if (xmlStrEqual(name, BAD_CAST "comment"))
  9507. return(1);
  9508. if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
  9509. return(1);
  9510. return(0);
  9511. }
  9512. /**
  9513. * xmlXPathCompFunctionCall:
  9514. * @ctxt: the XPath Parser context
  9515. *
  9516. * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
  9517. * [17] Argument ::= Expr
  9518. *
  9519. * Compile a function call, the evaluation of all arguments are
  9520. * pushed on the stack
  9521. */
  9522. static void
  9523. xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
  9524. xmlChar *name;
  9525. xmlChar *prefix;
  9526. int nbargs = 0;
  9527. int sort = 1;
  9528. name = xmlXPathParseQName(ctxt, &prefix);
  9529. if (name == NULL) {
  9530. xmlFree(prefix);
  9531. XP_ERROR(XPATH_EXPR_ERROR);
  9532. }
  9533. SKIP_BLANKS;
  9534. #ifdef DEBUG_EXPR
  9535. if (prefix == NULL)
  9536. xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
  9537. name);
  9538. else
  9539. xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
  9540. prefix, name);
  9541. #endif
  9542. if (CUR != '(') {
  9543. XP_ERROR(XPATH_EXPR_ERROR);
  9544. }
  9545. NEXT;
  9546. SKIP_BLANKS;
  9547. /*
  9548. * Optimization for count(): we don't need the node-set to be sorted.
  9549. */
  9550. if ((prefix == NULL) && (name[0] == 'c') &&
  9551. xmlStrEqual(name, BAD_CAST "count"))
  9552. {
  9553. sort = 0;
  9554. }
  9555. ctxt->comp->last = -1;
  9556. if (CUR != ')') {
  9557. while (CUR != 0) {
  9558. int op1 = ctxt->comp->last;
  9559. ctxt->comp->last = -1;
  9560. xmlXPathCompileExpr(ctxt, sort);
  9561. if (ctxt->error != XPATH_EXPRESSION_OK) {
  9562. xmlFree(name);
  9563. xmlFree(prefix);
  9564. return;
  9565. }
  9566. PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
  9567. nbargs++;
  9568. if (CUR == ')') break;
  9569. if (CUR != ',') {
  9570. XP_ERROR(XPATH_EXPR_ERROR);
  9571. }
  9572. NEXT;
  9573. SKIP_BLANKS;
  9574. }
  9575. }
  9576. PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
  9577. name, prefix);
  9578. NEXT;
  9579. SKIP_BLANKS;
  9580. }
  9581. /**
  9582. * xmlXPathCompPrimaryExpr:
  9583. * @ctxt: the XPath Parser context
  9584. *
  9585. * [15] PrimaryExpr ::= VariableReference
  9586. * | '(' Expr ')'
  9587. * | Literal
  9588. * | Number
  9589. * | FunctionCall
  9590. *
  9591. * Compile a primary expression.
  9592. */
  9593. static void
  9594. xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
  9595. SKIP_BLANKS;
  9596. if (CUR == '$') xmlXPathCompVariableReference(ctxt);
  9597. else if (CUR == '(') {
  9598. NEXT;
  9599. SKIP_BLANKS;
  9600. xmlXPathCompileExpr(ctxt, 1);
  9601. CHECK_ERROR;
  9602. if (CUR != ')') {
  9603. XP_ERROR(XPATH_EXPR_ERROR);
  9604. }
  9605. NEXT;
  9606. SKIP_BLANKS;
  9607. } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
  9608. xmlXPathCompNumber(ctxt);
  9609. } else if ((CUR == '\'') || (CUR == '"')) {
  9610. xmlXPathCompLiteral(ctxt);
  9611. } else {
  9612. xmlXPathCompFunctionCall(ctxt);
  9613. }
  9614. SKIP_BLANKS;
  9615. }
  9616. /**
  9617. * xmlXPathCompFilterExpr:
  9618. * @ctxt: the XPath Parser context
  9619. *
  9620. * [20] FilterExpr ::= PrimaryExpr
  9621. * | FilterExpr Predicate
  9622. *
  9623. * Compile a filter expression.
  9624. * Square brackets are used to filter expressions in the same way that
  9625. * they are used in location paths. It is an error if the expression to
  9626. * be filtered does not evaluate to a node-set. The context node list
  9627. * used for evaluating the expression in square brackets is the node-set
  9628. * to be filtered listed in document order.
  9629. */
  9630. static void
  9631. xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
  9632. xmlXPathCompPrimaryExpr(ctxt);
  9633. CHECK_ERROR;
  9634. SKIP_BLANKS;
  9635. while (CUR == '[') {
  9636. xmlXPathCompPredicate(ctxt, 1);
  9637. SKIP_BLANKS;
  9638. }
  9639. }
  9640. /**
  9641. * xmlXPathScanName:
  9642. * @ctxt: the XPath Parser context
  9643. *
  9644. * Trickery: parse an XML name but without consuming the input flow
  9645. * Needed to avoid insanity in the parser state.
  9646. *
  9647. * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
  9648. * CombiningChar | Extender
  9649. *
  9650. * [5] Name ::= (Letter | '_' | ':') (NameChar)*
  9651. *
  9652. * [6] Names ::= Name (S Name)*
  9653. *
  9654. * Returns the Name parsed or NULL
  9655. */
  9656. static xmlChar *
  9657. xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
  9658. int len = 0, l;
  9659. int c;
  9660. const xmlChar *cur;
  9661. xmlChar *ret;
  9662. cur = ctxt->cur;
  9663. c = CUR_CHAR(l);
  9664. if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
  9665. (!IS_LETTER(c) && (c != '_') &&
  9666. (c != ':'))) {
  9667. return(NULL);
  9668. }
  9669. while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
  9670. ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
  9671. (c == '.') || (c == '-') ||
  9672. (c == '_') || (c == ':') ||
  9673. (IS_COMBINING(c)) ||
  9674. (IS_EXTENDER(c)))) {
  9675. len += l;
  9676. NEXTL(l);
  9677. c = CUR_CHAR(l);
  9678. }
  9679. ret = xmlStrndup(cur, ctxt->cur - cur);
  9680. ctxt->cur = cur;
  9681. return(ret);
  9682. }
  9683. /**
  9684. * xmlXPathCompPathExpr:
  9685. * @ctxt: the XPath Parser context
  9686. *
  9687. * [19] PathExpr ::= LocationPath
  9688. * | FilterExpr
  9689. * | FilterExpr '/' RelativeLocationPath
  9690. * | FilterExpr '//' RelativeLocationPath
  9691. *
  9692. * Compile a path expression.
  9693. * The / operator and // operators combine an arbitrary expression
  9694. * and a relative location path. It is an error if the expression
  9695. * does not evaluate to a node-set.
  9696. * The / operator does composition in the same way as when / is
  9697. * used in a location path. As in location paths, // is short for
  9698. * /descendant-or-self::node()/.
  9699. */
  9700. static void
  9701. xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
  9702. int lc = 1; /* Should we branch to LocationPath ? */
  9703. xmlChar *name = NULL; /* we may have to preparse a name to find out */
  9704. SKIP_BLANKS;
  9705. if ((CUR == '$') || (CUR == '(') ||
  9706. (IS_ASCII_DIGIT(CUR)) ||
  9707. (CUR == '\'') || (CUR == '"') ||
  9708. (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
  9709. lc = 0;
  9710. } else if (CUR == '*') {
  9711. /* relative or absolute location path */
  9712. lc = 1;
  9713. } else if (CUR == '/') {
  9714. /* relative or absolute location path */
  9715. lc = 1;
  9716. } else if (CUR == '@') {
  9717. /* relative abbreviated attribute location path */
  9718. lc = 1;
  9719. } else if (CUR == '.') {
  9720. /* relative abbreviated attribute location path */
  9721. lc = 1;
  9722. } else {
  9723. /*
  9724. * Problem is finding if we have a name here whether it's:
  9725. * - a nodetype
  9726. * - a function call in which case it's followed by '('
  9727. * - an axis in which case it's followed by ':'
  9728. * - a element name
  9729. * We do an a priori analysis here rather than having to
  9730. * maintain parsed token content through the recursive function
  9731. * calls. This looks uglier but makes the code easier to
  9732. * read/write/debug.
  9733. */
  9734. SKIP_BLANKS;
  9735. name = xmlXPathScanName(ctxt);
  9736. if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
  9737. #ifdef DEBUG_STEP
  9738. xmlGenericError(xmlGenericErrorContext,
  9739. "PathExpr: Axis\n");
  9740. #endif
  9741. lc = 1;
  9742. xmlFree(name);
  9743. } else if (name != NULL) {
  9744. int len =xmlStrlen(name);
  9745. while (NXT(len) != 0) {
  9746. if (NXT(len) == '/') {
  9747. /* element name */
  9748. #ifdef DEBUG_STEP
  9749. xmlGenericError(xmlGenericErrorContext,
  9750. "PathExpr: AbbrRelLocation\n");
  9751. #endif
  9752. lc = 1;
  9753. break;
  9754. } else if (IS_BLANK_CH(NXT(len))) {
  9755. /* ignore blanks */
  9756. ;
  9757. } else if (NXT(len) == ':') {
  9758. #ifdef DEBUG_STEP
  9759. xmlGenericError(xmlGenericErrorContext,
  9760. "PathExpr: AbbrRelLocation\n");
  9761. #endif
  9762. lc = 1;
  9763. break;
  9764. } else if ((NXT(len) == '(')) {
  9765. /* Note Type or Function */
  9766. if (xmlXPathIsNodeType(name)) {
  9767. #ifdef DEBUG_STEP
  9768. xmlGenericError(xmlGenericErrorContext,
  9769. "PathExpr: Type search\n");
  9770. #endif
  9771. lc = 1;
  9772. } else {
  9773. #ifdef DEBUG_STEP
  9774. xmlGenericError(xmlGenericErrorContext,
  9775. "PathExpr: function call\n");
  9776. #endif
  9777. lc = 0;
  9778. }
  9779. break;
  9780. } else if ((NXT(len) == '[')) {
  9781. /* element name */
  9782. #ifdef DEBUG_STEP
  9783. xmlGenericError(xmlGenericErrorContext,
  9784. "PathExpr: AbbrRelLocation\n");
  9785. #endif
  9786. lc = 1;
  9787. break;
  9788. } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
  9789. (NXT(len) == '=')) {
  9790. lc = 1;
  9791. break;
  9792. } else {
  9793. lc = 1;
  9794. break;
  9795. }
  9796. len++;
  9797. }
  9798. if (NXT(len) == 0) {
  9799. #ifdef DEBUG_STEP
  9800. xmlGenericError(xmlGenericErrorContext,
  9801. "PathExpr: AbbrRelLocation\n");
  9802. #endif
  9803. /* element name */
  9804. lc = 1;
  9805. }
  9806. xmlFree(name);
  9807. } else {
  9808. /* make sure all cases are covered explicitly */
  9809. XP_ERROR(XPATH_EXPR_ERROR);
  9810. }
  9811. }
  9812. if (lc) {
  9813. if (CUR == '/') {
  9814. PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
  9815. } else {
  9816. PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
  9817. }
  9818. xmlXPathCompLocationPath(ctxt);
  9819. } else {
  9820. xmlXPathCompFilterExpr(ctxt);
  9821. CHECK_ERROR;
  9822. if ((CUR == '/') && (NXT(1) == '/')) {
  9823. SKIP(2);
  9824. SKIP_BLANKS;
  9825. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
  9826. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  9827. PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
  9828. xmlXPathCompRelativeLocationPath(ctxt);
  9829. } else if (CUR == '/') {
  9830. xmlXPathCompRelativeLocationPath(ctxt);
  9831. }
  9832. }
  9833. SKIP_BLANKS;
  9834. }
  9835. /**
  9836. * xmlXPathCompUnionExpr:
  9837. * @ctxt: the XPath Parser context
  9838. *
  9839. * [18] UnionExpr ::= PathExpr
  9840. * | UnionExpr '|' PathExpr
  9841. *
  9842. * Compile an union expression.
  9843. */
  9844. static void
  9845. xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
  9846. xmlXPathCompPathExpr(ctxt);
  9847. CHECK_ERROR;
  9848. SKIP_BLANKS;
  9849. while (CUR == '|') {
  9850. int op1 = ctxt->comp->last;
  9851. PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
  9852. NEXT;
  9853. SKIP_BLANKS;
  9854. xmlXPathCompPathExpr(ctxt);
  9855. PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
  9856. SKIP_BLANKS;
  9857. }
  9858. }
  9859. /**
  9860. * xmlXPathCompUnaryExpr:
  9861. * @ctxt: the XPath Parser context
  9862. *
  9863. * [27] UnaryExpr ::= UnionExpr
  9864. * | '-' UnaryExpr
  9865. *
  9866. * Compile an unary expression.
  9867. */
  9868. static void
  9869. xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
  9870. int minus = 0;
  9871. int found = 0;
  9872. SKIP_BLANKS;
  9873. while (CUR == '-') {
  9874. minus = 1 - minus;
  9875. found = 1;
  9876. NEXT;
  9877. SKIP_BLANKS;
  9878. }
  9879. xmlXPathCompUnionExpr(ctxt);
  9880. CHECK_ERROR;
  9881. if (found) {
  9882. if (minus)
  9883. PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
  9884. else
  9885. PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
  9886. }
  9887. }
  9888. /**
  9889. * xmlXPathCompMultiplicativeExpr:
  9890. * @ctxt: the XPath Parser context
  9891. *
  9892. * [26] MultiplicativeExpr ::= UnaryExpr
  9893. * | MultiplicativeExpr MultiplyOperator UnaryExpr
  9894. * | MultiplicativeExpr 'div' UnaryExpr
  9895. * | MultiplicativeExpr 'mod' UnaryExpr
  9896. * [34] MultiplyOperator ::= '*'
  9897. *
  9898. * Compile an Additive expression.
  9899. */
  9900. static void
  9901. xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
  9902. xmlXPathCompUnaryExpr(ctxt);
  9903. CHECK_ERROR;
  9904. SKIP_BLANKS;
  9905. while ((CUR == '*') ||
  9906. ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
  9907. ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
  9908. int op = -1;
  9909. int op1 = ctxt->comp->last;
  9910. if (CUR == '*') {
  9911. op = 0;
  9912. NEXT;
  9913. } else if (CUR == 'd') {
  9914. op = 1;
  9915. SKIP(3);
  9916. } else if (CUR == 'm') {
  9917. op = 2;
  9918. SKIP(3);
  9919. }
  9920. SKIP_BLANKS;
  9921. xmlXPathCompUnaryExpr(ctxt);
  9922. CHECK_ERROR;
  9923. PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
  9924. SKIP_BLANKS;
  9925. }
  9926. }
  9927. /**
  9928. * xmlXPathCompAdditiveExpr:
  9929. * @ctxt: the XPath Parser context
  9930. *
  9931. * [25] AdditiveExpr ::= MultiplicativeExpr
  9932. * | AdditiveExpr '+' MultiplicativeExpr
  9933. * | AdditiveExpr '-' MultiplicativeExpr
  9934. *
  9935. * Compile an Additive expression.
  9936. */
  9937. static void
  9938. xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
  9939. xmlXPathCompMultiplicativeExpr(ctxt);
  9940. CHECK_ERROR;
  9941. SKIP_BLANKS;
  9942. while ((CUR == '+') || (CUR == '-')) {
  9943. int plus;
  9944. int op1 = ctxt->comp->last;
  9945. if (CUR == '+') plus = 1;
  9946. else plus = 0;
  9947. NEXT;
  9948. SKIP_BLANKS;
  9949. xmlXPathCompMultiplicativeExpr(ctxt);
  9950. CHECK_ERROR;
  9951. PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
  9952. SKIP_BLANKS;
  9953. }
  9954. }
  9955. /**
  9956. * xmlXPathCompRelationalExpr:
  9957. * @ctxt: the XPath Parser context
  9958. *
  9959. * [24] RelationalExpr ::= AdditiveExpr
  9960. * | RelationalExpr '<' AdditiveExpr
  9961. * | RelationalExpr '>' AdditiveExpr
  9962. * | RelationalExpr '<=' AdditiveExpr
  9963. * | RelationalExpr '>=' AdditiveExpr
  9964. *
  9965. * A <= B > C is allowed ? Answer from James, yes with
  9966. * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
  9967. * which is basically what got implemented.
  9968. *
  9969. * Compile a Relational expression, then push the result
  9970. * on the stack
  9971. */
  9972. static void
  9973. xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
  9974. xmlXPathCompAdditiveExpr(ctxt);
  9975. CHECK_ERROR;
  9976. SKIP_BLANKS;
  9977. while ((CUR == '<') ||
  9978. (CUR == '>') ||
  9979. ((CUR == '<') && (NXT(1) == '=')) ||
  9980. ((CUR == '>') && (NXT(1) == '='))) {
  9981. int inf, strict;
  9982. int op1 = ctxt->comp->last;
  9983. if (CUR == '<') inf = 1;
  9984. else inf = 0;
  9985. if (NXT(1) == '=') strict = 0;
  9986. else strict = 1;
  9987. NEXT;
  9988. if (!strict) NEXT;
  9989. SKIP_BLANKS;
  9990. xmlXPathCompAdditiveExpr(ctxt);
  9991. CHECK_ERROR;
  9992. PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
  9993. SKIP_BLANKS;
  9994. }
  9995. }
  9996. /**
  9997. * xmlXPathCompEqualityExpr:
  9998. * @ctxt: the XPath Parser context
  9999. *
  10000. * [23] EqualityExpr ::= RelationalExpr
  10001. * | EqualityExpr '=' RelationalExpr
  10002. * | EqualityExpr '!=' RelationalExpr
  10003. *
  10004. * A != B != C is allowed ? Answer from James, yes with
  10005. * (RelationalExpr = RelationalExpr) = RelationalExpr
  10006. * (RelationalExpr != RelationalExpr) != RelationalExpr
  10007. * which is basically what got implemented.
  10008. *
  10009. * Compile an Equality expression.
  10010. *
  10011. */
  10012. static void
  10013. xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
  10014. xmlXPathCompRelationalExpr(ctxt);
  10015. CHECK_ERROR;
  10016. SKIP_BLANKS;
  10017. while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
  10018. int eq;
  10019. int op1 = ctxt->comp->last;
  10020. if (CUR == '=') eq = 1;
  10021. else eq = 0;
  10022. NEXT;
  10023. if (!eq) NEXT;
  10024. SKIP_BLANKS;
  10025. xmlXPathCompRelationalExpr(ctxt);
  10026. CHECK_ERROR;
  10027. PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
  10028. SKIP_BLANKS;
  10029. }
  10030. }
  10031. /**
  10032. * xmlXPathCompAndExpr:
  10033. * @ctxt: the XPath Parser context
  10034. *
  10035. * [22] AndExpr ::= EqualityExpr
  10036. * | AndExpr 'and' EqualityExpr
  10037. *
  10038. * Compile an AND expression.
  10039. *
  10040. */
  10041. static void
  10042. xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
  10043. xmlXPathCompEqualityExpr(ctxt);
  10044. CHECK_ERROR;
  10045. SKIP_BLANKS;
  10046. while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
  10047. int op1 = ctxt->comp->last;
  10048. SKIP(3);
  10049. SKIP_BLANKS;
  10050. xmlXPathCompEqualityExpr(ctxt);
  10051. CHECK_ERROR;
  10052. PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
  10053. SKIP_BLANKS;
  10054. }
  10055. }
  10056. /**
  10057. * xmlXPathCompileExpr:
  10058. * @ctxt: the XPath Parser context
  10059. *
  10060. * [14] Expr ::= OrExpr
  10061. * [21] OrExpr ::= AndExpr
  10062. * | OrExpr 'or' AndExpr
  10063. *
  10064. * Parse and compile an expression
  10065. */
  10066. static void
  10067. xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
  10068. xmlXPathCompAndExpr(ctxt);
  10069. CHECK_ERROR;
  10070. SKIP_BLANKS;
  10071. while ((CUR == 'o') && (NXT(1) == 'r')) {
  10072. int op1 = ctxt->comp->last;
  10073. SKIP(2);
  10074. SKIP_BLANKS;
  10075. xmlXPathCompAndExpr(ctxt);
  10076. CHECK_ERROR;
  10077. PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
  10078. SKIP_BLANKS;
  10079. }
  10080. if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
  10081. /* more ops could be optimized too */
  10082. /*
  10083. * This is the main place to eliminate sorting for
  10084. * operations which don't require a sorted node-set.
  10085. * E.g. count().
  10086. */
  10087. PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
  10088. }
  10089. }
  10090. /**
  10091. * xmlXPathCompPredicate:
  10092. * @ctxt: the XPath Parser context
  10093. * @filter: act as a filter
  10094. *
  10095. * [8] Predicate ::= '[' PredicateExpr ']'
  10096. * [9] PredicateExpr ::= Expr
  10097. *
  10098. * Compile a predicate expression
  10099. */
  10100. static void
  10101. xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
  10102. int op1 = ctxt->comp->last;
  10103. SKIP_BLANKS;
  10104. if (CUR != '[') {
  10105. XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
  10106. }
  10107. NEXT;
  10108. SKIP_BLANKS;
  10109. ctxt->comp->last = -1;
  10110. /*
  10111. * This call to xmlXPathCompileExpr() will deactivate sorting
  10112. * of the predicate result.
  10113. * TODO: Sorting is still activated for filters, since I'm not
  10114. * sure if needed. Normally sorting should not be needed, since
  10115. * a filter can only diminish the number of items in a sequence,
  10116. * but won't change its order; so if the initial sequence is sorted,
  10117. * subsequent sorting is not needed.
  10118. */
  10119. if (! filter)
  10120. xmlXPathCompileExpr(ctxt, 0);
  10121. else
  10122. xmlXPathCompileExpr(ctxt, 1);
  10123. CHECK_ERROR;
  10124. if (CUR != ']') {
  10125. XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
  10126. }
  10127. if (filter)
  10128. PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
  10129. else
  10130. PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
  10131. NEXT;
  10132. SKIP_BLANKS;
  10133. }
  10134. /**
  10135. * xmlXPathCompNodeTest:
  10136. * @ctxt: the XPath Parser context
  10137. * @test: pointer to a xmlXPathTestVal
  10138. * @type: pointer to a xmlXPathTypeVal
  10139. * @prefix: placeholder for a possible name prefix
  10140. *
  10141. * [7] NodeTest ::= NameTest
  10142. * | NodeType '(' ')'
  10143. * | 'processing-instruction' '(' Literal ')'
  10144. *
  10145. * [37] NameTest ::= '*'
  10146. * | NCName ':' '*'
  10147. * | QName
  10148. * [38] NodeType ::= 'comment'
  10149. * | 'text'
  10150. * | 'processing-instruction'
  10151. * | 'node'
  10152. *
  10153. * Returns the name found and updates @test, @type and @prefix appropriately
  10154. */
  10155. static xmlChar *
  10156. xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
  10157. xmlXPathTypeVal *type, const xmlChar **prefix,
  10158. xmlChar *name) {
  10159. int blanks;
  10160. if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
  10161. STRANGE;
  10162. return(NULL);
  10163. }
  10164. *type = (xmlXPathTypeVal) 0;
  10165. *test = (xmlXPathTestVal) 0;
  10166. *prefix = NULL;
  10167. SKIP_BLANKS;
  10168. if ((name == NULL) && (CUR == '*')) {
  10169. /*
  10170. * All elements
  10171. */
  10172. NEXT;
  10173. *test = NODE_TEST_ALL;
  10174. return(NULL);
  10175. }
  10176. if (name == NULL)
  10177. name = xmlXPathParseNCName(ctxt);
  10178. if (name == NULL) {
  10179. XP_ERRORNULL(XPATH_EXPR_ERROR);
  10180. }
  10181. blanks = IS_BLANK_CH(CUR);
  10182. SKIP_BLANKS;
  10183. if (CUR == '(') {
  10184. NEXT;
  10185. /*
  10186. * NodeType or PI search
  10187. */
  10188. if (xmlStrEqual(name, BAD_CAST "comment"))
  10189. *type = NODE_TYPE_COMMENT;
  10190. else if (xmlStrEqual(name, BAD_CAST "node"))
  10191. *type = NODE_TYPE_NODE;
  10192. else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
  10193. *type = NODE_TYPE_PI;
  10194. else if (xmlStrEqual(name, BAD_CAST "text"))
  10195. *type = NODE_TYPE_TEXT;
  10196. else {
  10197. if (name != NULL)
  10198. xmlFree(name);
  10199. XP_ERRORNULL(XPATH_EXPR_ERROR);
  10200. }
  10201. *test = NODE_TEST_TYPE;
  10202. SKIP_BLANKS;
  10203. if (*type == NODE_TYPE_PI) {
  10204. /*
  10205. * Specific case: search a PI by name.
  10206. */
  10207. if (name != NULL)
  10208. xmlFree(name);
  10209. name = NULL;
  10210. if (CUR != ')') {
  10211. name = xmlXPathParseLiteral(ctxt);
  10212. CHECK_ERROR NULL;
  10213. *test = NODE_TEST_PI;
  10214. SKIP_BLANKS;
  10215. }
  10216. }
  10217. if (CUR != ')') {
  10218. if (name != NULL)
  10219. xmlFree(name);
  10220. XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
  10221. }
  10222. NEXT;
  10223. return(name);
  10224. }
  10225. *test = NODE_TEST_NAME;
  10226. if ((!blanks) && (CUR == ':')) {
  10227. NEXT;
  10228. /*
  10229. * Since currently the parser context don't have a
  10230. * namespace list associated:
  10231. * The namespace name for this prefix can be computed
  10232. * only at evaluation time. The compilation is done
  10233. * outside of any context.
  10234. */
  10235. #if 0
  10236. *prefix = xmlXPathNsLookup(ctxt->context, name);
  10237. if (name != NULL)
  10238. xmlFree(name);
  10239. if (*prefix == NULL) {
  10240. XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
  10241. }
  10242. #else
  10243. *prefix = name;
  10244. #endif
  10245. if (CUR == '*') {
  10246. /*
  10247. * All elements
  10248. */
  10249. NEXT;
  10250. *test = NODE_TEST_ALL;
  10251. return(NULL);
  10252. }
  10253. name = xmlXPathParseNCName(ctxt);
  10254. if (name == NULL) {
  10255. XP_ERRORNULL(XPATH_EXPR_ERROR);
  10256. }
  10257. }
  10258. return(name);
  10259. }
  10260. /**
  10261. * xmlXPathIsAxisName:
  10262. * @name: a preparsed name token
  10263. *
  10264. * [6] AxisName ::= 'ancestor'
  10265. * | 'ancestor-or-self'
  10266. * | 'attribute'
  10267. * | 'child'
  10268. * | 'descendant'
  10269. * | 'descendant-or-self'
  10270. * | 'following'
  10271. * | 'following-sibling'
  10272. * | 'namespace'
  10273. * | 'parent'
  10274. * | 'preceding'
  10275. * | 'preceding-sibling'
  10276. * | 'self'
  10277. *
  10278. * Returns the axis or 0
  10279. */
  10280. static xmlXPathAxisVal
  10281. xmlXPathIsAxisName(const xmlChar *name) {
  10282. xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
  10283. switch (name[0]) {
  10284. case 'a':
  10285. if (xmlStrEqual(name, BAD_CAST "ancestor"))
  10286. ret = AXIS_ANCESTOR;
  10287. if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
  10288. ret = AXIS_ANCESTOR_OR_SELF;
  10289. if (xmlStrEqual(name, BAD_CAST "attribute"))
  10290. ret = AXIS_ATTRIBUTE;
  10291. break;
  10292. case 'c':
  10293. if (xmlStrEqual(name, BAD_CAST "child"))
  10294. ret = AXIS_CHILD;
  10295. break;
  10296. case 'd':
  10297. if (xmlStrEqual(name, BAD_CAST "descendant"))
  10298. ret = AXIS_DESCENDANT;
  10299. if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
  10300. ret = AXIS_DESCENDANT_OR_SELF;
  10301. break;
  10302. case 'f':
  10303. if (xmlStrEqual(name, BAD_CAST "following"))
  10304. ret = AXIS_FOLLOWING;
  10305. if (xmlStrEqual(name, BAD_CAST "following-sibling"))
  10306. ret = AXIS_FOLLOWING_SIBLING;
  10307. break;
  10308. case 'n':
  10309. if (xmlStrEqual(name, BAD_CAST "namespace"))
  10310. ret = AXIS_NAMESPACE;
  10311. break;
  10312. case 'p':
  10313. if (xmlStrEqual(name, BAD_CAST "parent"))
  10314. ret = AXIS_PARENT;
  10315. if (xmlStrEqual(name, BAD_CAST "preceding"))
  10316. ret = AXIS_PRECEDING;
  10317. if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
  10318. ret = AXIS_PRECEDING_SIBLING;
  10319. break;
  10320. case 's':
  10321. if (xmlStrEqual(name, BAD_CAST "self"))
  10322. ret = AXIS_SELF;
  10323. break;
  10324. }
  10325. return(ret);
  10326. }
  10327. /**
  10328. * xmlXPathCompStep:
  10329. * @ctxt: the XPath Parser context
  10330. *
  10331. * [4] Step ::= AxisSpecifier NodeTest Predicate*
  10332. * | AbbreviatedStep
  10333. *
  10334. * [12] AbbreviatedStep ::= '.' | '..'
  10335. *
  10336. * [5] AxisSpecifier ::= AxisName '::'
  10337. * | AbbreviatedAxisSpecifier
  10338. *
  10339. * [13] AbbreviatedAxisSpecifier ::= '@'?
  10340. *
  10341. * Modified for XPtr range support as:
  10342. *
  10343. * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
  10344. * | AbbreviatedStep
  10345. * | 'range-to' '(' Expr ')' Predicate*
  10346. *
  10347. * Compile one step in a Location Path
  10348. * A location step of . is short for self::node(). This is
  10349. * particularly useful in conjunction with //. For example, the
  10350. * location path .//para is short for
  10351. * self::node()/descendant-or-self::node()/child::para
  10352. * and so will select all para descendant elements of the context
  10353. * node.
  10354. * Similarly, a location step of .. is short for parent::node().
  10355. * For example, ../title is short for parent::node()/child::title
  10356. * and so will select the title children of the parent of the context
  10357. * node.
  10358. */
  10359. static void
  10360. xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
  10361. #ifdef LIBXML_XPTR_ENABLED
  10362. int rangeto = 0;
  10363. int op2 = -1;
  10364. #endif
  10365. SKIP_BLANKS;
  10366. if ((CUR == '.') && (NXT(1) == '.')) {
  10367. SKIP(2);
  10368. SKIP_BLANKS;
  10369. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
  10370. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  10371. } else if (CUR == '.') {
  10372. NEXT;
  10373. SKIP_BLANKS;
  10374. } else {
  10375. xmlChar *name = NULL;
  10376. const xmlChar *prefix = NULL;
  10377. xmlXPathTestVal test = (xmlXPathTestVal) 0;
  10378. xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
  10379. xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
  10380. int op1;
  10381. /*
  10382. * The modification needed for XPointer change to the production
  10383. */
  10384. #ifdef LIBXML_XPTR_ENABLED
  10385. if (ctxt->xptr) {
  10386. name = xmlXPathParseNCName(ctxt);
  10387. if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
  10388. op2 = ctxt->comp->last;
  10389. xmlFree(name);
  10390. SKIP_BLANKS;
  10391. if (CUR != '(') {
  10392. XP_ERROR(XPATH_EXPR_ERROR);
  10393. }
  10394. NEXT;
  10395. SKIP_BLANKS;
  10396. xmlXPathCompileExpr(ctxt, 1);
  10397. /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
  10398. CHECK_ERROR;
  10399. SKIP_BLANKS;
  10400. if (CUR != ')') {
  10401. XP_ERROR(XPATH_EXPR_ERROR);
  10402. }
  10403. NEXT;
  10404. rangeto = 1;
  10405. goto eval_predicates;
  10406. }
  10407. }
  10408. #endif
  10409. if (CUR == '*') {
  10410. axis = AXIS_CHILD;
  10411. } else {
  10412. if (name == NULL)
  10413. name = xmlXPathParseNCName(ctxt);
  10414. if (name != NULL) {
  10415. axis = xmlXPathIsAxisName(name);
  10416. if (axis != 0) {
  10417. SKIP_BLANKS;
  10418. if ((CUR == ':') && (NXT(1) == ':')) {
  10419. SKIP(2);
  10420. xmlFree(name);
  10421. name = NULL;
  10422. } else {
  10423. /* an element name can conflict with an axis one :-\ */
  10424. axis = AXIS_CHILD;
  10425. }
  10426. } else {
  10427. axis = AXIS_CHILD;
  10428. }
  10429. } else if (CUR == '@') {
  10430. NEXT;
  10431. axis = AXIS_ATTRIBUTE;
  10432. } else {
  10433. axis = AXIS_CHILD;
  10434. }
  10435. }
  10436. CHECK_ERROR;
  10437. name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
  10438. if (test == 0)
  10439. return;
  10440. if ((prefix != NULL) && (ctxt->context != NULL) &&
  10441. (ctxt->context->flags & XML_XPATH_CHECKNS)) {
  10442. if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
  10443. xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
  10444. }
  10445. }
  10446. #ifdef DEBUG_STEP
  10447. xmlGenericError(xmlGenericErrorContext,
  10448. "Basis : computing new set\n");
  10449. #endif
  10450. #ifdef DEBUG_STEP
  10451. xmlGenericError(xmlGenericErrorContext, "Basis : ");
  10452. if (ctxt->value == NULL)
  10453. xmlGenericError(xmlGenericErrorContext, "no value\n");
  10454. else if (ctxt->value->nodesetval == NULL)
  10455. xmlGenericError(xmlGenericErrorContext, "Empty\n");
  10456. else
  10457. xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
  10458. #endif
  10459. #ifdef LIBXML_XPTR_ENABLED
  10460. eval_predicates:
  10461. #endif
  10462. op1 = ctxt->comp->last;
  10463. ctxt->comp->last = -1;
  10464. SKIP_BLANKS;
  10465. while (CUR == '[') {
  10466. xmlXPathCompPredicate(ctxt, 0);
  10467. }
  10468. #ifdef LIBXML_XPTR_ENABLED
  10469. if (rangeto) {
  10470. PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
  10471. } else
  10472. #endif
  10473. PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
  10474. test, type, (void *)prefix, (void *)name);
  10475. }
  10476. #ifdef DEBUG_STEP
  10477. xmlGenericError(xmlGenericErrorContext, "Step : ");
  10478. if (ctxt->value == NULL)
  10479. xmlGenericError(xmlGenericErrorContext, "no value\n");
  10480. else if (ctxt->value->nodesetval == NULL)
  10481. xmlGenericError(xmlGenericErrorContext, "Empty\n");
  10482. else
  10483. xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
  10484. ctxt->value->nodesetval);
  10485. #endif
  10486. }
  10487. /**
  10488. * xmlXPathCompRelativeLocationPath:
  10489. * @ctxt: the XPath Parser context
  10490. *
  10491. * [3] RelativeLocationPath ::= Step
  10492. * | RelativeLocationPath '/' Step
  10493. * | AbbreviatedRelativeLocationPath
  10494. * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
  10495. *
  10496. * Compile a relative location path.
  10497. */
  10498. static void
  10499. xmlXPathCompRelativeLocationPath
  10500. (xmlXPathParserContextPtr ctxt) {
  10501. SKIP_BLANKS;
  10502. if ((CUR == '/') && (NXT(1) == '/')) {
  10503. SKIP(2);
  10504. SKIP_BLANKS;
  10505. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
  10506. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  10507. } else if (CUR == '/') {
  10508. NEXT;
  10509. SKIP_BLANKS;
  10510. }
  10511. xmlXPathCompStep(ctxt);
  10512. CHECK_ERROR;
  10513. SKIP_BLANKS;
  10514. while (CUR == '/') {
  10515. if ((CUR == '/') && (NXT(1) == '/')) {
  10516. SKIP(2);
  10517. SKIP_BLANKS;
  10518. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
  10519. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  10520. xmlXPathCompStep(ctxt);
  10521. } else if (CUR == '/') {
  10522. NEXT;
  10523. SKIP_BLANKS;
  10524. xmlXPathCompStep(ctxt);
  10525. }
  10526. SKIP_BLANKS;
  10527. }
  10528. }
  10529. /**
  10530. * xmlXPathCompLocationPath:
  10531. * @ctxt: the XPath Parser context
  10532. *
  10533. * [1] LocationPath ::= RelativeLocationPath
  10534. * | AbsoluteLocationPath
  10535. * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
  10536. * | AbbreviatedAbsoluteLocationPath
  10537. * [10] AbbreviatedAbsoluteLocationPath ::=
  10538. * '//' RelativeLocationPath
  10539. *
  10540. * Compile a location path
  10541. *
  10542. * // is short for /descendant-or-self::node()/. For example,
  10543. * //para is short for /descendant-or-self::node()/child::para and
  10544. * so will select any para element in the document (even a para element
  10545. * that is a document element will be selected by //para since the
  10546. * document element node is a child of the root node); div//para is
  10547. * short for div/descendant-or-self::node()/child::para and so will
  10548. * select all para descendants of div children.
  10549. */
  10550. static void
  10551. xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
  10552. SKIP_BLANKS;
  10553. if (CUR != '/') {
  10554. xmlXPathCompRelativeLocationPath(ctxt);
  10555. } else {
  10556. while (CUR == '/') {
  10557. if ((CUR == '/') && (NXT(1) == '/')) {
  10558. SKIP(2);
  10559. SKIP_BLANKS;
  10560. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
  10561. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  10562. xmlXPathCompRelativeLocationPath(ctxt);
  10563. } else if (CUR == '/') {
  10564. NEXT;
  10565. SKIP_BLANKS;
  10566. if ((CUR != 0 ) &&
  10567. ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
  10568. (CUR == '@') || (CUR == '*')))
  10569. xmlXPathCompRelativeLocationPath(ctxt);
  10570. }
  10571. CHECK_ERROR;
  10572. }
  10573. }
  10574. }
  10575. /************************************************************************
  10576. * *
  10577. * XPath precompiled expression evaluation *
  10578. * *
  10579. ************************************************************************/
  10580. static int
  10581. xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
  10582. #ifdef DEBUG_STEP
  10583. static void
  10584. xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
  10585. int nbNodes)
  10586. {
  10587. xmlGenericError(xmlGenericErrorContext, "new step : ");
  10588. switch (op->value) {
  10589. case AXIS_ANCESTOR:
  10590. xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
  10591. break;
  10592. case AXIS_ANCESTOR_OR_SELF:
  10593. xmlGenericError(xmlGenericErrorContext,
  10594. "axis 'ancestors-or-self' ");
  10595. break;
  10596. case AXIS_ATTRIBUTE:
  10597. xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
  10598. break;
  10599. case AXIS_CHILD:
  10600. xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
  10601. break;
  10602. case AXIS_DESCENDANT:
  10603. xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
  10604. break;
  10605. case AXIS_DESCENDANT_OR_SELF:
  10606. xmlGenericError(xmlGenericErrorContext,
  10607. "axis 'descendant-or-self' ");
  10608. break;
  10609. case AXIS_FOLLOWING:
  10610. xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
  10611. break;
  10612. case AXIS_FOLLOWING_SIBLING:
  10613. xmlGenericError(xmlGenericErrorContext,
  10614. "axis 'following-siblings' ");
  10615. break;
  10616. case AXIS_NAMESPACE:
  10617. xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
  10618. break;
  10619. case AXIS_PARENT:
  10620. xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
  10621. break;
  10622. case AXIS_PRECEDING:
  10623. xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
  10624. break;
  10625. case AXIS_PRECEDING_SIBLING:
  10626. xmlGenericError(xmlGenericErrorContext,
  10627. "axis 'preceding-sibling' ");
  10628. break;
  10629. case AXIS_SELF:
  10630. xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
  10631. break;
  10632. }
  10633. xmlGenericError(xmlGenericErrorContext,
  10634. " context contains %d nodes\n", nbNodes);
  10635. switch (op->value2) {
  10636. case NODE_TEST_NONE:
  10637. xmlGenericError(xmlGenericErrorContext,
  10638. " searching for none !!!\n");
  10639. break;
  10640. case NODE_TEST_TYPE:
  10641. xmlGenericError(xmlGenericErrorContext,
  10642. " searching for type %d\n", op->value3);
  10643. break;
  10644. case NODE_TEST_PI:
  10645. xmlGenericError(xmlGenericErrorContext,
  10646. " searching for PI !!!\n");
  10647. break;
  10648. case NODE_TEST_ALL:
  10649. xmlGenericError(xmlGenericErrorContext,
  10650. " searching for *\n");
  10651. break;
  10652. case NODE_TEST_NS:
  10653. xmlGenericError(xmlGenericErrorContext,
  10654. " searching for namespace %s\n",
  10655. op->value5);
  10656. break;
  10657. case NODE_TEST_NAME:
  10658. xmlGenericError(xmlGenericErrorContext,
  10659. " searching for name %s\n", op->value5);
  10660. if (op->value4)
  10661. xmlGenericError(xmlGenericErrorContext,
  10662. " with namespace %s\n", op->value4);
  10663. break;
  10664. }
  10665. xmlGenericError(xmlGenericErrorContext, "Testing : ");
  10666. }
  10667. #endif /* DEBUG_STEP */
  10668. static int
  10669. xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
  10670. xmlXPathStepOpPtr op,
  10671. xmlNodeSetPtr set,
  10672. int contextSize,
  10673. int hasNsNodes)
  10674. {
  10675. if (op->ch1 != -1) {
  10676. xmlXPathCompExprPtr comp = ctxt->comp;
  10677. /*
  10678. * Process inner predicates first.
  10679. */
  10680. if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
  10681. /*
  10682. * TODO: raise an internal error.
  10683. */
  10684. }
  10685. contextSize = xmlXPathCompOpEvalPredicate(ctxt,
  10686. &comp->steps[op->ch1], set, contextSize, hasNsNodes);
  10687. CHECK_ERROR0;
  10688. if (contextSize <= 0)
  10689. return(0);
  10690. }
  10691. if (op->ch2 != -1) {
  10692. xmlXPathContextPtr xpctxt = ctxt->context;
  10693. xmlNodePtr contextNode, oldContextNode;
  10694. xmlDocPtr oldContextDoc;
  10695. int i, res, contextPos = 0, newContextSize;
  10696. xmlXPathStepOpPtr exprOp;
  10697. xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
  10698. #ifdef LIBXML_XPTR_ENABLED
  10699. /*
  10700. * URGENT TODO: Check the following:
  10701. * We don't expect location sets if evaluating prediates, right?
  10702. * Only filters should expect location sets, right?
  10703. */
  10704. #endif
  10705. /*
  10706. * SPEC XPath 1.0:
  10707. * "For each node in the node-set to be filtered, the
  10708. * PredicateExpr is evaluated with that node as the
  10709. * context node, with the number of nodes in the
  10710. * node-set as the context size, and with the proximity
  10711. * position of the node in the node-set with respect to
  10712. * the axis as the context position;"
  10713. * @oldset is the node-set" to be filtered.
  10714. *
  10715. * SPEC XPath 1.0:
  10716. * "only predicates change the context position and
  10717. * context size (see [2.4 Predicates])."
  10718. * Example:
  10719. * node-set context pos
  10720. * nA 1
  10721. * nB 2
  10722. * nC 3
  10723. * After applying predicate [position() > 1] :
  10724. * node-set context pos
  10725. * nB 1
  10726. * nC 2
  10727. */
  10728. oldContextNode = xpctxt->node;
  10729. oldContextDoc = xpctxt->doc;
  10730. /*
  10731. * Get the expression of this predicate.
  10732. */
  10733. exprOp = &ctxt->comp->steps[op->ch2];
  10734. newContextSize = 0;
  10735. for (i = 0; i < set->nodeNr; i++) {
  10736. if (set->nodeTab[i] == NULL)
  10737. continue;
  10738. contextNode = set->nodeTab[i];
  10739. xpctxt->node = contextNode;
  10740. xpctxt->contextSize = contextSize;
  10741. xpctxt->proximityPosition = ++contextPos;
  10742. /*
  10743. * Also set the xpath document in case things like
  10744. * key() are evaluated in the predicate.
  10745. */
  10746. if ((contextNode->type != XML_NAMESPACE_DECL) &&
  10747. (contextNode->doc != NULL))
  10748. xpctxt->doc = contextNode->doc;
  10749. /*
  10750. * Evaluate the predicate expression with 1 context node
  10751. * at a time; this node is packaged into a node set; this
  10752. * node set is handed over to the evaluation mechanism.
  10753. */
  10754. if (contextObj == NULL)
  10755. contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
  10756. else
  10757. xmlXPathNodeSetAddUnique(contextObj->nodesetval,
  10758. contextNode);
  10759. valuePush(ctxt, contextObj);
  10760. res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
  10761. if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
  10762. xmlXPathNodeSetClear(set, hasNsNodes);
  10763. newContextSize = 0;
  10764. goto evaluation_exit;
  10765. }
  10766. if (res != 0) {
  10767. newContextSize++;
  10768. } else {
  10769. /*
  10770. * Remove the entry from the initial node set.
  10771. */
  10772. set->nodeTab[i] = NULL;
  10773. if (contextNode->type == XML_NAMESPACE_DECL)
  10774. xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
  10775. }
  10776. if (ctxt->value == contextObj) {
  10777. /*
  10778. * Don't free the temporary XPath object holding the
  10779. * context node, in order to avoid massive recreation
  10780. * inside this loop.
  10781. */
  10782. valuePop(ctxt);
  10783. xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
  10784. } else {
  10785. /*
  10786. * TODO: The object was lost in the evaluation machinery.
  10787. * Can this happen? Maybe in internal-error cases.
  10788. */
  10789. contextObj = NULL;
  10790. }
  10791. }
  10792. if (contextObj != NULL) {
  10793. if (ctxt->value == contextObj)
  10794. valuePop(ctxt);
  10795. xmlXPathReleaseObject(xpctxt, contextObj);
  10796. }
  10797. evaluation_exit:
  10798. if (exprRes != NULL)
  10799. xmlXPathReleaseObject(ctxt->context, exprRes);
  10800. /*
  10801. * Reset/invalidate the context.
  10802. */
  10803. xpctxt->node = oldContextNode;
  10804. xpctxt->doc = oldContextDoc;
  10805. xpctxt->contextSize = -1;
  10806. xpctxt->proximityPosition = -1;
  10807. return(newContextSize);
  10808. }
  10809. return(contextSize);
  10810. }
  10811. static int
  10812. xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
  10813. xmlXPathStepOpPtr op,
  10814. xmlNodeSetPtr set,
  10815. int contextSize,
  10816. int minPos,
  10817. int maxPos,
  10818. int hasNsNodes)
  10819. {
  10820. if (op->ch1 != -1) {
  10821. xmlXPathCompExprPtr comp = ctxt->comp;
  10822. if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
  10823. /*
  10824. * TODO: raise an internal error.
  10825. */
  10826. }
  10827. contextSize = xmlXPathCompOpEvalPredicate(ctxt,
  10828. &comp->steps[op->ch1], set, contextSize, hasNsNodes);
  10829. CHECK_ERROR0;
  10830. if (contextSize <= 0)
  10831. return(0);
  10832. }
  10833. /*
  10834. * Check if the node set contains a sufficient number of nodes for
  10835. * the requested range.
  10836. */
  10837. if (contextSize < minPos) {
  10838. xmlXPathNodeSetClear(set, hasNsNodes);
  10839. return(0);
  10840. }
  10841. if (op->ch2 == -1) {
  10842. /*
  10843. * TODO: Can this ever happen?
  10844. */
  10845. return (contextSize);
  10846. } else {
  10847. xmlDocPtr oldContextDoc;
  10848. int i, pos = 0, newContextSize = 0, contextPos = 0, res;
  10849. xmlXPathStepOpPtr exprOp;
  10850. xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
  10851. xmlNodePtr oldContextNode, contextNode = NULL;
  10852. xmlXPathContextPtr xpctxt = ctxt->context;
  10853. #ifdef LIBXML_XPTR_ENABLED
  10854. /*
  10855. * URGENT TODO: Check the following:
  10856. * We don't expect location sets if evaluating prediates, right?
  10857. * Only filters should expect location sets, right?
  10858. */
  10859. #endif /* LIBXML_XPTR_ENABLED */
  10860. /*
  10861. * Save old context.
  10862. */
  10863. oldContextNode = xpctxt->node;
  10864. oldContextDoc = xpctxt->doc;
  10865. /*
  10866. * Get the expression of this predicate.
  10867. */
  10868. exprOp = &ctxt->comp->steps[op->ch2];
  10869. for (i = 0; i < set->nodeNr; i++) {
  10870. if (set->nodeTab[i] == NULL)
  10871. continue;
  10872. contextNode = set->nodeTab[i];
  10873. xpctxt->node = contextNode;
  10874. xpctxt->contextSize = contextSize;
  10875. xpctxt->proximityPosition = ++contextPos;
  10876. /*
  10877. * Initialize the new set.
  10878. * Also set the xpath document in case things like
  10879. * key() evaluation are attempted on the predicate
  10880. */
  10881. if ((contextNode->type != XML_NAMESPACE_DECL) &&
  10882. (contextNode->doc != NULL))
  10883. xpctxt->doc = contextNode->doc;
  10884. /*
  10885. * Evaluate the predicate expression with 1 context node
  10886. * at a time; this node is packaged into a node set; this
  10887. * node set is handed over to the evaluation mechanism.
  10888. */
  10889. if (contextObj == NULL)
  10890. contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
  10891. else
  10892. xmlXPathNodeSetAddUnique(contextObj->nodesetval,
  10893. contextNode);
  10894. valuePush(ctxt, contextObj);
  10895. res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
  10896. if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
  10897. xmlXPathObjectPtr tmp;
  10898. /* pop the result */
  10899. tmp = valuePop(ctxt);
  10900. xmlXPathReleaseObject(xpctxt, tmp);
  10901. /* then pop off contextObj, which will be freed later */
  10902. valuePop(ctxt);
  10903. goto evaluation_error;
  10904. }
  10905. if (res)
  10906. pos++;
  10907. if (res && (pos >= minPos) && (pos <= maxPos)) {
  10908. /*
  10909. * Fits in the requested range.
  10910. */
  10911. newContextSize++;
  10912. if (minPos == maxPos) {
  10913. /*
  10914. * Only 1 node was requested.
  10915. */
  10916. if (contextNode->type == XML_NAMESPACE_DECL) {
  10917. /*
  10918. * As always: take care of those nasty
  10919. * namespace nodes.
  10920. */
  10921. set->nodeTab[i] = NULL;
  10922. }
  10923. xmlXPathNodeSetClear(set, hasNsNodes);
  10924. set->nodeNr = 1;
  10925. set->nodeTab[0] = contextNode;
  10926. goto evaluation_exit;
  10927. }
  10928. if (pos == maxPos) {
  10929. /*
  10930. * We are done.
  10931. */
  10932. xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
  10933. goto evaluation_exit;
  10934. }
  10935. } else {
  10936. /*
  10937. * Remove the entry from the initial node set.
  10938. */
  10939. set->nodeTab[i] = NULL;
  10940. if (contextNode->type == XML_NAMESPACE_DECL)
  10941. xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
  10942. }
  10943. if (exprRes != NULL) {
  10944. xmlXPathReleaseObject(ctxt->context, exprRes);
  10945. exprRes = NULL;
  10946. }
  10947. if (ctxt->value == contextObj) {
  10948. /*
  10949. * Don't free the temporary XPath object holding the
  10950. * context node, in order to avoid massive recreation
  10951. * inside this loop.
  10952. */
  10953. valuePop(ctxt);
  10954. xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
  10955. } else {
  10956. /*
  10957. * The object was lost in the evaluation machinery.
  10958. * Can this happen? Maybe in case of internal-errors.
  10959. */
  10960. contextObj = NULL;
  10961. }
  10962. }
  10963. goto evaluation_exit;
  10964. evaluation_error:
  10965. xmlXPathNodeSetClear(set, hasNsNodes);
  10966. newContextSize = 0;
  10967. evaluation_exit:
  10968. if (contextObj != NULL) {
  10969. if (ctxt->value == contextObj)
  10970. valuePop(ctxt);
  10971. xmlXPathReleaseObject(xpctxt, contextObj);
  10972. }
  10973. if (exprRes != NULL)
  10974. xmlXPathReleaseObject(ctxt->context, exprRes);
  10975. /*
  10976. * Reset/invalidate the context.
  10977. */
  10978. xpctxt->node = oldContextNode;
  10979. xpctxt->doc = oldContextDoc;
  10980. xpctxt->contextSize = -1;
  10981. xpctxt->proximityPosition = -1;
  10982. return(newContextSize);
  10983. }
  10984. return(contextSize);
  10985. }
  10986. static int
  10987. xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
  10988. xmlXPathStepOpPtr op,
  10989. int *maxPos)
  10990. {
  10991. xmlXPathStepOpPtr exprOp;
  10992. /*
  10993. * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
  10994. */
  10995. /*
  10996. * If not -1, then ch1 will point to:
  10997. * 1) For predicates (XPATH_OP_PREDICATE):
  10998. * - an inner predicate operator
  10999. * 2) For filters (XPATH_OP_FILTER):
  11000. * - an inner filter operater OR
  11001. * - an expression selecting the node set.
  11002. * E.g. "key('a', 'b')" or "(//foo | //bar)".
  11003. */
  11004. if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
  11005. return(0);
  11006. if (op->ch2 != -1) {
  11007. exprOp = &ctxt->comp->steps[op->ch2];
  11008. } else
  11009. return(0);
  11010. if ((exprOp != NULL) &&
  11011. (exprOp->op == XPATH_OP_VALUE) &&
  11012. (exprOp->value4 != NULL) &&
  11013. (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
  11014. {
  11015. /*
  11016. * We have a "[n]" predicate here.
  11017. * TODO: Unfortunately this simplistic test here is not
  11018. * able to detect a position() predicate in compound
  11019. * expressions like "[@attr = 'a" and position() = 1],
  11020. * and even not the usage of position() in
  11021. * "[position() = 1]"; thus - obviously - a position-range,
  11022. * like it "[position() < 5]", is also not detected.
  11023. * Maybe we could rewrite the AST to ease the optimization.
  11024. */
  11025. *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
  11026. if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
  11027. (float) *maxPos)
  11028. {
  11029. return(1);
  11030. }
  11031. }
  11032. return(0);
  11033. }
  11034. static int
  11035. xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
  11036. xmlXPathStepOpPtr op,
  11037. xmlNodePtr * first, xmlNodePtr * last,
  11038. int toBool)
  11039. {
  11040. #define XP_TEST_HIT \
  11041. if (hasAxisRange != 0) { \
  11042. if (++pos == maxPos) { \
  11043. addNode(seq, cur); \
  11044. goto axis_range_end; } \
  11045. } else { \
  11046. addNode(seq, cur); \
  11047. if (breakOnFirstHit) goto first_hit; }
  11048. #define XP_TEST_HIT_NS \
  11049. if (hasAxisRange != 0) { \
  11050. if (++pos == maxPos) { \
  11051. hasNsNodes = 1; \
  11052. xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
  11053. goto axis_range_end; } \
  11054. } else { \
  11055. hasNsNodes = 1; \
  11056. xmlXPathNodeSetAddNs(seq, \
  11057. xpctxt->node, (xmlNsPtr) cur); \
  11058. if (breakOnFirstHit) goto first_hit; }
  11059. xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
  11060. xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
  11061. xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
  11062. const xmlChar *prefix = op->value4;
  11063. const xmlChar *name = op->value5;
  11064. const xmlChar *URI = NULL;
  11065. #ifdef DEBUG_STEP
  11066. int nbMatches = 0, prevMatches = 0;
  11067. #endif
  11068. int total = 0, hasNsNodes = 0;
  11069. /* The popped object holding the context nodes */
  11070. xmlXPathObjectPtr obj;
  11071. /* The set of context nodes for the node tests */
  11072. xmlNodeSetPtr contextSeq;
  11073. int contextIdx;
  11074. xmlNodePtr contextNode;
  11075. /* The context node for a compound traversal */
  11076. xmlNodePtr outerContextNode;
  11077. /* The final resulting node set wrt to all context nodes */
  11078. xmlNodeSetPtr outSeq;
  11079. /*
  11080. * The temporary resulting node set wrt 1 context node.
  11081. * Used to feed predicate evaluation.
  11082. */
  11083. xmlNodeSetPtr seq;
  11084. xmlNodePtr cur;
  11085. /* First predicate operator */
  11086. xmlXPathStepOpPtr predOp;
  11087. int maxPos; /* The requested position() (when a "[n]" predicate) */
  11088. int hasPredicateRange, hasAxisRange, pos, size, newSize;
  11089. int breakOnFirstHit;
  11090. xmlXPathTraversalFunction next = NULL;
  11091. /* compound axis traversal */
  11092. xmlXPathTraversalFunctionExt outerNext = NULL;
  11093. void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
  11094. xmlXPathNodeSetMergeFunction mergeAndClear;
  11095. xmlNodePtr oldContextNode;
  11096. xmlXPathContextPtr xpctxt = ctxt->context;
  11097. CHECK_TYPE0(XPATH_NODESET);
  11098. obj = valuePop(ctxt);
  11099. /*
  11100. * Setup namespaces.
  11101. */
  11102. if (prefix != NULL) {
  11103. URI = xmlXPathNsLookup(xpctxt, prefix);
  11104. if (URI == NULL) {
  11105. xmlXPathReleaseObject(xpctxt, obj);
  11106. XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
  11107. }
  11108. }
  11109. /*
  11110. * Setup axis.
  11111. *
  11112. * MAYBE FUTURE TODO: merging optimizations:
  11113. * - If the nodes to be traversed wrt to the initial nodes and
  11114. * the current axis cannot overlap, then we could avoid searching
  11115. * for duplicates during the merge.
  11116. * But the question is how/when to evaluate if they cannot overlap.
  11117. * Example: if we know that for two initial nodes, the one is
  11118. * not in the ancestor-or-self axis of the other, then we could safely
  11119. * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
  11120. * the descendant-or-self axis.
  11121. */
  11122. mergeAndClear = xmlXPathNodeSetMergeAndClear;
  11123. switch (axis) {
  11124. case AXIS_ANCESTOR:
  11125. first = NULL;
  11126. next = xmlXPathNextAncestor;
  11127. break;
  11128. case AXIS_ANCESTOR_OR_SELF:
  11129. first = NULL;
  11130. next = xmlXPathNextAncestorOrSelf;
  11131. break;
  11132. case AXIS_ATTRIBUTE:
  11133. first = NULL;
  11134. last = NULL;
  11135. next = xmlXPathNextAttribute;
  11136. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  11137. break;
  11138. case AXIS_CHILD:
  11139. last = NULL;
  11140. if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
  11141. /*
  11142. * This iterator will give us only nodes which can
  11143. * hold element nodes.
  11144. */
  11145. outerNext = xmlXPathNextDescendantOrSelfElemParent;
  11146. }
  11147. if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
  11148. (type == NODE_TYPE_NODE))
  11149. {
  11150. /*
  11151. * Optimization if an element node type is 'element'.
  11152. */
  11153. next = xmlXPathNextChildElement;
  11154. } else
  11155. next = xmlXPathNextChild;
  11156. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  11157. break;
  11158. case AXIS_DESCENDANT:
  11159. last = NULL;
  11160. next = xmlXPathNextDescendant;
  11161. break;
  11162. case AXIS_DESCENDANT_OR_SELF:
  11163. last = NULL;
  11164. next = xmlXPathNextDescendantOrSelf;
  11165. break;
  11166. case AXIS_FOLLOWING:
  11167. last = NULL;
  11168. next = xmlXPathNextFollowing;
  11169. break;
  11170. case AXIS_FOLLOWING_SIBLING:
  11171. last = NULL;
  11172. next = xmlXPathNextFollowingSibling;
  11173. break;
  11174. case AXIS_NAMESPACE:
  11175. first = NULL;
  11176. last = NULL;
  11177. next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
  11178. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  11179. break;
  11180. case AXIS_PARENT:
  11181. first = NULL;
  11182. next = xmlXPathNextParent;
  11183. break;
  11184. case AXIS_PRECEDING:
  11185. first = NULL;
  11186. next = xmlXPathNextPrecedingInternal;
  11187. break;
  11188. case AXIS_PRECEDING_SIBLING:
  11189. first = NULL;
  11190. next = xmlXPathNextPrecedingSibling;
  11191. break;
  11192. case AXIS_SELF:
  11193. first = NULL;
  11194. last = NULL;
  11195. next = xmlXPathNextSelf;
  11196. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  11197. break;
  11198. }
  11199. #ifdef DEBUG_STEP
  11200. xmlXPathDebugDumpStepAxis(op,
  11201. (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
  11202. #endif
  11203. if (next == NULL) {
  11204. xmlXPathReleaseObject(xpctxt, obj);
  11205. return(0);
  11206. }
  11207. contextSeq = obj->nodesetval;
  11208. if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
  11209. xmlXPathReleaseObject(xpctxt, obj);
  11210. valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
  11211. return(0);
  11212. }
  11213. /*
  11214. * Predicate optimization ---------------------------------------------
  11215. * If this step has a last predicate, which contains a position(),
  11216. * then we'll optimize (although not exactly "position()", but only
  11217. * the short-hand form, i.e., "[n]".
  11218. *
  11219. * Example - expression "/foo[parent::bar][1]":
  11220. *
  11221. * COLLECT 'child' 'name' 'node' foo -- op (we are here)
  11222. * ROOT -- op->ch1
  11223. * PREDICATE -- op->ch2 (predOp)
  11224. * PREDICATE -- predOp->ch1 = [parent::bar]
  11225. * SORT
  11226. * COLLECT 'parent' 'name' 'node' bar
  11227. * NODE
  11228. * ELEM Object is a number : 1 -- predOp->ch2 = [1]
  11229. *
  11230. */
  11231. maxPos = 0;
  11232. predOp = NULL;
  11233. hasPredicateRange = 0;
  11234. hasAxisRange = 0;
  11235. if (op->ch2 != -1) {
  11236. /*
  11237. * There's at least one predicate. 16 == XPATH_OP_PREDICATE
  11238. */
  11239. predOp = &ctxt->comp->steps[op->ch2];
  11240. if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
  11241. if (predOp->ch1 != -1) {
  11242. /*
  11243. * Use the next inner predicate operator.
  11244. */
  11245. predOp = &ctxt->comp->steps[predOp->ch1];
  11246. hasPredicateRange = 1;
  11247. } else {
  11248. /*
  11249. * There's no other predicate than the [n] predicate.
  11250. */
  11251. predOp = NULL;
  11252. hasAxisRange = 1;
  11253. }
  11254. }
  11255. }
  11256. breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
  11257. /*
  11258. * Axis traversal -----------------------------------------------------
  11259. */
  11260. /*
  11261. * 2.3 Node Tests
  11262. * - For the attribute axis, the principal node type is attribute.
  11263. * - For the namespace axis, the principal node type is namespace.
  11264. * - For other axes, the principal node type is element.
  11265. *
  11266. * A node test * is true for any node of the
  11267. * principal node type. For example, child::* will
  11268. * select all element children of the context node
  11269. */
  11270. oldContextNode = xpctxt->node;
  11271. addNode = xmlXPathNodeSetAddUnique;
  11272. outSeq = NULL;
  11273. seq = NULL;
  11274. outerContextNode = NULL;
  11275. contextNode = NULL;
  11276. contextIdx = 0;
  11277. while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
  11278. if (outerNext != NULL) {
  11279. /*
  11280. * This is a compound traversal.
  11281. */
  11282. if (contextNode == NULL) {
  11283. /*
  11284. * Set the context for the outer traversal.
  11285. */
  11286. outerContextNode = contextSeq->nodeTab[contextIdx++];
  11287. contextNode = outerNext(NULL, outerContextNode);
  11288. } else
  11289. contextNode = outerNext(contextNode, outerContextNode);
  11290. if (contextNode == NULL)
  11291. continue;
  11292. /*
  11293. * Set the context for the main traversal.
  11294. */
  11295. xpctxt->node = contextNode;
  11296. } else
  11297. xpctxt->node = contextSeq->nodeTab[contextIdx++];
  11298. if (seq == NULL) {
  11299. seq = xmlXPathNodeSetCreate(NULL);
  11300. if (seq == NULL) {
  11301. total = 0;
  11302. goto error;
  11303. }
  11304. }
  11305. /*
  11306. * Traverse the axis and test the nodes.
  11307. */
  11308. pos = 0;
  11309. cur = NULL;
  11310. hasNsNodes = 0;
  11311. do {
  11312. cur = next(ctxt, cur);
  11313. if (cur == NULL)
  11314. break;
  11315. /*
  11316. * QUESTION TODO: What does the "first" and "last" stuff do?
  11317. */
  11318. if ((first != NULL) && (*first != NULL)) {
  11319. if (*first == cur)
  11320. break;
  11321. if (((total % 256) == 0) &&
  11322. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  11323. (xmlXPathCmpNodesExt(*first, cur) >= 0))
  11324. #else
  11325. (xmlXPathCmpNodes(*first, cur) >= 0))
  11326. #endif
  11327. {
  11328. break;
  11329. }
  11330. }
  11331. if ((last != NULL) && (*last != NULL)) {
  11332. if (*last == cur)
  11333. break;
  11334. if (((total % 256) == 0) &&
  11335. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  11336. (xmlXPathCmpNodesExt(cur, *last) >= 0))
  11337. #else
  11338. (xmlXPathCmpNodes(cur, *last) >= 0))
  11339. #endif
  11340. {
  11341. break;
  11342. }
  11343. }
  11344. total++;
  11345. #ifdef DEBUG_STEP
  11346. xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
  11347. #endif
  11348. switch (test) {
  11349. case NODE_TEST_NONE:
  11350. total = 0;
  11351. STRANGE
  11352. goto error;
  11353. case NODE_TEST_TYPE:
  11354. /*
  11355. * TODO: Don't we need to use
  11356. * xmlXPathNodeSetAddNs() for namespace nodes here?
  11357. * Surprisingly, some c14n tests fail, if we do this.
  11358. */
  11359. if (type == NODE_TYPE_NODE) {
  11360. switch (cur->type) {
  11361. case XML_DOCUMENT_NODE:
  11362. case XML_HTML_DOCUMENT_NODE:
  11363. #ifdef LIBXML_DOCB_ENABLED
  11364. case XML_DOCB_DOCUMENT_NODE:
  11365. #endif
  11366. case XML_ELEMENT_NODE:
  11367. case XML_ATTRIBUTE_NODE:
  11368. case XML_PI_NODE:
  11369. case XML_COMMENT_NODE:
  11370. case XML_CDATA_SECTION_NODE:
  11371. case XML_TEXT_NODE:
  11372. case XML_NAMESPACE_DECL:
  11373. XP_TEST_HIT
  11374. break;
  11375. default:
  11376. break;
  11377. }
  11378. } else if (cur->type == type) {
  11379. if (type == XML_NAMESPACE_DECL)
  11380. XP_TEST_HIT_NS
  11381. else
  11382. XP_TEST_HIT
  11383. } else if ((type == NODE_TYPE_TEXT) &&
  11384. (cur->type == XML_CDATA_SECTION_NODE))
  11385. {
  11386. XP_TEST_HIT
  11387. }
  11388. break;
  11389. case NODE_TEST_PI:
  11390. if ((cur->type == XML_PI_NODE) &&
  11391. ((name == NULL) || xmlStrEqual(name, cur->name)))
  11392. {
  11393. XP_TEST_HIT
  11394. }
  11395. break;
  11396. case NODE_TEST_ALL:
  11397. if (axis == AXIS_ATTRIBUTE) {
  11398. if (cur->type == XML_ATTRIBUTE_NODE)
  11399. {
  11400. XP_TEST_HIT
  11401. }
  11402. } else if (axis == AXIS_NAMESPACE) {
  11403. if (cur->type == XML_NAMESPACE_DECL)
  11404. {
  11405. XP_TEST_HIT_NS
  11406. }
  11407. } else {
  11408. if (cur->type == XML_ELEMENT_NODE) {
  11409. if (prefix == NULL)
  11410. {
  11411. XP_TEST_HIT
  11412. } else if ((cur->ns != NULL) &&
  11413. (xmlStrEqual(URI, cur->ns->href)))
  11414. {
  11415. XP_TEST_HIT
  11416. }
  11417. }
  11418. }
  11419. break;
  11420. case NODE_TEST_NS:{
  11421. TODO;
  11422. break;
  11423. }
  11424. case NODE_TEST_NAME:
  11425. if (axis == AXIS_ATTRIBUTE) {
  11426. if (cur->type != XML_ATTRIBUTE_NODE)
  11427. break;
  11428. } else if (axis == AXIS_NAMESPACE) {
  11429. if (cur->type != XML_NAMESPACE_DECL)
  11430. break;
  11431. } else {
  11432. if (cur->type != XML_ELEMENT_NODE)
  11433. break;
  11434. }
  11435. switch (cur->type) {
  11436. case XML_ELEMENT_NODE:
  11437. if (xmlStrEqual(name, cur->name)) {
  11438. if (prefix == NULL) {
  11439. if (cur->ns == NULL)
  11440. {
  11441. XP_TEST_HIT
  11442. }
  11443. } else {
  11444. if ((cur->ns != NULL) &&
  11445. (xmlStrEqual(URI, cur->ns->href)))
  11446. {
  11447. XP_TEST_HIT
  11448. }
  11449. }
  11450. }
  11451. break;
  11452. case XML_ATTRIBUTE_NODE:{
  11453. xmlAttrPtr attr = (xmlAttrPtr) cur;
  11454. if (xmlStrEqual(name, attr->name)) {
  11455. if (prefix == NULL) {
  11456. if ((attr->ns == NULL) ||
  11457. (attr->ns->prefix == NULL))
  11458. {
  11459. XP_TEST_HIT
  11460. }
  11461. } else {
  11462. if ((attr->ns != NULL) &&
  11463. (xmlStrEqual(URI,
  11464. attr->ns->href)))
  11465. {
  11466. XP_TEST_HIT
  11467. }
  11468. }
  11469. }
  11470. break;
  11471. }
  11472. case XML_NAMESPACE_DECL:
  11473. if (cur->type == XML_NAMESPACE_DECL) {
  11474. xmlNsPtr ns = (xmlNsPtr) cur;
  11475. if ((ns->prefix != NULL) && (name != NULL)
  11476. && (xmlStrEqual(ns->prefix, name)))
  11477. {
  11478. XP_TEST_HIT_NS
  11479. }
  11480. }
  11481. break;
  11482. default:
  11483. break;
  11484. }
  11485. break;
  11486. } /* switch(test) */
  11487. } while (cur != NULL);
  11488. goto apply_predicates;
  11489. axis_range_end: /* ----------------------------------------------------- */
  11490. /*
  11491. * We have a "/foo[n]", and position() = n was reached.
  11492. * Note that we can have as well "/foo/::parent::foo[1]", so
  11493. * a duplicate-aware merge is still needed.
  11494. * Merge with the result.
  11495. */
  11496. if (outSeq == NULL) {
  11497. outSeq = seq;
  11498. seq = NULL;
  11499. } else
  11500. outSeq = mergeAndClear(outSeq, seq, 0);
  11501. /*
  11502. * Break if only a true/false result was requested.
  11503. */
  11504. if (toBool)
  11505. break;
  11506. continue;
  11507. first_hit: /* ---------------------------------------------------------- */
  11508. /*
  11509. * Break if only a true/false result was requested and
  11510. * no predicates existed and a node test succeeded.
  11511. */
  11512. if (outSeq == NULL) {
  11513. outSeq = seq;
  11514. seq = NULL;
  11515. } else
  11516. outSeq = mergeAndClear(outSeq, seq, 0);
  11517. break;
  11518. #ifdef DEBUG_STEP
  11519. if (seq != NULL)
  11520. nbMatches += seq->nodeNr;
  11521. #endif
  11522. apply_predicates: /* --------------------------------------------------- */
  11523. /*
  11524. * Apply predicates.
  11525. */
  11526. if ((predOp != NULL) && (seq->nodeNr > 0)) {
  11527. /*
  11528. * E.g. when we have a "/foo[some expression][n]".
  11529. */
  11530. /*
  11531. * QUESTION TODO: The old predicate evaluation took into
  11532. * account location-sets.
  11533. * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
  11534. * Do we expect such a set here?
  11535. * All what I learned now from the evaluation semantics
  11536. * does not indicate that a location-set will be processed
  11537. * here, so this looks OK.
  11538. */
  11539. /*
  11540. * Iterate over all predicates, starting with the outermost
  11541. * predicate.
  11542. * TODO: Problem: we cannot execute the inner predicates first
  11543. * since we cannot go back *up* the operator tree!
  11544. * Options we have:
  11545. * 1) Use of recursive functions (like is it currently done
  11546. * via xmlXPathCompOpEval())
  11547. * 2) Add a predicate evaluation information stack to the
  11548. * context struct
  11549. * 3) Change the way the operators are linked; we need a
  11550. * "parent" field on xmlXPathStepOp
  11551. *
  11552. * For the moment, I'll try to solve this with a recursive
  11553. * function: xmlXPathCompOpEvalPredicate().
  11554. */
  11555. size = seq->nodeNr;
  11556. if (hasPredicateRange != 0)
  11557. newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
  11558. predOp, seq, size, maxPos, maxPos, hasNsNodes);
  11559. else
  11560. newSize = xmlXPathCompOpEvalPredicate(ctxt,
  11561. predOp, seq, size, hasNsNodes);
  11562. if (ctxt->error != XPATH_EXPRESSION_OK) {
  11563. total = 0;
  11564. goto error;
  11565. }
  11566. /*
  11567. * Add the filtered set of nodes to the result node set.
  11568. */
  11569. if (newSize == 0) {
  11570. /*
  11571. * The predicates filtered all nodes out.
  11572. */
  11573. xmlXPathNodeSetClear(seq, hasNsNodes);
  11574. } else if (seq->nodeNr > 0) {
  11575. /*
  11576. * Add to result set.
  11577. */
  11578. if (outSeq == NULL) {
  11579. if (size != newSize) {
  11580. /*
  11581. * We need to merge and clear here, since
  11582. * the sequence will contained NULLed entries.
  11583. */
  11584. outSeq = mergeAndClear(NULL, seq, 1);
  11585. } else {
  11586. outSeq = seq;
  11587. seq = NULL;
  11588. }
  11589. } else
  11590. outSeq = mergeAndClear(outSeq, seq,
  11591. (size != newSize) ? 1: 0);
  11592. /*
  11593. * Break if only a true/false result was requested.
  11594. */
  11595. if (toBool)
  11596. break;
  11597. }
  11598. } else if (seq->nodeNr > 0) {
  11599. /*
  11600. * Add to result set.
  11601. */
  11602. if (outSeq == NULL) {
  11603. outSeq = seq;
  11604. seq = NULL;
  11605. } else {
  11606. outSeq = mergeAndClear(outSeq, seq, 0);
  11607. }
  11608. }
  11609. }
  11610. error:
  11611. if ((obj->boolval) && (obj->user != NULL)) {
  11612. /*
  11613. * QUESTION TODO: What does this do and why?
  11614. * TODO: Do we have to do this also for the "error"
  11615. * cleanup further down?
  11616. */
  11617. ctxt->value->boolval = 1;
  11618. ctxt->value->user = obj->user;
  11619. obj->user = NULL;
  11620. obj->boolval = 0;
  11621. }
  11622. xmlXPathReleaseObject(xpctxt, obj);
  11623. /*
  11624. * Ensure we return at least an emtpy set.
  11625. */
  11626. if (outSeq == NULL) {
  11627. if ((seq != NULL) && (seq->nodeNr == 0))
  11628. outSeq = seq;
  11629. else
  11630. outSeq = xmlXPathNodeSetCreate(NULL);
  11631. /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
  11632. }
  11633. if ((seq != NULL) && (seq != outSeq)) {
  11634. xmlXPathFreeNodeSet(seq);
  11635. }
  11636. /*
  11637. * Hand over the result. Better to push the set also in
  11638. * case of errors.
  11639. */
  11640. valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
  11641. /*
  11642. * Reset the context node.
  11643. */
  11644. xpctxt->node = oldContextNode;
  11645. #ifdef DEBUG_STEP
  11646. xmlGenericError(xmlGenericErrorContext,
  11647. "\nExamined %d nodes, found %d nodes at that step\n",
  11648. total, nbMatches);
  11649. #endif
  11650. return(total);
  11651. }
  11652. static int
  11653. xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
  11654. xmlXPathStepOpPtr op, xmlNodePtr * first);
  11655. /**
  11656. * xmlXPathCompOpEvalFirst:
  11657. * @ctxt: the XPath parser context with the compiled expression
  11658. * @op: an XPath compiled operation
  11659. * @first: the first elem found so far
  11660. *
  11661. * Evaluate the Precompiled XPath operation searching only the first
  11662. * element in document order
  11663. *
  11664. * Returns the number of examined objects.
  11665. */
  11666. static int
  11667. xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
  11668. xmlXPathStepOpPtr op, xmlNodePtr * first)
  11669. {
  11670. int total = 0, cur;
  11671. xmlXPathCompExprPtr comp;
  11672. xmlXPathObjectPtr arg1, arg2;
  11673. CHECK_ERROR0;
  11674. comp = ctxt->comp;
  11675. switch (op->op) {
  11676. case XPATH_OP_END:
  11677. return (0);
  11678. case XPATH_OP_UNION:
  11679. total =
  11680. xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
  11681. first);
  11682. CHECK_ERROR0;
  11683. if ((ctxt->value != NULL)
  11684. && (ctxt->value->type == XPATH_NODESET)
  11685. && (ctxt->value->nodesetval != NULL)
  11686. && (ctxt->value->nodesetval->nodeNr >= 1)) {
  11687. /*
  11688. * limit tree traversing to first node in the result
  11689. */
  11690. /*
  11691. * OPTIMIZE TODO: This implicitely sorts
  11692. * the result, even if not needed. E.g. if the argument
  11693. * of the count() function, no sorting is needed.
  11694. * OPTIMIZE TODO: How do we know if the node-list wasn't
  11695. * aready sorted?
  11696. */
  11697. if (ctxt->value->nodesetval->nodeNr > 1)
  11698. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  11699. *first = ctxt->value->nodesetval->nodeTab[0];
  11700. }
  11701. cur =
  11702. xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
  11703. first);
  11704. CHECK_ERROR0;
  11705. CHECK_TYPE0(XPATH_NODESET);
  11706. arg2 = valuePop(ctxt);
  11707. CHECK_TYPE0(XPATH_NODESET);
  11708. arg1 = valuePop(ctxt);
  11709. arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
  11710. arg2->nodesetval);
  11711. valuePush(ctxt, arg1);
  11712. xmlXPathReleaseObject(ctxt->context, arg2);
  11713. /* optimizer */
  11714. if (total > cur)
  11715. xmlXPathCompSwap(op);
  11716. return (total + cur);
  11717. case XPATH_OP_ROOT:
  11718. xmlXPathRoot(ctxt);
  11719. return (0);
  11720. case XPATH_OP_NODE:
  11721. if (op->ch1 != -1)
  11722. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11723. CHECK_ERROR0;
  11724. if (op->ch2 != -1)
  11725. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11726. CHECK_ERROR0;
  11727. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  11728. ctxt->context->node));
  11729. return (total);
  11730. case XPATH_OP_RESET:
  11731. if (op->ch1 != -1)
  11732. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11733. CHECK_ERROR0;
  11734. if (op->ch2 != -1)
  11735. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11736. CHECK_ERROR0;
  11737. ctxt->context->node = NULL;
  11738. return (total);
  11739. case XPATH_OP_COLLECT:{
  11740. if (op->ch1 == -1)
  11741. return (total);
  11742. total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11743. CHECK_ERROR0;
  11744. total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
  11745. return (total);
  11746. }
  11747. case XPATH_OP_VALUE:
  11748. valuePush(ctxt,
  11749. xmlXPathCacheObjectCopy(ctxt->context,
  11750. (xmlXPathObjectPtr) op->value4));
  11751. return (0);
  11752. case XPATH_OP_SORT:
  11753. if (op->ch1 != -1)
  11754. total +=
  11755. xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
  11756. first);
  11757. CHECK_ERROR0;
  11758. if ((ctxt->value != NULL)
  11759. && (ctxt->value->type == XPATH_NODESET)
  11760. && (ctxt->value->nodesetval != NULL)
  11761. && (ctxt->value->nodesetval->nodeNr > 1))
  11762. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  11763. return (total);
  11764. #ifdef XP_OPTIMIZED_FILTER_FIRST
  11765. case XPATH_OP_FILTER:
  11766. total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
  11767. return (total);
  11768. #endif
  11769. default:
  11770. return (xmlXPathCompOpEval(ctxt, op));
  11771. }
  11772. }
  11773. /**
  11774. * xmlXPathCompOpEvalLast:
  11775. * @ctxt: the XPath parser context with the compiled expression
  11776. * @op: an XPath compiled operation
  11777. * @last: the last elem found so far
  11778. *
  11779. * Evaluate the Precompiled XPath operation searching only the last
  11780. * element in document order
  11781. *
  11782. * Returns the number of nodes traversed
  11783. */
  11784. static int
  11785. xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
  11786. xmlNodePtr * last)
  11787. {
  11788. int total = 0, cur;
  11789. xmlXPathCompExprPtr comp;
  11790. xmlXPathObjectPtr arg1, arg2;
  11791. xmlNodePtr bak;
  11792. xmlDocPtr bakd;
  11793. int pp;
  11794. int cs;
  11795. CHECK_ERROR0;
  11796. comp = ctxt->comp;
  11797. switch (op->op) {
  11798. case XPATH_OP_END:
  11799. return (0);
  11800. case XPATH_OP_UNION:
  11801. bakd = ctxt->context->doc;
  11802. bak = ctxt->context->node;
  11803. pp = ctxt->context->proximityPosition;
  11804. cs = ctxt->context->contextSize;
  11805. total =
  11806. xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
  11807. CHECK_ERROR0;
  11808. if ((ctxt->value != NULL)
  11809. && (ctxt->value->type == XPATH_NODESET)
  11810. && (ctxt->value->nodesetval != NULL)
  11811. && (ctxt->value->nodesetval->nodeNr >= 1)) {
  11812. /*
  11813. * limit tree traversing to first node in the result
  11814. */
  11815. if (ctxt->value->nodesetval->nodeNr > 1)
  11816. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  11817. *last =
  11818. ctxt->value->nodesetval->nodeTab[ctxt->value->
  11819. nodesetval->nodeNr -
  11820. 1];
  11821. }
  11822. ctxt->context->doc = bakd;
  11823. ctxt->context->node = bak;
  11824. ctxt->context->proximityPosition = pp;
  11825. ctxt->context->contextSize = cs;
  11826. cur =
  11827. xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
  11828. CHECK_ERROR0;
  11829. if ((ctxt->value != NULL)
  11830. && (ctxt->value->type == XPATH_NODESET)
  11831. && (ctxt->value->nodesetval != NULL)
  11832. && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
  11833. }
  11834. CHECK_TYPE0(XPATH_NODESET);
  11835. arg2 = valuePop(ctxt);
  11836. CHECK_TYPE0(XPATH_NODESET);
  11837. arg1 = valuePop(ctxt);
  11838. arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
  11839. arg2->nodesetval);
  11840. valuePush(ctxt, arg1);
  11841. xmlXPathReleaseObject(ctxt->context, arg2);
  11842. /* optimizer */
  11843. if (total > cur)
  11844. xmlXPathCompSwap(op);
  11845. return (total + cur);
  11846. case XPATH_OP_ROOT:
  11847. xmlXPathRoot(ctxt);
  11848. return (0);
  11849. case XPATH_OP_NODE:
  11850. if (op->ch1 != -1)
  11851. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11852. CHECK_ERROR0;
  11853. if (op->ch2 != -1)
  11854. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11855. CHECK_ERROR0;
  11856. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  11857. ctxt->context->node));
  11858. return (total);
  11859. case XPATH_OP_RESET:
  11860. if (op->ch1 != -1)
  11861. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11862. CHECK_ERROR0;
  11863. if (op->ch2 != -1)
  11864. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11865. CHECK_ERROR0;
  11866. ctxt->context->node = NULL;
  11867. return (total);
  11868. case XPATH_OP_COLLECT:{
  11869. if (op->ch1 == -1)
  11870. return (0);
  11871. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11872. CHECK_ERROR0;
  11873. total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
  11874. return (total);
  11875. }
  11876. case XPATH_OP_VALUE:
  11877. valuePush(ctxt,
  11878. xmlXPathCacheObjectCopy(ctxt->context,
  11879. (xmlXPathObjectPtr) op->value4));
  11880. return (0);
  11881. case XPATH_OP_SORT:
  11882. if (op->ch1 != -1)
  11883. total +=
  11884. xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
  11885. last);
  11886. CHECK_ERROR0;
  11887. if ((ctxt->value != NULL)
  11888. && (ctxt->value->type == XPATH_NODESET)
  11889. && (ctxt->value->nodesetval != NULL)
  11890. && (ctxt->value->nodesetval->nodeNr > 1))
  11891. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  11892. return (total);
  11893. default:
  11894. return (xmlXPathCompOpEval(ctxt, op));
  11895. }
  11896. }
  11897. #ifdef XP_OPTIMIZED_FILTER_FIRST
  11898. static int
  11899. xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
  11900. xmlXPathStepOpPtr op, xmlNodePtr * first)
  11901. {
  11902. int total = 0;
  11903. xmlXPathCompExprPtr comp;
  11904. xmlXPathObjectPtr res;
  11905. xmlXPathObjectPtr obj;
  11906. xmlNodeSetPtr oldset;
  11907. xmlNodePtr oldnode;
  11908. xmlDocPtr oldDoc;
  11909. int i;
  11910. CHECK_ERROR0;
  11911. comp = ctxt->comp;
  11912. /*
  11913. * Optimization for ()[last()] selection i.e. the last elem
  11914. */
  11915. if ((op->ch1 != -1) && (op->ch2 != -1) &&
  11916. (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
  11917. (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
  11918. int f = comp->steps[op->ch2].ch1;
  11919. if ((f != -1) &&
  11920. (comp->steps[f].op == XPATH_OP_FUNCTION) &&
  11921. (comp->steps[f].value5 == NULL) &&
  11922. (comp->steps[f].value == 0) &&
  11923. (comp->steps[f].value4 != NULL) &&
  11924. (xmlStrEqual
  11925. (comp->steps[f].value4, BAD_CAST "last"))) {
  11926. xmlNodePtr last = NULL;
  11927. total +=
  11928. xmlXPathCompOpEvalLast(ctxt,
  11929. &comp->steps[op->ch1],
  11930. &last);
  11931. CHECK_ERROR0;
  11932. /*
  11933. * The nodeset should be in document order,
  11934. * Keep only the last value
  11935. */
  11936. if ((ctxt->value != NULL) &&
  11937. (ctxt->value->type == XPATH_NODESET) &&
  11938. (ctxt->value->nodesetval != NULL) &&
  11939. (ctxt->value->nodesetval->nodeTab != NULL) &&
  11940. (ctxt->value->nodesetval->nodeNr > 1)) {
  11941. ctxt->value->nodesetval->nodeTab[0] =
  11942. ctxt->value->nodesetval->nodeTab[ctxt->
  11943. value->
  11944. nodesetval->
  11945. nodeNr -
  11946. 1];
  11947. ctxt->value->nodesetval->nodeNr = 1;
  11948. *first = *(ctxt->value->nodesetval->nodeTab);
  11949. }
  11950. return (total);
  11951. }
  11952. }
  11953. if (op->ch1 != -1)
  11954. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11955. CHECK_ERROR0;
  11956. if (op->ch2 == -1)
  11957. return (total);
  11958. if (ctxt->value == NULL)
  11959. return (total);
  11960. #ifdef LIBXML_XPTR_ENABLED
  11961. oldnode = ctxt->context->node;
  11962. /*
  11963. * Hum are we filtering the result of an XPointer expression
  11964. */
  11965. if (ctxt->value->type == XPATH_LOCATIONSET) {
  11966. xmlXPathObjectPtr tmp = NULL;
  11967. xmlLocationSetPtr newlocset = NULL;
  11968. xmlLocationSetPtr oldlocset;
  11969. /*
  11970. * Extract the old locset, and then evaluate the result of the
  11971. * expression for all the element in the locset. use it to grow
  11972. * up a new locset.
  11973. */
  11974. CHECK_TYPE0(XPATH_LOCATIONSET);
  11975. obj = valuePop(ctxt);
  11976. oldlocset = obj->user;
  11977. ctxt->context->node = NULL;
  11978. if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
  11979. ctxt->context->contextSize = 0;
  11980. ctxt->context->proximityPosition = 0;
  11981. if (op->ch2 != -1)
  11982. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11983. res = valuePop(ctxt);
  11984. if (res != NULL) {
  11985. xmlXPathReleaseObject(ctxt->context, res);
  11986. }
  11987. valuePush(ctxt, obj);
  11988. CHECK_ERROR0;
  11989. return (total);
  11990. }
  11991. newlocset = xmlXPtrLocationSetCreate(NULL);
  11992. for (i = 0; i < oldlocset->locNr; i++) {
  11993. /*
  11994. * Run the evaluation with a node list made of a
  11995. * single item in the nodelocset.
  11996. */
  11997. ctxt->context->node = oldlocset->locTab[i]->user;
  11998. ctxt->context->contextSize = oldlocset->locNr;
  11999. ctxt->context->proximityPosition = i + 1;
  12000. if (tmp == NULL) {
  12001. tmp = xmlXPathCacheNewNodeSet(ctxt->context,
  12002. ctxt->context->node);
  12003. } else {
  12004. xmlXPathNodeSetAddUnique(tmp->nodesetval,
  12005. ctxt->context->node);
  12006. }
  12007. valuePush(ctxt, tmp);
  12008. if (op->ch2 != -1)
  12009. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12010. if (ctxt->error != XPATH_EXPRESSION_OK) {
  12011. xmlXPathFreeObject(obj);
  12012. return(0);
  12013. }
  12014. /*
  12015. * The result of the evaluation need to be tested to
  12016. * decided whether the filter succeeded or not
  12017. */
  12018. res = valuePop(ctxt);
  12019. if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
  12020. xmlXPtrLocationSetAdd(newlocset,
  12021. xmlXPathCacheObjectCopy(ctxt->context,
  12022. oldlocset->locTab[i]));
  12023. }
  12024. /*
  12025. * Cleanup
  12026. */
  12027. if (res != NULL) {
  12028. xmlXPathReleaseObject(ctxt->context, res);
  12029. }
  12030. if (ctxt->value == tmp) {
  12031. valuePop(ctxt);
  12032. xmlXPathNodeSetClear(tmp->nodesetval, 1);
  12033. /*
  12034. * REVISIT TODO: Don't create a temporary nodeset
  12035. * for everly iteration.
  12036. */
  12037. /* OLD: xmlXPathFreeObject(res); */
  12038. } else
  12039. tmp = NULL;
  12040. ctxt->context->node = NULL;
  12041. /*
  12042. * Only put the first node in the result, then leave.
  12043. */
  12044. if (newlocset->locNr > 0) {
  12045. *first = (xmlNodePtr) oldlocset->locTab[i]->user;
  12046. break;
  12047. }
  12048. }
  12049. if (tmp != NULL) {
  12050. xmlXPathReleaseObject(ctxt->context, tmp);
  12051. }
  12052. /*
  12053. * The result is used as the new evaluation locset.
  12054. */
  12055. xmlXPathReleaseObject(ctxt->context, obj);
  12056. ctxt->context->node = NULL;
  12057. ctxt->context->contextSize = -1;
  12058. ctxt->context->proximityPosition = -1;
  12059. valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
  12060. ctxt->context->node = oldnode;
  12061. return (total);
  12062. }
  12063. #endif /* LIBXML_XPTR_ENABLED */
  12064. /*
  12065. * Extract the old set, and then evaluate the result of the
  12066. * expression for all the element in the set. use it to grow
  12067. * up a new set.
  12068. */
  12069. CHECK_TYPE0(XPATH_NODESET);
  12070. obj = valuePop(ctxt);
  12071. oldset = obj->nodesetval;
  12072. oldnode = ctxt->context->node;
  12073. oldDoc = ctxt->context->doc;
  12074. ctxt->context->node = NULL;
  12075. if ((oldset == NULL) || (oldset->nodeNr == 0)) {
  12076. ctxt->context->contextSize = 0;
  12077. ctxt->context->proximityPosition = 0;
  12078. /* QUESTION TODO: Why was this code commented out?
  12079. if (op->ch2 != -1)
  12080. total +=
  12081. xmlXPathCompOpEval(ctxt,
  12082. &comp->steps[op->ch2]);
  12083. CHECK_ERROR0;
  12084. res = valuePop(ctxt);
  12085. if (res != NULL)
  12086. xmlXPathFreeObject(res);
  12087. */
  12088. valuePush(ctxt, obj);
  12089. ctxt->context->node = oldnode;
  12090. CHECK_ERROR0;
  12091. } else {
  12092. xmlNodeSetPtr newset;
  12093. xmlXPathObjectPtr tmp = NULL;
  12094. /*
  12095. * Initialize the new set.
  12096. * Also set the xpath document in case things like
  12097. * key() evaluation are attempted on the predicate
  12098. */
  12099. newset = xmlXPathNodeSetCreate(NULL);
  12100. /* XXX what if xmlXPathNodeSetCreate returned NULL? */
  12101. for (i = 0; i < oldset->nodeNr; i++) {
  12102. /*
  12103. * Run the evaluation with a node list made of
  12104. * a single item in the nodeset.
  12105. */
  12106. ctxt->context->node = oldset->nodeTab[i];
  12107. if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
  12108. (oldset->nodeTab[i]->doc != NULL))
  12109. ctxt->context->doc = oldset->nodeTab[i]->doc;
  12110. if (tmp == NULL) {
  12111. tmp = xmlXPathCacheNewNodeSet(ctxt->context,
  12112. ctxt->context->node);
  12113. } else {
  12114. xmlXPathNodeSetAddUnique(tmp->nodesetval,
  12115. ctxt->context->node);
  12116. }
  12117. valuePush(ctxt, tmp);
  12118. ctxt->context->contextSize = oldset->nodeNr;
  12119. ctxt->context->proximityPosition = i + 1;
  12120. if (op->ch2 != -1)
  12121. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12122. if (ctxt->error != XPATH_EXPRESSION_OK) {
  12123. xmlXPathFreeNodeSet(newset);
  12124. xmlXPathFreeObject(obj);
  12125. return(0);
  12126. }
  12127. /*
  12128. * The result of the evaluation needs to be tested to
  12129. * decide whether the filter succeeded or not
  12130. */
  12131. res = valuePop(ctxt);
  12132. if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
  12133. xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
  12134. }
  12135. /*
  12136. * Cleanup
  12137. */
  12138. if (res != NULL) {
  12139. xmlXPathReleaseObject(ctxt->context, res);
  12140. }
  12141. if (ctxt->value == tmp) {
  12142. valuePop(ctxt);
  12143. /*
  12144. * Don't free the temporary nodeset
  12145. * in order to avoid massive recreation inside this
  12146. * loop.
  12147. */
  12148. xmlXPathNodeSetClear(tmp->nodesetval, 1);
  12149. } else
  12150. tmp = NULL;
  12151. ctxt->context->node = NULL;
  12152. /*
  12153. * Only put the first node in the result, then leave.
  12154. */
  12155. if (newset->nodeNr > 0) {
  12156. *first = *(newset->nodeTab);
  12157. break;
  12158. }
  12159. }
  12160. if (tmp != NULL) {
  12161. xmlXPathReleaseObject(ctxt->context, tmp);
  12162. }
  12163. /*
  12164. * The result is used as the new evaluation set.
  12165. */
  12166. xmlXPathReleaseObject(ctxt->context, obj);
  12167. ctxt->context->node = NULL;
  12168. ctxt->context->contextSize = -1;
  12169. ctxt->context->proximityPosition = -1;
  12170. /* may want to move this past the '}' later */
  12171. ctxt->context->doc = oldDoc;
  12172. valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
  12173. }
  12174. ctxt->context->node = oldnode;
  12175. return(total);
  12176. }
  12177. #endif /* XP_OPTIMIZED_FILTER_FIRST */
  12178. /**
  12179. * xmlXPathCompOpEval:
  12180. * @ctxt: the XPath parser context with the compiled expression
  12181. * @op: an XPath compiled operation
  12182. *
  12183. * Evaluate the Precompiled XPath operation
  12184. * Returns the number of nodes traversed
  12185. */
  12186. static int
  12187. xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
  12188. {
  12189. int total = 0;
  12190. int equal, ret;
  12191. xmlXPathCompExprPtr comp;
  12192. xmlXPathObjectPtr arg1, arg2;
  12193. xmlNodePtr bak;
  12194. xmlDocPtr bakd;
  12195. int pp;
  12196. int cs;
  12197. CHECK_ERROR0;
  12198. comp = ctxt->comp;
  12199. switch (op->op) {
  12200. case XPATH_OP_END:
  12201. return (0);
  12202. case XPATH_OP_AND:
  12203. bakd = ctxt->context->doc;
  12204. bak = ctxt->context->node;
  12205. pp = ctxt->context->proximityPosition;
  12206. cs = ctxt->context->contextSize;
  12207. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12208. CHECK_ERROR0;
  12209. xmlXPathBooleanFunction(ctxt, 1);
  12210. if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
  12211. return (total);
  12212. arg2 = valuePop(ctxt);
  12213. ctxt->context->doc = bakd;
  12214. ctxt->context->node = bak;
  12215. ctxt->context->proximityPosition = pp;
  12216. ctxt->context->contextSize = cs;
  12217. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12218. if (ctxt->error) {
  12219. xmlXPathFreeObject(arg2);
  12220. return(0);
  12221. }
  12222. xmlXPathBooleanFunction(ctxt, 1);
  12223. arg1 = valuePop(ctxt);
  12224. arg1->boolval &= arg2->boolval;
  12225. valuePush(ctxt, arg1);
  12226. xmlXPathReleaseObject(ctxt->context, arg2);
  12227. return (total);
  12228. case XPATH_OP_OR:
  12229. bakd = ctxt->context->doc;
  12230. bak = ctxt->context->node;
  12231. pp = ctxt->context->proximityPosition;
  12232. cs = ctxt->context->contextSize;
  12233. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12234. CHECK_ERROR0;
  12235. xmlXPathBooleanFunction(ctxt, 1);
  12236. if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
  12237. return (total);
  12238. arg2 = valuePop(ctxt);
  12239. ctxt->context->doc = bakd;
  12240. ctxt->context->node = bak;
  12241. ctxt->context->proximityPosition = pp;
  12242. ctxt->context->contextSize = cs;
  12243. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12244. if (ctxt->error) {
  12245. xmlXPathFreeObject(arg2);
  12246. return(0);
  12247. }
  12248. xmlXPathBooleanFunction(ctxt, 1);
  12249. arg1 = valuePop(ctxt);
  12250. arg1->boolval |= arg2->boolval;
  12251. valuePush(ctxt, arg1);
  12252. xmlXPathReleaseObject(ctxt->context, arg2);
  12253. return (total);
  12254. case XPATH_OP_EQUAL:
  12255. bakd = ctxt->context->doc;
  12256. bak = ctxt->context->node;
  12257. pp = ctxt->context->proximityPosition;
  12258. cs = ctxt->context->contextSize;
  12259. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12260. CHECK_ERROR0;
  12261. ctxt->context->doc = bakd;
  12262. ctxt->context->node = bak;
  12263. ctxt->context->proximityPosition = pp;
  12264. ctxt->context->contextSize = cs;
  12265. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12266. CHECK_ERROR0;
  12267. if (op->value)
  12268. equal = xmlXPathEqualValues(ctxt);
  12269. else
  12270. equal = xmlXPathNotEqualValues(ctxt);
  12271. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
  12272. return (total);
  12273. case XPATH_OP_CMP:
  12274. bakd = ctxt->context->doc;
  12275. bak = ctxt->context->node;
  12276. pp = ctxt->context->proximityPosition;
  12277. cs = ctxt->context->contextSize;
  12278. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12279. CHECK_ERROR0;
  12280. ctxt->context->doc = bakd;
  12281. ctxt->context->node = bak;
  12282. ctxt->context->proximityPosition = pp;
  12283. ctxt->context->contextSize = cs;
  12284. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12285. CHECK_ERROR0;
  12286. ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
  12287. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
  12288. return (total);
  12289. case XPATH_OP_PLUS:
  12290. bakd = ctxt->context->doc;
  12291. bak = ctxt->context->node;
  12292. pp = ctxt->context->proximityPosition;
  12293. cs = ctxt->context->contextSize;
  12294. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12295. CHECK_ERROR0;
  12296. if (op->ch2 != -1) {
  12297. ctxt->context->doc = bakd;
  12298. ctxt->context->node = bak;
  12299. ctxt->context->proximityPosition = pp;
  12300. ctxt->context->contextSize = cs;
  12301. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12302. }
  12303. CHECK_ERROR0;
  12304. if (op->value == 0)
  12305. xmlXPathSubValues(ctxt);
  12306. else if (op->value == 1)
  12307. xmlXPathAddValues(ctxt);
  12308. else if (op->value == 2)
  12309. xmlXPathValueFlipSign(ctxt);
  12310. else if (op->value == 3) {
  12311. CAST_TO_NUMBER;
  12312. CHECK_TYPE0(XPATH_NUMBER);
  12313. }
  12314. return (total);
  12315. case XPATH_OP_MULT:
  12316. bakd = ctxt->context->doc;
  12317. bak = ctxt->context->node;
  12318. pp = ctxt->context->proximityPosition;
  12319. cs = ctxt->context->contextSize;
  12320. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12321. CHECK_ERROR0;
  12322. ctxt->context->doc = bakd;
  12323. ctxt->context->node = bak;
  12324. ctxt->context->proximityPosition = pp;
  12325. ctxt->context->contextSize = cs;
  12326. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12327. CHECK_ERROR0;
  12328. if (op->value == 0)
  12329. xmlXPathMultValues(ctxt);
  12330. else if (op->value == 1)
  12331. xmlXPathDivValues(ctxt);
  12332. else if (op->value == 2)
  12333. xmlXPathModValues(ctxt);
  12334. return (total);
  12335. case XPATH_OP_UNION:
  12336. bakd = ctxt->context->doc;
  12337. bak = ctxt->context->node;
  12338. pp = ctxt->context->proximityPosition;
  12339. cs = ctxt->context->contextSize;
  12340. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12341. CHECK_ERROR0;
  12342. ctxt->context->doc = bakd;
  12343. ctxt->context->node = bak;
  12344. ctxt->context->proximityPosition = pp;
  12345. ctxt->context->contextSize = cs;
  12346. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12347. CHECK_ERROR0;
  12348. CHECK_TYPE0(XPATH_NODESET);
  12349. arg2 = valuePop(ctxt);
  12350. CHECK_TYPE0(XPATH_NODESET);
  12351. arg1 = valuePop(ctxt);
  12352. if ((arg1->nodesetval == NULL) ||
  12353. ((arg2->nodesetval != NULL) &&
  12354. (arg2->nodesetval->nodeNr != 0)))
  12355. {
  12356. arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
  12357. arg2->nodesetval);
  12358. }
  12359. valuePush(ctxt, arg1);
  12360. xmlXPathReleaseObject(ctxt->context, arg2);
  12361. return (total);
  12362. case XPATH_OP_ROOT:
  12363. xmlXPathRoot(ctxt);
  12364. return (total);
  12365. case XPATH_OP_NODE:
  12366. if (op->ch1 != -1)
  12367. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12368. CHECK_ERROR0;
  12369. if (op->ch2 != -1)
  12370. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12371. CHECK_ERROR0;
  12372. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  12373. ctxt->context->node));
  12374. return (total);
  12375. case XPATH_OP_RESET:
  12376. if (op->ch1 != -1)
  12377. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12378. CHECK_ERROR0;
  12379. if (op->ch2 != -1)
  12380. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12381. CHECK_ERROR0;
  12382. ctxt->context->node = NULL;
  12383. return (total);
  12384. case XPATH_OP_COLLECT:{
  12385. if (op->ch1 == -1)
  12386. return (total);
  12387. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12388. CHECK_ERROR0;
  12389. total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
  12390. return (total);
  12391. }
  12392. case XPATH_OP_VALUE:
  12393. valuePush(ctxt,
  12394. xmlXPathCacheObjectCopy(ctxt->context,
  12395. (xmlXPathObjectPtr) op->value4));
  12396. return (total);
  12397. case XPATH_OP_VARIABLE:{
  12398. xmlXPathObjectPtr val;
  12399. if (op->ch1 != -1)
  12400. total +=
  12401. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12402. if (op->value5 == NULL) {
  12403. val = xmlXPathVariableLookup(ctxt->context, op->value4);
  12404. if (val == NULL) {
  12405. ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
  12406. return(0);
  12407. }
  12408. valuePush(ctxt, val);
  12409. } else {
  12410. const xmlChar *URI;
  12411. URI = xmlXPathNsLookup(ctxt->context, op->value5);
  12412. if (URI == NULL) {
  12413. xmlGenericError(xmlGenericErrorContext,
  12414. "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
  12415. (char *) op->value4, (char *)op->value5);
  12416. return (total);
  12417. }
  12418. val = xmlXPathVariableLookupNS(ctxt->context,
  12419. op->value4, URI);
  12420. if (val == NULL) {
  12421. ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
  12422. return(0);
  12423. }
  12424. valuePush(ctxt, val);
  12425. }
  12426. return (total);
  12427. }
  12428. case XPATH_OP_FUNCTION:{
  12429. xmlXPathFunction func;
  12430. const xmlChar *oldFunc, *oldFuncURI;
  12431. int i;
  12432. if (op->ch1 != -1)
  12433. total +=
  12434. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12435. if (ctxt->valueNr < op->value) {
  12436. xmlGenericError(xmlGenericErrorContext,
  12437. "xmlXPathCompOpEval: parameter error\n");
  12438. ctxt->error = XPATH_INVALID_OPERAND;
  12439. return (total);
  12440. }
  12441. for (i = 0; i < op->value; i++)
  12442. if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
  12443. xmlGenericError(xmlGenericErrorContext,
  12444. "xmlXPathCompOpEval: parameter error\n");
  12445. ctxt->error = XPATH_INVALID_OPERAND;
  12446. return (total);
  12447. }
  12448. if (op->cache != NULL)
  12449. XML_CAST_FPTR(func) = op->cache;
  12450. else {
  12451. const xmlChar *URI = NULL;
  12452. if (op->value5 == NULL)
  12453. func =
  12454. xmlXPathFunctionLookup(ctxt->context,
  12455. op->value4);
  12456. else {
  12457. URI = xmlXPathNsLookup(ctxt->context, op->value5);
  12458. if (URI == NULL) {
  12459. xmlGenericError(xmlGenericErrorContext,
  12460. "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
  12461. (char *)op->value4, (char *)op->value5);
  12462. return (total);
  12463. }
  12464. func = xmlXPathFunctionLookupNS(ctxt->context,
  12465. op->value4, URI);
  12466. }
  12467. if (func == NULL) {
  12468. xmlGenericError(xmlGenericErrorContext,
  12469. "xmlXPathCompOpEval: function %s not found\n",
  12470. (char *)op->value4);
  12471. XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
  12472. }
  12473. op->cache = XML_CAST_FPTR(func);
  12474. op->cacheURI = (void *) URI;
  12475. }
  12476. oldFunc = ctxt->context->function;
  12477. oldFuncURI = ctxt->context->functionURI;
  12478. ctxt->context->function = op->value4;
  12479. ctxt->context->functionURI = op->cacheURI;
  12480. func(ctxt, op->value);
  12481. ctxt->context->function = oldFunc;
  12482. ctxt->context->functionURI = oldFuncURI;
  12483. return (total);
  12484. }
  12485. case XPATH_OP_ARG:
  12486. bakd = ctxt->context->doc;
  12487. bak = ctxt->context->node;
  12488. pp = ctxt->context->proximityPosition;
  12489. cs = ctxt->context->contextSize;
  12490. if (op->ch1 != -1)
  12491. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12492. ctxt->context->contextSize = cs;
  12493. ctxt->context->proximityPosition = pp;
  12494. ctxt->context->node = bak;
  12495. ctxt->context->doc = bakd;
  12496. CHECK_ERROR0;
  12497. if (op->ch2 != -1) {
  12498. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12499. ctxt->context->doc = bakd;
  12500. ctxt->context->node = bak;
  12501. CHECK_ERROR0;
  12502. }
  12503. return (total);
  12504. case XPATH_OP_PREDICATE:
  12505. case XPATH_OP_FILTER:{
  12506. xmlXPathObjectPtr res;
  12507. xmlXPathObjectPtr obj, tmp;
  12508. xmlNodeSetPtr newset = NULL;
  12509. xmlNodeSetPtr oldset;
  12510. xmlNodePtr oldnode;
  12511. xmlDocPtr oldDoc;
  12512. int i;
  12513. /*
  12514. * Optimization for ()[1] selection i.e. the first elem
  12515. */
  12516. if ((op->ch1 != -1) && (op->ch2 != -1) &&
  12517. #ifdef XP_OPTIMIZED_FILTER_FIRST
  12518. /*
  12519. * FILTER TODO: Can we assume that the inner processing
  12520. * will result in an ordered list if we have an
  12521. * XPATH_OP_FILTER?
  12522. * What about an additional field or flag on
  12523. * xmlXPathObject like @sorted ? This way we wouln'd need
  12524. * to assume anything, so it would be more robust and
  12525. * easier to optimize.
  12526. */
  12527. ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
  12528. (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
  12529. #else
  12530. (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
  12531. #endif
  12532. (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
  12533. xmlXPathObjectPtr val;
  12534. val = comp->steps[op->ch2].value4;
  12535. if ((val != NULL) && (val->type == XPATH_NUMBER) &&
  12536. (val->floatval == 1.0)) {
  12537. xmlNodePtr first = NULL;
  12538. total +=
  12539. xmlXPathCompOpEvalFirst(ctxt,
  12540. &comp->steps[op->ch1],
  12541. &first);
  12542. CHECK_ERROR0;
  12543. /*
  12544. * The nodeset should be in document order,
  12545. * Keep only the first value
  12546. */
  12547. if ((ctxt->value != NULL) &&
  12548. (ctxt->value->type == XPATH_NODESET) &&
  12549. (ctxt->value->nodesetval != NULL) &&
  12550. (ctxt->value->nodesetval->nodeNr > 1))
  12551. ctxt->value->nodesetval->nodeNr = 1;
  12552. return (total);
  12553. }
  12554. }
  12555. /*
  12556. * Optimization for ()[last()] selection i.e. the last elem
  12557. */
  12558. if ((op->ch1 != -1) && (op->ch2 != -1) &&
  12559. (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
  12560. (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
  12561. int f = comp->steps[op->ch2].ch1;
  12562. if ((f != -1) &&
  12563. (comp->steps[f].op == XPATH_OP_FUNCTION) &&
  12564. (comp->steps[f].value5 == NULL) &&
  12565. (comp->steps[f].value == 0) &&
  12566. (comp->steps[f].value4 != NULL) &&
  12567. (xmlStrEqual
  12568. (comp->steps[f].value4, BAD_CAST "last"))) {
  12569. xmlNodePtr last = NULL;
  12570. total +=
  12571. xmlXPathCompOpEvalLast(ctxt,
  12572. &comp->steps[op->ch1],
  12573. &last);
  12574. CHECK_ERROR0;
  12575. /*
  12576. * The nodeset should be in document order,
  12577. * Keep only the last value
  12578. */
  12579. if ((ctxt->value != NULL) &&
  12580. (ctxt->value->type == XPATH_NODESET) &&
  12581. (ctxt->value->nodesetval != NULL) &&
  12582. (ctxt->value->nodesetval->nodeTab != NULL) &&
  12583. (ctxt->value->nodesetval->nodeNr > 1)) {
  12584. ctxt->value->nodesetval->nodeTab[0] =
  12585. ctxt->value->nodesetval->nodeTab[ctxt->
  12586. value->
  12587. nodesetval->
  12588. nodeNr -
  12589. 1];
  12590. ctxt->value->nodesetval->nodeNr = 1;
  12591. }
  12592. return (total);
  12593. }
  12594. }
  12595. /*
  12596. * Process inner predicates first.
  12597. * Example "index[parent::book][1]":
  12598. * ...
  12599. * PREDICATE <-- we are here "[1]"
  12600. * PREDICATE <-- process "[parent::book]" first
  12601. * SORT
  12602. * COLLECT 'parent' 'name' 'node' book
  12603. * NODE
  12604. * ELEM Object is a number : 1
  12605. */
  12606. if (op->ch1 != -1)
  12607. total +=
  12608. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12609. CHECK_ERROR0;
  12610. if (op->ch2 == -1)
  12611. return (total);
  12612. if (ctxt->value == NULL)
  12613. return (total);
  12614. oldnode = ctxt->context->node;
  12615. #ifdef LIBXML_XPTR_ENABLED
  12616. /*
  12617. * Hum are we filtering the result of an XPointer expression
  12618. */
  12619. if (ctxt->value->type == XPATH_LOCATIONSET) {
  12620. xmlLocationSetPtr newlocset = NULL;
  12621. xmlLocationSetPtr oldlocset;
  12622. /*
  12623. * Extract the old locset, and then evaluate the result of the
  12624. * expression for all the element in the locset. use it to grow
  12625. * up a new locset.
  12626. */
  12627. CHECK_TYPE0(XPATH_LOCATIONSET);
  12628. obj = valuePop(ctxt);
  12629. oldlocset = obj->user;
  12630. ctxt->context->node = NULL;
  12631. if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
  12632. ctxt->context->contextSize = 0;
  12633. ctxt->context->proximityPosition = 0;
  12634. if (op->ch2 != -1)
  12635. total +=
  12636. xmlXPathCompOpEval(ctxt,
  12637. &comp->steps[op->ch2]);
  12638. res = valuePop(ctxt);
  12639. if (res != NULL) {
  12640. xmlXPathReleaseObject(ctxt->context, res);
  12641. }
  12642. valuePush(ctxt, obj);
  12643. CHECK_ERROR0;
  12644. return (total);
  12645. }
  12646. newlocset = xmlXPtrLocationSetCreate(NULL);
  12647. for (i = 0; i < oldlocset->locNr; i++) {
  12648. /*
  12649. * Run the evaluation with a node list made of a
  12650. * single item in the nodelocset.
  12651. */
  12652. ctxt->context->node = oldlocset->locTab[i]->user;
  12653. ctxt->context->contextSize = oldlocset->locNr;
  12654. ctxt->context->proximityPosition = i + 1;
  12655. tmp = xmlXPathCacheNewNodeSet(ctxt->context,
  12656. ctxt->context->node);
  12657. valuePush(ctxt, tmp);
  12658. if (op->ch2 != -1)
  12659. total +=
  12660. xmlXPathCompOpEval(ctxt,
  12661. &comp->steps[op->ch2]);
  12662. if (ctxt->error != XPATH_EXPRESSION_OK) {
  12663. xmlXPathFreeObject(obj);
  12664. return(0);
  12665. }
  12666. /*
  12667. * The result of the evaluation need to be tested to
  12668. * decided whether the filter succeeded or not
  12669. */
  12670. res = valuePop(ctxt);
  12671. if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
  12672. xmlXPtrLocationSetAdd(newlocset,
  12673. xmlXPathObjectCopy
  12674. (oldlocset->locTab[i]));
  12675. }
  12676. /*
  12677. * Cleanup
  12678. */
  12679. if (res != NULL) {
  12680. xmlXPathReleaseObject(ctxt->context, res);
  12681. }
  12682. if (ctxt->value == tmp) {
  12683. res = valuePop(ctxt);
  12684. xmlXPathReleaseObject(ctxt->context, res);
  12685. }
  12686. ctxt->context->node = NULL;
  12687. }
  12688. /*
  12689. * The result is used as the new evaluation locset.
  12690. */
  12691. xmlXPathReleaseObject(ctxt->context, obj);
  12692. ctxt->context->node = NULL;
  12693. ctxt->context->contextSize = -1;
  12694. ctxt->context->proximityPosition = -1;
  12695. valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
  12696. ctxt->context->node = oldnode;
  12697. return (total);
  12698. }
  12699. #endif /* LIBXML_XPTR_ENABLED */
  12700. /*
  12701. * Extract the old set, and then evaluate the result of the
  12702. * expression for all the element in the set. use it to grow
  12703. * up a new set.
  12704. */
  12705. CHECK_TYPE0(XPATH_NODESET);
  12706. obj = valuePop(ctxt);
  12707. oldset = obj->nodesetval;
  12708. oldnode = ctxt->context->node;
  12709. oldDoc = ctxt->context->doc;
  12710. ctxt->context->node = NULL;
  12711. if ((oldset == NULL) || (oldset->nodeNr == 0)) {
  12712. ctxt->context->contextSize = 0;
  12713. ctxt->context->proximityPosition = 0;
  12714. /*
  12715. if (op->ch2 != -1)
  12716. total +=
  12717. xmlXPathCompOpEval(ctxt,
  12718. &comp->steps[op->ch2]);
  12719. CHECK_ERROR0;
  12720. res = valuePop(ctxt);
  12721. if (res != NULL)
  12722. xmlXPathFreeObject(res);
  12723. */
  12724. valuePush(ctxt, obj);
  12725. ctxt->context->node = oldnode;
  12726. CHECK_ERROR0;
  12727. } else {
  12728. tmp = NULL;
  12729. /*
  12730. * Initialize the new set.
  12731. * Also set the xpath document in case things like
  12732. * key() evaluation are attempted on the predicate
  12733. */
  12734. newset = xmlXPathNodeSetCreate(NULL);
  12735. /*
  12736. * SPEC XPath 1.0:
  12737. * "For each node in the node-set to be filtered, the
  12738. * PredicateExpr is evaluated with that node as the
  12739. * context node, with the number of nodes in the
  12740. * node-set as the context size, and with the proximity
  12741. * position of the node in the node-set with respect to
  12742. * the axis as the context position;"
  12743. * @oldset is the node-set" to be filtered.
  12744. *
  12745. * SPEC XPath 1.0:
  12746. * "only predicates change the context position and
  12747. * context size (see [2.4 Predicates])."
  12748. * Example:
  12749. * node-set context pos
  12750. * nA 1
  12751. * nB 2
  12752. * nC 3
  12753. * After applying predicate [position() > 1] :
  12754. * node-set context pos
  12755. * nB 1
  12756. * nC 2
  12757. *
  12758. * removed the first node in the node-set, then
  12759. * the context position of the
  12760. */
  12761. for (i = 0; i < oldset->nodeNr; i++) {
  12762. /*
  12763. * Run the evaluation with a node list made of
  12764. * a single item in the nodeset.
  12765. */
  12766. ctxt->context->node = oldset->nodeTab[i];
  12767. if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
  12768. (oldset->nodeTab[i]->doc != NULL))
  12769. ctxt->context->doc = oldset->nodeTab[i]->doc;
  12770. if (tmp == NULL) {
  12771. tmp = xmlXPathCacheNewNodeSet(ctxt->context,
  12772. ctxt->context->node);
  12773. } else {
  12774. xmlXPathNodeSetAddUnique(tmp->nodesetval,
  12775. ctxt->context->node);
  12776. }
  12777. valuePush(ctxt, tmp);
  12778. ctxt->context->contextSize = oldset->nodeNr;
  12779. ctxt->context->proximityPosition = i + 1;
  12780. /*
  12781. * Evaluate the predicate against the context node.
  12782. * Can/should we optimize position() predicates
  12783. * here (e.g. "[1]")?
  12784. */
  12785. if (op->ch2 != -1)
  12786. total +=
  12787. xmlXPathCompOpEval(ctxt,
  12788. &comp->steps[op->ch2]);
  12789. if (ctxt->error != XPATH_EXPRESSION_OK) {
  12790. xmlXPathFreeNodeSet(newset);
  12791. xmlXPathFreeObject(obj);
  12792. return(0);
  12793. }
  12794. /*
  12795. * The result of the evaluation needs to be tested to
  12796. * decide whether the filter succeeded or not
  12797. */
  12798. /*
  12799. * OPTIMIZE TODO: Can we use
  12800. * xmlXPathNodeSetAdd*Unique()* instead?
  12801. */
  12802. res = valuePop(ctxt);
  12803. if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
  12804. xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
  12805. }
  12806. /*
  12807. * Cleanup
  12808. */
  12809. if (res != NULL) {
  12810. xmlXPathReleaseObject(ctxt->context, res);
  12811. }
  12812. if (ctxt->value == tmp) {
  12813. valuePop(ctxt);
  12814. xmlXPathNodeSetClear(tmp->nodesetval, 1);
  12815. /*
  12816. * Don't free the temporary nodeset
  12817. * in order to avoid massive recreation inside this
  12818. * loop.
  12819. */
  12820. } else
  12821. tmp = NULL;
  12822. ctxt->context->node = NULL;
  12823. }
  12824. if (tmp != NULL)
  12825. xmlXPathReleaseObject(ctxt->context, tmp);
  12826. /*
  12827. * The result is used as the new evaluation set.
  12828. */
  12829. xmlXPathReleaseObject(ctxt->context, obj);
  12830. ctxt->context->node = NULL;
  12831. ctxt->context->contextSize = -1;
  12832. ctxt->context->proximityPosition = -1;
  12833. /* may want to move this past the '}' later */
  12834. ctxt->context->doc = oldDoc;
  12835. valuePush(ctxt,
  12836. xmlXPathCacheWrapNodeSet(ctxt->context, newset));
  12837. }
  12838. ctxt->context->node = oldnode;
  12839. return (total);
  12840. }
  12841. case XPATH_OP_SORT:
  12842. if (op->ch1 != -1)
  12843. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12844. CHECK_ERROR0;
  12845. if ((ctxt->value != NULL) &&
  12846. (ctxt->value->type == XPATH_NODESET) &&
  12847. (ctxt->value->nodesetval != NULL) &&
  12848. (ctxt->value->nodesetval->nodeNr > 1))
  12849. {
  12850. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  12851. }
  12852. return (total);
  12853. #ifdef LIBXML_XPTR_ENABLED
  12854. case XPATH_OP_RANGETO:{
  12855. xmlXPathObjectPtr range;
  12856. xmlXPathObjectPtr res, obj;
  12857. xmlXPathObjectPtr tmp;
  12858. xmlLocationSetPtr newlocset = NULL;
  12859. xmlLocationSetPtr oldlocset;
  12860. xmlNodeSetPtr oldset;
  12861. int i, j;
  12862. if (op->ch1 != -1)
  12863. total +=
  12864. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12865. if (op->ch2 == -1)
  12866. return (total);
  12867. if (ctxt->value->type == XPATH_LOCATIONSET) {
  12868. /*
  12869. * Extract the old locset, and then evaluate the result of the
  12870. * expression for all the element in the locset. use it to grow
  12871. * up a new locset.
  12872. */
  12873. CHECK_TYPE0(XPATH_LOCATIONSET);
  12874. obj = valuePop(ctxt);
  12875. oldlocset = obj->user;
  12876. if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
  12877. ctxt->context->node = NULL;
  12878. ctxt->context->contextSize = 0;
  12879. ctxt->context->proximityPosition = 0;
  12880. total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
  12881. res = valuePop(ctxt);
  12882. if (res != NULL) {
  12883. xmlXPathReleaseObject(ctxt->context, res);
  12884. }
  12885. valuePush(ctxt, obj);
  12886. CHECK_ERROR0;
  12887. return (total);
  12888. }
  12889. newlocset = xmlXPtrLocationSetCreate(NULL);
  12890. for (i = 0; i < oldlocset->locNr; i++) {
  12891. /*
  12892. * Run the evaluation with a node list made of a
  12893. * single item in the nodelocset.
  12894. */
  12895. ctxt->context->node = oldlocset->locTab[i]->user;
  12896. ctxt->context->contextSize = oldlocset->locNr;
  12897. ctxt->context->proximityPosition = i + 1;
  12898. tmp = xmlXPathCacheNewNodeSet(ctxt->context,
  12899. ctxt->context->node);
  12900. valuePush(ctxt, tmp);
  12901. if (op->ch2 != -1)
  12902. total +=
  12903. xmlXPathCompOpEval(ctxt,
  12904. &comp->steps[op->ch2]);
  12905. if (ctxt->error != XPATH_EXPRESSION_OK) {
  12906. xmlXPathFreeObject(obj);
  12907. return(0);
  12908. }
  12909. res = valuePop(ctxt);
  12910. if (res->type == XPATH_LOCATIONSET) {
  12911. xmlLocationSetPtr rloc =
  12912. (xmlLocationSetPtr)res->user;
  12913. for (j=0; j<rloc->locNr; j++) {
  12914. range = xmlXPtrNewRange(
  12915. oldlocset->locTab[i]->user,
  12916. oldlocset->locTab[i]->index,
  12917. rloc->locTab[j]->user2,
  12918. rloc->locTab[j]->index2);
  12919. if (range != NULL) {
  12920. xmlXPtrLocationSetAdd(newlocset, range);
  12921. }
  12922. }
  12923. } else {
  12924. range = xmlXPtrNewRangeNodeObject(
  12925. (xmlNodePtr)oldlocset->locTab[i]->user, res);
  12926. if (range != NULL) {
  12927. xmlXPtrLocationSetAdd(newlocset,range);
  12928. }
  12929. }
  12930. /*
  12931. * Cleanup
  12932. */
  12933. if (res != NULL) {
  12934. xmlXPathReleaseObject(ctxt->context, res);
  12935. }
  12936. if (ctxt->value == tmp) {
  12937. res = valuePop(ctxt);
  12938. xmlXPathReleaseObject(ctxt->context, res);
  12939. }
  12940. ctxt->context->node = NULL;
  12941. }
  12942. } else { /* Not a location set */
  12943. CHECK_TYPE0(XPATH_NODESET);
  12944. obj = valuePop(ctxt);
  12945. oldset = obj->nodesetval;
  12946. ctxt->context->node = NULL;
  12947. newlocset = xmlXPtrLocationSetCreate(NULL);
  12948. if (oldset != NULL) {
  12949. for (i = 0; i < oldset->nodeNr; i++) {
  12950. /*
  12951. * Run the evaluation with a node list made of a single item
  12952. * in the nodeset.
  12953. */
  12954. ctxt->context->node = oldset->nodeTab[i];
  12955. /*
  12956. * OPTIMIZE TODO: Avoid recreation for every iteration.
  12957. */
  12958. tmp = xmlXPathCacheNewNodeSet(ctxt->context,
  12959. ctxt->context->node);
  12960. valuePush(ctxt, tmp);
  12961. if (op->ch2 != -1)
  12962. total +=
  12963. xmlXPathCompOpEval(ctxt,
  12964. &comp->steps[op->ch2]);
  12965. if (ctxt->error != XPATH_EXPRESSION_OK) {
  12966. xmlXPathFreeObject(obj);
  12967. return(0);
  12968. }
  12969. res = valuePop(ctxt);
  12970. range =
  12971. xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
  12972. res);
  12973. if (range != NULL) {
  12974. xmlXPtrLocationSetAdd(newlocset, range);
  12975. }
  12976. /*
  12977. * Cleanup
  12978. */
  12979. if (res != NULL) {
  12980. xmlXPathReleaseObject(ctxt->context, res);
  12981. }
  12982. if (ctxt->value == tmp) {
  12983. res = valuePop(ctxt);
  12984. xmlXPathReleaseObject(ctxt->context, res);
  12985. }
  12986. ctxt->context->node = NULL;
  12987. }
  12988. }
  12989. }
  12990. /*
  12991. * The result is used as the new evaluation set.
  12992. */
  12993. xmlXPathReleaseObject(ctxt->context, obj);
  12994. ctxt->context->node = NULL;
  12995. ctxt->context->contextSize = -1;
  12996. ctxt->context->proximityPosition = -1;
  12997. valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
  12998. return (total);
  12999. }
  13000. #endif /* LIBXML_XPTR_ENABLED */
  13001. }
  13002. xmlGenericError(xmlGenericErrorContext,
  13003. "XPath: unknown precompiled operation %d\n", op->op);
  13004. return (total);
  13005. }
  13006. /**
  13007. * xmlXPathCompOpEvalToBoolean:
  13008. * @ctxt: the XPath parser context
  13009. *
  13010. * Evaluates if the expression evaluates to true.
  13011. *
  13012. * Returns 1 if true, 0 if false and -1 on API or internal errors.
  13013. */
  13014. static int
  13015. xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
  13016. xmlXPathStepOpPtr op,
  13017. int isPredicate)
  13018. {
  13019. xmlXPathObjectPtr resObj = NULL;
  13020. start:
  13021. /* comp = ctxt->comp; */
  13022. switch (op->op) {
  13023. case XPATH_OP_END:
  13024. return (0);
  13025. case XPATH_OP_VALUE:
  13026. resObj = (xmlXPathObjectPtr) op->value4;
  13027. if (isPredicate)
  13028. return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
  13029. return(xmlXPathCastToBoolean(resObj));
  13030. case XPATH_OP_SORT:
  13031. /*
  13032. * We don't need sorting for boolean results. Skip this one.
  13033. */
  13034. if (op->ch1 != -1) {
  13035. op = &ctxt->comp->steps[op->ch1];
  13036. goto start;
  13037. }
  13038. return(0);
  13039. case XPATH_OP_COLLECT:
  13040. if (op->ch1 == -1)
  13041. return(0);
  13042. xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
  13043. if (ctxt->error != XPATH_EXPRESSION_OK)
  13044. return(-1);
  13045. xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
  13046. if (ctxt->error != XPATH_EXPRESSION_OK)
  13047. return(-1);
  13048. resObj = valuePop(ctxt);
  13049. if (resObj == NULL)
  13050. return(-1);
  13051. break;
  13052. default:
  13053. /*
  13054. * Fallback to call xmlXPathCompOpEval().
  13055. */
  13056. xmlXPathCompOpEval(ctxt, op);
  13057. if (ctxt->error != XPATH_EXPRESSION_OK)
  13058. return(-1);
  13059. resObj = valuePop(ctxt);
  13060. if (resObj == NULL)
  13061. return(-1);
  13062. break;
  13063. }
  13064. if (resObj) {
  13065. int res;
  13066. if (resObj->type == XPATH_BOOLEAN) {
  13067. res = resObj->boolval;
  13068. } else if (isPredicate) {
  13069. /*
  13070. * For predicates a result of type "number" is handled
  13071. * differently:
  13072. * SPEC XPath 1.0:
  13073. * "If the result is a number, the result will be converted
  13074. * to true if the number is equal to the context position
  13075. * and will be converted to false otherwise;"
  13076. */
  13077. res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
  13078. } else {
  13079. res = xmlXPathCastToBoolean(resObj);
  13080. }
  13081. xmlXPathReleaseObject(ctxt->context, resObj);
  13082. return(res);
  13083. }
  13084. return(0);
  13085. }
  13086. #ifdef XPATH_STREAMING
  13087. /**
  13088. * xmlXPathRunStreamEval:
  13089. * @ctxt: the XPath parser context with the compiled expression
  13090. *
  13091. * Evaluate the Precompiled Streamable XPath expression in the given context.
  13092. */
  13093. static int
  13094. xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
  13095. xmlXPathObjectPtr *resultSeq, int toBool)
  13096. {
  13097. int max_depth, min_depth;
  13098. int from_root;
  13099. int ret, depth;
  13100. int eval_all_nodes;
  13101. xmlNodePtr cur = NULL, limit = NULL;
  13102. xmlStreamCtxtPtr patstream = NULL;
  13103. int nb_nodes = 0;
  13104. if ((ctxt == NULL) || (comp == NULL))
  13105. return(-1);
  13106. max_depth = xmlPatternMaxDepth(comp);
  13107. if (max_depth == -1)
  13108. return(-1);
  13109. if (max_depth == -2)
  13110. max_depth = 10000;
  13111. min_depth = xmlPatternMinDepth(comp);
  13112. if (min_depth == -1)
  13113. return(-1);
  13114. from_root = xmlPatternFromRoot(comp);
  13115. if (from_root < 0)
  13116. return(-1);
  13117. #if 0
  13118. printf("stream eval: depth %d from root %d\n", max_depth, from_root);
  13119. #endif
  13120. if (! toBool) {
  13121. if (resultSeq == NULL)
  13122. return(-1);
  13123. *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
  13124. if (*resultSeq == NULL)
  13125. return(-1);
  13126. }
  13127. /*
  13128. * handle the special cases of "/" amd "." being matched
  13129. */
  13130. if (min_depth == 0) {
  13131. if (from_root) {
  13132. /* Select "/" */
  13133. if (toBool)
  13134. return(1);
  13135. xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
  13136. (xmlNodePtr) ctxt->doc);
  13137. } else {
  13138. /* Select "self::node()" */
  13139. if (toBool)
  13140. return(1);
  13141. xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
  13142. }
  13143. }
  13144. if (max_depth == 0) {
  13145. return(0);
  13146. }
  13147. if (from_root) {
  13148. cur = (xmlNodePtr)ctxt->doc;
  13149. } else if (ctxt->node != NULL) {
  13150. switch (ctxt->node->type) {
  13151. case XML_ELEMENT_NODE:
  13152. case XML_DOCUMENT_NODE:
  13153. case XML_DOCUMENT_FRAG_NODE:
  13154. case XML_HTML_DOCUMENT_NODE:
  13155. #ifdef LIBXML_DOCB_ENABLED
  13156. case XML_DOCB_DOCUMENT_NODE:
  13157. #endif
  13158. cur = ctxt->node;
  13159. break;
  13160. case XML_ATTRIBUTE_NODE:
  13161. case XML_TEXT_NODE:
  13162. case XML_CDATA_SECTION_NODE:
  13163. case XML_ENTITY_REF_NODE:
  13164. case XML_ENTITY_NODE:
  13165. case XML_PI_NODE:
  13166. case XML_COMMENT_NODE:
  13167. case XML_NOTATION_NODE:
  13168. case XML_DTD_NODE:
  13169. case XML_DOCUMENT_TYPE_NODE:
  13170. case XML_ELEMENT_DECL:
  13171. case XML_ATTRIBUTE_DECL:
  13172. case XML_ENTITY_DECL:
  13173. case XML_NAMESPACE_DECL:
  13174. case XML_XINCLUDE_START:
  13175. case XML_XINCLUDE_END:
  13176. break;
  13177. }
  13178. limit = cur;
  13179. }
  13180. if (cur == NULL) {
  13181. return(0);
  13182. }
  13183. patstream = xmlPatternGetStreamCtxt(comp);
  13184. if (patstream == NULL) {
  13185. /*
  13186. * QUESTION TODO: Is this an error?
  13187. */
  13188. return(0);
  13189. }
  13190. eval_all_nodes = xmlStreamWantsAnyNode(patstream);
  13191. if (from_root) {
  13192. ret = xmlStreamPush(patstream, NULL, NULL);
  13193. if (ret < 0) {
  13194. } else if (ret == 1) {
  13195. if (toBool)
  13196. goto return_1;
  13197. xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
  13198. }
  13199. }
  13200. depth = 0;
  13201. goto scan_children;
  13202. next_node:
  13203. do {
  13204. nb_nodes++;
  13205. switch (cur->type) {
  13206. case XML_ELEMENT_NODE:
  13207. case XML_TEXT_NODE:
  13208. case XML_CDATA_SECTION_NODE:
  13209. case XML_COMMENT_NODE:
  13210. case XML_PI_NODE:
  13211. if (cur->type == XML_ELEMENT_NODE) {
  13212. ret = xmlStreamPush(patstream, cur->name,
  13213. (cur->ns ? cur->ns->href : NULL));
  13214. } else if (eval_all_nodes)
  13215. ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
  13216. else
  13217. break;
  13218. if (ret < 0) {
  13219. /* NOP. */
  13220. } else if (ret == 1) {
  13221. if (toBool)
  13222. goto return_1;
  13223. xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
  13224. }
  13225. if ((cur->children == NULL) || (depth >= max_depth)) {
  13226. ret = xmlStreamPop(patstream);
  13227. while (cur->next != NULL) {
  13228. cur = cur->next;
  13229. if ((cur->type != XML_ENTITY_DECL) &&
  13230. (cur->type != XML_DTD_NODE))
  13231. goto next_node;
  13232. }
  13233. }
  13234. default:
  13235. break;
  13236. }
  13237. scan_children:
  13238. if ((cur->children != NULL) && (depth < max_depth)) {
  13239. /*
  13240. * Do not descend on entities declarations
  13241. */
  13242. if (cur->children->type != XML_ENTITY_DECL) {
  13243. cur = cur->children;
  13244. depth++;
  13245. /*
  13246. * Skip DTDs
  13247. */
  13248. if (cur->type != XML_DTD_NODE)
  13249. continue;
  13250. }
  13251. }
  13252. if (cur == limit)
  13253. break;
  13254. while (cur->next != NULL) {
  13255. cur = cur->next;
  13256. if ((cur->type != XML_ENTITY_DECL) &&
  13257. (cur->type != XML_DTD_NODE))
  13258. goto next_node;
  13259. }
  13260. do {
  13261. cur = cur->parent;
  13262. depth--;
  13263. if ((cur == NULL) || (cur == limit))
  13264. goto done;
  13265. if (cur->type == XML_ELEMENT_NODE) {
  13266. ret = xmlStreamPop(patstream);
  13267. } else if ((eval_all_nodes) &&
  13268. ((cur->type == XML_TEXT_NODE) ||
  13269. (cur->type == XML_CDATA_SECTION_NODE) ||
  13270. (cur->type == XML_COMMENT_NODE) ||
  13271. (cur->type == XML_PI_NODE)))
  13272. {
  13273. ret = xmlStreamPop(patstream);
  13274. }
  13275. if (cur->next != NULL) {
  13276. cur = cur->next;
  13277. break;
  13278. }
  13279. } while (cur != NULL);
  13280. } while ((cur != NULL) && (depth >= 0));
  13281. done:
  13282. #if 0
  13283. printf("stream eval: checked %d nodes selected %d\n",
  13284. nb_nodes, retObj->nodesetval->nodeNr);
  13285. #endif
  13286. if (patstream)
  13287. xmlFreeStreamCtxt(patstream);
  13288. return(0);
  13289. return_1:
  13290. if (patstream)
  13291. xmlFreeStreamCtxt(patstream);
  13292. return(1);
  13293. }
  13294. #endif /* XPATH_STREAMING */
  13295. /**
  13296. * xmlXPathRunEval:
  13297. * @ctxt: the XPath parser context with the compiled expression
  13298. * @toBool: evaluate to a boolean result
  13299. *
  13300. * Evaluate the Precompiled XPath expression in the given context.
  13301. */
  13302. static int
  13303. xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
  13304. {
  13305. xmlXPathCompExprPtr comp;
  13306. if ((ctxt == NULL) || (ctxt->comp == NULL))
  13307. return(-1);
  13308. if (ctxt->valueTab == NULL) {
  13309. /* Allocate the value stack */
  13310. ctxt->valueTab = (xmlXPathObjectPtr *)
  13311. xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
  13312. if (ctxt->valueTab == NULL) {
  13313. xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
  13314. xmlFree(ctxt);
  13315. }
  13316. ctxt->valueNr = 0;
  13317. ctxt->valueMax = 10;
  13318. ctxt->value = NULL;
  13319. }
  13320. #ifdef XPATH_STREAMING
  13321. if (ctxt->comp->stream) {
  13322. int res;
  13323. if (toBool) {
  13324. /*
  13325. * Evaluation to boolean result.
  13326. */
  13327. res = xmlXPathRunStreamEval(ctxt->context,
  13328. ctxt->comp->stream, NULL, 1);
  13329. if (res != -1)
  13330. return(res);
  13331. } else {
  13332. xmlXPathObjectPtr resObj = NULL;
  13333. /*
  13334. * Evaluation to a sequence.
  13335. */
  13336. res = xmlXPathRunStreamEval(ctxt->context,
  13337. ctxt->comp->stream, &resObj, 0);
  13338. if ((res != -1) && (resObj != NULL)) {
  13339. valuePush(ctxt, resObj);
  13340. return(0);
  13341. }
  13342. if (resObj != NULL)
  13343. xmlXPathReleaseObject(ctxt->context, resObj);
  13344. }
  13345. /*
  13346. * QUESTION TODO: This falls back to normal XPath evaluation
  13347. * if res == -1. Is this intended?
  13348. */
  13349. }
  13350. #endif
  13351. comp = ctxt->comp;
  13352. if (comp->last < 0) {
  13353. xmlGenericError(xmlGenericErrorContext,
  13354. "xmlXPathRunEval: last is less than zero\n");
  13355. return(-1);
  13356. }
  13357. if (toBool)
  13358. return(xmlXPathCompOpEvalToBoolean(ctxt,
  13359. &comp->steps[comp->last], 0));
  13360. else
  13361. xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
  13362. return(0);
  13363. }
  13364. /************************************************************************
  13365. * *
  13366. * Public interfaces *
  13367. * *
  13368. ************************************************************************/
  13369. /**
  13370. * xmlXPathEvalPredicate:
  13371. * @ctxt: the XPath context
  13372. * @res: the Predicate Expression evaluation result
  13373. *
  13374. * Evaluate a predicate result for the current node.
  13375. * A PredicateExpr is evaluated by evaluating the Expr and converting
  13376. * the result to a boolean. If the result is a number, the result will
  13377. * be converted to true if the number is equal to the position of the
  13378. * context node in the context node list (as returned by the position
  13379. * function) and will be converted to false otherwise; if the result
  13380. * is not a number, then the result will be converted as if by a call
  13381. * to the boolean function.
  13382. *
  13383. * Returns 1 if predicate is true, 0 otherwise
  13384. */
  13385. int
  13386. xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
  13387. if ((ctxt == NULL) || (res == NULL)) return(0);
  13388. switch (res->type) {
  13389. case XPATH_BOOLEAN:
  13390. return(res->boolval);
  13391. case XPATH_NUMBER:
  13392. return(res->floatval == ctxt->proximityPosition);
  13393. case XPATH_NODESET:
  13394. case XPATH_XSLT_TREE:
  13395. if (res->nodesetval == NULL)
  13396. return(0);
  13397. return(res->nodesetval->nodeNr != 0);
  13398. case XPATH_STRING:
  13399. return((res->stringval != NULL) &&
  13400. (xmlStrlen(res->stringval) != 0));
  13401. default:
  13402. STRANGE
  13403. }
  13404. return(0);
  13405. }
  13406. /**
  13407. * xmlXPathEvaluatePredicateResult:
  13408. * @ctxt: the XPath Parser context
  13409. * @res: the Predicate Expression evaluation result
  13410. *
  13411. * Evaluate a predicate result for the current node.
  13412. * A PredicateExpr is evaluated by evaluating the Expr and converting
  13413. * the result to a boolean. If the result is a number, the result will
  13414. * be converted to true if the number is equal to the position of the
  13415. * context node in the context node list (as returned by the position
  13416. * function) and will be converted to false otherwise; if the result
  13417. * is not a number, then the result will be converted as if by a call
  13418. * to the boolean function.
  13419. *
  13420. * Returns 1 if predicate is true, 0 otherwise
  13421. */
  13422. int
  13423. xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
  13424. xmlXPathObjectPtr res) {
  13425. if ((ctxt == NULL) || (res == NULL)) return(0);
  13426. switch (res->type) {
  13427. case XPATH_BOOLEAN:
  13428. return(res->boolval);
  13429. case XPATH_NUMBER:
  13430. #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
  13431. return((res->floatval == ctxt->context->proximityPosition) &&
  13432. (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
  13433. #else
  13434. return(res->floatval == ctxt->context->proximityPosition);
  13435. #endif
  13436. case XPATH_NODESET:
  13437. case XPATH_XSLT_TREE:
  13438. if (res->nodesetval == NULL)
  13439. return(0);
  13440. return(res->nodesetval->nodeNr != 0);
  13441. case XPATH_STRING:
  13442. return((res->stringval != NULL) && (res->stringval[0] != 0));
  13443. #ifdef LIBXML_XPTR_ENABLED
  13444. case XPATH_LOCATIONSET:{
  13445. xmlLocationSetPtr ptr = res->user;
  13446. if (ptr == NULL)
  13447. return(0);
  13448. return (ptr->locNr != 0);
  13449. }
  13450. #endif
  13451. default:
  13452. STRANGE
  13453. }
  13454. return(0);
  13455. }
  13456. #ifdef XPATH_STREAMING
  13457. /**
  13458. * xmlXPathTryStreamCompile:
  13459. * @ctxt: an XPath context
  13460. * @str: the XPath expression
  13461. *
  13462. * Try to compile the XPath expression as a streamable subset.
  13463. *
  13464. * Returns the compiled expression or NULL if failed to compile.
  13465. */
  13466. static xmlXPathCompExprPtr
  13467. xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
  13468. /*
  13469. * Optimization: use streaming patterns when the XPath expression can
  13470. * be compiled to a stream lookup
  13471. */
  13472. xmlPatternPtr stream;
  13473. xmlXPathCompExprPtr comp;
  13474. xmlDictPtr dict = NULL;
  13475. const xmlChar **namespaces = NULL;
  13476. xmlNsPtr ns;
  13477. int i, j;
  13478. if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
  13479. (!xmlStrchr(str, '@'))) {
  13480. const xmlChar *tmp;
  13481. /*
  13482. * We don't try to handle expressions using the verbose axis
  13483. * specifiers ("::"), just the simplied form at this point.
  13484. * Additionally, if there is no list of namespaces available and
  13485. * there's a ":" in the expression, indicating a prefixed QName,
  13486. * then we won't try to compile either. xmlPatterncompile() needs
  13487. * to have a list of namespaces at compilation time in order to
  13488. * compile prefixed name tests.
  13489. */
  13490. tmp = xmlStrchr(str, ':');
  13491. if ((tmp != NULL) &&
  13492. ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
  13493. return(NULL);
  13494. if (ctxt != NULL) {
  13495. dict = ctxt->dict;
  13496. if (ctxt->nsNr > 0) {
  13497. namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
  13498. if (namespaces == NULL) {
  13499. xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
  13500. return(NULL);
  13501. }
  13502. for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
  13503. ns = ctxt->namespaces[j];
  13504. namespaces[i++] = ns->href;
  13505. namespaces[i++] = ns->prefix;
  13506. }
  13507. namespaces[i++] = NULL;
  13508. namespaces[i] = NULL;
  13509. }
  13510. }
  13511. stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
  13512. &namespaces[0]);
  13513. if (namespaces != NULL) {
  13514. xmlFree((xmlChar **)namespaces);
  13515. }
  13516. if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
  13517. comp = xmlXPathNewCompExpr();
  13518. if (comp == NULL) {
  13519. xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
  13520. return(NULL);
  13521. }
  13522. comp->stream = stream;
  13523. comp->dict = dict;
  13524. if (comp->dict)
  13525. xmlDictReference(comp->dict);
  13526. return(comp);
  13527. }
  13528. xmlFreePattern(stream);
  13529. }
  13530. return(NULL);
  13531. }
  13532. #endif /* XPATH_STREAMING */
  13533. static int
  13534. xmlXPathCanRewriteDosExpression(xmlChar *expr)
  13535. {
  13536. if (expr == NULL)
  13537. return(0);
  13538. do {
  13539. if ((*expr == '/') && (*(++expr) == '/'))
  13540. return(1);
  13541. } while (*expr++);
  13542. return(0);
  13543. }
  13544. static void
  13545. xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
  13546. {
  13547. /*
  13548. * Try to rewrite "descendant-or-self::node()/foo" to an optimized
  13549. * internal representation.
  13550. */
  13551. if (op->ch1 != -1) {
  13552. if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
  13553. ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
  13554. ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
  13555. ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
  13556. {
  13557. /*
  13558. * This is a "child::foo"
  13559. */
  13560. xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
  13561. if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
  13562. (prevop->ch1 != -1) &&
  13563. ((xmlXPathAxisVal) prevop->value ==
  13564. AXIS_DESCENDANT_OR_SELF) &&
  13565. (prevop->ch2 == -1) &&
  13566. ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
  13567. ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
  13568. (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
  13569. {
  13570. /*
  13571. * This is a "/descendant-or-self::node()" without predicates.
  13572. * Eliminate it.
  13573. */
  13574. op->ch1 = prevop->ch1;
  13575. op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
  13576. }
  13577. }
  13578. if (op->ch1 != -1)
  13579. xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
  13580. }
  13581. if (op->ch2 != -1)
  13582. xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
  13583. }
  13584. /**
  13585. * xmlXPathCtxtCompile:
  13586. * @ctxt: an XPath context
  13587. * @str: the XPath expression
  13588. *
  13589. * Compile an XPath expression
  13590. *
  13591. * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
  13592. * the caller has to free the object.
  13593. */
  13594. xmlXPathCompExprPtr
  13595. xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
  13596. xmlXPathParserContextPtr pctxt;
  13597. xmlXPathCompExprPtr comp;
  13598. #ifdef XPATH_STREAMING
  13599. comp = xmlXPathTryStreamCompile(ctxt, str);
  13600. if (comp != NULL)
  13601. return(comp);
  13602. #endif
  13603. xmlXPathInit();
  13604. pctxt = xmlXPathNewParserContext(str, ctxt);
  13605. if (pctxt == NULL)
  13606. return NULL;
  13607. xmlXPathCompileExpr(pctxt, 1);
  13608. if( pctxt->error != XPATH_EXPRESSION_OK )
  13609. {
  13610. xmlXPathFreeParserContext(pctxt);
  13611. return(NULL);
  13612. }
  13613. if (*pctxt->cur != 0) {
  13614. /*
  13615. * aleksey: in some cases this line prints *second* error message
  13616. * (see bug #78858) and probably this should be fixed.
  13617. * However, we are not sure that all error messages are printed
  13618. * out in other places. It's not critical so we leave it as-is for now
  13619. */
  13620. xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
  13621. comp = NULL;
  13622. } else {
  13623. comp = pctxt->comp;
  13624. pctxt->comp = NULL;
  13625. }
  13626. xmlXPathFreeParserContext(pctxt);
  13627. if (comp != NULL) {
  13628. comp->expr = xmlStrdup(str);
  13629. #ifdef DEBUG_EVAL_COUNTS
  13630. comp->string = xmlStrdup(str);
  13631. comp->nb = 0;
  13632. #endif
  13633. if ((comp->expr != NULL) &&
  13634. (comp->nbStep > 2) &&
  13635. (comp->last >= 0) &&
  13636. (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
  13637. {
  13638. xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
  13639. }
  13640. }
  13641. return(comp);
  13642. }
  13643. /**
  13644. * xmlXPathCompile:
  13645. * @str: the XPath expression
  13646. *
  13647. * Compile an XPath expression
  13648. *
  13649. * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
  13650. * the caller has to free the object.
  13651. */
  13652. xmlXPathCompExprPtr
  13653. xmlXPathCompile(const xmlChar *str) {
  13654. return(xmlXPathCtxtCompile(NULL, str));
  13655. }
  13656. /**
  13657. * xmlXPathCompiledEvalInternal:
  13658. * @comp: the compiled XPath expression
  13659. * @ctxt: the XPath context
  13660. * @resObj: the resulting XPath object or NULL
  13661. * @toBool: 1 if only a boolean result is requested
  13662. *
  13663. * Evaluate the Precompiled XPath expression in the given context.
  13664. * The caller has to free @resObj.
  13665. *
  13666. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  13667. * the caller has to free the object.
  13668. */
  13669. static int
  13670. xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
  13671. xmlXPathContextPtr ctxt,
  13672. xmlXPathObjectPtr *resObj,
  13673. int toBool)
  13674. {
  13675. xmlXPathParserContextPtr pctxt;
  13676. #ifndef LIBXML_THREAD_ENABLED
  13677. static int reentance = 0;
  13678. #endif
  13679. int res;
  13680. CHECK_CTXT_NEG(ctxt)
  13681. if (comp == NULL)
  13682. return(-1);
  13683. xmlXPathInit();
  13684. #ifndef LIBXML_THREAD_ENABLED
  13685. reentance++;
  13686. if (reentance > 1)
  13687. xmlXPathDisableOptimizer = 1;
  13688. #endif
  13689. #ifdef DEBUG_EVAL_COUNTS
  13690. comp->nb++;
  13691. if ((comp->string != NULL) && (comp->nb > 100)) {
  13692. fprintf(stderr, "100 x %s\n", comp->string);
  13693. comp->nb = 0;
  13694. }
  13695. #endif
  13696. pctxt = xmlXPathCompParserContext(comp, ctxt);
  13697. res = xmlXPathRunEval(pctxt, toBool);
  13698. if (resObj) {
  13699. if (pctxt->value == NULL) {
  13700. xmlGenericError(xmlGenericErrorContext,
  13701. "xmlXPathCompiledEval: evaluation failed\n");
  13702. *resObj = NULL;
  13703. } else {
  13704. *resObj = valuePop(pctxt);
  13705. }
  13706. }
  13707. /*
  13708. * Pop all remaining objects from the stack.
  13709. */
  13710. if (pctxt->valueNr > 0) {
  13711. xmlXPathObjectPtr tmp;
  13712. int stack = 0;
  13713. do {
  13714. tmp = valuePop(pctxt);
  13715. if (tmp != NULL) {
  13716. stack++;
  13717. xmlXPathReleaseObject(ctxt, tmp);
  13718. }
  13719. } while (tmp != NULL);
  13720. if ((stack != 0) &&
  13721. ((toBool) || ((resObj) && (*resObj))))
  13722. {
  13723. xmlGenericError(xmlGenericErrorContext,
  13724. "xmlXPathCompiledEval: %d objects left on the stack.\n",
  13725. stack);
  13726. }
  13727. }
  13728. if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
  13729. xmlXPathFreeObject(*resObj);
  13730. *resObj = NULL;
  13731. }
  13732. pctxt->comp = NULL;
  13733. xmlXPathFreeParserContext(pctxt);
  13734. #ifndef LIBXML_THREAD_ENABLED
  13735. reentance--;
  13736. #endif
  13737. return(res);
  13738. }
  13739. /**
  13740. * xmlXPathCompiledEval:
  13741. * @comp: the compiled XPath expression
  13742. * @ctx: the XPath context
  13743. *
  13744. * Evaluate the Precompiled XPath expression in the given context.
  13745. *
  13746. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  13747. * the caller has to free the object.
  13748. */
  13749. xmlXPathObjectPtr
  13750. xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
  13751. {
  13752. xmlXPathObjectPtr res = NULL;
  13753. xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
  13754. return(res);
  13755. }
  13756. /**
  13757. * xmlXPathCompiledEvalToBoolean:
  13758. * @comp: the compiled XPath expression
  13759. * @ctxt: the XPath context
  13760. *
  13761. * Applies the XPath boolean() function on the result of the given
  13762. * compiled expression.
  13763. *
  13764. * Returns 1 if the expression evaluated to true, 0 if to false and
  13765. * -1 in API and internal errors.
  13766. */
  13767. int
  13768. xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
  13769. xmlXPathContextPtr ctxt)
  13770. {
  13771. return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
  13772. }
  13773. /**
  13774. * xmlXPathEvalExpr:
  13775. * @ctxt: the XPath Parser context
  13776. *
  13777. * Parse and evaluate an XPath expression in the given context,
  13778. * then push the result on the context stack
  13779. */
  13780. void
  13781. xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
  13782. #ifdef XPATH_STREAMING
  13783. xmlXPathCompExprPtr comp;
  13784. #endif
  13785. if (ctxt == NULL) return;
  13786. #ifdef XPATH_STREAMING
  13787. comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
  13788. if (comp != NULL) {
  13789. if (ctxt->comp != NULL)
  13790. xmlXPathFreeCompExpr(ctxt->comp);
  13791. ctxt->comp = comp;
  13792. if (ctxt->cur != NULL)
  13793. while (*ctxt->cur != 0) ctxt->cur++;
  13794. } else
  13795. #endif
  13796. {
  13797. xmlXPathCompileExpr(ctxt, 1);
  13798. /*
  13799. * In this scenario the expression string will sit in ctxt->base.
  13800. */
  13801. if ((ctxt->error == XPATH_EXPRESSION_OK) &&
  13802. (ctxt->comp != NULL) &&
  13803. (ctxt->base != NULL) &&
  13804. (ctxt->comp->nbStep > 2) &&
  13805. (ctxt->comp->last >= 0) &&
  13806. (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
  13807. {
  13808. xmlXPathRewriteDOSExpression(ctxt->comp,
  13809. &ctxt->comp->steps[ctxt->comp->last]);
  13810. }
  13811. }
  13812. CHECK_ERROR;
  13813. xmlXPathRunEval(ctxt, 0);
  13814. }
  13815. /**
  13816. * xmlXPathEval:
  13817. * @str: the XPath expression
  13818. * @ctx: the XPath context
  13819. *
  13820. * Evaluate the XPath Location Path in the given context.
  13821. *
  13822. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  13823. * the caller has to free the object.
  13824. */
  13825. xmlXPathObjectPtr
  13826. xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
  13827. xmlXPathParserContextPtr ctxt;
  13828. xmlXPathObjectPtr res, tmp, init = NULL;
  13829. int stack = 0;
  13830. CHECK_CTXT(ctx)
  13831. xmlXPathInit();
  13832. ctxt = xmlXPathNewParserContext(str, ctx);
  13833. if (ctxt == NULL)
  13834. return NULL;
  13835. xmlXPathEvalExpr(ctxt);
  13836. if (ctxt->value == NULL) {
  13837. xmlGenericError(xmlGenericErrorContext,
  13838. "xmlXPathEval: evaluation failed\n");
  13839. res = NULL;
  13840. } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
  13841. #ifdef XPATH_STREAMING
  13842. && (ctxt->comp->stream == NULL)
  13843. #endif
  13844. ) {
  13845. xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
  13846. res = NULL;
  13847. } else {
  13848. res = valuePop(ctxt);
  13849. }
  13850. do {
  13851. tmp = valuePop(ctxt);
  13852. if (tmp != NULL) {
  13853. if (tmp != init)
  13854. stack++;
  13855. xmlXPathReleaseObject(ctx, tmp);
  13856. }
  13857. } while (tmp != NULL);
  13858. if ((stack != 0) && (res != NULL)) {
  13859. xmlGenericError(xmlGenericErrorContext,
  13860. "xmlXPathEval: %d object left on the stack\n",
  13861. stack);
  13862. }
  13863. if (ctxt->error != XPATH_EXPRESSION_OK) {
  13864. xmlXPathFreeObject(res);
  13865. res = NULL;
  13866. }
  13867. xmlXPathFreeParserContext(ctxt);
  13868. return(res);
  13869. }
  13870. /**
  13871. * xmlXPathEvalExpression:
  13872. * @str: the XPath expression
  13873. * @ctxt: the XPath context
  13874. *
  13875. * Evaluate the XPath expression in the given context.
  13876. *
  13877. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  13878. * the caller has to free the object.
  13879. */
  13880. xmlXPathObjectPtr
  13881. xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
  13882. xmlXPathParserContextPtr pctxt;
  13883. xmlXPathObjectPtr res, tmp;
  13884. int stack = 0;
  13885. CHECK_CTXT(ctxt)
  13886. xmlXPathInit();
  13887. pctxt = xmlXPathNewParserContext(str, ctxt);
  13888. if (pctxt == NULL)
  13889. return NULL;
  13890. xmlXPathEvalExpr(pctxt);
  13891. if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
  13892. xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
  13893. res = NULL;
  13894. } else {
  13895. res = valuePop(pctxt);
  13896. }
  13897. do {
  13898. tmp = valuePop(pctxt);
  13899. if (tmp != NULL) {
  13900. xmlXPathReleaseObject(ctxt, tmp);
  13901. stack++;
  13902. }
  13903. } while (tmp != NULL);
  13904. if ((stack != 0) && (res != NULL)) {
  13905. xmlGenericError(xmlGenericErrorContext,
  13906. "xmlXPathEvalExpression: %d object left on the stack\n",
  13907. stack);
  13908. }
  13909. xmlXPathFreeParserContext(pctxt);
  13910. return(res);
  13911. }
  13912. /************************************************************************
  13913. * *
  13914. * Extra functions not pertaining to the XPath spec *
  13915. * *
  13916. ************************************************************************/
  13917. /**
  13918. * xmlXPathEscapeUriFunction:
  13919. * @ctxt: the XPath Parser context
  13920. * @nargs: the number of arguments
  13921. *
  13922. * Implement the escape-uri() XPath function
  13923. * string escape-uri(string $str, bool $escape-reserved)
  13924. *
  13925. * This function applies the URI escaping rules defined in section 2 of [RFC
  13926. * 2396] to the string supplied as $uri-part, which typically represents all
  13927. * or part of a URI. The effect of the function is to replace any special
  13928. * character in the string by an escape sequence of the form %xx%yy...,
  13929. * where xxyy... is the hexadecimal representation of the octets used to
  13930. * represent the character in UTF-8.
  13931. *
  13932. * The set of characters that are escaped depends on the setting of the
  13933. * boolean argument $escape-reserved.
  13934. *
  13935. * If $escape-reserved is true, all characters are escaped other than lower
  13936. * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
  13937. * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
  13938. * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
  13939. * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
  13940. * A-F).
  13941. *
  13942. * If $escape-reserved is false, the behavior differs in that characters
  13943. * referred to in [RFC 2396] as reserved characters are not escaped. These
  13944. * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
  13945. *
  13946. * [RFC 2396] does not define whether escaped URIs should use lower case or
  13947. * upper case for hexadecimal digits. To ensure that escaped URIs can be
  13948. * compared using string comparison functions, this function must always use
  13949. * the upper-case letters A-F.
  13950. *
  13951. * Generally, $escape-reserved should be set to true when escaping a string
  13952. * that is to form a single part of a URI, and to false when escaping an
  13953. * entire URI or URI reference.
  13954. *
  13955. * In the case of non-ascii characters, the string is encoded according to
  13956. * utf-8 and then converted according to RFC 2396.
  13957. *
  13958. * Examples
  13959. * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
  13960. * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
  13961. * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
  13962. * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
  13963. *
  13964. */
  13965. static void
  13966. xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  13967. xmlXPathObjectPtr str;
  13968. int escape_reserved;
  13969. xmlBufferPtr target;
  13970. xmlChar *cptr;
  13971. xmlChar escape[4];
  13972. CHECK_ARITY(2);
  13973. escape_reserved = xmlXPathPopBoolean(ctxt);
  13974. CAST_TO_STRING;
  13975. str = valuePop(ctxt);
  13976. target = xmlBufferCreate();
  13977. escape[0] = '%';
  13978. escape[3] = 0;
  13979. if (target) {
  13980. for (cptr = str->stringval; *cptr; cptr++) {
  13981. if ((*cptr >= 'A' && *cptr <= 'Z') ||
  13982. (*cptr >= 'a' && *cptr <= 'z') ||
  13983. (*cptr >= '0' && *cptr <= '9') ||
  13984. *cptr == '-' || *cptr == '_' || *cptr == '.' ||
  13985. *cptr == '!' || *cptr == '~' || *cptr == '*' ||
  13986. *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
  13987. (*cptr == '%' &&
  13988. ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
  13989. (cptr[1] >= 'a' && cptr[1] <= 'f') ||
  13990. (cptr[1] >= '0' && cptr[1] <= '9')) &&
  13991. ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
  13992. (cptr[2] >= 'a' && cptr[2] <= 'f') ||
  13993. (cptr[2] >= '0' && cptr[2] <= '9'))) ||
  13994. (!escape_reserved &&
  13995. (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
  13996. *cptr == ':' || *cptr == '@' || *cptr == '&' ||
  13997. *cptr == '=' || *cptr == '+' || *cptr == '$' ||
  13998. *cptr == ','))) {
  13999. xmlBufferAdd(target, cptr, 1);
  14000. } else {
  14001. if ((*cptr >> 4) < 10)
  14002. escape[1] = '0' + (*cptr >> 4);
  14003. else
  14004. escape[1] = 'A' - 10 + (*cptr >> 4);
  14005. if ((*cptr & 0xF) < 10)
  14006. escape[2] = '0' + (*cptr & 0xF);
  14007. else
  14008. escape[2] = 'A' - 10 + (*cptr & 0xF);
  14009. xmlBufferAdd(target, &escape[0], 3);
  14010. }
  14011. }
  14012. }
  14013. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  14014. xmlBufferContent(target)));
  14015. xmlBufferFree(target);
  14016. xmlXPathReleaseObject(ctxt->context, str);
  14017. }
  14018. /**
  14019. * xmlXPathRegisterAllFunctions:
  14020. * @ctxt: the XPath context
  14021. *
  14022. * Registers all default XPath functions in this context
  14023. */
  14024. void
  14025. xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
  14026. {
  14027. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
  14028. xmlXPathBooleanFunction);
  14029. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
  14030. xmlXPathCeilingFunction);
  14031. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
  14032. xmlXPathCountFunction);
  14033. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
  14034. xmlXPathConcatFunction);
  14035. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
  14036. xmlXPathContainsFunction);
  14037. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
  14038. xmlXPathIdFunction);
  14039. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
  14040. xmlXPathFalseFunction);
  14041. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
  14042. xmlXPathFloorFunction);
  14043. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
  14044. xmlXPathLastFunction);
  14045. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
  14046. xmlXPathLangFunction);
  14047. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
  14048. xmlXPathLocalNameFunction);
  14049. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
  14050. xmlXPathNotFunction);
  14051. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
  14052. xmlXPathNameFunction);
  14053. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
  14054. xmlXPathNamespaceURIFunction);
  14055. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
  14056. xmlXPathNormalizeFunction);
  14057. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
  14058. xmlXPathNumberFunction);
  14059. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
  14060. xmlXPathPositionFunction);
  14061. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
  14062. xmlXPathRoundFunction);
  14063. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
  14064. xmlXPathStringFunction);
  14065. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
  14066. xmlXPathStringLengthFunction);
  14067. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
  14068. xmlXPathStartsWithFunction);
  14069. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
  14070. xmlXPathSubstringFunction);
  14071. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
  14072. xmlXPathSubstringBeforeFunction);
  14073. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
  14074. xmlXPathSubstringAfterFunction);
  14075. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
  14076. xmlXPathSumFunction);
  14077. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
  14078. xmlXPathTrueFunction);
  14079. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
  14080. xmlXPathTranslateFunction);
  14081. xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
  14082. (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
  14083. xmlXPathEscapeUriFunction);
  14084. }
  14085. #endif /* LIBXML_XPATH_ENABLED */
  14086. #define bottom_xpath
  14087. #include "elfgcchack.h"