xpath.c 400 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735
  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. *
  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. /* To avoid EBCDIC trouble when parsing on zOS */
  17. #if defined(__MVS__)
  18. #pragma convert("ISO8859-1")
  19. #endif
  20. #define IN_LIBXML
  21. #include "libxml.h"
  22. #include <limits.h>
  23. #include <string.h>
  24. #include <stddef.h>
  25. #ifdef HAVE_SYS_TYPES_H
  26. #include <sys/types.h>
  27. #endif
  28. #ifdef HAVE_MATH_H
  29. #include <math.h>
  30. #endif
  31. #ifdef HAVE_FLOAT_H
  32. #include <float.h>
  33. #endif
  34. #ifdef HAVE_CTYPE_H
  35. #include <ctype.h>
  36. #endif
  37. #ifdef HAVE_SIGNAL_H
  38. #include <signal.h>
  39. #endif
  40. #include <libxml/xmlmemory.h>
  41. #include <libxml/tree.h>
  42. #include <libxml/valid.h>
  43. #include <libxml/xpath.h>
  44. #include <libxml/xpathInternals.h>
  45. #include <libxml/parserInternals.h>
  46. #include <libxml/hash.h>
  47. #ifdef LIBXML_XPTR_ENABLED
  48. #include <libxml/xpointer.h>
  49. #endif
  50. #ifdef LIBXML_DEBUG_ENABLED
  51. #include <libxml/debugXML.h>
  52. #endif
  53. #include <libxml/xmlerror.h>
  54. #include <libxml/threads.h>
  55. #include <libxml/globals.h>
  56. #ifdef LIBXML_PATTERN_ENABLED
  57. #include <libxml/pattern.h>
  58. #endif
  59. #include "buf.h"
  60. #ifdef LIBXML_PATTERN_ENABLED
  61. #define XPATH_STREAMING
  62. #endif
  63. #define TODO \
  64. xmlGenericError(xmlGenericErrorContext, \
  65. "Unimplemented block at %s:%d\n", \
  66. __FILE__, __LINE__);
  67. /**
  68. * WITH_TIM_SORT:
  69. *
  70. * Use the Timsort algorithm provided in timsort.h to sort
  71. * nodeset as this is a great improvement over the old Shell sort
  72. * used in xmlXPathNodeSetSort()
  73. */
  74. #define WITH_TIM_SORT
  75. /*
  76. * XP_OPTIMIZED_NON_ELEM_COMPARISON:
  77. * If defined, this will use xmlXPathCmpNodesExt() instead of
  78. * xmlXPathCmpNodes(). The new function is optimized comparison of
  79. * non-element nodes; actually it will speed up comparison only if
  80. * xmlXPathOrderDocElems() was called in order to index the elements of
  81. * a tree in document order; Libxslt does such an indexing, thus it will
  82. * benefit from this optimization.
  83. */
  84. #define XP_OPTIMIZED_NON_ELEM_COMPARISON
  85. /*
  86. * XP_OPTIMIZED_FILTER_FIRST:
  87. * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
  88. * in a way, that it stop evaluation at the first node.
  89. */
  90. #define XP_OPTIMIZED_FILTER_FIRST
  91. /*
  92. * XP_DEBUG_OBJ_USAGE:
  93. * Internal flag to enable tracking of how much XPath objects have been
  94. * created.
  95. */
  96. /* #define XP_DEBUG_OBJ_USAGE */
  97. /*
  98. * XPATH_MAX_STEPS:
  99. * when compiling an XPath expression we arbitrary limit the maximum
  100. * number of step operation in the compiled expression. 1000000 is
  101. * an insanely large value which should never be reached under normal
  102. * circumstances
  103. */
  104. #define XPATH_MAX_STEPS 1000000
  105. /*
  106. * XPATH_MAX_STACK_DEPTH:
  107. * when evaluating an XPath expression we arbitrary limit the maximum
  108. * number of object allowed to be pushed on the stack. 1000000 is
  109. * an insanely large value which should never be reached under normal
  110. * circumstances
  111. */
  112. #define XPATH_MAX_STACK_DEPTH 1000000
  113. /*
  114. * XPATH_MAX_NODESET_LENGTH:
  115. * when evaluating an XPath expression nodesets are created and we
  116. * arbitrary limit the maximum length of those node set. 10000000 is
  117. * an insanely large value which should never be reached under normal
  118. * circumstances, one would first need to construct an in memory tree
  119. * with more than 10 millions nodes.
  120. */
  121. #define XPATH_MAX_NODESET_LENGTH 10000000
  122. /*
  123. * XPATH_MAX_RECRUSION_DEPTH:
  124. * Maximum amount of nested functions calls when parsing or evaluating
  125. * expressions
  126. */
  127. #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
  128. #define XPATH_MAX_RECURSION_DEPTH 500
  129. #else
  130. #define XPATH_MAX_RECURSION_DEPTH 5000
  131. #endif
  132. /*
  133. * TODO:
  134. * There are a few spots where some tests are done which depend upon ascii
  135. * data. These should be enhanced for full UTF8 support (see particularly
  136. * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
  137. */
  138. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  139. /**
  140. * xmlXPathCmpNodesExt:
  141. * @node1: the first node
  142. * @node2: the second node
  143. *
  144. * Compare two nodes w.r.t document order.
  145. * This one is optimized for handling of non-element nodes.
  146. *
  147. * Returns -2 in case of error 1 if first point < second point, 0 if
  148. * it's the same node, -1 otherwise
  149. */
  150. static int
  151. xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
  152. int depth1, depth2;
  153. int misc = 0, precedence1 = 0, precedence2 = 0;
  154. xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
  155. xmlNodePtr cur, root;
  156. ptrdiff_t l1, l2;
  157. if ((node1 == NULL) || (node2 == NULL))
  158. return(-2);
  159. if (node1 == node2)
  160. return(0);
  161. /*
  162. * a couple of optimizations which will avoid computations in most cases
  163. */
  164. switch (node1->type) {
  165. case XML_ELEMENT_NODE:
  166. if (node2->type == XML_ELEMENT_NODE) {
  167. if ((0 > (ptrdiff_t) node1->content) &&
  168. (0 > (ptrdiff_t) node2->content) &&
  169. (node1->doc == node2->doc))
  170. {
  171. l1 = -((ptrdiff_t) node1->content);
  172. l2 = -((ptrdiff_t) node2->content);
  173. if (l1 < l2)
  174. return(1);
  175. if (l1 > l2)
  176. return(-1);
  177. } else
  178. goto turtle_comparison;
  179. }
  180. break;
  181. case XML_ATTRIBUTE_NODE:
  182. precedence1 = 1; /* element is owner */
  183. miscNode1 = node1;
  184. node1 = node1->parent;
  185. misc = 1;
  186. break;
  187. case XML_TEXT_NODE:
  188. case XML_CDATA_SECTION_NODE:
  189. case XML_COMMENT_NODE:
  190. case XML_PI_NODE: {
  191. miscNode1 = node1;
  192. /*
  193. * Find nearest element node.
  194. */
  195. if (node1->prev != NULL) {
  196. do {
  197. node1 = node1->prev;
  198. if (node1->type == XML_ELEMENT_NODE) {
  199. precedence1 = 3; /* element in prev-sibl axis */
  200. break;
  201. }
  202. if (node1->prev == NULL) {
  203. precedence1 = 2; /* element is parent */
  204. /*
  205. * URGENT TODO: Are there any cases, where the
  206. * parent of such a node is not an element node?
  207. */
  208. node1 = node1->parent;
  209. break;
  210. }
  211. } while (1);
  212. } else {
  213. precedence1 = 2; /* element is parent */
  214. node1 = node1->parent;
  215. }
  216. if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
  217. (0 <= (ptrdiff_t) node1->content)) {
  218. /*
  219. * Fallback for whatever case.
  220. */
  221. node1 = miscNode1;
  222. precedence1 = 0;
  223. } else
  224. misc = 1;
  225. }
  226. break;
  227. case XML_NAMESPACE_DECL:
  228. /*
  229. * TODO: why do we return 1 for namespace nodes?
  230. */
  231. return(1);
  232. default:
  233. break;
  234. }
  235. switch (node2->type) {
  236. case XML_ELEMENT_NODE:
  237. break;
  238. case XML_ATTRIBUTE_NODE:
  239. precedence2 = 1; /* element is owner */
  240. miscNode2 = node2;
  241. node2 = node2->parent;
  242. misc = 1;
  243. break;
  244. case XML_TEXT_NODE:
  245. case XML_CDATA_SECTION_NODE:
  246. case XML_COMMENT_NODE:
  247. case XML_PI_NODE: {
  248. miscNode2 = node2;
  249. if (node2->prev != NULL) {
  250. do {
  251. node2 = node2->prev;
  252. if (node2->type == XML_ELEMENT_NODE) {
  253. precedence2 = 3; /* element in prev-sibl axis */
  254. break;
  255. }
  256. if (node2->prev == NULL) {
  257. precedence2 = 2; /* element is parent */
  258. node2 = node2->parent;
  259. break;
  260. }
  261. } while (1);
  262. } else {
  263. precedence2 = 2; /* element is parent */
  264. node2 = node2->parent;
  265. }
  266. if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
  267. (0 <= (ptrdiff_t) node2->content))
  268. {
  269. node2 = miscNode2;
  270. precedence2 = 0;
  271. } else
  272. misc = 1;
  273. }
  274. break;
  275. case XML_NAMESPACE_DECL:
  276. return(1);
  277. default:
  278. break;
  279. }
  280. if (misc) {
  281. if (node1 == node2) {
  282. if (precedence1 == precedence2) {
  283. /*
  284. * The ugly case; but normally there aren't many
  285. * adjacent non-element nodes around.
  286. */
  287. cur = miscNode2->prev;
  288. while (cur != NULL) {
  289. if (cur == miscNode1)
  290. return(1);
  291. if (cur->type == XML_ELEMENT_NODE)
  292. return(-1);
  293. cur = cur->prev;
  294. }
  295. return (-1);
  296. } else {
  297. /*
  298. * Evaluate based on higher precedence wrt to the element.
  299. * TODO: This assumes attributes are sorted before content.
  300. * Is this 100% correct?
  301. */
  302. if (precedence1 < precedence2)
  303. return(1);
  304. else
  305. return(-1);
  306. }
  307. }
  308. /*
  309. * Special case: One of the helper-elements is contained by the other.
  310. * <foo>
  311. * <node2>
  312. * <node1>Text-1(precedence1 == 2)</node1>
  313. * </node2>
  314. * Text-6(precedence2 == 3)
  315. * </foo>
  316. */
  317. if ((precedence2 == 3) && (precedence1 > 1)) {
  318. cur = node1->parent;
  319. while (cur) {
  320. if (cur == node2)
  321. return(1);
  322. cur = cur->parent;
  323. }
  324. }
  325. if ((precedence1 == 3) && (precedence2 > 1)) {
  326. cur = node2->parent;
  327. while (cur) {
  328. if (cur == node1)
  329. return(-1);
  330. cur = cur->parent;
  331. }
  332. }
  333. }
  334. /*
  335. * Speedup using document order if available.
  336. */
  337. if ((node1->type == XML_ELEMENT_NODE) &&
  338. (node2->type == XML_ELEMENT_NODE) &&
  339. (0 > (ptrdiff_t) node1->content) &&
  340. (0 > (ptrdiff_t) node2->content) &&
  341. (node1->doc == node2->doc)) {
  342. l1 = -((ptrdiff_t) node1->content);
  343. l2 = -((ptrdiff_t) node2->content);
  344. if (l1 < l2)
  345. return(1);
  346. if (l1 > l2)
  347. return(-1);
  348. }
  349. turtle_comparison:
  350. if (node1 == node2->prev)
  351. return(1);
  352. if (node1 == node2->next)
  353. return(-1);
  354. /*
  355. * compute depth to root
  356. */
  357. for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
  358. if (cur->parent == node1)
  359. return(1);
  360. depth2++;
  361. }
  362. root = cur;
  363. for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
  364. if (cur->parent == node2)
  365. return(-1);
  366. depth1++;
  367. }
  368. /*
  369. * Distinct document (or distinct entities :-( ) case.
  370. */
  371. if (root != cur) {
  372. return(-2);
  373. }
  374. /*
  375. * get the nearest common ancestor.
  376. */
  377. while (depth1 > depth2) {
  378. depth1--;
  379. node1 = node1->parent;
  380. }
  381. while (depth2 > depth1) {
  382. depth2--;
  383. node2 = node2->parent;
  384. }
  385. while (node1->parent != node2->parent) {
  386. node1 = node1->parent;
  387. node2 = node2->parent;
  388. /* should not happen but just in case ... */
  389. if ((node1 == NULL) || (node2 == NULL))
  390. return(-2);
  391. }
  392. /*
  393. * Find who's first.
  394. */
  395. if (node1 == node2->prev)
  396. return(1);
  397. if (node1 == node2->next)
  398. return(-1);
  399. /*
  400. * Speedup using document order if available.
  401. */
  402. if ((node1->type == XML_ELEMENT_NODE) &&
  403. (node2->type == XML_ELEMENT_NODE) &&
  404. (0 > (ptrdiff_t) node1->content) &&
  405. (0 > (ptrdiff_t) node2->content) &&
  406. (node1->doc == node2->doc)) {
  407. l1 = -((ptrdiff_t) node1->content);
  408. l2 = -((ptrdiff_t) node2->content);
  409. if (l1 < l2)
  410. return(1);
  411. if (l1 > l2)
  412. return(-1);
  413. }
  414. for (cur = node1->next;cur != NULL;cur = cur->next)
  415. if (cur == node2)
  416. return(1);
  417. return(-1); /* assume there is no sibling list corruption */
  418. }
  419. #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
  420. /*
  421. * Wrapper for the Timsort algorithm from timsort.h
  422. */
  423. #ifdef WITH_TIM_SORT
  424. #define SORT_NAME libxml_domnode
  425. #define SORT_TYPE xmlNodePtr
  426. /**
  427. * wrap_cmp:
  428. * @x: a node
  429. * @y: another node
  430. *
  431. * Comparison function for the Timsort implementation
  432. *
  433. * Returns -2 in case of error -1 if first point < second point, 0 if
  434. * it's the same node, +1 otherwise
  435. */
  436. static
  437. int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
  438. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  439. static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
  440. {
  441. int res = xmlXPathCmpNodesExt(x, y);
  442. return res == -2 ? res : -res;
  443. }
  444. #else
  445. static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
  446. {
  447. int res = xmlXPathCmpNodes(x, y);
  448. return res == -2 ? res : -res;
  449. }
  450. #endif
  451. #define SORT_CMP(x, y) (wrap_cmp(x, y))
  452. #include "timsort.h"
  453. #endif /* WITH_TIM_SORT */
  454. #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
  455. /************************************************************************
  456. * *
  457. * Floating point stuff *
  458. * *
  459. ************************************************************************/
  460. double xmlXPathNAN;
  461. double xmlXPathPINF;
  462. double xmlXPathNINF;
  463. /**
  464. * xmlXPathInit:
  465. *
  466. * Initialize the XPath environment
  467. */
  468. void
  469. xmlXPathInit(void) {
  470. /* Use MSVC definitions */
  471. xmlXPathNAN = NAN;
  472. xmlXPathPINF = INFINITY;
  473. xmlXPathNINF = -INFINITY;
  474. }
  475. /**
  476. * xmlXPathIsNaN:
  477. * @val: a double value
  478. *
  479. * Returns 1 if the value is a NaN, 0 otherwise
  480. */
  481. int
  482. xmlXPathIsNaN(double val) {
  483. #ifdef isnan
  484. return isnan(val);
  485. #else
  486. return !(val == val);
  487. #endif
  488. }
  489. /**
  490. * xmlXPathIsInf:
  491. * @val: a double value
  492. *
  493. * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
  494. */
  495. int
  496. xmlXPathIsInf(double val) {
  497. #ifdef isinf
  498. return isinf(val) ? (val > 0 ? 1 : -1) : 0;
  499. #else
  500. if (val >= xmlXPathPINF)
  501. return 1;
  502. if (val <= -xmlXPathPINF)
  503. return -1;
  504. return 0;
  505. #endif
  506. }
  507. #endif /* SCHEMAS or XPATH */
  508. #ifdef LIBXML_XPATH_ENABLED
  509. /*
  510. * TODO: when compatibility allows remove all "fake node libxslt" strings
  511. * the test should just be name[0] = ' '
  512. */
  513. #ifdef DEBUG_XPATH_EXPRESSION
  514. #define DEBUG_STEP
  515. #define DEBUG_EXPR
  516. #define DEBUG_EVAL_COUNTS
  517. #endif
  518. static xmlNs xmlXPathXMLNamespaceStruct = {
  519. NULL,
  520. XML_NAMESPACE_DECL,
  521. XML_XML_NAMESPACE,
  522. BAD_CAST "xml",
  523. NULL,
  524. NULL
  525. };
  526. static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
  527. #ifndef LIBXML_THREAD_ENABLED
  528. /*
  529. * Optimizer is disabled only when threaded apps are detected while
  530. * the library ain't compiled for thread safety.
  531. */
  532. static int xmlXPathDisableOptimizer = 0;
  533. #endif
  534. /************************************************************************
  535. * *
  536. * Error handling routines *
  537. * *
  538. ************************************************************************/
  539. /**
  540. * XP_ERRORNULL:
  541. * @X: the error code
  542. *
  543. * Macro to raise an XPath error and return NULL.
  544. */
  545. #define XP_ERRORNULL(X) \
  546. { xmlXPathErr(ctxt, X); return(NULL); }
  547. /*
  548. * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
  549. */
  550. static const char *xmlXPathErrorMessages[] = {
  551. "Ok\n",
  552. "Number encoding\n",
  553. "Unfinished literal\n",
  554. "Start of literal\n",
  555. "Expected $ for variable reference\n",
  556. "Undefined variable\n",
  557. "Invalid predicate\n",
  558. "Invalid expression\n",
  559. "Missing closing curly brace\n",
  560. "Unregistered function\n",
  561. "Invalid operand\n",
  562. "Invalid type\n",
  563. "Invalid number of arguments\n",
  564. "Invalid context size\n",
  565. "Invalid context position\n",
  566. "Memory allocation error\n",
  567. "Syntax error\n",
  568. "Resource error\n",
  569. "Sub resource error\n",
  570. "Undefined namespace prefix\n",
  571. "Encoding error\n",
  572. "Char out of XML range\n",
  573. "Invalid or incomplete context\n",
  574. "Stack usage error\n",
  575. "Forbidden variable\n",
  576. "Operation limit exceeded\n",
  577. "Recursion limit exceeded\n",
  578. "?? Unknown error ??\n" /* Must be last in the list! */
  579. };
  580. #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
  581. sizeof(xmlXPathErrorMessages[0])) - 1)
  582. /**
  583. * xmlXPathErrMemory:
  584. * @ctxt: an XPath context
  585. * @extra: extra information
  586. *
  587. * Handle a redefinition of attribute error
  588. */
  589. static void
  590. xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
  591. {
  592. if (ctxt != NULL) {
  593. xmlResetError(&ctxt->lastError);
  594. if (extra) {
  595. xmlChar buf[200];
  596. xmlStrPrintf(buf, 200,
  597. "Memory allocation failed : %s\n",
  598. extra);
  599. ctxt->lastError.message = (char *) xmlStrdup(buf);
  600. } else {
  601. ctxt->lastError.message = (char *)
  602. xmlStrdup(BAD_CAST "Memory allocation failed\n");
  603. }
  604. ctxt->lastError.domain = XML_FROM_XPATH;
  605. ctxt->lastError.code = XML_ERR_NO_MEMORY;
  606. if (ctxt->error != NULL)
  607. ctxt->error(ctxt->userData, &ctxt->lastError);
  608. } else {
  609. if (extra)
  610. __xmlRaiseError(NULL, NULL, NULL,
  611. NULL, NULL, XML_FROM_XPATH,
  612. XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
  613. extra, NULL, NULL, 0, 0,
  614. "Memory allocation failed : %s\n", extra);
  615. else
  616. __xmlRaiseError(NULL, NULL, NULL,
  617. NULL, NULL, XML_FROM_XPATH,
  618. XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
  619. NULL, NULL, NULL, 0, 0,
  620. "Memory allocation failed\n");
  621. }
  622. }
  623. /**
  624. * xmlXPathPErrMemory:
  625. * @ctxt: an XPath parser context
  626. * @extra: extra information
  627. *
  628. * Handle a redefinition of attribute error
  629. */
  630. static void
  631. xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
  632. {
  633. if (ctxt == NULL)
  634. xmlXPathErrMemory(NULL, extra);
  635. else {
  636. ctxt->error = XPATH_MEMORY_ERROR;
  637. xmlXPathErrMemory(ctxt->context, extra);
  638. }
  639. }
  640. /**
  641. * xmlXPathErr:
  642. * @ctxt: a XPath parser context
  643. * @error: the error code
  644. *
  645. * Handle an XPath error
  646. */
  647. void
  648. xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
  649. {
  650. if ((error < 0) || (error > MAXERRNO))
  651. error = MAXERRNO;
  652. if (ctxt == NULL) {
  653. __xmlRaiseError(NULL, NULL, NULL,
  654. NULL, NULL, XML_FROM_XPATH,
  655. error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  656. XML_ERR_ERROR, NULL, 0,
  657. NULL, NULL, NULL, 0, 0,
  658. "%s", xmlXPathErrorMessages[error]);
  659. return;
  660. }
  661. ctxt->error = error;
  662. if (ctxt->context == NULL) {
  663. __xmlRaiseError(NULL, NULL, NULL,
  664. NULL, NULL, XML_FROM_XPATH,
  665. error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  666. XML_ERR_ERROR, NULL, 0,
  667. (const char *) ctxt->base, NULL, NULL,
  668. ctxt->cur - ctxt->base, 0,
  669. "%s", xmlXPathErrorMessages[error]);
  670. return;
  671. }
  672. /* cleanup current last error */
  673. xmlResetError(&ctxt->context->lastError);
  674. ctxt->context->lastError.domain = XML_FROM_XPATH;
  675. ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
  676. XPATH_EXPRESSION_OK;
  677. ctxt->context->lastError.level = XML_ERR_ERROR;
  678. ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
  679. ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
  680. ctxt->context->lastError.node = ctxt->context->debugNode;
  681. if (ctxt->context->error != NULL) {
  682. ctxt->context->error(ctxt->context->userData,
  683. &ctxt->context->lastError);
  684. } else {
  685. __xmlRaiseError(NULL, NULL, NULL,
  686. NULL, ctxt->context->debugNode, XML_FROM_XPATH,
  687. error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
  688. XML_ERR_ERROR, NULL, 0,
  689. (const char *) ctxt->base, NULL, NULL,
  690. ctxt->cur - ctxt->base, 0,
  691. "%s", xmlXPathErrorMessages[error]);
  692. }
  693. }
  694. /**
  695. * xmlXPatherror:
  696. * @ctxt: the XPath Parser context
  697. * @file: the file name
  698. * @line: the line number
  699. * @no: the error number
  700. *
  701. * Formats an error message.
  702. */
  703. void
  704. xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
  705. int line ATTRIBUTE_UNUSED, int no) {
  706. xmlXPathErr(ctxt, no);
  707. }
  708. /**
  709. * xmlXPathCheckOpLimit:
  710. * @ctxt: the XPath Parser context
  711. * @opCount: the number of operations to be added
  712. *
  713. * Adds opCount to the running total of operations and returns -1 if the
  714. * operation limit is exceeded. Returns 0 otherwise.
  715. */
  716. static int
  717. xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
  718. xmlXPathContextPtr xpctxt = ctxt->context;
  719. if ((opCount > xpctxt->opLimit) ||
  720. (xpctxt->opCount > xpctxt->opLimit - opCount)) {
  721. xpctxt->opCount = xpctxt->opLimit;
  722. xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
  723. return(-1);
  724. }
  725. xpctxt->opCount += opCount;
  726. return(0);
  727. }
  728. #define OP_LIMIT_EXCEEDED(ctxt, n) \
  729. ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
  730. /************************************************************************
  731. * *
  732. * Utilities *
  733. * *
  734. ************************************************************************/
  735. /**
  736. * xsltPointerList:
  737. *
  738. * Pointer-list for various purposes.
  739. */
  740. typedef struct _xmlPointerList xmlPointerList;
  741. typedef xmlPointerList *xmlPointerListPtr;
  742. struct _xmlPointerList {
  743. void **items;
  744. int number;
  745. int size;
  746. };
  747. /*
  748. * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
  749. * and here, we should make the functions public.
  750. */
  751. static int
  752. xmlPointerListAddSize(xmlPointerListPtr list,
  753. void *item,
  754. int initialSize)
  755. {
  756. if (list->items == NULL) {
  757. if (initialSize <= 0)
  758. initialSize = 1;
  759. list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
  760. if (list->items == NULL) {
  761. xmlXPathErrMemory(NULL,
  762. "xmlPointerListCreate: allocating item\n");
  763. return(-1);
  764. }
  765. list->number = 0;
  766. list->size = initialSize;
  767. } else if (list->size <= list->number) {
  768. if (list->size > 50000000) {
  769. xmlXPathErrMemory(NULL,
  770. "xmlPointerListAddSize: re-allocating item\n");
  771. return(-1);
  772. }
  773. list->size *= 2;
  774. list->items = (void **) xmlRealloc(list->items,
  775. list->size * sizeof(void *));
  776. if (list->items == NULL) {
  777. xmlXPathErrMemory(NULL,
  778. "xmlPointerListAddSize: re-allocating item\n");
  779. list->size = 0;
  780. return(-1);
  781. }
  782. }
  783. list->items[list->number++] = item;
  784. return(0);
  785. }
  786. /**
  787. * xsltPointerListCreate:
  788. *
  789. * Creates an xsltPointerList structure.
  790. *
  791. * Returns a xsltPointerList structure or NULL in case of an error.
  792. */
  793. static xmlPointerListPtr
  794. xmlPointerListCreate(int initialSize)
  795. {
  796. xmlPointerListPtr ret;
  797. ret = xmlMalloc(sizeof(xmlPointerList));
  798. if (ret == NULL) {
  799. xmlXPathErrMemory(NULL,
  800. "xmlPointerListCreate: allocating item\n");
  801. return (NULL);
  802. }
  803. memset(ret, 0, sizeof(xmlPointerList));
  804. if (initialSize > 0) {
  805. xmlPointerListAddSize(ret, NULL, initialSize);
  806. ret->number = 0;
  807. }
  808. return (ret);
  809. }
  810. /**
  811. * xsltPointerListFree:
  812. *
  813. * Frees the xsltPointerList structure. This does not free
  814. * the content of the list.
  815. */
  816. static void
  817. xmlPointerListFree(xmlPointerListPtr list)
  818. {
  819. if (list == NULL)
  820. return;
  821. if (list->items != NULL)
  822. xmlFree(list->items);
  823. xmlFree(list);
  824. }
  825. /************************************************************************
  826. * *
  827. * Parser Types *
  828. * *
  829. ************************************************************************/
  830. /*
  831. * Types are private:
  832. */
  833. typedef enum {
  834. XPATH_OP_END=0,
  835. XPATH_OP_AND,
  836. XPATH_OP_OR,
  837. XPATH_OP_EQUAL,
  838. XPATH_OP_CMP,
  839. XPATH_OP_PLUS,
  840. XPATH_OP_MULT,
  841. XPATH_OP_UNION,
  842. XPATH_OP_ROOT,
  843. XPATH_OP_NODE,
  844. XPATH_OP_COLLECT,
  845. XPATH_OP_VALUE, /* 11 */
  846. XPATH_OP_VARIABLE,
  847. XPATH_OP_FUNCTION,
  848. XPATH_OP_ARG,
  849. XPATH_OP_PREDICATE,
  850. XPATH_OP_FILTER, /* 16 */
  851. XPATH_OP_SORT /* 17 */
  852. #ifdef LIBXML_XPTR_ENABLED
  853. ,XPATH_OP_RANGETO
  854. #endif
  855. } xmlXPathOp;
  856. typedef enum {
  857. AXIS_ANCESTOR = 1,
  858. AXIS_ANCESTOR_OR_SELF,
  859. AXIS_ATTRIBUTE,
  860. AXIS_CHILD,
  861. AXIS_DESCENDANT,
  862. AXIS_DESCENDANT_OR_SELF,
  863. AXIS_FOLLOWING,
  864. AXIS_FOLLOWING_SIBLING,
  865. AXIS_NAMESPACE,
  866. AXIS_PARENT,
  867. AXIS_PRECEDING,
  868. AXIS_PRECEDING_SIBLING,
  869. AXIS_SELF
  870. } xmlXPathAxisVal;
  871. typedef enum {
  872. NODE_TEST_NONE = 0,
  873. NODE_TEST_TYPE = 1,
  874. NODE_TEST_PI = 2,
  875. NODE_TEST_ALL = 3,
  876. NODE_TEST_NS = 4,
  877. NODE_TEST_NAME = 5
  878. } xmlXPathTestVal;
  879. typedef enum {
  880. NODE_TYPE_NODE = 0,
  881. NODE_TYPE_COMMENT = XML_COMMENT_NODE,
  882. NODE_TYPE_TEXT = XML_TEXT_NODE,
  883. NODE_TYPE_PI = XML_PI_NODE
  884. } xmlXPathTypeVal;
  885. typedef struct _xmlXPathStepOp xmlXPathStepOp;
  886. typedef xmlXPathStepOp *xmlXPathStepOpPtr;
  887. struct _xmlXPathStepOp {
  888. xmlXPathOp op; /* The identifier of the operation */
  889. int ch1; /* First child */
  890. int ch2; /* Second child */
  891. int value;
  892. int value2;
  893. int value3;
  894. void *value4;
  895. void *value5;
  896. xmlXPathFunction cache;
  897. void *cacheURI;
  898. };
  899. struct _xmlXPathCompExpr {
  900. int nbStep; /* Number of steps in this expression */
  901. int maxStep; /* Maximum number of steps allocated */
  902. xmlXPathStepOp *steps; /* ops for computation of this expression */
  903. int last; /* index of last step in expression */
  904. xmlChar *expr; /* the expression being computed */
  905. xmlDictPtr dict; /* the dictionary to use if any */
  906. #ifdef DEBUG_EVAL_COUNTS
  907. int nb;
  908. xmlChar *string;
  909. #endif
  910. #ifdef XPATH_STREAMING
  911. xmlPatternPtr stream;
  912. #endif
  913. };
  914. /************************************************************************
  915. * *
  916. * Forward declarations *
  917. * *
  918. ************************************************************************/
  919. static void
  920. xmlXPathFreeValueTree(xmlNodeSetPtr obj);
  921. static void
  922. xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
  923. static int
  924. xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
  925. xmlXPathStepOpPtr op, xmlNodePtr *first);
  926. static int
  927. xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
  928. xmlXPathStepOpPtr op,
  929. int isPredicate);
  930. static void
  931. xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
  932. /************************************************************************
  933. * *
  934. * Parser Type functions *
  935. * *
  936. ************************************************************************/
  937. /**
  938. * xmlXPathNewCompExpr:
  939. *
  940. * Create a new Xpath component
  941. *
  942. * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
  943. */
  944. static xmlXPathCompExprPtr
  945. xmlXPathNewCompExpr(void) {
  946. xmlXPathCompExprPtr cur;
  947. cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
  948. if (cur == NULL) {
  949. xmlXPathErrMemory(NULL, "allocating component\n");
  950. return(NULL);
  951. }
  952. memset(cur, 0, sizeof(xmlXPathCompExpr));
  953. cur->maxStep = 10;
  954. cur->nbStep = 0;
  955. cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
  956. sizeof(xmlXPathStepOp));
  957. if (cur->steps == NULL) {
  958. xmlXPathErrMemory(NULL, "allocating steps\n");
  959. xmlFree(cur);
  960. return(NULL);
  961. }
  962. memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
  963. cur->last = -1;
  964. #ifdef DEBUG_EVAL_COUNTS
  965. cur->nb = 0;
  966. #endif
  967. return(cur);
  968. }
  969. /**
  970. * xmlXPathFreeCompExpr:
  971. * @comp: an XPATH comp
  972. *
  973. * Free up the memory allocated by @comp
  974. */
  975. void
  976. xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
  977. {
  978. xmlXPathStepOpPtr op;
  979. int i;
  980. if (comp == NULL)
  981. return;
  982. if (comp->dict == NULL) {
  983. for (i = 0; i < comp->nbStep; i++) {
  984. op = &comp->steps[i];
  985. if (op->value4 != NULL) {
  986. if (op->op == XPATH_OP_VALUE)
  987. xmlXPathFreeObject(op->value4);
  988. else
  989. xmlFree(op->value4);
  990. }
  991. if (op->value5 != NULL)
  992. xmlFree(op->value5);
  993. }
  994. } else {
  995. for (i = 0; i < comp->nbStep; i++) {
  996. op = &comp->steps[i];
  997. if (op->value4 != NULL) {
  998. if (op->op == XPATH_OP_VALUE)
  999. xmlXPathFreeObject(op->value4);
  1000. }
  1001. }
  1002. xmlDictFree(comp->dict);
  1003. }
  1004. if (comp->steps != NULL) {
  1005. xmlFree(comp->steps);
  1006. }
  1007. #ifdef DEBUG_EVAL_COUNTS
  1008. if (comp->string != NULL) {
  1009. xmlFree(comp->string);
  1010. }
  1011. #endif
  1012. #ifdef XPATH_STREAMING
  1013. if (comp->stream != NULL) {
  1014. xmlFreePatternList(comp->stream);
  1015. }
  1016. #endif
  1017. if (comp->expr != NULL) {
  1018. xmlFree(comp->expr);
  1019. }
  1020. xmlFree(comp);
  1021. }
  1022. /**
  1023. * xmlXPathCompExprAdd:
  1024. * @comp: the compiled expression
  1025. * @ch1: first child index
  1026. * @ch2: second child index
  1027. * @op: an op
  1028. * @value: the first int value
  1029. * @value2: the second int value
  1030. * @value3: the third int value
  1031. * @value4: the first string value
  1032. * @value5: the second string value
  1033. *
  1034. * Add a step to an XPath Compiled Expression
  1035. *
  1036. * Returns -1 in case of failure, the index otherwise
  1037. */
  1038. static int
  1039. xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
  1040. xmlXPathOp op, int value,
  1041. int value2, int value3, void *value4, void *value5) {
  1042. xmlXPathCompExprPtr comp = ctxt->comp;
  1043. if (comp->nbStep >= comp->maxStep) {
  1044. xmlXPathStepOp *real;
  1045. if (comp->maxStep >= XPATH_MAX_STEPS) {
  1046. xmlXPathPErrMemory(ctxt, "adding step\n");
  1047. return(-1);
  1048. }
  1049. comp->maxStep *= 2;
  1050. real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
  1051. comp->maxStep * sizeof(xmlXPathStepOp));
  1052. if (real == NULL) {
  1053. comp->maxStep /= 2;
  1054. xmlXPathPErrMemory(ctxt, "adding step\n");
  1055. return(-1);
  1056. }
  1057. comp->steps = real;
  1058. }
  1059. comp->last = comp->nbStep;
  1060. comp->steps[comp->nbStep].ch1 = ch1;
  1061. comp->steps[comp->nbStep].ch2 = ch2;
  1062. comp->steps[comp->nbStep].op = op;
  1063. comp->steps[comp->nbStep].value = value;
  1064. comp->steps[comp->nbStep].value2 = value2;
  1065. comp->steps[comp->nbStep].value3 = value3;
  1066. if ((comp->dict != NULL) &&
  1067. ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
  1068. (op == XPATH_OP_COLLECT))) {
  1069. if (value4 != NULL) {
  1070. comp->steps[comp->nbStep].value4 = (xmlChar *)
  1071. (void *)xmlDictLookup(comp->dict, value4, -1);
  1072. xmlFree(value4);
  1073. } else
  1074. comp->steps[comp->nbStep].value4 = NULL;
  1075. if (value5 != NULL) {
  1076. comp->steps[comp->nbStep].value5 = (xmlChar *)
  1077. (void *)xmlDictLookup(comp->dict, value5, -1);
  1078. xmlFree(value5);
  1079. } else
  1080. comp->steps[comp->nbStep].value5 = NULL;
  1081. } else {
  1082. comp->steps[comp->nbStep].value4 = value4;
  1083. comp->steps[comp->nbStep].value5 = value5;
  1084. }
  1085. comp->steps[comp->nbStep].cache = NULL;
  1086. return(comp->nbStep++);
  1087. }
  1088. /**
  1089. * xmlXPathCompSwap:
  1090. * @comp: the compiled expression
  1091. * @op: operation index
  1092. *
  1093. * Swaps 2 operations in the compiled expression
  1094. */
  1095. static void
  1096. xmlXPathCompSwap(xmlXPathStepOpPtr op) {
  1097. int tmp;
  1098. #ifndef LIBXML_THREAD_ENABLED
  1099. /*
  1100. * Since this manipulates possibly shared variables, this is
  1101. * disabled if one detects that the library is used in a multithreaded
  1102. * application
  1103. */
  1104. if (xmlXPathDisableOptimizer)
  1105. return;
  1106. #endif
  1107. tmp = op->ch1;
  1108. op->ch1 = op->ch2;
  1109. op->ch2 = tmp;
  1110. }
  1111. #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
  1112. xmlXPathCompExprAdd(ctxt, (op1), (op2), \
  1113. (op), (val), (val2), (val3), (val4), (val5))
  1114. #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
  1115. xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
  1116. (op), (val), (val2), (val3), (val4), (val5))
  1117. #define PUSH_LEAVE_EXPR(op, val, val2) \
  1118. xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
  1119. #define PUSH_UNARY_EXPR(op, ch, val, val2) \
  1120. xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
  1121. #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
  1122. xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
  1123. (val), (val2), 0 ,NULL ,NULL)
  1124. /************************************************************************
  1125. * *
  1126. * XPath object cache structures *
  1127. * *
  1128. ************************************************************************/
  1129. /* #define XP_DEFAULT_CACHE_ON */
  1130. #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
  1131. typedef struct _xmlXPathContextCache xmlXPathContextCache;
  1132. typedef xmlXPathContextCache *xmlXPathContextCachePtr;
  1133. struct _xmlXPathContextCache {
  1134. xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
  1135. xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
  1136. xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
  1137. xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
  1138. xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
  1139. int maxNodeset;
  1140. int maxString;
  1141. int maxBoolean;
  1142. int maxNumber;
  1143. int maxMisc;
  1144. #ifdef XP_DEBUG_OBJ_USAGE
  1145. int dbgCachedAll;
  1146. int dbgCachedNodeset;
  1147. int dbgCachedString;
  1148. int dbgCachedBool;
  1149. int dbgCachedNumber;
  1150. int dbgCachedPoint;
  1151. int dbgCachedRange;
  1152. int dbgCachedLocset;
  1153. int dbgCachedUsers;
  1154. int dbgCachedXSLTTree;
  1155. int dbgCachedUndefined;
  1156. int dbgReusedAll;
  1157. int dbgReusedNodeset;
  1158. int dbgReusedString;
  1159. int dbgReusedBool;
  1160. int dbgReusedNumber;
  1161. int dbgReusedPoint;
  1162. int dbgReusedRange;
  1163. int dbgReusedLocset;
  1164. int dbgReusedUsers;
  1165. int dbgReusedXSLTTree;
  1166. int dbgReusedUndefined;
  1167. #endif
  1168. };
  1169. /************************************************************************
  1170. * *
  1171. * Debugging related functions *
  1172. * *
  1173. ************************************************************************/
  1174. #define STRANGE \
  1175. xmlGenericError(xmlGenericErrorContext, \
  1176. "Internal error at %s:%d\n", \
  1177. __FILE__, __LINE__);
  1178. #ifdef LIBXML_DEBUG_ENABLED
  1179. static void
  1180. xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
  1181. int i;
  1182. char shift[100];
  1183. for (i = 0;((i < depth) && (i < 25));i++)
  1184. shift[2 * i] = shift[2 * i + 1] = ' ';
  1185. shift[2 * i] = shift[2 * i + 1] = 0;
  1186. if (cur == NULL) {
  1187. fprintf(output, "%s", shift);
  1188. fprintf(output, "Node is NULL !\n");
  1189. return;
  1190. }
  1191. if ((cur->type == XML_DOCUMENT_NODE) ||
  1192. (cur->type == XML_HTML_DOCUMENT_NODE)) {
  1193. fprintf(output, "%s", shift);
  1194. fprintf(output, " /\n");
  1195. } else if (cur->type == XML_ATTRIBUTE_NODE)
  1196. xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
  1197. else
  1198. xmlDebugDumpOneNode(output, cur, depth);
  1199. }
  1200. static void
  1201. xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
  1202. xmlNodePtr tmp;
  1203. int i;
  1204. char shift[100];
  1205. for (i = 0;((i < depth) && (i < 25));i++)
  1206. shift[2 * i] = shift[2 * i + 1] = ' ';
  1207. shift[2 * i] = shift[2 * i + 1] = 0;
  1208. if (cur == NULL) {
  1209. fprintf(output, "%s", shift);
  1210. fprintf(output, "Node is NULL !\n");
  1211. return;
  1212. }
  1213. while (cur != NULL) {
  1214. tmp = cur;
  1215. cur = cur->next;
  1216. xmlDebugDumpOneNode(output, tmp, depth);
  1217. }
  1218. }
  1219. static void
  1220. xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
  1221. int i;
  1222. char shift[100];
  1223. for (i = 0;((i < depth) && (i < 25));i++)
  1224. shift[2 * i] = shift[2 * i + 1] = ' ';
  1225. shift[2 * i] = shift[2 * i + 1] = 0;
  1226. if (cur == NULL) {
  1227. fprintf(output, "%s", shift);
  1228. fprintf(output, "NodeSet is NULL !\n");
  1229. return;
  1230. }
  1231. if (cur != NULL) {
  1232. fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
  1233. for (i = 0;i < cur->nodeNr;i++) {
  1234. fprintf(output, "%s", shift);
  1235. fprintf(output, "%d", i + 1);
  1236. xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
  1237. }
  1238. }
  1239. }
  1240. static void
  1241. xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
  1242. int i;
  1243. char shift[100];
  1244. for (i = 0;((i < depth) && (i < 25));i++)
  1245. shift[2 * i] = shift[2 * i + 1] = ' ';
  1246. shift[2 * i] = shift[2 * i + 1] = 0;
  1247. if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
  1248. fprintf(output, "%s", shift);
  1249. fprintf(output, "Value Tree is NULL !\n");
  1250. return;
  1251. }
  1252. fprintf(output, "%s", shift);
  1253. fprintf(output, "%d", i + 1);
  1254. xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
  1255. }
  1256. #if defined(LIBXML_XPTR_ENABLED)
  1257. static void
  1258. xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
  1259. int i;
  1260. char shift[100];
  1261. for (i = 0;((i < depth) && (i < 25));i++)
  1262. shift[2 * i] = shift[2 * i + 1] = ' ';
  1263. shift[2 * i] = shift[2 * i + 1] = 0;
  1264. if (cur == NULL) {
  1265. fprintf(output, "%s", shift);
  1266. fprintf(output, "LocationSet is NULL !\n");
  1267. return;
  1268. }
  1269. for (i = 0;i < cur->locNr;i++) {
  1270. fprintf(output, "%s", shift);
  1271. fprintf(output, "%d : ", i + 1);
  1272. xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
  1273. }
  1274. }
  1275. #endif /* LIBXML_XPTR_ENABLED */
  1276. /**
  1277. * xmlXPathDebugDumpObject:
  1278. * @output: the FILE * to dump the output
  1279. * @cur: the object to inspect
  1280. * @depth: indentation level
  1281. *
  1282. * Dump the content of the object for debugging purposes
  1283. */
  1284. void
  1285. xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
  1286. int i;
  1287. char shift[100];
  1288. if (output == NULL) return;
  1289. for (i = 0;((i < depth) && (i < 25));i++)
  1290. shift[2 * i] = shift[2 * i + 1] = ' ';
  1291. shift[2 * i] = shift[2 * i + 1] = 0;
  1292. fprintf(output, "%s", shift);
  1293. if (cur == NULL) {
  1294. fprintf(output, "Object is empty (NULL)\n");
  1295. return;
  1296. }
  1297. switch(cur->type) {
  1298. case XPATH_UNDEFINED:
  1299. fprintf(output, "Object is uninitialized\n");
  1300. break;
  1301. case XPATH_NODESET:
  1302. fprintf(output, "Object is a Node Set :\n");
  1303. xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
  1304. break;
  1305. case XPATH_XSLT_TREE:
  1306. fprintf(output, "Object is an XSLT value tree :\n");
  1307. xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
  1308. break;
  1309. case XPATH_BOOLEAN:
  1310. fprintf(output, "Object is a Boolean : ");
  1311. if (cur->boolval) fprintf(output, "true\n");
  1312. else fprintf(output, "false\n");
  1313. break;
  1314. case XPATH_NUMBER:
  1315. switch (xmlXPathIsInf(cur->floatval)) {
  1316. case 1:
  1317. fprintf(output, "Object is a number : Infinity\n");
  1318. break;
  1319. case -1:
  1320. fprintf(output, "Object is a number : -Infinity\n");
  1321. break;
  1322. default:
  1323. if (xmlXPathIsNaN(cur->floatval)) {
  1324. fprintf(output, "Object is a number : NaN\n");
  1325. } else if (cur->floatval == 0) {
  1326. /* Omit sign for negative zero. */
  1327. fprintf(output, "Object is a number : 0\n");
  1328. } else {
  1329. fprintf(output, "Object is a number : %0g\n", cur->floatval);
  1330. }
  1331. }
  1332. break;
  1333. case XPATH_STRING:
  1334. fprintf(output, "Object is a string : ");
  1335. xmlDebugDumpString(output, cur->stringval);
  1336. fprintf(output, "\n");
  1337. break;
  1338. case XPATH_POINT:
  1339. fprintf(output, "Object is a point : index %d in node", cur->index);
  1340. xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
  1341. fprintf(output, "\n");
  1342. break;
  1343. case XPATH_RANGE:
  1344. if ((cur->user2 == NULL) ||
  1345. ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
  1346. fprintf(output, "Object is a collapsed range :\n");
  1347. fprintf(output, "%s", shift);
  1348. if (cur->index >= 0)
  1349. fprintf(output, "index %d in ", cur->index);
  1350. fprintf(output, "node\n");
  1351. xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
  1352. depth + 1);
  1353. } else {
  1354. fprintf(output, "Object is a range :\n");
  1355. fprintf(output, "%s", shift);
  1356. fprintf(output, "From ");
  1357. if (cur->index >= 0)
  1358. fprintf(output, "index %d in ", cur->index);
  1359. fprintf(output, "node\n");
  1360. xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
  1361. depth + 1);
  1362. fprintf(output, "%s", shift);
  1363. fprintf(output, "To ");
  1364. if (cur->index2 >= 0)
  1365. fprintf(output, "index %d in ", cur->index2);
  1366. fprintf(output, "node\n");
  1367. xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
  1368. depth + 1);
  1369. fprintf(output, "\n");
  1370. }
  1371. break;
  1372. case XPATH_LOCATIONSET:
  1373. #if defined(LIBXML_XPTR_ENABLED)
  1374. fprintf(output, "Object is a Location Set:\n");
  1375. xmlXPathDebugDumpLocationSet(output,
  1376. (xmlLocationSetPtr) cur->user, depth);
  1377. #endif
  1378. break;
  1379. case XPATH_USERS:
  1380. fprintf(output, "Object is user defined\n");
  1381. break;
  1382. }
  1383. }
  1384. static void
  1385. xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
  1386. xmlXPathStepOpPtr op, int depth) {
  1387. int i;
  1388. char shift[100];
  1389. for (i = 0;((i < depth) && (i < 25));i++)
  1390. shift[2 * i] = shift[2 * i + 1] = ' ';
  1391. shift[2 * i] = shift[2 * i + 1] = 0;
  1392. fprintf(output, "%s", shift);
  1393. if (op == NULL) {
  1394. fprintf(output, "Step is NULL\n");
  1395. return;
  1396. }
  1397. switch (op->op) {
  1398. case XPATH_OP_END:
  1399. fprintf(output, "END"); break;
  1400. case XPATH_OP_AND:
  1401. fprintf(output, "AND"); break;
  1402. case XPATH_OP_OR:
  1403. fprintf(output, "OR"); break;
  1404. case XPATH_OP_EQUAL:
  1405. if (op->value)
  1406. fprintf(output, "EQUAL =");
  1407. else
  1408. fprintf(output, "EQUAL !=");
  1409. break;
  1410. case XPATH_OP_CMP:
  1411. if (op->value)
  1412. fprintf(output, "CMP <");
  1413. else
  1414. fprintf(output, "CMP >");
  1415. if (!op->value2)
  1416. fprintf(output, "=");
  1417. break;
  1418. case XPATH_OP_PLUS:
  1419. if (op->value == 0)
  1420. fprintf(output, "PLUS -");
  1421. else if (op->value == 1)
  1422. fprintf(output, "PLUS +");
  1423. else if (op->value == 2)
  1424. fprintf(output, "PLUS unary -");
  1425. else if (op->value == 3)
  1426. fprintf(output, "PLUS unary - -");
  1427. break;
  1428. case XPATH_OP_MULT:
  1429. if (op->value == 0)
  1430. fprintf(output, "MULT *");
  1431. else if (op->value == 1)
  1432. fprintf(output, "MULT div");
  1433. else
  1434. fprintf(output, "MULT mod");
  1435. break;
  1436. case XPATH_OP_UNION:
  1437. fprintf(output, "UNION"); break;
  1438. case XPATH_OP_ROOT:
  1439. fprintf(output, "ROOT"); break;
  1440. case XPATH_OP_NODE:
  1441. fprintf(output, "NODE"); break;
  1442. case XPATH_OP_SORT:
  1443. fprintf(output, "SORT"); break;
  1444. case XPATH_OP_COLLECT: {
  1445. xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
  1446. xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
  1447. xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
  1448. const xmlChar *prefix = op->value4;
  1449. const xmlChar *name = op->value5;
  1450. fprintf(output, "COLLECT ");
  1451. switch (axis) {
  1452. case AXIS_ANCESTOR:
  1453. fprintf(output, " 'ancestors' "); break;
  1454. case AXIS_ANCESTOR_OR_SELF:
  1455. fprintf(output, " 'ancestors-or-self' "); break;
  1456. case AXIS_ATTRIBUTE:
  1457. fprintf(output, " 'attributes' "); break;
  1458. case AXIS_CHILD:
  1459. fprintf(output, " 'child' "); break;
  1460. case AXIS_DESCENDANT:
  1461. fprintf(output, " 'descendant' "); break;
  1462. case AXIS_DESCENDANT_OR_SELF:
  1463. fprintf(output, " 'descendant-or-self' "); break;
  1464. case AXIS_FOLLOWING:
  1465. fprintf(output, " 'following' "); break;
  1466. case AXIS_FOLLOWING_SIBLING:
  1467. fprintf(output, " 'following-siblings' "); break;
  1468. case AXIS_NAMESPACE:
  1469. fprintf(output, " 'namespace' "); break;
  1470. case AXIS_PARENT:
  1471. fprintf(output, " 'parent' "); break;
  1472. case AXIS_PRECEDING:
  1473. fprintf(output, " 'preceding' "); break;
  1474. case AXIS_PRECEDING_SIBLING:
  1475. fprintf(output, " 'preceding-sibling' "); break;
  1476. case AXIS_SELF:
  1477. fprintf(output, " 'self' "); break;
  1478. }
  1479. switch (test) {
  1480. case NODE_TEST_NONE:
  1481. fprintf(output, "'none' "); break;
  1482. case NODE_TEST_TYPE:
  1483. fprintf(output, "'type' "); break;
  1484. case NODE_TEST_PI:
  1485. fprintf(output, "'PI' "); break;
  1486. case NODE_TEST_ALL:
  1487. fprintf(output, "'all' "); break;
  1488. case NODE_TEST_NS:
  1489. fprintf(output, "'namespace' "); break;
  1490. case NODE_TEST_NAME:
  1491. fprintf(output, "'name' "); break;
  1492. }
  1493. switch (type) {
  1494. case NODE_TYPE_NODE:
  1495. fprintf(output, "'node' "); break;
  1496. case NODE_TYPE_COMMENT:
  1497. fprintf(output, "'comment' "); break;
  1498. case NODE_TYPE_TEXT:
  1499. fprintf(output, "'text' "); break;
  1500. case NODE_TYPE_PI:
  1501. fprintf(output, "'PI' "); break;
  1502. }
  1503. if (prefix != NULL)
  1504. fprintf(output, "%s:", prefix);
  1505. if (name != NULL)
  1506. fprintf(output, "%s", (const char *) name);
  1507. break;
  1508. }
  1509. case XPATH_OP_VALUE: {
  1510. xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
  1511. fprintf(output, "ELEM ");
  1512. xmlXPathDebugDumpObject(output, object, 0);
  1513. goto finish;
  1514. }
  1515. case XPATH_OP_VARIABLE: {
  1516. const xmlChar *prefix = op->value5;
  1517. const xmlChar *name = op->value4;
  1518. if (prefix != NULL)
  1519. fprintf(output, "VARIABLE %s:%s", prefix, name);
  1520. else
  1521. fprintf(output, "VARIABLE %s", name);
  1522. break;
  1523. }
  1524. case XPATH_OP_FUNCTION: {
  1525. int nbargs = op->value;
  1526. const xmlChar *prefix = op->value5;
  1527. const xmlChar *name = op->value4;
  1528. if (prefix != NULL)
  1529. fprintf(output, "FUNCTION %s:%s(%d args)",
  1530. prefix, name, nbargs);
  1531. else
  1532. fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
  1533. break;
  1534. }
  1535. case XPATH_OP_ARG: fprintf(output, "ARG"); break;
  1536. case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
  1537. case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
  1538. #ifdef LIBXML_XPTR_ENABLED
  1539. case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
  1540. #endif
  1541. default:
  1542. fprintf(output, "UNKNOWN %d\n", op->op); return;
  1543. }
  1544. fprintf(output, "\n");
  1545. finish:
  1546. if (op->ch1 >= 0)
  1547. xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
  1548. if (op->ch2 >= 0)
  1549. xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
  1550. }
  1551. /**
  1552. * xmlXPathDebugDumpCompExpr:
  1553. * @output: the FILE * for the output
  1554. * @comp: the precompiled XPath expression
  1555. * @depth: the indentation level.
  1556. *
  1557. * Dumps the tree of the compiled XPath expression.
  1558. */
  1559. void
  1560. xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
  1561. int depth) {
  1562. int i;
  1563. char shift[100];
  1564. if ((output == NULL) || (comp == NULL)) return;
  1565. for (i = 0;((i < depth) && (i < 25));i++)
  1566. shift[2 * i] = shift[2 * i + 1] = ' ';
  1567. shift[2 * i] = shift[2 * i + 1] = 0;
  1568. fprintf(output, "%s", shift);
  1569. #ifdef XPATH_STREAMING
  1570. if (comp->stream) {
  1571. fprintf(output, "Streaming Expression\n");
  1572. } else
  1573. #endif
  1574. {
  1575. fprintf(output, "Compiled Expression : %d elements\n",
  1576. comp->nbStep);
  1577. i = comp->last;
  1578. xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
  1579. }
  1580. }
  1581. #ifdef XP_DEBUG_OBJ_USAGE
  1582. /*
  1583. * XPath object usage related debugging variables.
  1584. */
  1585. static int xmlXPathDebugObjCounterUndefined = 0;
  1586. static int xmlXPathDebugObjCounterNodeset = 0;
  1587. static int xmlXPathDebugObjCounterBool = 0;
  1588. static int xmlXPathDebugObjCounterNumber = 0;
  1589. static int xmlXPathDebugObjCounterString = 0;
  1590. static int xmlXPathDebugObjCounterPoint = 0;
  1591. static int xmlXPathDebugObjCounterRange = 0;
  1592. static int xmlXPathDebugObjCounterLocset = 0;
  1593. static int xmlXPathDebugObjCounterUsers = 0;
  1594. static int xmlXPathDebugObjCounterXSLTTree = 0;
  1595. static int xmlXPathDebugObjCounterAll = 0;
  1596. static int xmlXPathDebugObjTotalUndefined = 0;
  1597. static int xmlXPathDebugObjTotalNodeset = 0;
  1598. static int xmlXPathDebugObjTotalBool = 0;
  1599. static int xmlXPathDebugObjTotalNumber = 0;
  1600. static int xmlXPathDebugObjTotalString = 0;
  1601. static int xmlXPathDebugObjTotalPoint = 0;
  1602. static int xmlXPathDebugObjTotalRange = 0;
  1603. static int xmlXPathDebugObjTotalLocset = 0;
  1604. static int xmlXPathDebugObjTotalUsers = 0;
  1605. static int xmlXPathDebugObjTotalXSLTTree = 0;
  1606. static int xmlXPathDebugObjTotalAll = 0;
  1607. static int xmlXPathDebugObjMaxUndefined = 0;
  1608. static int xmlXPathDebugObjMaxNodeset = 0;
  1609. static int xmlXPathDebugObjMaxBool = 0;
  1610. static int xmlXPathDebugObjMaxNumber = 0;
  1611. static int xmlXPathDebugObjMaxString = 0;
  1612. static int xmlXPathDebugObjMaxPoint = 0;
  1613. static int xmlXPathDebugObjMaxRange = 0;
  1614. static int xmlXPathDebugObjMaxLocset = 0;
  1615. static int xmlXPathDebugObjMaxUsers = 0;
  1616. static int xmlXPathDebugObjMaxXSLTTree = 0;
  1617. static int xmlXPathDebugObjMaxAll = 0;
  1618. static void
  1619. xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
  1620. {
  1621. if (ctxt != NULL) {
  1622. if (ctxt->cache != NULL) {
  1623. xmlXPathContextCachePtr cache =
  1624. (xmlXPathContextCachePtr) ctxt->cache;
  1625. cache->dbgCachedAll = 0;
  1626. cache->dbgCachedNodeset = 0;
  1627. cache->dbgCachedString = 0;
  1628. cache->dbgCachedBool = 0;
  1629. cache->dbgCachedNumber = 0;
  1630. cache->dbgCachedPoint = 0;
  1631. cache->dbgCachedRange = 0;
  1632. cache->dbgCachedLocset = 0;
  1633. cache->dbgCachedUsers = 0;
  1634. cache->dbgCachedXSLTTree = 0;
  1635. cache->dbgCachedUndefined = 0;
  1636. cache->dbgReusedAll = 0;
  1637. cache->dbgReusedNodeset = 0;
  1638. cache->dbgReusedString = 0;
  1639. cache->dbgReusedBool = 0;
  1640. cache->dbgReusedNumber = 0;
  1641. cache->dbgReusedPoint = 0;
  1642. cache->dbgReusedRange = 0;
  1643. cache->dbgReusedLocset = 0;
  1644. cache->dbgReusedUsers = 0;
  1645. cache->dbgReusedXSLTTree = 0;
  1646. cache->dbgReusedUndefined = 0;
  1647. }
  1648. }
  1649. xmlXPathDebugObjCounterUndefined = 0;
  1650. xmlXPathDebugObjCounterNodeset = 0;
  1651. xmlXPathDebugObjCounterBool = 0;
  1652. xmlXPathDebugObjCounterNumber = 0;
  1653. xmlXPathDebugObjCounterString = 0;
  1654. xmlXPathDebugObjCounterPoint = 0;
  1655. xmlXPathDebugObjCounterRange = 0;
  1656. xmlXPathDebugObjCounterLocset = 0;
  1657. xmlXPathDebugObjCounterUsers = 0;
  1658. xmlXPathDebugObjCounterXSLTTree = 0;
  1659. xmlXPathDebugObjCounterAll = 0;
  1660. xmlXPathDebugObjTotalUndefined = 0;
  1661. xmlXPathDebugObjTotalNodeset = 0;
  1662. xmlXPathDebugObjTotalBool = 0;
  1663. xmlXPathDebugObjTotalNumber = 0;
  1664. xmlXPathDebugObjTotalString = 0;
  1665. xmlXPathDebugObjTotalPoint = 0;
  1666. xmlXPathDebugObjTotalRange = 0;
  1667. xmlXPathDebugObjTotalLocset = 0;
  1668. xmlXPathDebugObjTotalUsers = 0;
  1669. xmlXPathDebugObjTotalXSLTTree = 0;
  1670. xmlXPathDebugObjTotalAll = 0;
  1671. xmlXPathDebugObjMaxUndefined = 0;
  1672. xmlXPathDebugObjMaxNodeset = 0;
  1673. xmlXPathDebugObjMaxBool = 0;
  1674. xmlXPathDebugObjMaxNumber = 0;
  1675. xmlXPathDebugObjMaxString = 0;
  1676. xmlXPathDebugObjMaxPoint = 0;
  1677. xmlXPathDebugObjMaxRange = 0;
  1678. xmlXPathDebugObjMaxLocset = 0;
  1679. xmlXPathDebugObjMaxUsers = 0;
  1680. xmlXPathDebugObjMaxXSLTTree = 0;
  1681. xmlXPathDebugObjMaxAll = 0;
  1682. }
  1683. static void
  1684. xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
  1685. xmlXPathObjectType objType)
  1686. {
  1687. int isCached = 0;
  1688. if (ctxt != NULL) {
  1689. if (ctxt->cache != NULL) {
  1690. xmlXPathContextCachePtr cache =
  1691. (xmlXPathContextCachePtr) ctxt->cache;
  1692. isCached = 1;
  1693. cache->dbgReusedAll++;
  1694. switch (objType) {
  1695. case XPATH_UNDEFINED:
  1696. cache->dbgReusedUndefined++;
  1697. break;
  1698. case XPATH_NODESET:
  1699. cache->dbgReusedNodeset++;
  1700. break;
  1701. case XPATH_BOOLEAN:
  1702. cache->dbgReusedBool++;
  1703. break;
  1704. case XPATH_NUMBER:
  1705. cache->dbgReusedNumber++;
  1706. break;
  1707. case XPATH_STRING:
  1708. cache->dbgReusedString++;
  1709. break;
  1710. case XPATH_POINT:
  1711. cache->dbgReusedPoint++;
  1712. break;
  1713. case XPATH_RANGE:
  1714. cache->dbgReusedRange++;
  1715. break;
  1716. case XPATH_LOCATIONSET:
  1717. cache->dbgReusedLocset++;
  1718. break;
  1719. case XPATH_USERS:
  1720. cache->dbgReusedUsers++;
  1721. break;
  1722. case XPATH_XSLT_TREE:
  1723. cache->dbgReusedXSLTTree++;
  1724. break;
  1725. default:
  1726. break;
  1727. }
  1728. }
  1729. }
  1730. switch (objType) {
  1731. case XPATH_UNDEFINED:
  1732. if (! isCached)
  1733. xmlXPathDebugObjTotalUndefined++;
  1734. xmlXPathDebugObjCounterUndefined++;
  1735. if (xmlXPathDebugObjCounterUndefined >
  1736. xmlXPathDebugObjMaxUndefined)
  1737. xmlXPathDebugObjMaxUndefined =
  1738. xmlXPathDebugObjCounterUndefined;
  1739. break;
  1740. case XPATH_NODESET:
  1741. if (! isCached)
  1742. xmlXPathDebugObjTotalNodeset++;
  1743. xmlXPathDebugObjCounterNodeset++;
  1744. if (xmlXPathDebugObjCounterNodeset >
  1745. xmlXPathDebugObjMaxNodeset)
  1746. xmlXPathDebugObjMaxNodeset =
  1747. xmlXPathDebugObjCounterNodeset;
  1748. break;
  1749. case XPATH_BOOLEAN:
  1750. if (! isCached)
  1751. xmlXPathDebugObjTotalBool++;
  1752. xmlXPathDebugObjCounterBool++;
  1753. if (xmlXPathDebugObjCounterBool >
  1754. xmlXPathDebugObjMaxBool)
  1755. xmlXPathDebugObjMaxBool =
  1756. xmlXPathDebugObjCounterBool;
  1757. break;
  1758. case XPATH_NUMBER:
  1759. if (! isCached)
  1760. xmlXPathDebugObjTotalNumber++;
  1761. xmlXPathDebugObjCounterNumber++;
  1762. if (xmlXPathDebugObjCounterNumber >
  1763. xmlXPathDebugObjMaxNumber)
  1764. xmlXPathDebugObjMaxNumber =
  1765. xmlXPathDebugObjCounterNumber;
  1766. break;
  1767. case XPATH_STRING:
  1768. if (! isCached)
  1769. xmlXPathDebugObjTotalString++;
  1770. xmlXPathDebugObjCounterString++;
  1771. if (xmlXPathDebugObjCounterString >
  1772. xmlXPathDebugObjMaxString)
  1773. xmlXPathDebugObjMaxString =
  1774. xmlXPathDebugObjCounterString;
  1775. break;
  1776. case XPATH_POINT:
  1777. if (! isCached)
  1778. xmlXPathDebugObjTotalPoint++;
  1779. xmlXPathDebugObjCounterPoint++;
  1780. if (xmlXPathDebugObjCounterPoint >
  1781. xmlXPathDebugObjMaxPoint)
  1782. xmlXPathDebugObjMaxPoint =
  1783. xmlXPathDebugObjCounterPoint;
  1784. break;
  1785. case XPATH_RANGE:
  1786. if (! isCached)
  1787. xmlXPathDebugObjTotalRange++;
  1788. xmlXPathDebugObjCounterRange++;
  1789. if (xmlXPathDebugObjCounterRange >
  1790. xmlXPathDebugObjMaxRange)
  1791. xmlXPathDebugObjMaxRange =
  1792. xmlXPathDebugObjCounterRange;
  1793. break;
  1794. case XPATH_LOCATIONSET:
  1795. if (! isCached)
  1796. xmlXPathDebugObjTotalLocset++;
  1797. xmlXPathDebugObjCounterLocset++;
  1798. if (xmlXPathDebugObjCounterLocset >
  1799. xmlXPathDebugObjMaxLocset)
  1800. xmlXPathDebugObjMaxLocset =
  1801. xmlXPathDebugObjCounterLocset;
  1802. break;
  1803. case XPATH_USERS:
  1804. if (! isCached)
  1805. xmlXPathDebugObjTotalUsers++;
  1806. xmlXPathDebugObjCounterUsers++;
  1807. if (xmlXPathDebugObjCounterUsers >
  1808. xmlXPathDebugObjMaxUsers)
  1809. xmlXPathDebugObjMaxUsers =
  1810. xmlXPathDebugObjCounterUsers;
  1811. break;
  1812. case XPATH_XSLT_TREE:
  1813. if (! isCached)
  1814. xmlXPathDebugObjTotalXSLTTree++;
  1815. xmlXPathDebugObjCounterXSLTTree++;
  1816. if (xmlXPathDebugObjCounterXSLTTree >
  1817. xmlXPathDebugObjMaxXSLTTree)
  1818. xmlXPathDebugObjMaxXSLTTree =
  1819. xmlXPathDebugObjCounterXSLTTree;
  1820. break;
  1821. default:
  1822. break;
  1823. }
  1824. if (! isCached)
  1825. xmlXPathDebugObjTotalAll++;
  1826. xmlXPathDebugObjCounterAll++;
  1827. if (xmlXPathDebugObjCounterAll >
  1828. xmlXPathDebugObjMaxAll)
  1829. xmlXPathDebugObjMaxAll =
  1830. xmlXPathDebugObjCounterAll;
  1831. }
  1832. static void
  1833. xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
  1834. xmlXPathObjectType objType)
  1835. {
  1836. int isCached = 0;
  1837. if (ctxt != NULL) {
  1838. if (ctxt->cache != NULL) {
  1839. xmlXPathContextCachePtr cache =
  1840. (xmlXPathContextCachePtr) ctxt->cache;
  1841. isCached = 1;
  1842. cache->dbgCachedAll++;
  1843. switch (objType) {
  1844. case XPATH_UNDEFINED:
  1845. cache->dbgCachedUndefined++;
  1846. break;
  1847. case XPATH_NODESET:
  1848. cache->dbgCachedNodeset++;
  1849. break;
  1850. case XPATH_BOOLEAN:
  1851. cache->dbgCachedBool++;
  1852. break;
  1853. case XPATH_NUMBER:
  1854. cache->dbgCachedNumber++;
  1855. break;
  1856. case XPATH_STRING:
  1857. cache->dbgCachedString++;
  1858. break;
  1859. case XPATH_POINT:
  1860. cache->dbgCachedPoint++;
  1861. break;
  1862. case XPATH_RANGE:
  1863. cache->dbgCachedRange++;
  1864. break;
  1865. case XPATH_LOCATIONSET:
  1866. cache->dbgCachedLocset++;
  1867. break;
  1868. case XPATH_USERS:
  1869. cache->dbgCachedUsers++;
  1870. break;
  1871. case XPATH_XSLT_TREE:
  1872. cache->dbgCachedXSLTTree++;
  1873. break;
  1874. default:
  1875. break;
  1876. }
  1877. }
  1878. }
  1879. switch (objType) {
  1880. case XPATH_UNDEFINED:
  1881. xmlXPathDebugObjCounterUndefined--;
  1882. break;
  1883. case XPATH_NODESET:
  1884. xmlXPathDebugObjCounterNodeset--;
  1885. break;
  1886. case XPATH_BOOLEAN:
  1887. xmlXPathDebugObjCounterBool--;
  1888. break;
  1889. case XPATH_NUMBER:
  1890. xmlXPathDebugObjCounterNumber--;
  1891. break;
  1892. case XPATH_STRING:
  1893. xmlXPathDebugObjCounterString--;
  1894. break;
  1895. case XPATH_POINT:
  1896. xmlXPathDebugObjCounterPoint--;
  1897. break;
  1898. case XPATH_RANGE:
  1899. xmlXPathDebugObjCounterRange--;
  1900. break;
  1901. case XPATH_LOCATIONSET:
  1902. xmlXPathDebugObjCounterLocset--;
  1903. break;
  1904. case XPATH_USERS:
  1905. xmlXPathDebugObjCounterUsers--;
  1906. break;
  1907. case XPATH_XSLT_TREE:
  1908. xmlXPathDebugObjCounterXSLTTree--;
  1909. break;
  1910. default:
  1911. break;
  1912. }
  1913. xmlXPathDebugObjCounterAll--;
  1914. }
  1915. static void
  1916. xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
  1917. {
  1918. int reqAll, reqNodeset, reqString, reqBool, reqNumber,
  1919. reqXSLTTree, reqUndefined;
  1920. int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
  1921. caNumber = 0, caXSLTTree = 0, caUndefined = 0;
  1922. int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
  1923. reNumber = 0, reXSLTTree = 0, reUndefined = 0;
  1924. int leftObjs = xmlXPathDebugObjCounterAll;
  1925. reqAll = xmlXPathDebugObjTotalAll;
  1926. reqNodeset = xmlXPathDebugObjTotalNodeset;
  1927. reqString = xmlXPathDebugObjTotalString;
  1928. reqBool = xmlXPathDebugObjTotalBool;
  1929. reqNumber = xmlXPathDebugObjTotalNumber;
  1930. reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
  1931. reqUndefined = xmlXPathDebugObjTotalUndefined;
  1932. printf("# XPath object usage:\n");
  1933. if (ctxt != NULL) {
  1934. if (ctxt->cache != NULL) {
  1935. xmlXPathContextCachePtr cache =
  1936. (xmlXPathContextCachePtr) ctxt->cache;
  1937. reAll = cache->dbgReusedAll;
  1938. reqAll += reAll;
  1939. reNodeset = cache->dbgReusedNodeset;
  1940. reqNodeset += reNodeset;
  1941. reString = cache->dbgReusedString;
  1942. reqString += reString;
  1943. reBool = cache->dbgReusedBool;
  1944. reqBool += reBool;
  1945. reNumber = cache->dbgReusedNumber;
  1946. reqNumber += reNumber;
  1947. reXSLTTree = cache->dbgReusedXSLTTree;
  1948. reqXSLTTree += reXSLTTree;
  1949. reUndefined = cache->dbgReusedUndefined;
  1950. reqUndefined += reUndefined;
  1951. caAll = cache->dbgCachedAll;
  1952. caBool = cache->dbgCachedBool;
  1953. caNodeset = cache->dbgCachedNodeset;
  1954. caString = cache->dbgCachedString;
  1955. caNumber = cache->dbgCachedNumber;
  1956. caXSLTTree = cache->dbgCachedXSLTTree;
  1957. caUndefined = cache->dbgCachedUndefined;
  1958. if (cache->nodesetObjs)
  1959. leftObjs -= cache->nodesetObjs->number;
  1960. if (cache->stringObjs)
  1961. leftObjs -= cache->stringObjs->number;
  1962. if (cache->booleanObjs)
  1963. leftObjs -= cache->booleanObjs->number;
  1964. if (cache->numberObjs)
  1965. leftObjs -= cache->numberObjs->number;
  1966. if (cache->miscObjs)
  1967. leftObjs -= cache->miscObjs->number;
  1968. }
  1969. }
  1970. printf("# all\n");
  1971. printf("# total : %d\n", reqAll);
  1972. printf("# left : %d\n", leftObjs);
  1973. printf("# created: %d\n", xmlXPathDebugObjTotalAll);
  1974. printf("# reused : %d\n", reAll);
  1975. printf("# max : %d\n", xmlXPathDebugObjMaxAll);
  1976. printf("# node-sets\n");
  1977. printf("# total : %d\n", reqNodeset);
  1978. printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
  1979. printf("# reused : %d\n", reNodeset);
  1980. printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
  1981. printf("# strings\n");
  1982. printf("# total : %d\n", reqString);
  1983. printf("# created: %d\n", xmlXPathDebugObjTotalString);
  1984. printf("# reused : %d\n", reString);
  1985. printf("# max : %d\n", xmlXPathDebugObjMaxString);
  1986. printf("# booleans\n");
  1987. printf("# total : %d\n", reqBool);
  1988. printf("# created: %d\n", xmlXPathDebugObjTotalBool);
  1989. printf("# reused : %d\n", reBool);
  1990. printf("# max : %d\n", xmlXPathDebugObjMaxBool);
  1991. printf("# numbers\n");
  1992. printf("# total : %d\n", reqNumber);
  1993. printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
  1994. printf("# reused : %d\n", reNumber);
  1995. printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
  1996. printf("# XSLT result tree fragments\n");
  1997. printf("# total : %d\n", reqXSLTTree);
  1998. printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
  1999. printf("# reused : %d\n", reXSLTTree);
  2000. printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
  2001. printf("# undefined\n");
  2002. printf("# total : %d\n", reqUndefined);
  2003. printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
  2004. printf("# reused : %d\n", reUndefined);
  2005. printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
  2006. }
  2007. #endif /* XP_DEBUG_OBJ_USAGE */
  2008. #endif /* LIBXML_DEBUG_ENABLED */
  2009. /************************************************************************
  2010. * *
  2011. * XPath object caching *
  2012. * *
  2013. ************************************************************************/
  2014. /**
  2015. * xmlXPathNewCache:
  2016. *
  2017. * Create a new object cache
  2018. *
  2019. * Returns the xmlXPathCache just allocated.
  2020. */
  2021. static xmlXPathContextCachePtr
  2022. xmlXPathNewCache(void)
  2023. {
  2024. xmlXPathContextCachePtr ret;
  2025. ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
  2026. if (ret == NULL) {
  2027. xmlXPathErrMemory(NULL, "creating object cache\n");
  2028. return(NULL);
  2029. }
  2030. memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
  2031. ret->maxNodeset = 100;
  2032. ret->maxString = 100;
  2033. ret->maxBoolean = 100;
  2034. ret->maxNumber = 100;
  2035. ret->maxMisc = 100;
  2036. return(ret);
  2037. }
  2038. static void
  2039. xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
  2040. {
  2041. int i;
  2042. xmlXPathObjectPtr obj;
  2043. if (list == NULL)
  2044. return;
  2045. for (i = 0; i < list->number; i++) {
  2046. obj = list->items[i];
  2047. /*
  2048. * Note that it is already assured that we don't need to
  2049. * look out for namespace nodes in the node-set.
  2050. */
  2051. if (obj->nodesetval != NULL) {
  2052. if (obj->nodesetval->nodeTab != NULL)
  2053. xmlFree(obj->nodesetval->nodeTab);
  2054. xmlFree(obj->nodesetval);
  2055. }
  2056. xmlFree(obj);
  2057. #ifdef XP_DEBUG_OBJ_USAGE
  2058. xmlXPathDebugObjCounterAll--;
  2059. #endif
  2060. }
  2061. xmlPointerListFree(list);
  2062. }
  2063. static void
  2064. xmlXPathFreeCache(xmlXPathContextCachePtr cache)
  2065. {
  2066. if (cache == NULL)
  2067. return;
  2068. if (cache->nodesetObjs)
  2069. xmlXPathCacheFreeObjectList(cache->nodesetObjs);
  2070. if (cache->stringObjs)
  2071. xmlXPathCacheFreeObjectList(cache->stringObjs);
  2072. if (cache->booleanObjs)
  2073. xmlXPathCacheFreeObjectList(cache->booleanObjs);
  2074. if (cache->numberObjs)
  2075. xmlXPathCacheFreeObjectList(cache->numberObjs);
  2076. if (cache->miscObjs)
  2077. xmlXPathCacheFreeObjectList(cache->miscObjs);
  2078. xmlFree(cache);
  2079. }
  2080. /**
  2081. * xmlXPathContextSetCache:
  2082. *
  2083. * @ctxt: the XPath context
  2084. * @active: enables/disables (creates/frees) the cache
  2085. * @value: a value with semantics dependent on @options
  2086. * @options: options (currently only the value 0 is used)
  2087. *
  2088. * Creates/frees an object cache on the XPath context.
  2089. * If activates XPath objects (xmlXPathObject) will be cached internally
  2090. * to be reused.
  2091. * @options:
  2092. * 0: This will set the XPath object caching:
  2093. * @value:
  2094. * This will set the maximum number of XPath objects
  2095. * to be cached per slot
  2096. * There are 5 slots for: node-set, string, number, boolean, and
  2097. * misc objects. Use <0 for the default number (100).
  2098. * Other values for @options have currently no effect.
  2099. *
  2100. * Returns 0 if the setting succeeded, and -1 on API or internal errors.
  2101. */
  2102. int
  2103. xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
  2104. int active,
  2105. int value,
  2106. int options)
  2107. {
  2108. if (ctxt == NULL)
  2109. return(-1);
  2110. if (active) {
  2111. xmlXPathContextCachePtr cache;
  2112. if (ctxt->cache == NULL) {
  2113. ctxt->cache = xmlXPathNewCache();
  2114. if (ctxt->cache == NULL)
  2115. return(-1);
  2116. }
  2117. cache = (xmlXPathContextCachePtr) ctxt->cache;
  2118. if (options == 0) {
  2119. if (value < 0)
  2120. value = 100;
  2121. cache->maxNodeset = value;
  2122. cache->maxString = value;
  2123. cache->maxNumber = value;
  2124. cache->maxBoolean = value;
  2125. cache->maxMisc = value;
  2126. }
  2127. } else if (ctxt->cache != NULL) {
  2128. xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
  2129. ctxt->cache = NULL;
  2130. }
  2131. return(0);
  2132. }
  2133. /**
  2134. * xmlXPathCacheWrapNodeSet:
  2135. * @ctxt: the XPath context
  2136. * @val: the NodePtr value
  2137. *
  2138. * This is the cached version of xmlXPathWrapNodeSet().
  2139. * Wrap the Nodeset @val in a new xmlXPathObjectPtr
  2140. *
  2141. * Returns the created or reused object.
  2142. */
  2143. static xmlXPathObjectPtr
  2144. xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
  2145. {
  2146. if ((ctxt != NULL) && (ctxt->cache != NULL)) {
  2147. xmlXPathContextCachePtr cache =
  2148. (xmlXPathContextCachePtr) ctxt->cache;
  2149. if ((cache->miscObjs != NULL) &&
  2150. (cache->miscObjs->number != 0))
  2151. {
  2152. xmlXPathObjectPtr ret;
  2153. ret = (xmlXPathObjectPtr)
  2154. cache->miscObjs->items[--cache->miscObjs->number];
  2155. ret->type = XPATH_NODESET;
  2156. ret->nodesetval = val;
  2157. #ifdef XP_DEBUG_OBJ_USAGE
  2158. xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
  2159. #endif
  2160. return(ret);
  2161. }
  2162. }
  2163. return(xmlXPathWrapNodeSet(val));
  2164. }
  2165. /**
  2166. * xmlXPathCacheWrapString:
  2167. * @ctxt: the XPath context
  2168. * @val: the xmlChar * value
  2169. *
  2170. * This is the cached version of xmlXPathWrapString().
  2171. * Wraps the @val string into an XPath object.
  2172. *
  2173. * Returns the created or reused object.
  2174. */
  2175. static xmlXPathObjectPtr
  2176. xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
  2177. {
  2178. if ((ctxt != NULL) && (ctxt->cache != NULL)) {
  2179. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  2180. if ((cache->stringObjs != NULL) &&
  2181. (cache->stringObjs->number != 0))
  2182. {
  2183. xmlXPathObjectPtr ret;
  2184. ret = (xmlXPathObjectPtr)
  2185. cache->stringObjs->items[--cache->stringObjs->number];
  2186. ret->type = XPATH_STRING;
  2187. ret->stringval = val;
  2188. #ifdef XP_DEBUG_OBJ_USAGE
  2189. xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
  2190. #endif
  2191. return(ret);
  2192. } else if ((cache->miscObjs != NULL) &&
  2193. (cache->miscObjs->number != 0))
  2194. {
  2195. xmlXPathObjectPtr ret;
  2196. /*
  2197. * Fallback to misc-cache.
  2198. */
  2199. ret = (xmlXPathObjectPtr)
  2200. cache->miscObjs->items[--cache->miscObjs->number];
  2201. ret->type = XPATH_STRING;
  2202. ret->stringval = val;
  2203. #ifdef XP_DEBUG_OBJ_USAGE
  2204. xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
  2205. #endif
  2206. return(ret);
  2207. }
  2208. }
  2209. return(xmlXPathWrapString(val));
  2210. }
  2211. /**
  2212. * xmlXPathCacheNewNodeSet:
  2213. * @ctxt: the XPath context
  2214. * @val: the NodePtr value
  2215. *
  2216. * This is the cached version of xmlXPathNewNodeSet().
  2217. * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
  2218. * it with the single Node @val
  2219. *
  2220. * Returns the created or reused object.
  2221. */
  2222. static xmlXPathObjectPtr
  2223. xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
  2224. {
  2225. if ((ctxt != NULL) && (ctxt->cache)) {
  2226. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  2227. if ((cache->nodesetObjs != NULL) &&
  2228. (cache->nodesetObjs->number != 0))
  2229. {
  2230. xmlXPathObjectPtr ret;
  2231. /*
  2232. * Use the nodeset-cache.
  2233. */
  2234. ret = (xmlXPathObjectPtr)
  2235. cache->nodesetObjs->items[--cache->nodesetObjs->number];
  2236. ret->type = XPATH_NODESET;
  2237. ret->boolval = 0;
  2238. if (val) {
  2239. if ((ret->nodesetval->nodeMax == 0) ||
  2240. (val->type == XML_NAMESPACE_DECL))
  2241. {
  2242. /* TODO: Check memory error. */
  2243. xmlXPathNodeSetAddUnique(ret->nodesetval, val);
  2244. } else {
  2245. ret->nodesetval->nodeTab[0] = val;
  2246. ret->nodesetval->nodeNr = 1;
  2247. }
  2248. }
  2249. #ifdef XP_DEBUG_OBJ_USAGE
  2250. xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
  2251. #endif
  2252. return(ret);
  2253. } else if ((cache->miscObjs != NULL) &&
  2254. (cache->miscObjs->number != 0))
  2255. {
  2256. xmlXPathObjectPtr ret;
  2257. /*
  2258. * Fallback to misc-cache.
  2259. */
  2260. ret = (xmlXPathObjectPtr)
  2261. cache->miscObjs->items[--cache->miscObjs->number];
  2262. ret->type = XPATH_NODESET;
  2263. ret->boolval = 0;
  2264. ret->nodesetval = xmlXPathNodeSetCreate(val);
  2265. if (ret->nodesetval == NULL) {
  2266. ctxt->lastError.domain = XML_FROM_XPATH;
  2267. ctxt->lastError.code = XML_ERR_NO_MEMORY;
  2268. return(NULL);
  2269. }
  2270. #ifdef XP_DEBUG_OBJ_USAGE
  2271. xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
  2272. #endif
  2273. return(ret);
  2274. }
  2275. }
  2276. return(xmlXPathNewNodeSet(val));
  2277. }
  2278. /**
  2279. * xmlXPathCacheNewCString:
  2280. * @ctxt: the XPath context
  2281. * @val: the char * value
  2282. *
  2283. * This is the cached version of xmlXPathNewCString().
  2284. * Acquire an xmlXPathObjectPtr of type string and of value @val
  2285. *
  2286. * Returns the created or reused object.
  2287. */
  2288. static xmlXPathObjectPtr
  2289. xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
  2290. {
  2291. if ((ctxt != NULL) && (ctxt->cache)) {
  2292. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  2293. if ((cache->stringObjs != NULL) &&
  2294. (cache->stringObjs->number != 0))
  2295. {
  2296. xmlXPathObjectPtr ret;
  2297. ret = (xmlXPathObjectPtr)
  2298. cache->stringObjs->items[--cache->stringObjs->number];
  2299. ret->type = XPATH_STRING;
  2300. ret->stringval = xmlStrdup(BAD_CAST val);
  2301. #ifdef XP_DEBUG_OBJ_USAGE
  2302. xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
  2303. #endif
  2304. return(ret);
  2305. } else if ((cache->miscObjs != NULL) &&
  2306. (cache->miscObjs->number != 0))
  2307. {
  2308. xmlXPathObjectPtr ret;
  2309. ret = (xmlXPathObjectPtr)
  2310. cache->miscObjs->items[--cache->miscObjs->number];
  2311. ret->type = XPATH_STRING;
  2312. ret->stringval = xmlStrdup(BAD_CAST val);
  2313. #ifdef XP_DEBUG_OBJ_USAGE
  2314. xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
  2315. #endif
  2316. return(ret);
  2317. }
  2318. }
  2319. return(xmlXPathNewCString(val));
  2320. }
  2321. /**
  2322. * xmlXPathCacheNewString:
  2323. * @ctxt: the XPath context
  2324. * @val: the xmlChar * value
  2325. *
  2326. * This is the cached version of xmlXPathNewString().
  2327. * Acquire an xmlXPathObjectPtr of type string and of value @val
  2328. *
  2329. * Returns the created or reused object.
  2330. */
  2331. static xmlXPathObjectPtr
  2332. xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
  2333. {
  2334. if ((ctxt != NULL) && (ctxt->cache)) {
  2335. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  2336. if ((cache->stringObjs != NULL) &&
  2337. (cache->stringObjs->number != 0))
  2338. {
  2339. xmlXPathObjectPtr ret;
  2340. ret = (xmlXPathObjectPtr)
  2341. cache->stringObjs->items[--cache->stringObjs->number];
  2342. ret->type = XPATH_STRING;
  2343. if (val != NULL)
  2344. ret->stringval = xmlStrdup(val);
  2345. else
  2346. ret->stringval = xmlStrdup((const xmlChar *)"");
  2347. #ifdef XP_DEBUG_OBJ_USAGE
  2348. xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
  2349. #endif
  2350. return(ret);
  2351. } else if ((cache->miscObjs != NULL) &&
  2352. (cache->miscObjs->number != 0))
  2353. {
  2354. xmlXPathObjectPtr ret;
  2355. ret = (xmlXPathObjectPtr)
  2356. cache->miscObjs->items[--cache->miscObjs->number];
  2357. ret->type = XPATH_STRING;
  2358. if (val != NULL)
  2359. ret->stringval = xmlStrdup(val);
  2360. else
  2361. ret->stringval = xmlStrdup((const xmlChar *)"");
  2362. #ifdef XP_DEBUG_OBJ_USAGE
  2363. xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
  2364. #endif
  2365. return(ret);
  2366. }
  2367. }
  2368. return(xmlXPathNewString(val));
  2369. }
  2370. /**
  2371. * xmlXPathCacheNewBoolean:
  2372. * @ctxt: the XPath context
  2373. * @val: the boolean value
  2374. *
  2375. * This is the cached version of xmlXPathNewBoolean().
  2376. * Acquires an xmlXPathObjectPtr of type boolean and of value @val
  2377. *
  2378. * Returns the created or reused object.
  2379. */
  2380. static xmlXPathObjectPtr
  2381. xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
  2382. {
  2383. if ((ctxt != NULL) && (ctxt->cache)) {
  2384. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  2385. if ((cache->booleanObjs != NULL) &&
  2386. (cache->booleanObjs->number != 0))
  2387. {
  2388. xmlXPathObjectPtr ret;
  2389. ret = (xmlXPathObjectPtr)
  2390. cache->booleanObjs->items[--cache->booleanObjs->number];
  2391. ret->type = XPATH_BOOLEAN;
  2392. ret->boolval = (val != 0);
  2393. #ifdef XP_DEBUG_OBJ_USAGE
  2394. xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
  2395. #endif
  2396. return(ret);
  2397. } else if ((cache->miscObjs != NULL) &&
  2398. (cache->miscObjs->number != 0))
  2399. {
  2400. xmlXPathObjectPtr ret;
  2401. ret = (xmlXPathObjectPtr)
  2402. cache->miscObjs->items[--cache->miscObjs->number];
  2403. ret->type = XPATH_BOOLEAN;
  2404. ret->boolval = (val != 0);
  2405. #ifdef XP_DEBUG_OBJ_USAGE
  2406. xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
  2407. #endif
  2408. return(ret);
  2409. }
  2410. }
  2411. return(xmlXPathNewBoolean(val));
  2412. }
  2413. /**
  2414. * xmlXPathCacheNewFloat:
  2415. * @ctxt: the XPath context
  2416. * @val: the double value
  2417. *
  2418. * This is the cached version of xmlXPathNewFloat().
  2419. * Acquires an xmlXPathObjectPtr of type double and of value @val
  2420. *
  2421. * Returns the created or reused object.
  2422. */
  2423. static xmlXPathObjectPtr
  2424. xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
  2425. {
  2426. if ((ctxt != NULL) && (ctxt->cache)) {
  2427. xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
  2428. if ((cache->numberObjs != NULL) &&
  2429. (cache->numberObjs->number != 0))
  2430. {
  2431. xmlXPathObjectPtr ret;
  2432. ret = (xmlXPathObjectPtr)
  2433. cache->numberObjs->items[--cache->numberObjs->number];
  2434. ret->type = XPATH_NUMBER;
  2435. ret->floatval = val;
  2436. #ifdef XP_DEBUG_OBJ_USAGE
  2437. xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
  2438. #endif
  2439. return(ret);
  2440. } else if ((cache->miscObjs != NULL) &&
  2441. (cache->miscObjs->number != 0))
  2442. {
  2443. xmlXPathObjectPtr ret;
  2444. ret = (xmlXPathObjectPtr)
  2445. cache->miscObjs->items[--cache->miscObjs->number];
  2446. ret->type = XPATH_NUMBER;
  2447. ret->floatval = val;
  2448. #ifdef XP_DEBUG_OBJ_USAGE
  2449. xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
  2450. #endif
  2451. return(ret);
  2452. }
  2453. }
  2454. return(xmlXPathNewFloat(val));
  2455. }
  2456. /**
  2457. * xmlXPathCacheConvertString:
  2458. * @ctxt: the XPath context
  2459. * @val: an XPath object
  2460. *
  2461. * This is the cached version of xmlXPathConvertString().
  2462. * Converts an existing object to its string() equivalent
  2463. *
  2464. * Returns a created or reused object, the old one is freed (cached)
  2465. * (or the operation is done directly on @val)
  2466. */
  2467. static xmlXPathObjectPtr
  2468. xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
  2469. xmlChar *res = NULL;
  2470. if (val == NULL)
  2471. return(xmlXPathCacheNewCString(ctxt, ""));
  2472. switch (val->type) {
  2473. case XPATH_UNDEFINED:
  2474. #ifdef DEBUG_EXPR
  2475. xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
  2476. #endif
  2477. break;
  2478. case XPATH_NODESET:
  2479. case XPATH_XSLT_TREE:
  2480. res = xmlXPathCastNodeSetToString(val->nodesetval);
  2481. break;
  2482. case XPATH_STRING:
  2483. return(val);
  2484. case XPATH_BOOLEAN:
  2485. res = xmlXPathCastBooleanToString(val->boolval);
  2486. break;
  2487. case XPATH_NUMBER:
  2488. res = xmlXPathCastNumberToString(val->floatval);
  2489. break;
  2490. case XPATH_USERS:
  2491. case XPATH_POINT:
  2492. case XPATH_RANGE:
  2493. case XPATH_LOCATIONSET:
  2494. TODO;
  2495. break;
  2496. }
  2497. xmlXPathReleaseObject(ctxt, val);
  2498. if (res == NULL)
  2499. return(xmlXPathCacheNewCString(ctxt, ""));
  2500. return(xmlXPathCacheWrapString(ctxt, res));
  2501. }
  2502. /**
  2503. * xmlXPathCacheObjectCopy:
  2504. * @ctxt: the XPath context
  2505. * @val: the original object
  2506. *
  2507. * This is the cached version of xmlXPathObjectCopy().
  2508. * Acquire a copy of a given object
  2509. *
  2510. * Returns a created or reused created object.
  2511. */
  2512. static xmlXPathObjectPtr
  2513. xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
  2514. {
  2515. if (val == NULL)
  2516. return(NULL);
  2517. if (XP_HAS_CACHE(ctxt)) {
  2518. switch (val->type) {
  2519. case XPATH_NODESET:
  2520. return(xmlXPathCacheWrapNodeSet(ctxt,
  2521. xmlXPathNodeSetMerge(NULL, val->nodesetval)));
  2522. case XPATH_STRING:
  2523. return(xmlXPathCacheNewString(ctxt, val->stringval));
  2524. case XPATH_BOOLEAN:
  2525. return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
  2526. case XPATH_NUMBER:
  2527. return(xmlXPathCacheNewFloat(ctxt, val->floatval));
  2528. default:
  2529. break;
  2530. }
  2531. }
  2532. return(xmlXPathObjectCopy(val));
  2533. }
  2534. /**
  2535. * xmlXPathCacheConvertBoolean:
  2536. * @ctxt: the XPath context
  2537. * @val: an XPath object
  2538. *
  2539. * This is the cached version of xmlXPathConvertBoolean().
  2540. * Converts an existing object to its boolean() equivalent
  2541. *
  2542. * Returns a created or reused object, the old one is freed (or the operation
  2543. * is done directly on @val)
  2544. */
  2545. static xmlXPathObjectPtr
  2546. xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
  2547. xmlXPathObjectPtr ret;
  2548. if (val == NULL)
  2549. return(xmlXPathCacheNewBoolean(ctxt, 0));
  2550. if (val->type == XPATH_BOOLEAN)
  2551. return(val);
  2552. ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
  2553. xmlXPathReleaseObject(ctxt, val);
  2554. return(ret);
  2555. }
  2556. /**
  2557. * xmlXPathCacheConvertNumber:
  2558. * @ctxt: the XPath context
  2559. * @val: an XPath object
  2560. *
  2561. * This is the cached version of xmlXPathConvertNumber().
  2562. * Converts an existing object to its number() equivalent
  2563. *
  2564. * Returns a created or reused object, the old one is freed (or the operation
  2565. * is done directly on @val)
  2566. */
  2567. static xmlXPathObjectPtr
  2568. xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
  2569. xmlXPathObjectPtr ret;
  2570. if (val == NULL)
  2571. return(xmlXPathCacheNewFloat(ctxt, 0.0));
  2572. if (val->type == XPATH_NUMBER)
  2573. return(val);
  2574. ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
  2575. xmlXPathReleaseObject(ctxt, val);
  2576. return(ret);
  2577. }
  2578. /************************************************************************
  2579. * *
  2580. * Parser stacks related functions and macros *
  2581. * *
  2582. ************************************************************************/
  2583. /**
  2584. * xmlXPathSetFrame:
  2585. * @ctxt: an XPath parser context
  2586. *
  2587. * Set the callee evaluation frame
  2588. *
  2589. * Returns the previous frame value to be restored once done
  2590. */
  2591. static int
  2592. xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
  2593. int ret;
  2594. if (ctxt == NULL)
  2595. return(0);
  2596. ret = ctxt->valueFrame;
  2597. ctxt->valueFrame = ctxt->valueNr;
  2598. return(ret);
  2599. }
  2600. /**
  2601. * xmlXPathPopFrame:
  2602. * @ctxt: an XPath parser context
  2603. * @frame: the previous frame value
  2604. *
  2605. * Remove the callee evaluation frame
  2606. */
  2607. static void
  2608. xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
  2609. if (ctxt == NULL)
  2610. return;
  2611. if (ctxt->valueNr < ctxt->valueFrame) {
  2612. xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
  2613. }
  2614. ctxt->valueFrame = frame;
  2615. }
  2616. /**
  2617. * valuePop:
  2618. * @ctxt: an XPath evaluation context
  2619. *
  2620. * Pops the top XPath object from the value stack
  2621. *
  2622. * Returns the XPath object just removed
  2623. */
  2624. xmlXPathObjectPtr
  2625. valuePop(xmlXPathParserContextPtr ctxt)
  2626. {
  2627. xmlXPathObjectPtr ret;
  2628. if ((ctxt == NULL) || (ctxt->valueNr <= 0))
  2629. return (NULL);
  2630. if (ctxt->valueNr <= ctxt->valueFrame) {
  2631. xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
  2632. return (NULL);
  2633. }
  2634. ctxt->valueNr--;
  2635. if (ctxt->valueNr > 0)
  2636. ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
  2637. else
  2638. ctxt->value = NULL;
  2639. ret = ctxt->valueTab[ctxt->valueNr];
  2640. ctxt->valueTab[ctxt->valueNr] = NULL;
  2641. return (ret);
  2642. }
  2643. /**
  2644. * valuePush:
  2645. * @ctxt: an XPath evaluation context
  2646. * @value: the XPath object
  2647. *
  2648. * Pushes a new XPath object on top of the value stack. If value is NULL,
  2649. * a memory error is recorded in the parser context.
  2650. *
  2651. * Returns the number of items on the value stack, or -1 in case of error.
  2652. */
  2653. int
  2654. valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
  2655. {
  2656. if (ctxt == NULL) return(-1);
  2657. if (value == NULL) {
  2658. /*
  2659. * A NULL value typically indicates that a memory allocation failed,
  2660. * so we set ctxt->error here to propagate the error.
  2661. */
  2662. ctxt->error = XPATH_MEMORY_ERROR;
  2663. return(-1);
  2664. }
  2665. if (ctxt->valueNr >= ctxt->valueMax) {
  2666. xmlXPathObjectPtr *tmp;
  2667. if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
  2668. xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
  2669. return (-1);
  2670. }
  2671. tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
  2672. 2 * ctxt->valueMax *
  2673. sizeof(ctxt->valueTab[0]));
  2674. if (tmp == NULL) {
  2675. xmlXPathPErrMemory(ctxt, "pushing value\n");
  2676. return (-1);
  2677. }
  2678. ctxt->valueMax *= 2;
  2679. ctxt->valueTab = tmp;
  2680. }
  2681. ctxt->valueTab[ctxt->valueNr] = value;
  2682. ctxt->value = value;
  2683. return (ctxt->valueNr++);
  2684. }
  2685. /**
  2686. * xmlXPathPopBoolean:
  2687. * @ctxt: an XPath parser context
  2688. *
  2689. * Pops a boolean from the stack, handling conversion if needed.
  2690. * Check error with #xmlXPathCheckError.
  2691. *
  2692. * Returns the boolean
  2693. */
  2694. int
  2695. xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
  2696. xmlXPathObjectPtr obj;
  2697. int ret;
  2698. obj = valuePop(ctxt);
  2699. if (obj == NULL) {
  2700. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2701. return(0);
  2702. }
  2703. if (obj->type != XPATH_BOOLEAN)
  2704. ret = xmlXPathCastToBoolean(obj);
  2705. else
  2706. ret = obj->boolval;
  2707. xmlXPathReleaseObject(ctxt->context, obj);
  2708. return(ret);
  2709. }
  2710. /**
  2711. * xmlXPathPopNumber:
  2712. * @ctxt: an XPath parser context
  2713. *
  2714. * Pops a number from the stack, handling conversion if needed.
  2715. * Check error with #xmlXPathCheckError.
  2716. *
  2717. * Returns the number
  2718. */
  2719. double
  2720. xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
  2721. xmlXPathObjectPtr obj;
  2722. double ret;
  2723. obj = valuePop(ctxt);
  2724. if (obj == NULL) {
  2725. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2726. return(0);
  2727. }
  2728. if (obj->type != XPATH_NUMBER)
  2729. ret = xmlXPathCastToNumber(obj);
  2730. else
  2731. ret = obj->floatval;
  2732. xmlXPathReleaseObject(ctxt->context, obj);
  2733. return(ret);
  2734. }
  2735. /**
  2736. * xmlXPathPopString:
  2737. * @ctxt: an XPath parser context
  2738. *
  2739. * Pops a string from the stack, handling conversion if needed.
  2740. * Check error with #xmlXPathCheckError.
  2741. *
  2742. * Returns the string
  2743. */
  2744. xmlChar *
  2745. xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
  2746. xmlXPathObjectPtr obj;
  2747. xmlChar * ret;
  2748. obj = valuePop(ctxt);
  2749. if (obj == NULL) {
  2750. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2751. return(NULL);
  2752. }
  2753. ret = xmlXPathCastToString(obj); /* this does required strdup */
  2754. /* TODO: needs refactoring somewhere else */
  2755. if (obj->stringval == ret)
  2756. obj->stringval = NULL;
  2757. xmlXPathReleaseObject(ctxt->context, obj);
  2758. return(ret);
  2759. }
  2760. /**
  2761. * xmlXPathPopNodeSet:
  2762. * @ctxt: an XPath parser context
  2763. *
  2764. * Pops a node-set from the stack, handling conversion if needed.
  2765. * Check error with #xmlXPathCheckError.
  2766. *
  2767. * Returns the node-set
  2768. */
  2769. xmlNodeSetPtr
  2770. xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
  2771. xmlXPathObjectPtr obj;
  2772. xmlNodeSetPtr ret;
  2773. if (ctxt == NULL) return(NULL);
  2774. if (ctxt->value == NULL) {
  2775. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2776. return(NULL);
  2777. }
  2778. if (!xmlXPathStackIsNodeSet(ctxt)) {
  2779. xmlXPathSetTypeError(ctxt);
  2780. return(NULL);
  2781. }
  2782. obj = valuePop(ctxt);
  2783. ret = obj->nodesetval;
  2784. #if 0
  2785. /* to fix memory leak of not clearing obj->user */
  2786. if (obj->boolval && obj->user != NULL)
  2787. xmlFreeNodeList((xmlNodePtr) obj->user);
  2788. #endif
  2789. obj->nodesetval = NULL;
  2790. xmlXPathReleaseObject(ctxt->context, obj);
  2791. return(ret);
  2792. }
  2793. /**
  2794. * xmlXPathPopExternal:
  2795. * @ctxt: an XPath parser context
  2796. *
  2797. * Pops an external object from the stack, handling conversion if needed.
  2798. * Check error with #xmlXPathCheckError.
  2799. *
  2800. * Returns the object
  2801. */
  2802. void *
  2803. xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
  2804. xmlXPathObjectPtr obj;
  2805. void * ret;
  2806. if ((ctxt == NULL) || (ctxt->value == NULL)) {
  2807. xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
  2808. return(NULL);
  2809. }
  2810. if (ctxt->value->type != XPATH_USERS) {
  2811. xmlXPathSetTypeError(ctxt);
  2812. return(NULL);
  2813. }
  2814. obj = valuePop(ctxt);
  2815. ret = obj->user;
  2816. obj->user = NULL;
  2817. xmlXPathReleaseObject(ctxt->context, obj);
  2818. return(ret);
  2819. }
  2820. /*
  2821. * Macros for accessing the content. Those should be used only by the parser,
  2822. * and not exported.
  2823. *
  2824. * Dirty macros, i.e. one need to make assumption on the context to use them
  2825. *
  2826. * CUR_PTR return the current pointer to the xmlChar to be parsed.
  2827. * CUR returns the current xmlChar value, i.e. a 8 bit value
  2828. * in ISO-Latin or UTF-8.
  2829. * This should be used internally by the parser
  2830. * only to compare to ASCII values otherwise it would break when
  2831. * running with UTF-8 encoding.
  2832. * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
  2833. * to compare on ASCII based substring.
  2834. * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
  2835. * strings within the parser.
  2836. * CURRENT Returns the current char value, with the full decoding of
  2837. * UTF-8 if we are using this mode. It returns an int.
  2838. * NEXT Skip to the next character, this does the proper decoding
  2839. * in UTF-8 mode. It also pop-up unfinished entities on the fly.
  2840. * It returns the pointer to the current xmlChar.
  2841. */
  2842. #define CUR (*ctxt->cur)
  2843. #define SKIP(val) ctxt->cur += (val)
  2844. #define NXT(val) ctxt->cur[(val)]
  2845. #define CUR_PTR ctxt->cur
  2846. #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
  2847. #define COPY_BUF(l,b,i,v) \
  2848. if (l == 1) b[i++] = (xmlChar) v; \
  2849. else i += xmlCopyChar(l,&b[i],v)
  2850. #define NEXTL(l) ctxt->cur += l
  2851. #define SKIP_BLANKS \
  2852. while (IS_BLANK_CH(*(ctxt->cur))) NEXT
  2853. #define CURRENT (*ctxt->cur)
  2854. #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
  2855. #ifndef DBL_DIG
  2856. #define DBL_DIG 16
  2857. #endif
  2858. #ifndef DBL_EPSILON
  2859. #define DBL_EPSILON 1E-9
  2860. #endif
  2861. #define UPPER_DOUBLE 1E9
  2862. #define LOWER_DOUBLE 1E-5
  2863. #define LOWER_DOUBLE_EXP 5
  2864. #define INTEGER_DIGITS DBL_DIG
  2865. #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
  2866. #define EXPONENT_DIGITS (3 + 2)
  2867. /**
  2868. * xmlXPathFormatNumber:
  2869. * @number: number to format
  2870. * @buffer: output buffer
  2871. * @buffersize: size of output buffer
  2872. *
  2873. * Convert the number into a string representation.
  2874. */
  2875. static void
  2876. xmlXPathFormatNumber(double number, char buffer[], int buffersize)
  2877. {
  2878. switch (xmlXPathIsInf(number)) {
  2879. case 1:
  2880. if (buffersize > (int)sizeof("Infinity"))
  2881. snprintf(buffer, buffersize, "Infinity");
  2882. break;
  2883. case -1:
  2884. if (buffersize > (int)sizeof("-Infinity"))
  2885. snprintf(buffer, buffersize, "-Infinity");
  2886. break;
  2887. default:
  2888. if (xmlXPathIsNaN(number)) {
  2889. if (buffersize > (int)sizeof("NaN"))
  2890. snprintf(buffer, buffersize, "NaN");
  2891. } else if (number == 0) {
  2892. /* Omit sign for negative zero. */
  2893. snprintf(buffer, buffersize, "0");
  2894. } else if ((number > INT_MIN) && (number < INT_MAX) &&
  2895. (number == (int) number)) {
  2896. char work[30];
  2897. char *ptr, *cur;
  2898. int value = (int) number;
  2899. ptr = &buffer[0];
  2900. if (value == 0) {
  2901. *ptr++ = '0';
  2902. } else {
  2903. snprintf(work, 29, "%d", value);
  2904. cur = &work[0];
  2905. while ((*cur) && (ptr - buffer < buffersize)) {
  2906. *ptr++ = *cur++;
  2907. }
  2908. }
  2909. if (ptr - buffer < buffersize) {
  2910. *ptr = 0;
  2911. } else if (buffersize > 0) {
  2912. ptr--;
  2913. *ptr = 0;
  2914. }
  2915. } else {
  2916. /*
  2917. For the dimension of work,
  2918. DBL_DIG is number of significant digits
  2919. EXPONENT is only needed for "scientific notation"
  2920. 3 is sign, decimal point, and terminating zero
  2921. LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
  2922. Note that this dimension is slightly (a few characters)
  2923. larger than actually necessary.
  2924. */
  2925. char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
  2926. int integer_place, fraction_place;
  2927. char *ptr;
  2928. char *after_fraction;
  2929. double absolute_value;
  2930. int size;
  2931. absolute_value = fabs(number);
  2932. /*
  2933. * First choose format - scientific or regular floating point.
  2934. * In either case, result is in work, and after_fraction points
  2935. * just past the fractional part.
  2936. */
  2937. if ( ((absolute_value > UPPER_DOUBLE) ||
  2938. (absolute_value < LOWER_DOUBLE)) &&
  2939. (absolute_value != 0.0) ) {
  2940. /* Use scientific notation */
  2941. integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
  2942. fraction_place = DBL_DIG - 1;
  2943. size = snprintf(work, sizeof(work),"%*.*e",
  2944. integer_place, fraction_place, number);
  2945. while ((size > 0) && (work[size] != 'e')) size--;
  2946. }
  2947. else {
  2948. /* Use regular notation */
  2949. if (absolute_value > 0.0) {
  2950. integer_place = (int)log10(absolute_value);
  2951. if (integer_place > 0)
  2952. fraction_place = DBL_DIG - integer_place - 1;
  2953. else
  2954. fraction_place = DBL_DIG - integer_place;
  2955. } else {
  2956. fraction_place = 1;
  2957. }
  2958. size = snprintf(work, sizeof(work), "%0.*f",
  2959. fraction_place, number);
  2960. }
  2961. /* Remove leading spaces sometimes inserted by snprintf */
  2962. while (work[0] == ' ') {
  2963. for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
  2964. size--;
  2965. }
  2966. /* Remove fractional trailing zeroes */
  2967. after_fraction = work + size;
  2968. ptr = after_fraction;
  2969. while (*(--ptr) == '0')
  2970. ;
  2971. if (*ptr != '.')
  2972. ptr++;
  2973. while ((*ptr++ = *after_fraction++) != 0);
  2974. /* Finally copy result back to caller */
  2975. size = strlen(work) + 1;
  2976. if (size > buffersize) {
  2977. work[buffersize - 1] = 0;
  2978. size = buffersize;
  2979. }
  2980. memmove(buffer, work, size);
  2981. }
  2982. break;
  2983. }
  2984. }
  2985. /************************************************************************
  2986. * *
  2987. * Routines to handle NodeSets *
  2988. * *
  2989. ************************************************************************/
  2990. /**
  2991. * xmlXPathOrderDocElems:
  2992. * @doc: an input document
  2993. *
  2994. * Call this routine to speed up XPath computation on static documents.
  2995. * This stamps all the element nodes with the document order
  2996. * Like for line information, the order is kept in the element->content
  2997. * field, the value stored is actually - the node number (starting at -1)
  2998. * to be able to differentiate from line numbers.
  2999. *
  3000. * Returns the number of elements found in the document or -1 in case
  3001. * of error.
  3002. */
  3003. long
  3004. xmlXPathOrderDocElems(xmlDocPtr doc) {
  3005. ptrdiff_t count = 0;
  3006. xmlNodePtr cur;
  3007. if (doc == NULL)
  3008. return(-1);
  3009. cur = doc->children;
  3010. while (cur != NULL) {
  3011. if (cur->type == XML_ELEMENT_NODE) {
  3012. cur->content = (void *) (-(++count));
  3013. if (cur->children != NULL) {
  3014. cur = cur->children;
  3015. continue;
  3016. }
  3017. }
  3018. if (cur->next != NULL) {
  3019. cur = cur->next;
  3020. continue;
  3021. }
  3022. do {
  3023. cur = cur->parent;
  3024. if (cur == NULL)
  3025. break;
  3026. if (cur == (xmlNodePtr) doc) {
  3027. cur = NULL;
  3028. break;
  3029. }
  3030. if (cur->next != NULL) {
  3031. cur = cur->next;
  3032. break;
  3033. }
  3034. } while (cur != NULL);
  3035. }
  3036. return((long) count);
  3037. }
  3038. /**
  3039. * xmlXPathCmpNodes:
  3040. * @node1: the first node
  3041. * @node2: the second node
  3042. *
  3043. * Compare two nodes w.r.t document order
  3044. *
  3045. * Returns -2 in case of error 1 if first point < second point, 0 if
  3046. * it's the same node, -1 otherwise
  3047. */
  3048. int
  3049. xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
  3050. int depth1, depth2;
  3051. int attr1 = 0, attr2 = 0;
  3052. xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
  3053. xmlNodePtr cur, root;
  3054. if ((node1 == NULL) || (node2 == NULL))
  3055. return(-2);
  3056. /*
  3057. * a couple of optimizations which will avoid computations in most cases
  3058. */
  3059. if (node1 == node2) /* trivial case */
  3060. return(0);
  3061. if (node1->type == XML_ATTRIBUTE_NODE) {
  3062. attr1 = 1;
  3063. attrNode1 = node1;
  3064. node1 = node1->parent;
  3065. }
  3066. if (node2->type == XML_ATTRIBUTE_NODE) {
  3067. attr2 = 1;
  3068. attrNode2 = node2;
  3069. node2 = node2->parent;
  3070. }
  3071. if (node1 == node2) {
  3072. if (attr1 == attr2) {
  3073. /* not required, but we keep attributes in order */
  3074. if (attr1 != 0) {
  3075. cur = attrNode2->prev;
  3076. while (cur != NULL) {
  3077. if (cur == attrNode1)
  3078. return (1);
  3079. cur = cur->prev;
  3080. }
  3081. return (-1);
  3082. }
  3083. return(0);
  3084. }
  3085. if (attr2 == 1)
  3086. return(1);
  3087. return(-1);
  3088. }
  3089. if ((node1->type == XML_NAMESPACE_DECL) ||
  3090. (node2->type == XML_NAMESPACE_DECL))
  3091. return(1);
  3092. if (node1 == node2->prev)
  3093. return(1);
  3094. if (node1 == node2->next)
  3095. return(-1);
  3096. /*
  3097. * Speedup using document order if available.
  3098. */
  3099. if ((node1->type == XML_ELEMENT_NODE) &&
  3100. (node2->type == XML_ELEMENT_NODE) &&
  3101. (0 > (ptrdiff_t) node1->content) &&
  3102. (0 > (ptrdiff_t) node2->content) &&
  3103. (node1->doc == node2->doc)) {
  3104. ptrdiff_t l1, l2;
  3105. l1 = -((ptrdiff_t) node1->content);
  3106. l2 = -((ptrdiff_t) node2->content);
  3107. if (l1 < l2)
  3108. return(1);
  3109. if (l1 > l2)
  3110. return(-1);
  3111. }
  3112. /*
  3113. * compute depth to root
  3114. */
  3115. for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
  3116. if (cur->parent == node1)
  3117. return(1);
  3118. depth2++;
  3119. }
  3120. root = cur;
  3121. for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
  3122. if (cur->parent == node2)
  3123. return(-1);
  3124. depth1++;
  3125. }
  3126. /*
  3127. * Distinct document (or distinct entities :-( ) case.
  3128. */
  3129. if (root != cur) {
  3130. return(-2);
  3131. }
  3132. /*
  3133. * get the nearest common ancestor.
  3134. */
  3135. while (depth1 > depth2) {
  3136. depth1--;
  3137. node1 = node1->parent;
  3138. }
  3139. while (depth2 > depth1) {
  3140. depth2--;
  3141. node2 = node2->parent;
  3142. }
  3143. while (node1->parent != node2->parent) {
  3144. node1 = node1->parent;
  3145. node2 = node2->parent;
  3146. /* should not happen but just in case ... */
  3147. if ((node1 == NULL) || (node2 == NULL))
  3148. return(-2);
  3149. }
  3150. /*
  3151. * Find who's first.
  3152. */
  3153. if (node1 == node2->prev)
  3154. return(1);
  3155. if (node1 == node2->next)
  3156. return(-1);
  3157. /*
  3158. * Speedup using document order if available.
  3159. */
  3160. if ((node1->type == XML_ELEMENT_NODE) &&
  3161. (node2->type == XML_ELEMENT_NODE) &&
  3162. (0 > (ptrdiff_t) node1->content) &&
  3163. (0 > (ptrdiff_t) node2->content) &&
  3164. (node1->doc == node2->doc)) {
  3165. ptrdiff_t l1, l2;
  3166. l1 = -((ptrdiff_t) node1->content);
  3167. l2 = -((ptrdiff_t) node2->content);
  3168. if (l1 < l2)
  3169. return(1);
  3170. if (l1 > l2)
  3171. return(-1);
  3172. }
  3173. for (cur = node1->next;cur != NULL;cur = cur->next)
  3174. if (cur == node2)
  3175. return(1);
  3176. return(-1); /* assume there is no sibling list corruption */
  3177. }
  3178. /**
  3179. * xmlXPathNodeSetSort:
  3180. * @set: the node set
  3181. *
  3182. * Sort the node set in document order
  3183. */
  3184. void
  3185. xmlXPathNodeSetSort(xmlNodeSetPtr set) {
  3186. #ifndef WITH_TIM_SORT
  3187. int i, j, incr, len;
  3188. xmlNodePtr tmp;
  3189. #endif
  3190. if (set == NULL)
  3191. return;
  3192. #ifndef WITH_TIM_SORT
  3193. /*
  3194. * Use the old Shell's sort implementation to sort the node-set
  3195. * Timsort ought to be quite faster
  3196. */
  3197. len = set->nodeNr;
  3198. for (incr = len / 2; incr > 0; incr /= 2) {
  3199. for (i = incr; i < len; i++) {
  3200. j = i - incr;
  3201. while (j >= 0) {
  3202. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  3203. if (xmlXPathCmpNodesExt(set->nodeTab[j],
  3204. set->nodeTab[j + incr]) == -1)
  3205. #else
  3206. if (xmlXPathCmpNodes(set->nodeTab[j],
  3207. set->nodeTab[j + incr]) == -1)
  3208. #endif
  3209. {
  3210. tmp = set->nodeTab[j];
  3211. set->nodeTab[j] = set->nodeTab[j + incr];
  3212. set->nodeTab[j + incr] = tmp;
  3213. j -= incr;
  3214. } else
  3215. break;
  3216. }
  3217. }
  3218. }
  3219. #else /* WITH_TIM_SORT */
  3220. libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
  3221. #endif /* WITH_TIM_SORT */
  3222. }
  3223. #define XML_NODESET_DEFAULT 10
  3224. /**
  3225. * xmlXPathNodeSetDupNs:
  3226. * @node: the parent node of the namespace XPath node
  3227. * @ns: the libxml namespace declaration node.
  3228. *
  3229. * Namespace node in libxml don't match the XPath semantic. In a node set
  3230. * the namespace nodes are duplicated and the next pointer is set to the
  3231. * parent node in the XPath semantic.
  3232. *
  3233. * Returns the newly created object.
  3234. */
  3235. static xmlNodePtr
  3236. xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
  3237. xmlNsPtr cur;
  3238. if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
  3239. return(NULL);
  3240. if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
  3241. return((xmlNodePtr) ns);
  3242. /*
  3243. * Allocate a new Namespace and fill the fields.
  3244. */
  3245. cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
  3246. if (cur == NULL) {
  3247. xmlXPathErrMemory(NULL, "duplicating namespace\n");
  3248. return(NULL);
  3249. }
  3250. memset(cur, 0, sizeof(xmlNs));
  3251. cur->type = XML_NAMESPACE_DECL;
  3252. if (ns->href != NULL)
  3253. cur->href = xmlStrdup(ns->href);
  3254. if (ns->prefix != NULL)
  3255. cur->prefix = xmlStrdup(ns->prefix);
  3256. cur->next = (xmlNsPtr) node;
  3257. return((xmlNodePtr) cur);
  3258. }
  3259. /**
  3260. * xmlXPathNodeSetFreeNs:
  3261. * @ns: the XPath namespace node found in a nodeset.
  3262. *
  3263. * Namespace nodes in libxml don't match the XPath semantic. In a node set
  3264. * the namespace nodes are duplicated and the next pointer is set to the
  3265. * parent node in the XPath semantic. Check if such a node needs to be freed
  3266. */
  3267. void
  3268. xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
  3269. if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
  3270. return;
  3271. if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
  3272. if (ns->href != NULL)
  3273. xmlFree((xmlChar *)ns->href);
  3274. if (ns->prefix != NULL)
  3275. xmlFree((xmlChar *)ns->prefix);
  3276. xmlFree(ns);
  3277. }
  3278. }
  3279. /**
  3280. * xmlXPathNodeSetCreate:
  3281. * @val: an initial xmlNodePtr, or NULL
  3282. *
  3283. * Create a new xmlNodeSetPtr of type double and of value @val
  3284. *
  3285. * Returns the newly created object.
  3286. */
  3287. xmlNodeSetPtr
  3288. xmlXPathNodeSetCreate(xmlNodePtr val) {
  3289. xmlNodeSetPtr ret;
  3290. ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
  3291. if (ret == NULL) {
  3292. xmlXPathErrMemory(NULL, "creating nodeset\n");
  3293. return(NULL);
  3294. }
  3295. memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
  3296. if (val != NULL) {
  3297. ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  3298. sizeof(xmlNodePtr));
  3299. if (ret->nodeTab == NULL) {
  3300. xmlXPathErrMemory(NULL, "creating nodeset\n");
  3301. xmlFree(ret);
  3302. return(NULL);
  3303. }
  3304. memset(ret->nodeTab, 0 ,
  3305. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3306. ret->nodeMax = XML_NODESET_DEFAULT;
  3307. if (val->type == XML_NAMESPACE_DECL) {
  3308. xmlNsPtr ns = (xmlNsPtr) val;
  3309. /* TODO: Check memory error. */
  3310. ret->nodeTab[ret->nodeNr++] =
  3311. xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
  3312. } else
  3313. ret->nodeTab[ret->nodeNr++] = val;
  3314. }
  3315. return(ret);
  3316. }
  3317. /**
  3318. * xmlXPathNodeSetContains:
  3319. * @cur: the node-set
  3320. * @val: the node
  3321. *
  3322. * checks whether @cur contains @val
  3323. *
  3324. * Returns true (1) if @cur contains @val, false (0) otherwise
  3325. */
  3326. int
  3327. xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
  3328. int i;
  3329. if ((cur == NULL) || (val == NULL)) return(0);
  3330. if (val->type == XML_NAMESPACE_DECL) {
  3331. for (i = 0; i < cur->nodeNr; i++) {
  3332. if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
  3333. xmlNsPtr ns1, ns2;
  3334. ns1 = (xmlNsPtr) val;
  3335. ns2 = (xmlNsPtr) cur->nodeTab[i];
  3336. if (ns1 == ns2)
  3337. return(1);
  3338. if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
  3339. (xmlStrEqual(ns1->prefix, ns2->prefix)))
  3340. return(1);
  3341. }
  3342. }
  3343. } else {
  3344. for (i = 0; i < cur->nodeNr; i++) {
  3345. if (cur->nodeTab[i] == val)
  3346. return(1);
  3347. }
  3348. }
  3349. return(0);
  3350. }
  3351. /**
  3352. * xmlXPathNodeSetAddNs:
  3353. * @cur: the initial node set
  3354. * @node: the hosting node
  3355. * @ns: a the namespace node
  3356. *
  3357. * add a new namespace node to an existing NodeSet
  3358. *
  3359. * Returns 0 in case of success and -1 in case of error
  3360. */
  3361. int
  3362. xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
  3363. int i;
  3364. if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
  3365. (ns->type != XML_NAMESPACE_DECL) ||
  3366. (node->type != XML_ELEMENT_NODE))
  3367. return(-1);
  3368. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3369. /*
  3370. * prevent duplicates
  3371. */
  3372. for (i = 0;i < cur->nodeNr;i++) {
  3373. if ((cur->nodeTab[i] != NULL) &&
  3374. (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
  3375. (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
  3376. (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
  3377. return(0);
  3378. }
  3379. /*
  3380. * grow the nodeTab if needed
  3381. */
  3382. if (cur->nodeMax == 0) {
  3383. cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  3384. sizeof(xmlNodePtr));
  3385. if (cur->nodeTab == NULL) {
  3386. xmlXPathErrMemory(NULL, "growing nodeset\n");
  3387. return(-1);
  3388. }
  3389. memset(cur->nodeTab, 0 ,
  3390. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3391. cur->nodeMax = XML_NODESET_DEFAULT;
  3392. } else if (cur->nodeNr == cur->nodeMax) {
  3393. xmlNodePtr *temp;
  3394. if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
  3395. xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
  3396. return(-1);
  3397. }
  3398. temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
  3399. sizeof(xmlNodePtr));
  3400. if (temp == NULL) {
  3401. xmlXPathErrMemory(NULL, "growing nodeset\n");
  3402. return(-1);
  3403. }
  3404. cur->nodeMax *= 2;
  3405. cur->nodeTab = temp;
  3406. }
  3407. /* TODO: Check memory error. */
  3408. cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
  3409. return(0);
  3410. }
  3411. /**
  3412. * xmlXPathNodeSetAdd:
  3413. * @cur: the initial node set
  3414. * @val: a new xmlNodePtr
  3415. *
  3416. * add a new xmlNodePtr to an existing NodeSet
  3417. *
  3418. * Returns 0 in case of success, and -1 in case of error
  3419. */
  3420. int
  3421. xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
  3422. int i;
  3423. if ((cur == NULL) || (val == NULL)) return(-1);
  3424. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3425. /*
  3426. * prevent duplicates
  3427. */
  3428. for (i = 0;i < cur->nodeNr;i++)
  3429. if (cur->nodeTab[i] == val) return(0);
  3430. /*
  3431. * grow the nodeTab if needed
  3432. */
  3433. if (cur->nodeMax == 0) {
  3434. cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  3435. sizeof(xmlNodePtr));
  3436. if (cur->nodeTab == NULL) {
  3437. xmlXPathErrMemory(NULL, "growing nodeset\n");
  3438. return(-1);
  3439. }
  3440. memset(cur->nodeTab, 0 ,
  3441. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3442. cur->nodeMax = XML_NODESET_DEFAULT;
  3443. } else if (cur->nodeNr == cur->nodeMax) {
  3444. xmlNodePtr *temp;
  3445. if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
  3446. xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
  3447. return(-1);
  3448. }
  3449. temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
  3450. sizeof(xmlNodePtr));
  3451. if (temp == NULL) {
  3452. xmlXPathErrMemory(NULL, "growing nodeset\n");
  3453. return(-1);
  3454. }
  3455. cur->nodeMax *= 2;
  3456. cur->nodeTab = temp;
  3457. }
  3458. if (val->type == XML_NAMESPACE_DECL) {
  3459. xmlNsPtr ns = (xmlNsPtr) val;
  3460. /* TODO: Check memory error. */
  3461. cur->nodeTab[cur->nodeNr++] =
  3462. xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
  3463. } else
  3464. cur->nodeTab[cur->nodeNr++] = val;
  3465. return(0);
  3466. }
  3467. /**
  3468. * xmlXPathNodeSetAddUnique:
  3469. * @cur: the initial node set
  3470. * @val: a new xmlNodePtr
  3471. *
  3472. * add a new xmlNodePtr to an existing NodeSet, optimized version
  3473. * when we are sure the node is not already in the set.
  3474. *
  3475. * Returns 0 in case of success and -1 in case of failure
  3476. */
  3477. int
  3478. xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
  3479. if ((cur == NULL) || (val == NULL)) return(-1);
  3480. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3481. /*
  3482. * grow the nodeTab if needed
  3483. */
  3484. if (cur->nodeMax == 0) {
  3485. cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  3486. sizeof(xmlNodePtr));
  3487. if (cur->nodeTab == NULL) {
  3488. xmlXPathErrMemory(NULL, "growing nodeset\n");
  3489. return(-1);
  3490. }
  3491. memset(cur->nodeTab, 0 ,
  3492. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3493. cur->nodeMax = XML_NODESET_DEFAULT;
  3494. } else if (cur->nodeNr == cur->nodeMax) {
  3495. xmlNodePtr *temp;
  3496. if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
  3497. xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
  3498. return(-1);
  3499. }
  3500. temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
  3501. sizeof(xmlNodePtr));
  3502. if (temp == NULL) {
  3503. xmlXPathErrMemory(NULL, "growing nodeset\n");
  3504. return(-1);
  3505. }
  3506. cur->nodeTab = temp;
  3507. cur->nodeMax *= 2;
  3508. }
  3509. if (val->type == XML_NAMESPACE_DECL) {
  3510. xmlNsPtr ns = (xmlNsPtr) val;
  3511. /* TODO: Check memory error. */
  3512. cur->nodeTab[cur->nodeNr++] =
  3513. xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
  3514. } else
  3515. cur->nodeTab[cur->nodeNr++] = val;
  3516. return(0);
  3517. }
  3518. /**
  3519. * xmlXPathNodeSetMerge:
  3520. * @val1: the first NodeSet or NULL
  3521. * @val2: the second NodeSet
  3522. *
  3523. * Merges two nodesets, all nodes from @val2 are added to @val1
  3524. * if @val1 is NULL, a new set is created and copied from @val2
  3525. *
  3526. * Returns @val1 once extended or NULL in case of error.
  3527. */
  3528. xmlNodeSetPtr
  3529. xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
  3530. int i, j, initNr, skip;
  3531. xmlNodePtr n1, n2;
  3532. if (val2 == NULL) return(val1);
  3533. if (val1 == NULL) {
  3534. val1 = xmlXPathNodeSetCreate(NULL);
  3535. if (val1 == NULL)
  3536. return (NULL);
  3537. #if 0
  3538. /*
  3539. * TODO: The optimization won't work in every case, since
  3540. * those nasty namespace nodes need to be added with
  3541. * xmlXPathNodeSetDupNs() to the set; thus a pure
  3542. * memcpy is not possible.
  3543. * If there was a flag on the nodesetval, indicating that
  3544. * some temporary nodes are in, that would be helpful.
  3545. */
  3546. /*
  3547. * Optimization: Create an equally sized node-set
  3548. * and memcpy the content.
  3549. */
  3550. val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
  3551. if (val1 == NULL)
  3552. return(NULL);
  3553. if (val2->nodeNr != 0) {
  3554. if (val2->nodeNr == 1)
  3555. *(val1->nodeTab) = *(val2->nodeTab);
  3556. else {
  3557. memcpy(val1->nodeTab, val2->nodeTab,
  3558. val2->nodeNr * sizeof(xmlNodePtr));
  3559. }
  3560. val1->nodeNr = val2->nodeNr;
  3561. }
  3562. return(val1);
  3563. #endif
  3564. }
  3565. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3566. initNr = val1->nodeNr;
  3567. for (i = 0;i < val2->nodeNr;i++) {
  3568. n2 = val2->nodeTab[i];
  3569. /*
  3570. * check against duplicates
  3571. */
  3572. skip = 0;
  3573. for (j = 0; j < initNr; j++) {
  3574. n1 = val1->nodeTab[j];
  3575. if (n1 == n2) {
  3576. skip = 1;
  3577. break;
  3578. } else if ((n1->type == XML_NAMESPACE_DECL) &&
  3579. (n2->type == XML_NAMESPACE_DECL)) {
  3580. if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
  3581. (xmlStrEqual(((xmlNsPtr) n1)->prefix,
  3582. ((xmlNsPtr) n2)->prefix)))
  3583. {
  3584. skip = 1;
  3585. break;
  3586. }
  3587. }
  3588. }
  3589. if (skip)
  3590. continue;
  3591. /*
  3592. * grow the nodeTab if needed
  3593. */
  3594. if (val1->nodeMax == 0) {
  3595. val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
  3596. sizeof(xmlNodePtr));
  3597. if (val1->nodeTab == NULL) {
  3598. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3599. return(NULL);
  3600. }
  3601. memset(val1->nodeTab, 0 ,
  3602. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3603. val1->nodeMax = XML_NODESET_DEFAULT;
  3604. } else if (val1->nodeNr == val1->nodeMax) {
  3605. xmlNodePtr *temp;
  3606. if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
  3607. xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
  3608. return(NULL);
  3609. }
  3610. temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
  3611. sizeof(xmlNodePtr));
  3612. if (temp == NULL) {
  3613. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3614. return(NULL);
  3615. }
  3616. val1->nodeTab = temp;
  3617. val1->nodeMax *= 2;
  3618. }
  3619. if (n2->type == XML_NAMESPACE_DECL) {
  3620. xmlNsPtr ns = (xmlNsPtr) n2;
  3621. /* TODO: Check memory error. */
  3622. val1->nodeTab[val1->nodeNr++] =
  3623. xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
  3624. } else
  3625. val1->nodeTab[val1->nodeNr++] = n2;
  3626. }
  3627. return(val1);
  3628. }
  3629. /**
  3630. * xmlXPathNodeSetMergeAndClear:
  3631. * @set1: the first NodeSet or NULL
  3632. * @set2: the second NodeSet
  3633. *
  3634. * Merges two nodesets, all nodes from @set2 are added to @set1.
  3635. * Checks for duplicate nodes. Clears set2.
  3636. *
  3637. * Returns @set1 once extended or NULL in case of error.
  3638. */
  3639. static xmlNodeSetPtr
  3640. xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
  3641. {
  3642. {
  3643. int i, j, initNbSet1;
  3644. xmlNodePtr n1, n2;
  3645. initNbSet1 = set1->nodeNr;
  3646. for (i = 0;i < set2->nodeNr;i++) {
  3647. n2 = set2->nodeTab[i];
  3648. /*
  3649. * Skip duplicates.
  3650. */
  3651. for (j = 0; j < initNbSet1; j++) {
  3652. n1 = set1->nodeTab[j];
  3653. if (n1 == n2) {
  3654. goto skip_node;
  3655. } else if ((n1->type == XML_NAMESPACE_DECL) &&
  3656. (n2->type == XML_NAMESPACE_DECL))
  3657. {
  3658. if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
  3659. (xmlStrEqual(((xmlNsPtr) n1)->prefix,
  3660. ((xmlNsPtr) n2)->prefix)))
  3661. {
  3662. /*
  3663. * Free the namespace node.
  3664. */
  3665. set2->nodeTab[i] = NULL;
  3666. xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
  3667. goto skip_node;
  3668. }
  3669. }
  3670. }
  3671. /*
  3672. * grow the nodeTab if needed
  3673. */
  3674. if (set1->nodeMax == 0) {
  3675. set1->nodeTab = (xmlNodePtr *) xmlMalloc(
  3676. XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
  3677. if (set1->nodeTab == NULL) {
  3678. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3679. return(NULL);
  3680. }
  3681. memset(set1->nodeTab, 0,
  3682. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3683. set1->nodeMax = XML_NODESET_DEFAULT;
  3684. } else if (set1->nodeNr >= set1->nodeMax) {
  3685. xmlNodePtr *temp;
  3686. if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
  3687. xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
  3688. return(NULL);
  3689. }
  3690. temp = (xmlNodePtr *) xmlRealloc(
  3691. set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
  3692. if (temp == NULL) {
  3693. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3694. return(NULL);
  3695. }
  3696. set1->nodeTab = temp;
  3697. set1->nodeMax *= 2;
  3698. }
  3699. set1->nodeTab[set1->nodeNr++] = n2;
  3700. skip_node:
  3701. {}
  3702. }
  3703. }
  3704. set2->nodeNr = 0;
  3705. return(set1);
  3706. }
  3707. /**
  3708. * xmlXPathNodeSetMergeAndClearNoDupls:
  3709. * @set1: the first NodeSet or NULL
  3710. * @set2: the second NodeSet
  3711. *
  3712. * Merges two nodesets, all nodes from @set2 are added to @set1.
  3713. * Doesn't check for duplicate nodes. Clears set2.
  3714. *
  3715. * Returns @set1 once extended or NULL in case of error.
  3716. */
  3717. static xmlNodeSetPtr
  3718. xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
  3719. {
  3720. {
  3721. int i;
  3722. xmlNodePtr n2;
  3723. for (i = 0;i < set2->nodeNr;i++) {
  3724. n2 = set2->nodeTab[i];
  3725. if (set1->nodeMax == 0) {
  3726. set1->nodeTab = (xmlNodePtr *) xmlMalloc(
  3727. XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
  3728. if (set1->nodeTab == NULL) {
  3729. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3730. return(NULL);
  3731. }
  3732. memset(set1->nodeTab, 0,
  3733. XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
  3734. set1->nodeMax = XML_NODESET_DEFAULT;
  3735. } else if (set1->nodeNr >= set1->nodeMax) {
  3736. xmlNodePtr *temp;
  3737. if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
  3738. xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
  3739. return(NULL);
  3740. }
  3741. temp = (xmlNodePtr *) xmlRealloc(
  3742. set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
  3743. if (temp == NULL) {
  3744. xmlXPathErrMemory(NULL, "merging nodeset\n");
  3745. return(NULL);
  3746. }
  3747. set1->nodeTab = temp;
  3748. set1->nodeMax *= 2;
  3749. }
  3750. set1->nodeTab[set1->nodeNr++] = n2;
  3751. }
  3752. }
  3753. set2->nodeNr = 0;
  3754. return(set1);
  3755. }
  3756. /**
  3757. * xmlXPathNodeSetDel:
  3758. * @cur: the initial node set
  3759. * @val: an xmlNodePtr
  3760. *
  3761. * Removes an xmlNodePtr from an existing NodeSet
  3762. */
  3763. void
  3764. xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
  3765. int i;
  3766. if (cur == NULL) return;
  3767. if (val == NULL) return;
  3768. /*
  3769. * find node in nodeTab
  3770. */
  3771. for (i = 0;i < cur->nodeNr;i++)
  3772. if (cur->nodeTab[i] == val) break;
  3773. if (i >= cur->nodeNr) { /* not found */
  3774. #ifdef DEBUG
  3775. xmlGenericError(xmlGenericErrorContext,
  3776. "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
  3777. val->name);
  3778. #endif
  3779. return;
  3780. }
  3781. if ((cur->nodeTab[i] != NULL) &&
  3782. (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
  3783. xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
  3784. cur->nodeNr--;
  3785. for (;i < cur->nodeNr;i++)
  3786. cur->nodeTab[i] = cur->nodeTab[i + 1];
  3787. cur->nodeTab[cur->nodeNr] = NULL;
  3788. }
  3789. /**
  3790. * xmlXPathNodeSetRemove:
  3791. * @cur: the initial node set
  3792. * @val: the index to remove
  3793. *
  3794. * Removes an entry from an existing NodeSet list.
  3795. */
  3796. void
  3797. xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
  3798. if (cur == NULL) return;
  3799. if (val >= cur->nodeNr) return;
  3800. if ((cur->nodeTab[val] != NULL) &&
  3801. (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
  3802. xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
  3803. cur->nodeNr--;
  3804. for (;val < cur->nodeNr;val++)
  3805. cur->nodeTab[val] = cur->nodeTab[val + 1];
  3806. cur->nodeTab[cur->nodeNr] = NULL;
  3807. }
  3808. /**
  3809. * xmlXPathFreeNodeSet:
  3810. * @obj: the xmlNodeSetPtr to free
  3811. *
  3812. * Free the NodeSet compound (not the actual nodes !).
  3813. */
  3814. void
  3815. xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
  3816. if (obj == NULL) return;
  3817. if (obj->nodeTab != NULL) {
  3818. int i;
  3819. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3820. for (i = 0;i < obj->nodeNr;i++)
  3821. if ((obj->nodeTab[i] != NULL) &&
  3822. (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
  3823. xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
  3824. xmlFree(obj->nodeTab);
  3825. }
  3826. xmlFree(obj);
  3827. }
  3828. /**
  3829. * xmlXPathNodeSetClearFromPos:
  3830. * @set: the node set to be cleared
  3831. * @pos: the start position to clear from
  3832. *
  3833. * Clears the list from temporary XPath objects (e.g. namespace nodes
  3834. * are feed) starting with the entry at @pos, but does *not* free the list
  3835. * itself. Sets the length of the list to @pos.
  3836. */
  3837. static void
  3838. xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
  3839. {
  3840. if ((set == NULL) || (pos >= set->nodeNr))
  3841. return;
  3842. else if ((hasNsNodes)) {
  3843. int i;
  3844. xmlNodePtr node;
  3845. for (i = pos; i < set->nodeNr; i++) {
  3846. node = set->nodeTab[i];
  3847. if ((node != NULL) &&
  3848. (node->type == XML_NAMESPACE_DECL))
  3849. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  3850. }
  3851. }
  3852. set->nodeNr = pos;
  3853. }
  3854. /**
  3855. * xmlXPathNodeSetClear:
  3856. * @set: the node set to clear
  3857. *
  3858. * Clears the list from all temporary XPath objects (e.g. namespace nodes
  3859. * are feed), but does *not* free the list itself. Sets the length of the
  3860. * list to 0.
  3861. */
  3862. static void
  3863. xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
  3864. {
  3865. xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
  3866. }
  3867. /**
  3868. * xmlXPathNodeSetKeepLast:
  3869. * @set: the node set to be cleared
  3870. *
  3871. * Move the last node to the first position and clear temporary XPath objects
  3872. * (e.g. namespace nodes) from all other nodes. Sets the length of the list
  3873. * to 1.
  3874. */
  3875. static void
  3876. xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
  3877. {
  3878. int i;
  3879. xmlNodePtr node;
  3880. if ((set == NULL) || (set->nodeNr <= 1))
  3881. return;
  3882. for (i = 0; i < set->nodeNr - 1; i++) {
  3883. node = set->nodeTab[i];
  3884. if ((node != NULL) &&
  3885. (node->type == XML_NAMESPACE_DECL))
  3886. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  3887. }
  3888. set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
  3889. set->nodeNr = 1;
  3890. }
  3891. /**
  3892. * xmlXPathFreeValueTree:
  3893. * @obj: the xmlNodeSetPtr to free
  3894. *
  3895. * Free the NodeSet compound and the actual tree, this is different
  3896. * from xmlXPathFreeNodeSet()
  3897. */
  3898. static void
  3899. xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
  3900. int i;
  3901. if (obj == NULL) return;
  3902. if (obj->nodeTab != NULL) {
  3903. for (i = 0;i < obj->nodeNr;i++) {
  3904. if (obj->nodeTab[i] != NULL) {
  3905. if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
  3906. xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
  3907. } else {
  3908. xmlFreeNodeList(obj->nodeTab[i]);
  3909. }
  3910. }
  3911. }
  3912. xmlFree(obj->nodeTab);
  3913. }
  3914. xmlFree(obj);
  3915. }
  3916. #if defined(DEBUG) || defined(DEBUG_STEP)
  3917. /**
  3918. * xmlGenericErrorContextNodeSet:
  3919. * @output: a FILE * for the output
  3920. * @obj: the xmlNodeSetPtr to display
  3921. *
  3922. * Quick display of a NodeSet
  3923. */
  3924. void
  3925. xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
  3926. int i;
  3927. if (output == NULL) output = xmlGenericErrorContext;
  3928. if (obj == NULL) {
  3929. fprintf(output, "NodeSet == NULL !\n");
  3930. return;
  3931. }
  3932. if (obj->nodeNr == 0) {
  3933. fprintf(output, "NodeSet is empty\n");
  3934. return;
  3935. }
  3936. if (obj->nodeTab == NULL) {
  3937. fprintf(output, " nodeTab == NULL !\n");
  3938. return;
  3939. }
  3940. for (i = 0; i < obj->nodeNr; i++) {
  3941. if (obj->nodeTab[i] == NULL) {
  3942. fprintf(output, " NULL !\n");
  3943. return;
  3944. }
  3945. if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
  3946. (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
  3947. fprintf(output, " /");
  3948. else if (obj->nodeTab[i]->name == NULL)
  3949. fprintf(output, " noname!");
  3950. else fprintf(output, " %s", obj->nodeTab[i]->name);
  3951. }
  3952. fprintf(output, "\n");
  3953. }
  3954. #endif
  3955. /**
  3956. * xmlXPathNewNodeSet:
  3957. * @val: the NodePtr value
  3958. *
  3959. * Create a new xmlXPathObjectPtr of type NodeSet and initialize
  3960. * it with the single Node @val
  3961. *
  3962. * Returns the newly created object.
  3963. */
  3964. xmlXPathObjectPtr
  3965. xmlXPathNewNodeSet(xmlNodePtr val) {
  3966. xmlXPathObjectPtr ret;
  3967. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  3968. if (ret == NULL) {
  3969. xmlXPathErrMemory(NULL, "creating nodeset\n");
  3970. return(NULL);
  3971. }
  3972. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  3973. ret->type = XPATH_NODESET;
  3974. ret->boolval = 0;
  3975. /* TODO: Check memory error. */
  3976. ret->nodesetval = xmlXPathNodeSetCreate(val);
  3977. /* @@ with_ns to check whether namespace nodes should be looked at @@ */
  3978. #ifdef XP_DEBUG_OBJ_USAGE
  3979. xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
  3980. #endif
  3981. return(ret);
  3982. }
  3983. /**
  3984. * xmlXPathNewValueTree:
  3985. * @val: the NodePtr value
  3986. *
  3987. * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
  3988. * it with the tree root @val
  3989. *
  3990. * Returns the newly created object.
  3991. */
  3992. xmlXPathObjectPtr
  3993. xmlXPathNewValueTree(xmlNodePtr val) {
  3994. xmlXPathObjectPtr ret;
  3995. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  3996. if (ret == NULL) {
  3997. xmlXPathErrMemory(NULL, "creating result value tree\n");
  3998. return(NULL);
  3999. }
  4000. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4001. ret->type = XPATH_XSLT_TREE;
  4002. ret->boolval = 1;
  4003. ret->user = (void *) val;
  4004. ret->nodesetval = xmlXPathNodeSetCreate(val);
  4005. #ifdef XP_DEBUG_OBJ_USAGE
  4006. xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
  4007. #endif
  4008. return(ret);
  4009. }
  4010. /**
  4011. * xmlXPathNewNodeSetList:
  4012. * @val: an existing NodeSet
  4013. *
  4014. * Create a new xmlXPathObjectPtr of type NodeSet and initialize
  4015. * it with the Nodeset @val
  4016. *
  4017. * Returns the newly created object.
  4018. */
  4019. xmlXPathObjectPtr
  4020. xmlXPathNewNodeSetList(xmlNodeSetPtr val)
  4021. {
  4022. xmlXPathObjectPtr ret;
  4023. int i;
  4024. if (val == NULL)
  4025. ret = NULL;
  4026. else if (val->nodeTab == NULL)
  4027. ret = xmlXPathNewNodeSet(NULL);
  4028. else {
  4029. ret = xmlXPathNewNodeSet(val->nodeTab[0]);
  4030. if (ret) {
  4031. for (i = 1; i < val->nodeNr; ++i) {
  4032. /* TODO: Propagate memory error. */
  4033. if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
  4034. < 0) break;
  4035. }
  4036. }
  4037. }
  4038. return (ret);
  4039. }
  4040. /**
  4041. * xmlXPathWrapNodeSet:
  4042. * @val: the NodePtr value
  4043. *
  4044. * Wrap the Nodeset @val in a new xmlXPathObjectPtr
  4045. *
  4046. * Returns the newly created object.
  4047. */
  4048. xmlXPathObjectPtr
  4049. xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
  4050. xmlXPathObjectPtr ret;
  4051. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4052. if (ret == NULL) {
  4053. xmlXPathErrMemory(NULL, "creating node set object\n");
  4054. return(NULL);
  4055. }
  4056. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4057. ret->type = XPATH_NODESET;
  4058. ret->nodesetval = val;
  4059. #ifdef XP_DEBUG_OBJ_USAGE
  4060. xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
  4061. #endif
  4062. return(ret);
  4063. }
  4064. /**
  4065. * xmlXPathFreeNodeSetList:
  4066. * @obj: an existing NodeSetList object
  4067. *
  4068. * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
  4069. * the list contrary to xmlXPathFreeObject().
  4070. */
  4071. void
  4072. xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
  4073. if (obj == NULL) return;
  4074. #ifdef XP_DEBUG_OBJ_USAGE
  4075. xmlXPathDebugObjUsageReleased(NULL, obj->type);
  4076. #endif
  4077. xmlFree(obj);
  4078. }
  4079. /**
  4080. * xmlXPathDifference:
  4081. * @nodes1: a node-set
  4082. * @nodes2: a node-set
  4083. *
  4084. * Implements the EXSLT - Sets difference() function:
  4085. * node-set set:difference (node-set, node-set)
  4086. *
  4087. * Returns the difference between the two node sets, or nodes1 if
  4088. * nodes2 is empty
  4089. */
  4090. xmlNodeSetPtr
  4091. xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4092. xmlNodeSetPtr ret;
  4093. int i, l1;
  4094. xmlNodePtr cur;
  4095. if (xmlXPathNodeSetIsEmpty(nodes2))
  4096. return(nodes1);
  4097. /* TODO: Check memory error. */
  4098. ret = xmlXPathNodeSetCreate(NULL);
  4099. if (xmlXPathNodeSetIsEmpty(nodes1))
  4100. return(ret);
  4101. l1 = xmlXPathNodeSetGetLength(nodes1);
  4102. for (i = 0; i < l1; i++) {
  4103. cur = xmlXPathNodeSetItem(nodes1, i);
  4104. if (!xmlXPathNodeSetContains(nodes2, cur)) {
  4105. /* TODO: Propagate memory error. */
  4106. if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
  4107. break;
  4108. }
  4109. }
  4110. return(ret);
  4111. }
  4112. /**
  4113. * xmlXPathIntersection:
  4114. * @nodes1: a node-set
  4115. * @nodes2: a node-set
  4116. *
  4117. * Implements the EXSLT - Sets intersection() function:
  4118. * node-set set:intersection (node-set, node-set)
  4119. *
  4120. * Returns a node set comprising the nodes that are within both the
  4121. * node sets passed as arguments
  4122. */
  4123. xmlNodeSetPtr
  4124. xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4125. xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
  4126. int i, l1;
  4127. xmlNodePtr cur;
  4128. if (ret == NULL)
  4129. return(ret);
  4130. if (xmlXPathNodeSetIsEmpty(nodes1))
  4131. return(ret);
  4132. if (xmlXPathNodeSetIsEmpty(nodes2))
  4133. return(ret);
  4134. l1 = xmlXPathNodeSetGetLength(nodes1);
  4135. for (i = 0; i < l1; i++) {
  4136. cur = xmlXPathNodeSetItem(nodes1, i);
  4137. if (xmlXPathNodeSetContains(nodes2, cur)) {
  4138. /* TODO: Propagate memory error. */
  4139. if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
  4140. break;
  4141. }
  4142. }
  4143. return(ret);
  4144. }
  4145. /**
  4146. * xmlXPathDistinctSorted:
  4147. * @nodes: a node-set, sorted by document order
  4148. *
  4149. * Implements the EXSLT - Sets distinct() function:
  4150. * node-set set:distinct (node-set)
  4151. *
  4152. * Returns a subset of the nodes contained in @nodes, or @nodes if
  4153. * it is empty
  4154. */
  4155. xmlNodeSetPtr
  4156. xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
  4157. xmlNodeSetPtr ret;
  4158. xmlHashTablePtr hash;
  4159. int i, l;
  4160. xmlChar * strval;
  4161. xmlNodePtr cur;
  4162. if (xmlXPathNodeSetIsEmpty(nodes))
  4163. return(nodes);
  4164. ret = xmlXPathNodeSetCreate(NULL);
  4165. if (ret == NULL)
  4166. return(ret);
  4167. l = xmlXPathNodeSetGetLength(nodes);
  4168. hash = xmlHashCreate (l);
  4169. for (i = 0; i < l; i++) {
  4170. cur = xmlXPathNodeSetItem(nodes, i);
  4171. strval = xmlXPathCastNodeToString(cur);
  4172. if (xmlHashLookup(hash, strval) == NULL) {
  4173. xmlHashAddEntry(hash, strval, strval);
  4174. /* TODO: Propagate memory error. */
  4175. if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
  4176. break;
  4177. } else {
  4178. xmlFree(strval);
  4179. }
  4180. }
  4181. xmlHashFree(hash, xmlHashDefaultDeallocator);
  4182. return(ret);
  4183. }
  4184. /**
  4185. * xmlXPathDistinct:
  4186. * @nodes: a node-set
  4187. *
  4188. * Implements the EXSLT - Sets distinct() function:
  4189. * node-set set:distinct (node-set)
  4190. * @nodes is sorted by document order, then #exslSetsDistinctSorted
  4191. * is called with the sorted node-set
  4192. *
  4193. * Returns a subset of the nodes contained in @nodes, or @nodes if
  4194. * it is empty
  4195. */
  4196. xmlNodeSetPtr
  4197. xmlXPathDistinct (xmlNodeSetPtr nodes) {
  4198. if (xmlXPathNodeSetIsEmpty(nodes))
  4199. return(nodes);
  4200. xmlXPathNodeSetSort(nodes);
  4201. return(xmlXPathDistinctSorted(nodes));
  4202. }
  4203. /**
  4204. * xmlXPathHasSameNodes:
  4205. * @nodes1: a node-set
  4206. * @nodes2: a node-set
  4207. *
  4208. * Implements the EXSLT - Sets has-same-nodes function:
  4209. * boolean set:has-same-node(node-set, node-set)
  4210. *
  4211. * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
  4212. * otherwise
  4213. */
  4214. int
  4215. xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4216. int i, l;
  4217. xmlNodePtr cur;
  4218. if (xmlXPathNodeSetIsEmpty(nodes1) ||
  4219. xmlXPathNodeSetIsEmpty(nodes2))
  4220. return(0);
  4221. l = xmlXPathNodeSetGetLength(nodes1);
  4222. for (i = 0; i < l; i++) {
  4223. cur = xmlXPathNodeSetItem(nodes1, i);
  4224. if (xmlXPathNodeSetContains(nodes2, cur))
  4225. return(1);
  4226. }
  4227. return(0);
  4228. }
  4229. /**
  4230. * xmlXPathNodeLeadingSorted:
  4231. * @nodes: a node-set, sorted by document order
  4232. * @node: a node
  4233. *
  4234. * Implements the EXSLT - Sets leading() function:
  4235. * node-set set:leading (node-set, node-set)
  4236. *
  4237. * Returns the nodes in @nodes that precede @node in document order,
  4238. * @nodes if @node is NULL or an empty node-set if @nodes
  4239. * doesn't contain @node
  4240. */
  4241. xmlNodeSetPtr
  4242. xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
  4243. int i, l;
  4244. xmlNodePtr cur;
  4245. xmlNodeSetPtr ret;
  4246. if (node == NULL)
  4247. return(nodes);
  4248. ret = xmlXPathNodeSetCreate(NULL);
  4249. if (ret == NULL)
  4250. return(ret);
  4251. if (xmlXPathNodeSetIsEmpty(nodes) ||
  4252. (!xmlXPathNodeSetContains(nodes, node)))
  4253. return(ret);
  4254. l = xmlXPathNodeSetGetLength(nodes);
  4255. for (i = 0; i < l; i++) {
  4256. cur = xmlXPathNodeSetItem(nodes, i);
  4257. if (cur == node)
  4258. break;
  4259. /* TODO: Propagate memory error. */
  4260. if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
  4261. break;
  4262. }
  4263. return(ret);
  4264. }
  4265. /**
  4266. * xmlXPathNodeLeading:
  4267. * @nodes: a node-set
  4268. * @node: a node
  4269. *
  4270. * Implements the EXSLT - Sets leading() function:
  4271. * node-set set:leading (node-set, node-set)
  4272. * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
  4273. * is called.
  4274. *
  4275. * Returns the nodes in @nodes that precede @node in document order,
  4276. * @nodes if @node is NULL or an empty node-set if @nodes
  4277. * doesn't contain @node
  4278. */
  4279. xmlNodeSetPtr
  4280. xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
  4281. xmlXPathNodeSetSort(nodes);
  4282. return(xmlXPathNodeLeadingSorted(nodes, node));
  4283. }
  4284. /**
  4285. * xmlXPathLeadingSorted:
  4286. * @nodes1: a node-set, sorted by document order
  4287. * @nodes2: a node-set, sorted by document order
  4288. *
  4289. * Implements the EXSLT - Sets leading() function:
  4290. * node-set set:leading (node-set, node-set)
  4291. *
  4292. * Returns the nodes in @nodes1 that precede the first node in @nodes2
  4293. * in document order, @nodes1 if @nodes2 is NULL or empty or
  4294. * an empty node-set if @nodes1 doesn't contain @nodes2
  4295. */
  4296. xmlNodeSetPtr
  4297. xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4298. if (xmlXPathNodeSetIsEmpty(nodes2))
  4299. return(nodes1);
  4300. return(xmlXPathNodeLeadingSorted(nodes1,
  4301. xmlXPathNodeSetItem(nodes2, 1)));
  4302. }
  4303. /**
  4304. * xmlXPathLeading:
  4305. * @nodes1: a node-set
  4306. * @nodes2: a node-set
  4307. *
  4308. * Implements the EXSLT - Sets leading() function:
  4309. * node-set set:leading (node-set, node-set)
  4310. * @nodes1 and @nodes2 are sorted by document order, then
  4311. * #exslSetsLeadingSorted is called.
  4312. *
  4313. * Returns the nodes in @nodes1 that precede the first node in @nodes2
  4314. * in document order, @nodes1 if @nodes2 is NULL or empty or
  4315. * an empty node-set if @nodes1 doesn't contain @nodes2
  4316. */
  4317. xmlNodeSetPtr
  4318. xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4319. if (xmlXPathNodeSetIsEmpty(nodes2))
  4320. return(nodes1);
  4321. if (xmlXPathNodeSetIsEmpty(nodes1))
  4322. return(xmlXPathNodeSetCreate(NULL));
  4323. xmlXPathNodeSetSort(nodes1);
  4324. xmlXPathNodeSetSort(nodes2);
  4325. return(xmlXPathNodeLeadingSorted(nodes1,
  4326. xmlXPathNodeSetItem(nodes2, 1)));
  4327. }
  4328. /**
  4329. * xmlXPathNodeTrailingSorted:
  4330. * @nodes: a node-set, sorted by document order
  4331. * @node: a node
  4332. *
  4333. * Implements the EXSLT - Sets trailing() function:
  4334. * node-set set:trailing (node-set, node-set)
  4335. *
  4336. * Returns the nodes in @nodes that follow @node in document order,
  4337. * @nodes if @node is NULL or an empty node-set if @nodes
  4338. * doesn't contain @node
  4339. */
  4340. xmlNodeSetPtr
  4341. xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
  4342. int i, l;
  4343. xmlNodePtr cur;
  4344. xmlNodeSetPtr ret;
  4345. if (node == NULL)
  4346. return(nodes);
  4347. ret = xmlXPathNodeSetCreate(NULL);
  4348. if (ret == NULL)
  4349. return(ret);
  4350. if (xmlXPathNodeSetIsEmpty(nodes) ||
  4351. (!xmlXPathNodeSetContains(nodes, node)))
  4352. return(ret);
  4353. l = xmlXPathNodeSetGetLength(nodes);
  4354. for (i = l - 1; i >= 0; i--) {
  4355. cur = xmlXPathNodeSetItem(nodes, i);
  4356. if (cur == node)
  4357. break;
  4358. /* TODO: Propagate memory error. */
  4359. if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
  4360. break;
  4361. }
  4362. xmlXPathNodeSetSort(ret); /* bug 413451 */
  4363. return(ret);
  4364. }
  4365. /**
  4366. * xmlXPathNodeTrailing:
  4367. * @nodes: a node-set
  4368. * @node: a node
  4369. *
  4370. * Implements the EXSLT - Sets trailing() function:
  4371. * node-set set:trailing (node-set, node-set)
  4372. * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
  4373. * is called.
  4374. *
  4375. * Returns the nodes in @nodes that follow @node in document order,
  4376. * @nodes if @node is NULL or an empty node-set if @nodes
  4377. * doesn't contain @node
  4378. */
  4379. xmlNodeSetPtr
  4380. xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
  4381. xmlXPathNodeSetSort(nodes);
  4382. return(xmlXPathNodeTrailingSorted(nodes, node));
  4383. }
  4384. /**
  4385. * xmlXPathTrailingSorted:
  4386. * @nodes1: a node-set, sorted by document order
  4387. * @nodes2: a node-set, sorted by document order
  4388. *
  4389. * Implements the EXSLT - Sets trailing() function:
  4390. * node-set set:trailing (node-set, node-set)
  4391. *
  4392. * Returns the nodes in @nodes1 that follow the first node in @nodes2
  4393. * in document order, @nodes1 if @nodes2 is NULL or empty or
  4394. * an empty node-set if @nodes1 doesn't contain @nodes2
  4395. */
  4396. xmlNodeSetPtr
  4397. xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4398. if (xmlXPathNodeSetIsEmpty(nodes2))
  4399. return(nodes1);
  4400. return(xmlXPathNodeTrailingSorted(nodes1,
  4401. xmlXPathNodeSetItem(nodes2, 0)));
  4402. }
  4403. /**
  4404. * xmlXPathTrailing:
  4405. * @nodes1: a node-set
  4406. * @nodes2: a node-set
  4407. *
  4408. * Implements the EXSLT - Sets trailing() function:
  4409. * node-set set:trailing (node-set, node-set)
  4410. * @nodes1 and @nodes2 are sorted by document order, then
  4411. * #xmlXPathTrailingSorted is called.
  4412. *
  4413. * Returns the nodes in @nodes1 that follow the first node in @nodes2
  4414. * in document order, @nodes1 if @nodes2 is NULL or empty or
  4415. * an empty node-set if @nodes1 doesn't contain @nodes2
  4416. */
  4417. xmlNodeSetPtr
  4418. xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
  4419. if (xmlXPathNodeSetIsEmpty(nodes2))
  4420. return(nodes1);
  4421. if (xmlXPathNodeSetIsEmpty(nodes1))
  4422. return(xmlXPathNodeSetCreate(NULL));
  4423. xmlXPathNodeSetSort(nodes1);
  4424. xmlXPathNodeSetSort(nodes2);
  4425. return(xmlXPathNodeTrailingSorted(nodes1,
  4426. xmlXPathNodeSetItem(nodes2, 0)));
  4427. }
  4428. /************************************************************************
  4429. * *
  4430. * Routines to handle extra functions *
  4431. * *
  4432. ************************************************************************/
  4433. /**
  4434. * xmlXPathRegisterFunc:
  4435. * @ctxt: the XPath context
  4436. * @name: the function name
  4437. * @f: the function implementation or NULL
  4438. *
  4439. * Register a new function. If @f is NULL it unregisters the function
  4440. *
  4441. * Returns 0 in case of success, -1 in case of error
  4442. */
  4443. int
  4444. xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
  4445. xmlXPathFunction f) {
  4446. return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
  4447. }
  4448. /**
  4449. * xmlXPathRegisterFuncNS:
  4450. * @ctxt: the XPath context
  4451. * @name: the function name
  4452. * @ns_uri: the function namespace URI
  4453. * @f: the function implementation or NULL
  4454. *
  4455. * Register a new function. If @f is NULL it unregisters the function
  4456. *
  4457. * Returns 0 in case of success, -1 in case of error
  4458. */
  4459. int
  4460. xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
  4461. const xmlChar *ns_uri, xmlXPathFunction f) {
  4462. if (ctxt == NULL)
  4463. return(-1);
  4464. if (name == NULL)
  4465. return(-1);
  4466. if (ctxt->funcHash == NULL)
  4467. ctxt->funcHash = xmlHashCreate(0);
  4468. if (ctxt->funcHash == NULL)
  4469. return(-1);
  4470. if (f == NULL)
  4471. return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
  4472. XML_IGNORE_PEDANTIC_WARNINGS
  4473. return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
  4474. XML_POP_WARNINGS
  4475. }
  4476. /**
  4477. * xmlXPathRegisterFuncLookup:
  4478. * @ctxt: the XPath context
  4479. * @f: the lookup function
  4480. * @funcCtxt: the lookup data
  4481. *
  4482. * Registers an external mechanism to do function lookup.
  4483. */
  4484. void
  4485. xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
  4486. xmlXPathFuncLookupFunc f,
  4487. void *funcCtxt) {
  4488. if (ctxt == NULL)
  4489. return;
  4490. ctxt->funcLookupFunc = f;
  4491. ctxt->funcLookupData = funcCtxt;
  4492. }
  4493. /**
  4494. * xmlXPathFunctionLookup:
  4495. * @ctxt: the XPath context
  4496. * @name: the function name
  4497. *
  4498. * Search in the Function array of the context for the given
  4499. * function.
  4500. *
  4501. * Returns the xmlXPathFunction or NULL if not found
  4502. */
  4503. xmlXPathFunction
  4504. xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
  4505. if (ctxt == NULL)
  4506. return (NULL);
  4507. if (ctxt->funcLookupFunc != NULL) {
  4508. xmlXPathFunction ret;
  4509. xmlXPathFuncLookupFunc f;
  4510. f = ctxt->funcLookupFunc;
  4511. ret = f(ctxt->funcLookupData, name, NULL);
  4512. if (ret != NULL)
  4513. return(ret);
  4514. }
  4515. return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
  4516. }
  4517. /**
  4518. * xmlXPathFunctionLookupNS:
  4519. * @ctxt: the XPath context
  4520. * @name: the function name
  4521. * @ns_uri: the function namespace URI
  4522. *
  4523. * Search in the Function array of the context for the given
  4524. * function.
  4525. *
  4526. * Returns the xmlXPathFunction or NULL if not found
  4527. */
  4528. xmlXPathFunction
  4529. xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
  4530. const xmlChar *ns_uri) {
  4531. xmlXPathFunction ret;
  4532. if (ctxt == NULL)
  4533. return(NULL);
  4534. if (name == NULL)
  4535. return(NULL);
  4536. if (ctxt->funcLookupFunc != NULL) {
  4537. xmlXPathFuncLookupFunc f;
  4538. f = ctxt->funcLookupFunc;
  4539. ret = f(ctxt->funcLookupData, name, ns_uri);
  4540. if (ret != NULL)
  4541. return(ret);
  4542. }
  4543. if (ctxt->funcHash == NULL)
  4544. return(NULL);
  4545. XML_IGNORE_PEDANTIC_WARNINGS
  4546. ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
  4547. XML_POP_WARNINGS
  4548. return(ret);
  4549. }
  4550. /**
  4551. * xmlXPathRegisteredFuncsCleanup:
  4552. * @ctxt: the XPath context
  4553. *
  4554. * Cleanup the XPath context data associated to registered functions
  4555. */
  4556. void
  4557. xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
  4558. if (ctxt == NULL)
  4559. return;
  4560. xmlHashFree(ctxt->funcHash, NULL);
  4561. ctxt->funcHash = NULL;
  4562. }
  4563. /************************************************************************
  4564. * *
  4565. * Routines to handle Variables *
  4566. * *
  4567. ************************************************************************/
  4568. /**
  4569. * xmlXPathRegisterVariable:
  4570. * @ctxt: the XPath context
  4571. * @name: the variable name
  4572. * @value: the variable value or NULL
  4573. *
  4574. * Register a new variable value. If @value is NULL it unregisters
  4575. * the variable
  4576. *
  4577. * Returns 0 in case of success, -1 in case of error
  4578. */
  4579. int
  4580. xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
  4581. xmlXPathObjectPtr value) {
  4582. return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
  4583. }
  4584. /**
  4585. * xmlXPathRegisterVariableNS:
  4586. * @ctxt: the XPath context
  4587. * @name: the variable name
  4588. * @ns_uri: the variable namespace URI
  4589. * @value: the variable value or NULL
  4590. *
  4591. * Register a new variable value. If @value is NULL it unregisters
  4592. * the variable
  4593. *
  4594. * Returns 0 in case of success, -1 in case of error
  4595. */
  4596. int
  4597. xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
  4598. const xmlChar *ns_uri,
  4599. xmlXPathObjectPtr value) {
  4600. if (ctxt == NULL)
  4601. return(-1);
  4602. if (name == NULL)
  4603. return(-1);
  4604. if (ctxt->varHash == NULL)
  4605. ctxt->varHash = xmlHashCreate(0);
  4606. if (ctxt->varHash == NULL)
  4607. return(-1);
  4608. if (value == NULL)
  4609. return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
  4610. xmlXPathFreeObjectEntry));
  4611. return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
  4612. (void *) value, xmlXPathFreeObjectEntry));
  4613. }
  4614. /**
  4615. * xmlXPathRegisterVariableLookup:
  4616. * @ctxt: the XPath context
  4617. * @f: the lookup function
  4618. * @data: the lookup data
  4619. *
  4620. * register an external mechanism to do variable lookup
  4621. */
  4622. void
  4623. xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
  4624. xmlXPathVariableLookupFunc f, void *data) {
  4625. if (ctxt == NULL)
  4626. return;
  4627. ctxt->varLookupFunc = f;
  4628. ctxt->varLookupData = data;
  4629. }
  4630. /**
  4631. * xmlXPathVariableLookup:
  4632. * @ctxt: the XPath context
  4633. * @name: the variable name
  4634. *
  4635. * Search in the Variable array of the context for the given
  4636. * variable value.
  4637. *
  4638. * Returns a copy of the value or NULL if not found
  4639. */
  4640. xmlXPathObjectPtr
  4641. xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
  4642. if (ctxt == NULL)
  4643. return(NULL);
  4644. if (ctxt->varLookupFunc != NULL) {
  4645. xmlXPathObjectPtr ret;
  4646. ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
  4647. (ctxt->varLookupData, name, NULL);
  4648. return(ret);
  4649. }
  4650. return(xmlXPathVariableLookupNS(ctxt, name, NULL));
  4651. }
  4652. /**
  4653. * xmlXPathVariableLookupNS:
  4654. * @ctxt: the XPath context
  4655. * @name: the variable name
  4656. * @ns_uri: the variable namespace URI
  4657. *
  4658. * Search in the Variable array of the context for the given
  4659. * variable value.
  4660. *
  4661. * Returns the a copy of the value or NULL if not found
  4662. */
  4663. xmlXPathObjectPtr
  4664. xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
  4665. const xmlChar *ns_uri) {
  4666. if (ctxt == NULL)
  4667. return(NULL);
  4668. if (ctxt->varLookupFunc != NULL) {
  4669. xmlXPathObjectPtr ret;
  4670. ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
  4671. (ctxt->varLookupData, name, ns_uri);
  4672. if (ret != NULL) return(ret);
  4673. }
  4674. if (ctxt->varHash == NULL)
  4675. return(NULL);
  4676. if (name == NULL)
  4677. return(NULL);
  4678. return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
  4679. xmlHashLookup2(ctxt->varHash, name, ns_uri)));
  4680. }
  4681. /**
  4682. * xmlXPathRegisteredVariablesCleanup:
  4683. * @ctxt: the XPath context
  4684. *
  4685. * Cleanup the XPath context data associated to registered variables
  4686. */
  4687. void
  4688. xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
  4689. if (ctxt == NULL)
  4690. return;
  4691. xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
  4692. ctxt->varHash = NULL;
  4693. }
  4694. /**
  4695. * xmlXPathRegisterNs:
  4696. * @ctxt: the XPath context
  4697. * @prefix: the namespace prefix cannot be NULL or empty string
  4698. * @ns_uri: the namespace name
  4699. *
  4700. * Register a new namespace. If @ns_uri is NULL it unregisters
  4701. * the namespace
  4702. *
  4703. * Returns 0 in case of success, -1 in case of error
  4704. */
  4705. int
  4706. xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
  4707. const xmlChar *ns_uri) {
  4708. if (ctxt == NULL)
  4709. return(-1);
  4710. if (prefix == NULL)
  4711. return(-1);
  4712. if (prefix[0] == 0)
  4713. return(-1);
  4714. if (ctxt->nsHash == NULL)
  4715. ctxt->nsHash = xmlHashCreate(10);
  4716. if (ctxt->nsHash == NULL)
  4717. return(-1);
  4718. if (ns_uri == NULL)
  4719. return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
  4720. xmlHashDefaultDeallocator));
  4721. return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
  4722. xmlHashDefaultDeallocator));
  4723. }
  4724. /**
  4725. * xmlXPathNsLookup:
  4726. * @ctxt: the XPath context
  4727. * @prefix: the namespace prefix value
  4728. *
  4729. * Search in the namespace declaration array of the context for the given
  4730. * namespace name associated to the given prefix
  4731. *
  4732. * Returns the value or NULL if not found
  4733. */
  4734. const xmlChar *
  4735. xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
  4736. if (ctxt == NULL)
  4737. return(NULL);
  4738. if (prefix == NULL)
  4739. return(NULL);
  4740. #ifdef XML_XML_NAMESPACE
  4741. if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
  4742. return(XML_XML_NAMESPACE);
  4743. #endif
  4744. if (ctxt->namespaces != NULL) {
  4745. int i;
  4746. for (i = 0;i < ctxt->nsNr;i++) {
  4747. if ((ctxt->namespaces[i] != NULL) &&
  4748. (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
  4749. return(ctxt->namespaces[i]->href);
  4750. }
  4751. }
  4752. return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
  4753. }
  4754. /**
  4755. * xmlXPathRegisteredNsCleanup:
  4756. * @ctxt: the XPath context
  4757. *
  4758. * Cleanup the XPath context data associated to registered variables
  4759. */
  4760. void
  4761. xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
  4762. if (ctxt == NULL)
  4763. return;
  4764. xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
  4765. ctxt->nsHash = NULL;
  4766. }
  4767. /************************************************************************
  4768. * *
  4769. * Routines to handle Values *
  4770. * *
  4771. ************************************************************************/
  4772. /* Allocations are terrible, one needs to optimize all this !!! */
  4773. /**
  4774. * xmlXPathNewFloat:
  4775. * @val: the double value
  4776. *
  4777. * Create a new xmlXPathObjectPtr of type double and of value @val
  4778. *
  4779. * Returns the newly created object.
  4780. */
  4781. xmlXPathObjectPtr
  4782. xmlXPathNewFloat(double val) {
  4783. xmlXPathObjectPtr ret;
  4784. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4785. if (ret == NULL) {
  4786. xmlXPathErrMemory(NULL, "creating float object\n");
  4787. return(NULL);
  4788. }
  4789. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4790. ret->type = XPATH_NUMBER;
  4791. ret->floatval = val;
  4792. #ifdef XP_DEBUG_OBJ_USAGE
  4793. xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
  4794. #endif
  4795. return(ret);
  4796. }
  4797. /**
  4798. * xmlXPathNewBoolean:
  4799. * @val: the boolean value
  4800. *
  4801. * Create a new xmlXPathObjectPtr of type boolean and of value @val
  4802. *
  4803. * Returns the newly created object.
  4804. */
  4805. xmlXPathObjectPtr
  4806. xmlXPathNewBoolean(int val) {
  4807. xmlXPathObjectPtr ret;
  4808. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4809. if (ret == NULL) {
  4810. xmlXPathErrMemory(NULL, "creating boolean object\n");
  4811. return(NULL);
  4812. }
  4813. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4814. ret->type = XPATH_BOOLEAN;
  4815. ret->boolval = (val != 0);
  4816. #ifdef XP_DEBUG_OBJ_USAGE
  4817. xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
  4818. #endif
  4819. return(ret);
  4820. }
  4821. /**
  4822. * xmlXPathNewString:
  4823. * @val: the xmlChar * value
  4824. *
  4825. * Create a new xmlXPathObjectPtr of type string and of value @val
  4826. *
  4827. * Returns the newly created object.
  4828. */
  4829. xmlXPathObjectPtr
  4830. xmlXPathNewString(const xmlChar *val) {
  4831. xmlXPathObjectPtr ret;
  4832. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4833. if (ret == NULL) {
  4834. xmlXPathErrMemory(NULL, "creating string object\n");
  4835. return(NULL);
  4836. }
  4837. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4838. ret->type = XPATH_STRING;
  4839. if (val != NULL)
  4840. ret->stringval = xmlStrdup(val);
  4841. else
  4842. ret->stringval = xmlStrdup((const xmlChar *)"");
  4843. #ifdef XP_DEBUG_OBJ_USAGE
  4844. xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
  4845. #endif
  4846. return(ret);
  4847. }
  4848. /**
  4849. * xmlXPathWrapString:
  4850. * @val: the xmlChar * value
  4851. *
  4852. * Wraps the @val string into an XPath object.
  4853. *
  4854. * Returns the newly created object.
  4855. */
  4856. xmlXPathObjectPtr
  4857. xmlXPathWrapString (xmlChar *val) {
  4858. xmlXPathObjectPtr ret;
  4859. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4860. if (ret == NULL) {
  4861. xmlXPathErrMemory(NULL, "creating string object\n");
  4862. return(NULL);
  4863. }
  4864. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4865. ret->type = XPATH_STRING;
  4866. ret->stringval = val;
  4867. #ifdef XP_DEBUG_OBJ_USAGE
  4868. xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
  4869. #endif
  4870. return(ret);
  4871. }
  4872. /**
  4873. * xmlXPathNewCString:
  4874. * @val: the char * value
  4875. *
  4876. * Create a new xmlXPathObjectPtr of type string and of value @val
  4877. *
  4878. * Returns the newly created object.
  4879. */
  4880. xmlXPathObjectPtr
  4881. xmlXPathNewCString(const char *val) {
  4882. xmlXPathObjectPtr ret;
  4883. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4884. if (ret == NULL) {
  4885. xmlXPathErrMemory(NULL, "creating string object\n");
  4886. return(NULL);
  4887. }
  4888. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4889. ret->type = XPATH_STRING;
  4890. ret->stringval = xmlStrdup(BAD_CAST val);
  4891. #ifdef XP_DEBUG_OBJ_USAGE
  4892. xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
  4893. #endif
  4894. return(ret);
  4895. }
  4896. /**
  4897. * xmlXPathWrapCString:
  4898. * @val: the char * value
  4899. *
  4900. * Wraps a string into an XPath object.
  4901. *
  4902. * Returns the newly created object.
  4903. */
  4904. xmlXPathObjectPtr
  4905. xmlXPathWrapCString (char * val) {
  4906. return(xmlXPathWrapString((xmlChar *)(val)));
  4907. }
  4908. /**
  4909. * xmlXPathWrapExternal:
  4910. * @val: the user data
  4911. *
  4912. * Wraps the @val data into an XPath object.
  4913. *
  4914. * Returns the newly created object.
  4915. */
  4916. xmlXPathObjectPtr
  4917. xmlXPathWrapExternal (void *val) {
  4918. xmlXPathObjectPtr ret;
  4919. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4920. if (ret == NULL) {
  4921. xmlXPathErrMemory(NULL, "creating user object\n");
  4922. return(NULL);
  4923. }
  4924. memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
  4925. ret->type = XPATH_USERS;
  4926. ret->user = val;
  4927. #ifdef XP_DEBUG_OBJ_USAGE
  4928. xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
  4929. #endif
  4930. return(ret);
  4931. }
  4932. /**
  4933. * xmlXPathObjectCopy:
  4934. * @val: the original object
  4935. *
  4936. * allocate a new copy of a given object
  4937. *
  4938. * Returns the newly created object.
  4939. */
  4940. xmlXPathObjectPtr
  4941. xmlXPathObjectCopy(xmlXPathObjectPtr val) {
  4942. xmlXPathObjectPtr ret;
  4943. if (val == NULL)
  4944. return(NULL);
  4945. ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
  4946. if (ret == NULL) {
  4947. xmlXPathErrMemory(NULL, "copying object\n");
  4948. return(NULL);
  4949. }
  4950. memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
  4951. #ifdef XP_DEBUG_OBJ_USAGE
  4952. xmlXPathDebugObjUsageRequested(NULL, val->type);
  4953. #endif
  4954. switch (val->type) {
  4955. case XPATH_BOOLEAN:
  4956. case XPATH_NUMBER:
  4957. case XPATH_POINT:
  4958. case XPATH_RANGE:
  4959. break;
  4960. case XPATH_STRING:
  4961. ret->stringval = xmlStrdup(val->stringval);
  4962. break;
  4963. case XPATH_XSLT_TREE:
  4964. #if 0
  4965. /*
  4966. Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
  4967. this previous handling is no longer correct, and can cause some serious
  4968. problems (ref. bug 145547)
  4969. */
  4970. if ((val->nodesetval != NULL) &&
  4971. (val->nodesetval->nodeTab != NULL)) {
  4972. xmlNodePtr cur, tmp;
  4973. xmlDocPtr top;
  4974. ret->boolval = 1;
  4975. top = xmlNewDoc(NULL);
  4976. top->name = (char *)
  4977. xmlStrdup(val->nodesetval->nodeTab[0]->name);
  4978. ret->user = top;
  4979. if (top != NULL) {
  4980. top->doc = top;
  4981. cur = val->nodesetval->nodeTab[0]->children;
  4982. while (cur != NULL) {
  4983. tmp = xmlDocCopyNode(cur, top, 1);
  4984. xmlAddChild((xmlNodePtr) top, tmp);
  4985. cur = cur->next;
  4986. }
  4987. }
  4988. ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
  4989. } else
  4990. ret->nodesetval = xmlXPathNodeSetCreate(NULL);
  4991. /* Deallocate the copied tree value */
  4992. break;
  4993. #endif
  4994. case XPATH_NODESET:
  4995. /* TODO: Check memory error. */
  4996. ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
  4997. /* Do not deallocate the copied tree value */
  4998. ret->boolval = 0;
  4999. break;
  5000. case XPATH_LOCATIONSET:
  5001. #ifdef LIBXML_XPTR_ENABLED
  5002. {
  5003. xmlLocationSetPtr loc = val->user;
  5004. ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
  5005. break;
  5006. }
  5007. #endif
  5008. case XPATH_USERS:
  5009. ret->user = val->user;
  5010. break;
  5011. case XPATH_UNDEFINED:
  5012. xmlGenericError(xmlGenericErrorContext,
  5013. "xmlXPathObjectCopy: unsupported type %d\n",
  5014. val->type);
  5015. break;
  5016. }
  5017. return(ret);
  5018. }
  5019. /**
  5020. * xmlXPathFreeObject:
  5021. * @obj: the object to free
  5022. *
  5023. * Free up an xmlXPathObjectPtr object.
  5024. */
  5025. void
  5026. xmlXPathFreeObject(xmlXPathObjectPtr obj) {
  5027. if (obj == NULL) return;
  5028. if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
  5029. if (obj->boolval) {
  5030. #if 0
  5031. if (obj->user != NULL) {
  5032. xmlXPathFreeNodeSet(obj->nodesetval);
  5033. xmlFreeNodeList((xmlNodePtr) obj->user);
  5034. } else
  5035. #endif
  5036. obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
  5037. if (obj->nodesetval != NULL)
  5038. xmlXPathFreeValueTree(obj->nodesetval);
  5039. } else {
  5040. if (obj->nodesetval != NULL)
  5041. xmlXPathFreeNodeSet(obj->nodesetval);
  5042. }
  5043. #ifdef LIBXML_XPTR_ENABLED
  5044. } else if (obj->type == XPATH_LOCATIONSET) {
  5045. if (obj->user != NULL)
  5046. xmlXPtrFreeLocationSet(obj->user);
  5047. #endif
  5048. } else if (obj->type == XPATH_STRING) {
  5049. if (obj->stringval != NULL)
  5050. xmlFree(obj->stringval);
  5051. }
  5052. #ifdef XP_DEBUG_OBJ_USAGE
  5053. xmlXPathDebugObjUsageReleased(NULL, obj->type);
  5054. #endif
  5055. xmlFree(obj);
  5056. }
  5057. static void
  5058. xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
  5059. xmlXPathFreeObject((xmlXPathObjectPtr) obj);
  5060. }
  5061. /**
  5062. * xmlXPathReleaseObject:
  5063. * @obj: the xmlXPathObjectPtr to free or to cache
  5064. *
  5065. * Depending on the state of the cache this frees the given
  5066. * XPath object or stores it in the cache.
  5067. */
  5068. static void
  5069. xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
  5070. {
  5071. #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
  5072. sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
  5073. if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
  5074. #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
  5075. if (obj == NULL)
  5076. return;
  5077. if ((ctxt == NULL) || (ctxt->cache == NULL)) {
  5078. xmlXPathFreeObject(obj);
  5079. } else {
  5080. xmlXPathContextCachePtr cache =
  5081. (xmlXPathContextCachePtr) ctxt->cache;
  5082. switch (obj->type) {
  5083. case XPATH_NODESET:
  5084. case XPATH_XSLT_TREE:
  5085. if (obj->nodesetval != NULL) {
  5086. if (obj->boolval) {
  5087. /*
  5088. * It looks like the @boolval is used for
  5089. * evaluation if this an XSLT Result Tree Fragment.
  5090. * TODO: Check if this assumption is correct.
  5091. */
  5092. obj->type = XPATH_XSLT_TREE; /* just for debugging */
  5093. xmlXPathFreeValueTree(obj->nodesetval);
  5094. obj->nodesetval = NULL;
  5095. } else if ((obj->nodesetval->nodeMax <= 40) &&
  5096. (XP_CACHE_WANTS(cache->nodesetObjs,
  5097. cache->maxNodeset)))
  5098. {
  5099. XP_CACHE_ADD(cache->nodesetObjs, obj);
  5100. goto obj_cached;
  5101. } else {
  5102. xmlXPathFreeNodeSet(obj->nodesetval);
  5103. obj->nodesetval = NULL;
  5104. }
  5105. }
  5106. break;
  5107. case XPATH_STRING:
  5108. if (obj->stringval != NULL)
  5109. xmlFree(obj->stringval);
  5110. if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
  5111. XP_CACHE_ADD(cache->stringObjs, obj);
  5112. goto obj_cached;
  5113. }
  5114. break;
  5115. case XPATH_BOOLEAN:
  5116. if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
  5117. XP_CACHE_ADD(cache->booleanObjs, obj);
  5118. goto obj_cached;
  5119. }
  5120. break;
  5121. case XPATH_NUMBER:
  5122. if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
  5123. XP_CACHE_ADD(cache->numberObjs, obj);
  5124. goto obj_cached;
  5125. }
  5126. break;
  5127. #ifdef LIBXML_XPTR_ENABLED
  5128. case XPATH_LOCATIONSET:
  5129. if (obj->user != NULL) {
  5130. xmlXPtrFreeLocationSet(obj->user);
  5131. }
  5132. goto free_obj;
  5133. #endif
  5134. default:
  5135. goto free_obj;
  5136. }
  5137. /*
  5138. * Fallback to adding to the misc-objects slot.
  5139. */
  5140. if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
  5141. XP_CACHE_ADD(cache->miscObjs, obj);
  5142. } else
  5143. goto free_obj;
  5144. obj_cached:
  5145. #ifdef XP_DEBUG_OBJ_USAGE
  5146. xmlXPathDebugObjUsageReleased(ctxt, obj->type);
  5147. #endif
  5148. if (obj->nodesetval != NULL) {
  5149. xmlNodeSetPtr tmpset = obj->nodesetval;
  5150. /*
  5151. * TODO: Due to those nasty ns-nodes, we need to traverse
  5152. * the list and free the ns-nodes.
  5153. * URGENT TODO: Check if it's actually slowing things down.
  5154. * Maybe we shouldn't try to preserve the list.
  5155. */
  5156. if (tmpset->nodeNr > 1) {
  5157. int i;
  5158. xmlNodePtr node;
  5159. for (i = 0; i < tmpset->nodeNr; i++) {
  5160. node = tmpset->nodeTab[i];
  5161. if ((node != NULL) &&
  5162. (node->type == XML_NAMESPACE_DECL))
  5163. {
  5164. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  5165. }
  5166. }
  5167. } else if (tmpset->nodeNr == 1) {
  5168. if ((tmpset->nodeTab[0] != NULL) &&
  5169. (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
  5170. xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
  5171. }
  5172. tmpset->nodeNr = 0;
  5173. memset(obj, 0, sizeof(xmlXPathObject));
  5174. obj->nodesetval = tmpset;
  5175. } else
  5176. memset(obj, 0, sizeof(xmlXPathObject));
  5177. return;
  5178. free_obj:
  5179. /*
  5180. * Cache is full; free the object.
  5181. */
  5182. if (obj->nodesetval != NULL)
  5183. xmlXPathFreeNodeSet(obj->nodesetval);
  5184. #ifdef XP_DEBUG_OBJ_USAGE
  5185. xmlXPathDebugObjUsageReleased(NULL, obj->type);
  5186. #endif
  5187. xmlFree(obj);
  5188. }
  5189. return;
  5190. }
  5191. /************************************************************************
  5192. * *
  5193. * Type Casting Routines *
  5194. * *
  5195. ************************************************************************/
  5196. /**
  5197. * xmlXPathCastBooleanToString:
  5198. * @val: a boolean
  5199. *
  5200. * Converts a boolean to its string value.
  5201. *
  5202. * Returns a newly allocated string.
  5203. */
  5204. xmlChar *
  5205. xmlXPathCastBooleanToString (int val) {
  5206. xmlChar *ret;
  5207. if (val)
  5208. ret = xmlStrdup((const xmlChar *) "true");
  5209. else
  5210. ret = xmlStrdup((const xmlChar *) "false");
  5211. return(ret);
  5212. }
  5213. /**
  5214. * xmlXPathCastNumberToString:
  5215. * @val: a number
  5216. *
  5217. * Converts a number to its string value.
  5218. *
  5219. * Returns a newly allocated string.
  5220. */
  5221. xmlChar *
  5222. xmlXPathCastNumberToString (double val) {
  5223. xmlChar *ret;
  5224. switch (xmlXPathIsInf(val)) {
  5225. case 1:
  5226. ret = xmlStrdup((const xmlChar *) "Infinity");
  5227. break;
  5228. case -1:
  5229. ret = xmlStrdup((const xmlChar *) "-Infinity");
  5230. break;
  5231. default:
  5232. if (xmlXPathIsNaN(val)) {
  5233. ret = xmlStrdup((const xmlChar *) "NaN");
  5234. } else if (val == 0) {
  5235. /* Omit sign for negative zero. */
  5236. ret = xmlStrdup((const xmlChar *) "0");
  5237. } else {
  5238. /* could be improved */
  5239. char buf[100];
  5240. xmlXPathFormatNumber(val, buf, 99);
  5241. buf[99] = 0;
  5242. ret = xmlStrdup((const xmlChar *) buf);
  5243. }
  5244. }
  5245. return(ret);
  5246. }
  5247. /**
  5248. * xmlXPathCastNodeToString:
  5249. * @node: a node
  5250. *
  5251. * Converts a node to its string value.
  5252. *
  5253. * Returns a newly allocated string.
  5254. */
  5255. xmlChar *
  5256. xmlXPathCastNodeToString (xmlNodePtr node) {
  5257. xmlChar *ret;
  5258. if ((ret = xmlNodeGetContent(node)) == NULL)
  5259. ret = xmlStrdup((const xmlChar *) "");
  5260. return(ret);
  5261. }
  5262. /**
  5263. * xmlXPathCastNodeSetToString:
  5264. * @ns: a node-set
  5265. *
  5266. * Converts a node-set to its string value.
  5267. *
  5268. * Returns a newly allocated string.
  5269. */
  5270. xmlChar *
  5271. xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
  5272. if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
  5273. return(xmlStrdup((const xmlChar *) ""));
  5274. if (ns->nodeNr > 1)
  5275. xmlXPathNodeSetSort(ns);
  5276. return(xmlXPathCastNodeToString(ns->nodeTab[0]));
  5277. }
  5278. /**
  5279. * xmlXPathCastToString:
  5280. * @val: an XPath object
  5281. *
  5282. * Converts an existing object to its string() equivalent
  5283. *
  5284. * Returns the allocated string value of the object, NULL in case of error.
  5285. * It's up to the caller to free the string memory with xmlFree().
  5286. */
  5287. xmlChar *
  5288. xmlXPathCastToString(xmlXPathObjectPtr val) {
  5289. xmlChar *ret = NULL;
  5290. if (val == NULL)
  5291. return(xmlStrdup((const xmlChar *) ""));
  5292. switch (val->type) {
  5293. case XPATH_UNDEFINED:
  5294. #ifdef DEBUG_EXPR
  5295. xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
  5296. #endif
  5297. ret = xmlStrdup((const xmlChar *) "");
  5298. break;
  5299. case XPATH_NODESET:
  5300. case XPATH_XSLT_TREE:
  5301. ret = xmlXPathCastNodeSetToString(val->nodesetval);
  5302. break;
  5303. case XPATH_STRING:
  5304. return(xmlStrdup(val->stringval));
  5305. case XPATH_BOOLEAN:
  5306. ret = xmlXPathCastBooleanToString(val->boolval);
  5307. break;
  5308. case XPATH_NUMBER: {
  5309. ret = xmlXPathCastNumberToString(val->floatval);
  5310. break;
  5311. }
  5312. case XPATH_USERS:
  5313. case XPATH_POINT:
  5314. case XPATH_RANGE:
  5315. case XPATH_LOCATIONSET:
  5316. TODO
  5317. ret = xmlStrdup((const xmlChar *) "");
  5318. break;
  5319. }
  5320. return(ret);
  5321. }
  5322. /**
  5323. * xmlXPathConvertString:
  5324. * @val: an XPath object
  5325. *
  5326. * Converts an existing object to its string() equivalent
  5327. *
  5328. * Returns the new object, the old one is freed (or the operation
  5329. * is done directly on @val)
  5330. */
  5331. xmlXPathObjectPtr
  5332. xmlXPathConvertString(xmlXPathObjectPtr val) {
  5333. xmlChar *res = NULL;
  5334. if (val == NULL)
  5335. return(xmlXPathNewCString(""));
  5336. switch (val->type) {
  5337. case XPATH_UNDEFINED:
  5338. #ifdef DEBUG_EXPR
  5339. xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
  5340. #endif
  5341. break;
  5342. case XPATH_NODESET:
  5343. case XPATH_XSLT_TREE:
  5344. res = xmlXPathCastNodeSetToString(val->nodesetval);
  5345. break;
  5346. case XPATH_STRING:
  5347. return(val);
  5348. case XPATH_BOOLEAN:
  5349. res = xmlXPathCastBooleanToString(val->boolval);
  5350. break;
  5351. case XPATH_NUMBER:
  5352. res = xmlXPathCastNumberToString(val->floatval);
  5353. break;
  5354. case XPATH_USERS:
  5355. case XPATH_POINT:
  5356. case XPATH_RANGE:
  5357. case XPATH_LOCATIONSET:
  5358. TODO;
  5359. break;
  5360. }
  5361. xmlXPathFreeObject(val);
  5362. if (res == NULL)
  5363. return(xmlXPathNewCString(""));
  5364. return(xmlXPathWrapString(res));
  5365. }
  5366. /**
  5367. * xmlXPathCastBooleanToNumber:
  5368. * @val: a boolean
  5369. *
  5370. * Converts a boolean to its number value
  5371. *
  5372. * Returns the number value
  5373. */
  5374. double
  5375. xmlXPathCastBooleanToNumber(int val) {
  5376. if (val)
  5377. return(1.0);
  5378. return(0.0);
  5379. }
  5380. /**
  5381. * xmlXPathCastStringToNumber:
  5382. * @val: a string
  5383. *
  5384. * Converts a string to its number value
  5385. *
  5386. * Returns the number value
  5387. */
  5388. double
  5389. xmlXPathCastStringToNumber(const xmlChar * val) {
  5390. return(xmlXPathStringEvalNumber(val));
  5391. }
  5392. /**
  5393. * xmlXPathCastNodeToNumber:
  5394. * @node: a node
  5395. *
  5396. * Converts a node to its number value
  5397. *
  5398. * Returns the number value
  5399. */
  5400. double
  5401. xmlXPathCastNodeToNumber (xmlNodePtr node) {
  5402. xmlChar *strval;
  5403. double ret;
  5404. if (node == NULL)
  5405. return(xmlXPathNAN);
  5406. strval = xmlXPathCastNodeToString(node);
  5407. if (strval == NULL)
  5408. return(xmlXPathNAN);
  5409. ret = xmlXPathCastStringToNumber(strval);
  5410. xmlFree(strval);
  5411. return(ret);
  5412. }
  5413. /**
  5414. * xmlXPathCastNodeSetToNumber:
  5415. * @ns: a node-set
  5416. *
  5417. * Converts a node-set to its number value
  5418. *
  5419. * Returns the number value
  5420. */
  5421. double
  5422. xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
  5423. xmlChar *str;
  5424. double ret;
  5425. if (ns == NULL)
  5426. return(xmlXPathNAN);
  5427. str = xmlXPathCastNodeSetToString(ns);
  5428. ret = xmlXPathCastStringToNumber(str);
  5429. xmlFree(str);
  5430. return(ret);
  5431. }
  5432. /**
  5433. * xmlXPathCastToNumber:
  5434. * @val: an XPath object
  5435. *
  5436. * Converts an XPath object to its number value
  5437. *
  5438. * Returns the number value
  5439. */
  5440. double
  5441. xmlXPathCastToNumber(xmlXPathObjectPtr val) {
  5442. double ret = 0.0;
  5443. if (val == NULL)
  5444. return(xmlXPathNAN);
  5445. switch (val->type) {
  5446. case XPATH_UNDEFINED:
  5447. #ifdef DEBUG_EXPR
  5448. xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
  5449. #endif
  5450. ret = xmlXPathNAN;
  5451. break;
  5452. case XPATH_NODESET:
  5453. case XPATH_XSLT_TREE:
  5454. ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
  5455. break;
  5456. case XPATH_STRING:
  5457. ret = xmlXPathCastStringToNumber(val->stringval);
  5458. break;
  5459. case XPATH_NUMBER:
  5460. ret = val->floatval;
  5461. break;
  5462. case XPATH_BOOLEAN:
  5463. ret = xmlXPathCastBooleanToNumber(val->boolval);
  5464. break;
  5465. case XPATH_USERS:
  5466. case XPATH_POINT:
  5467. case XPATH_RANGE:
  5468. case XPATH_LOCATIONSET:
  5469. TODO;
  5470. ret = xmlXPathNAN;
  5471. break;
  5472. }
  5473. return(ret);
  5474. }
  5475. /**
  5476. * xmlXPathConvertNumber:
  5477. * @val: an XPath object
  5478. *
  5479. * Converts an existing object to its number() equivalent
  5480. *
  5481. * Returns the new object, the old one is freed (or the operation
  5482. * is done directly on @val)
  5483. */
  5484. xmlXPathObjectPtr
  5485. xmlXPathConvertNumber(xmlXPathObjectPtr val) {
  5486. xmlXPathObjectPtr ret;
  5487. if (val == NULL)
  5488. return(xmlXPathNewFloat(0.0));
  5489. if (val->type == XPATH_NUMBER)
  5490. return(val);
  5491. ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
  5492. xmlXPathFreeObject(val);
  5493. return(ret);
  5494. }
  5495. /**
  5496. * xmlXPathCastNumberToBoolean:
  5497. * @val: a number
  5498. *
  5499. * Converts a number to its boolean value
  5500. *
  5501. * Returns the boolean value
  5502. */
  5503. int
  5504. xmlXPathCastNumberToBoolean (double val) {
  5505. if (xmlXPathIsNaN(val) || (val == 0.0))
  5506. return(0);
  5507. return(1);
  5508. }
  5509. /**
  5510. * xmlXPathCastStringToBoolean:
  5511. * @val: a string
  5512. *
  5513. * Converts a string to its boolean value
  5514. *
  5515. * Returns the boolean value
  5516. */
  5517. int
  5518. xmlXPathCastStringToBoolean (const xmlChar *val) {
  5519. if ((val == NULL) || (xmlStrlen(val) == 0))
  5520. return(0);
  5521. return(1);
  5522. }
  5523. /**
  5524. * xmlXPathCastNodeSetToBoolean:
  5525. * @ns: a node-set
  5526. *
  5527. * Converts a node-set to its boolean value
  5528. *
  5529. * Returns the boolean value
  5530. */
  5531. int
  5532. xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
  5533. if ((ns == NULL) || (ns->nodeNr == 0))
  5534. return(0);
  5535. return(1);
  5536. }
  5537. /**
  5538. * xmlXPathCastToBoolean:
  5539. * @val: an XPath object
  5540. *
  5541. * Converts an XPath object to its boolean value
  5542. *
  5543. * Returns the boolean value
  5544. */
  5545. int
  5546. xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
  5547. int ret = 0;
  5548. if (val == NULL)
  5549. return(0);
  5550. switch (val->type) {
  5551. case XPATH_UNDEFINED:
  5552. #ifdef DEBUG_EXPR
  5553. xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
  5554. #endif
  5555. ret = 0;
  5556. break;
  5557. case XPATH_NODESET:
  5558. case XPATH_XSLT_TREE:
  5559. ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
  5560. break;
  5561. case XPATH_STRING:
  5562. ret = xmlXPathCastStringToBoolean(val->stringval);
  5563. break;
  5564. case XPATH_NUMBER:
  5565. ret = xmlXPathCastNumberToBoolean(val->floatval);
  5566. break;
  5567. case XPATH_BOOLEAN:
  5568. ret = val->boolval;
  5569. break;
  5570. case XPATH_USERS:
  5571. case XPATH_POINT:
  5572. case XPATH_RANGE:
  5573. case XPATH_LOCATIONSET:
  5574. TODO;
  5575. ret = 0;
  5576. break;
  5577. }
  5578. return(ret);
  5579. }
  5580. /**
  5581. * xmlXPathConvertBoolean:
  5582. * @val: an XPath object
  5583. *
  5584. * Converts an existing object to its boolean() equivalent
  5585. *
  5586. * Returns the new object, the old one is freed (or the operation
  5587. * is done directly on @val)
  5588. */
  5589. xmlXPathObjectPtr
  5590. xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
  5591. xmlXPathObjectPtr ret;
  5592. if (val == NULL)
  5593. return(xmlXPathNewBoolean(0));
  5594. if (val->type == XPATH_BOOLEAN)
  5595. return(val);
  5596. ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
  5597. xmlXPathFreeObject(val);
  5598. return(ret);
  5599. }
  5600. /************************************************************************
  5601. * *
  5602. * Routines to handle XPath contexts *
  5603. * *
  5604. ************************************************************************/
  5605. /**
  5606. * xmlXPathNewContext:
  5607. * @doc: the XML document
  5608. *
  5609. * Create a new xmlXPathContext
  5610. *
  5611. * Returns the xmlXPathContext just allocated. The caller will need to free it.
  5612. */
  5613. xmlXPathContextPtr
  5614. xmlXPathNewContext(xmlDocPtr doc) {
  5615. xmlXPathContextPtr ret;
  5616. ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
  5617. if (ret == NULL) {
  5618. xmlXPathErrMemory(NULL, "creating context\n");
  5619. return(NULL);
  5620. }
  5621. memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
  5622. ret->doc = doc;
  5623. ret->node = NULL;
  5624. ret->varHash = NULL;
  5625. ret->nb_types = 0;
  5626. ret->max_types = 0;
  5627. ret->types = NULL;
  5628. ret->funcHash = xmlHashCreate(0);
  5629. ret->nb_axis = 0;
  5630. ret->max_axis = 0;
  5631. ret->axis = NULL;
  5632. ret->nsHash = NULL;
  5633. ret->user = NULL;
  5634. ret->contextSize = -1;
  5635. ret->proximityPosition = -1;
  5636. #ifdef XP_DEFAULT_CACHE_ON
  5637. if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
  5638. xmlXPathFreeContext(ret);
  5639. return(NULL);
  5640. }
  5641. #endif
  5642. xmlXPathRegisterAllFunctions(ret);
  5643. return(ret);
  5644. }
  5645. /**
  5646. * xmlXPathFreeContext:
  5647. * @ctxt: the context to free
  5648. *
  5649. * Free up an xmlXPathContext
  5650. */
  5651. void
  5652. xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
  5653. if (ctxt == NULL) return;
  5654. if (ctxt->cache != NULL)
  5655. xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
  5656. xmlXPathRegisteredNsCleanup(ctxt);
  5657. xmlXPathRegisteredFuncsCleanup(ctxt);
  5658. xmlXPathRegisteredVariablesCleanup(ctxt);
  5659. xmlResetError(&ctxt->lastError);
  5660. xmlFree(ctxt);
  5661. }
  5662. /************************************************************************
  5663. * *
  5664. * Routines to handle XPath parser contexts *
  5665. * *
  5666. ************************************************************************/
  5667. #define CHECK_CTXT(ctxt) \
  5668. if (ctxt == NULL) { \
  5669. __xmlRaiseError(NULL, NULL, NULL, \
  5670. NULL, NULL, XML_FROM_XPATH, \
  5671. XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
  5672. __FILE__, __LINE__, \
  5673. NULL, NULL, NULL, 0, 0, \
  5674. "NULL context pointer\n"); \
  5675. return(NULL); \
  5676. } \
  5677. #define CHECK_CTXT_NEG(ctxt) \
  5678. if (ctxt == NULL) { \
  5679. __xmlRaiseError(NULL, NULL, NULL, \
  5680. NULL, NULL, XML_FROM_XPATH, \
  5681. XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
  5682. __FILE__, __LINE__, \
  5683. NULL, NULL, NULL, 0, 0, \
  5684. "NULL context pointer\n"); \
  5685. return(-1); \
  5686. } \
  5687. #define CHECK_CONTEXT(ctxt) \
  5688. if ((ctxt == NULL) || (ctxt->doc == NULL) || \
  5689. (ctxt->doc->children == NULL)) { \
  5690. xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
  5691. return(NULL); \
  5692. }
  5693. /**
  5694. * xmlXPathNewParserContext:
  5695. * @str: the XPath expression
  5696. * @ctxt: the XPath context
  5697. *
  5698. * Create a new xmlXPathParserContext
  5699. *
  5700. * Returns the xmlXPathParserContext just allocated.
  5701. */
  5702. xmlXPathParserContextPtr
  5703. xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
  5704. xmlXPathParserContextPtr ret;
  5705. ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
  5706. if (ret == NULL) {
  5707. xmlXPathErrMemory(ctxt, "creating parser context\n");
  5708. return(NULL);
  5709. }
  5710. memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
  5711. ret->cur = ret->base = str;
  5712. ret->context = ctxt;
  5713. ret->comp = xmlXPathNewCompExpr();
  5714. if (ret->comp == NULL) {
  5715. xmlFree(ret->valueTab);
  5716. xmlFree(ret);
  5717. return(NULL);
  5718. }
  5719. if ((ctxt != NULL) && (ctxt->dict != NULL)) {
  5720. ret->comp->dict = ctxt->dict;
  5721. xmlDictReference(ret->comp->dict);
  5722. }
  5723. return(ret);
  5724. }
  5725. /**
  5726. * xmlXPathCompParserContext:
  5727. * @comp: the XPath compiled expression
  5728. * @ctxt: the XPath context
  5729. *
  5730. * Create a new xmlXPathParserContext when processing a compiled expression
  5731. *
  5732. * Returns the xmlXPathParserContext just allocated.
  5733. */
  5734. static xmlXPathParserContextPtr
  5735. xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
  5736. xmlXPathParserContextPtr ret;
  5737. ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
  5738. if (ret == NULL) {
  5739. xmlXPathErrMemory(ctxt, "creating evaluation context\n");
  5740. return(NULL);
  5741. }
  5742. memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
  5743. /* Allocate the value stack */
  5744. ret->valueTab = (xmlXPathObjectPtr *)
  5745. xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
  5746. if (ret->valueTab == NULL) {
  5747. xmlFree(ret);
  5748. xmlXPathErrMemory(ctxt, "creating evaluation context\n");
  5749. return(NULL);
  5750. }
  5751. ret->valueNr = 0;
  5752. ret->valueMax = 10;
  5753. ret->value = NULL;
  5754. ret->valueFrame = 0;
  5755. ret->context = ctxt;
  5756. ret->comp = comp;
  5757. return(ret);
  5758. }
  5759. /**
  5760. * xmlXPathFreeParserContext:
  5761. * @ctxt: the context to free
  5762. *
  5763. * Free up an xmlXPathParserContext
  5764. */
  5765. void
  5766. xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
  5767. int i;
  5768. if (ctxt->valueTab != NULL) {
  5769. for (i = 0; i < ctxt->valueNr; i++) {
  5770. if (ctxt->context)
  5771. xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
  5772. else
  5773. xmlXPathFreeObject(ctxt->valueTab[i]);
  5774. }
  5775. xmlFree(ctxt->valueTab);
  5776. }
  5777. if (ctxt->comp != NULL) {
  5778. #ifdef XPATH_STREAMING
  5779. if (ctxt->comp->stream != NULL) {
  5780. xmlFreePatternList(ctxt->comp->stream);
  5781. ctxt->comp->stream = NULL;
  5782. }
  5783. #endif
  5784. xmlXPathFreeCompExpr(ctxt->comp);
  5785. }
  5786. xmlFree(ctxt);
  5787. }
  5788. /************************************************************************
  5789. * *
  5790. * The implicit core function library *
  5791. * *
  5792. ************************************************************************/
  5793. /**
  5794. * xmlXPathNodeValHash:
  5795. * @node: a node pointer
  5796. *
  5797. * Function computing the beginning of the string value of the node,
  5798. * used to speed up comparisons
  5799. *
  5800. * Returns an int usable as a hash
  5801. */
  5802. static unsigned int
  5803. xmlXPathNodeValHash(xmlNodePtr node) {
  5804. int len = 2;
  5805. const xmlChar * string = NULL;
  5806. xmlNodePtr tmp = NULL;
  5807. unsigned int ret = 0;
  5808. if (node == NULL)
  5809. return(0);
  5810. if (node->type == XML_DOCUMENT_NODE) {
  5811. tmp = xmlDocGetRootElement((xmlDocPtr) node);
  5812. if (tmp == NULL)
  5813. node = node->children;
  5814. else
  5815. node = tmp;
  5816. if (node == NULL)
  5817. return(0);
  5818. }
  5819. switch (node->type) {
  5820. case XML_COMMENT_NODE:
  5821. case XML_PI_NODE:
  5822. case XML_CDATA_SECTION_NODE:
  5823. case XML_TEXT_NODE:
  5824. string = node->content;
  5825. if (string == NULL)
  5826. return(0);
  5827. if (string[0] == 0)
  5828. return(0);
  5829. return(((unsigned int) string[0]) +
  5830. (((unsigned int) string[1]) << 8));
  5831. case XML_NAMESPACE_DECL:
  5832. string = ((xmlNsPtr)node)->href;
  5833. if (string == NULL)
  5834. return(0);
  5835. if (string[0] == 0)
  5836. return(0);
  5837. return(((unsigned int) string[0]) +
  5838. (((unsigned int) string[1]) << 8));
  5839. case XML_ATTRIBUTE_NODE:
  5840. tmp = ((xmlAttrPtr) node)->children;
  5841. break;
  5842. case XML_ELEMENT_NODE:
  5843. tmp = node->children;
  5844. break;
  5845. default:
  5846. return(0);
  5847. }
  5848. while (tmp != NULL) {
  5849. switch (tmp->type) {
  5850. case XML_CDATA_SECTION_NODE:
  5851. case XML_TEXT_NODE:
  5852. string = tmp->content;
  5853. break;
  5854. default:
  5855. string = NULL;
  5856. break;
  5857. }
  5858. if ((string != NULL) && (string[0] != 0)) {
  5859. if (len == 1) {
  5860. return(ret + (((unsigned int) string[0]) << 8));
  5861. }
  5862. if (string[1] == 0) {
  5863. len = 1;
  5864. ret = (unsigned int) string[0];
  5865. } else {
  5866. return(((unsigned int) string[0]) +
  5867. (((unsigned int) string[1]) << 8));
  5868. }
  5869. }
  5870. /*
  5871. * Skip to next node
  5872. */
  5873. if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
  5874. if (tmp->children->type != XML_ENTITY_DECL) {
  5875. tmp = tmp->children;
  5876. continue;
  5877. }
  5878. }
  5879. if (tmp == node)
  5880. break;
  5881. if (tmp->next != NULL) {
  5882. tmp = tmp->next;
  5883. continue;
  5884. }
  5885. do {
  5886. tmp = tmp->parent;
  5887. if (tmp == NULL)
  5888. break;
  5889. if (tmp == node) {
  5890. tmp = NULL;
  5891. break;
  5892. }
  5893. if (tmp->next != NULL) {
  5894. tmp = tmp->next;
  5895. break;
  5896. }
  5897. } while (tmp != NULL);
  5898. }
  5899. return(ret);
  5900. }
  5901. /**
  5902. * xmlXPathStringHash:
  5903. * @string: a string
  5904. *
  5905. * Function computing the beginning of the string value of the node,
  5906. * used to speed up comparisons
  5907. *
  5908. * Returns an int usable as a hash
  5909. */
  5910. static unsigned int
  5911. xmlXPathStringHash(const xmlChar * string) {
  5912. if (string == NULL)
  5913. return((unsigned int) 0);
  5914. if (string[0] == 0)
  5915. return(0);
  5916. return(((unsigned int) string[0]) +
  5917. (((unsigned int) string[1]) << 8));
  5918. }
  5919. /**
  5920. * xmlXPathCompareNodeSetFloat:
  5921. * @ctxt: the XPath Parser context
  5922. * @inf: less than (1) or greater than (0)
  5923. * @strict: is the comparison strict
  5924. * @arg: the node set
  5925. * @f: the value
  5926. *
  5927. * Implement the compare operation between a nodeset and a number
  5928. * @ns < @val (1, 1, ...
  5929. * @ns <= @val (1, 0, ...
  5930. * @ns > @val (0, 1, ...
  5931. * @ns >= @val (0, 0, ...
  5932. *
  5933. * If one object to be compared is a node-set and the other is a number,
  5934. * then the comparison will be true if and only if there is a node in the
  5935. * node-set such that the result of performing the comparison on the number
  5936. * to be compared and on the result of converting the string-value of that
  5937. * node to a number using the number function is true.
  5938. *
  5939. * Returns 0 or 1 depending on the results of the test.
  5940. */
  5941. static int
  5942. xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
  5943. xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
  5944. int i, ret = 0;
  5945. xmlNodeSetPtr ns;
  5946. xmlChar *str2;
  5947. if ((f == NULL) || (arg == NULL) ||
  5948. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
  5949. xmlXPathReleaseObject(ctxt->context, arg);
  5950. xmlXPathReleaseObject(ctxt->context, f);
  5951. return(0);
  5952. }
  5953. ns = arg->nodesetval;
  5954. if (ns != NULL) {
  5955. for (i = 0;i < ns->nodeNr;i++) {
  5956. str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
  5957. if (str2 != NULL) {
  5958. valuePush(ctxt,
  5959. xmlXPathCacheNewString(ctxt->context, str2));
  5960. xmlFree(str2);
  5961. xmlXPathNumberFunction(ctxt, 1);
  5962. valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
  5963. ret = xmlXPathCompareValues(ctxt, inf, strict);
  5964. if (ret)
  5965. break;
  5966. }
  5967. }
  5968. }
  5969. xmlXPathReleaseObject(ctxt->context, arg);
  5970. xmlXPathReleaseObject(ctxt->context, f);
  5971. return(ret);
  5972. }
  5973. /**
  5974. * xmlXPathCompareNodeSetString:
  5975. * @ctxt: the XPath Parser context
  5976. * @inf: less than (1) or greater than (0)
  5977. * @strict: is the comparison strict
  5978. * @arg: the node set
  5979. * @s: the value
  5980. *
  5981. * Implement the compare operation between a nodeset and a string
  5982. * @ns < @val (1, 1, ...
  5983. * @ns <= @val (1, 0, ...
  5984. * @ns > @val (0, 1, ...
  5985. * @ns >= @val (0, 0, ...
  5986. *
  5987. * If one object to be compared is a node-set and the other is a string,
  5988. * then the comparison will be true if and only if there is a node in
  5989. * the node-set such that the result of performing the comparison on the
  5990. * string-value of the node and the other string is true.
  5991. *
  5992. * Returns 0 or 1 depending on the results of the test.
  5993. */
  5994. static int
  5995. xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
  5996. xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
  5997. int i, ret = 0;
  5998. xmlNodeSetPtr ns;
  5999. xmlChar *str2;
  6000. if ((s == NULL) || (arg == NULL) ||
  6001. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
  6002. xmlXPathReleaseObject(ctxt->context, arg);
  6003. xmlXPathReleaseObject(ctxt->context, s);
  6004. return(0);
  6005. }
  6006. ns = arg->nodesetval;
  6007. if (ns != NULL) {
  6008. for (i = 0;i < ns->nodeNr;i++) {
  6009. str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
  6010. if (str2 != NULL) {
  6011. valuePush(ctxt,
  6012. xmlXPathCacheNewString(ctxt->context, str2));
  6013. xmlFree(str2);
  6014. valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
  6015. ret = xmlXPathCompareValues(ctxt, inf, strict);
  6016. if (ret)
  6017. break;
  6018. }
  6019. }
  6020. }
  6021. xmlXPathReleaseObject(ctxt->context, arg);
  6022. xmlXPathReleaseObject(ctxt->context, s);
  6023. return(ret);
  6024. }
  6025. /**
  6026. * xmlXPathCompareNodeSets:
  6027. * @inf: less than (1) or greater than (0)
  6028. * @strict: is the comparison strict
  6029. * @arg1: the first node set object
  6030. * @arg2: the second node set object
  6031. *
  6032. * Implement the compare operation on nodesets:
  6033. *
  6034. * If both objects to be compared are node-sets, then the comparison
  6035. * will be true if and only if there is a node in the first node-set
  6036. * and a node in the second node-set such that the result of performing
  6037. * the comparison on the string-values of the two nodes is true.
  6038. * ....
  6039. * When neither object to be compared is a node-set and the operator
  6040. * is <=, <, >= or >, then the objects are compared by converting both
  6041. * objects to numbers and comparing the numbers according to IEEE 754.
  6042. * ....
  6043. * The number function converts its argument to a number as follows:
  6044. * - a string that consists of optional whitespace followed by an
  6045. * optional minus sign followed by a Number followed by whitespace
  6046. * is converted to the IEEE 754 number that is nearest (according
  6047. * to the IEEE 754 round-to-nearest rule) to the mathematical value
  6048. * represented by the string; any other string is converted to NaN
  6049. *
  6050. * Conclusion all nodes need to be converted first to their string value
  6051. * and then the comparison must be done when possible
  6052. */
  6053. static int
  6054. xmlXPathCompareNodeSets(int inf, int strict,
  6055. xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
  6056. int i, j, init = 0;
  6057. double val1;
  6058. double *values2;
  6059. int ret = 0;
  6060. xmlNodeSetPtr ns1;
  6061. xmlNodeSetPtr ns2;
  6062. if ((arg1 == NULL) ||
  6063. ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
  6064. xmlXPathFreeObject(arg2);
  6065. return(0);
  6066. }
  6067. if ((arg2 == NULL) ||
  6068. ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
  6069. xmlXPathFreeObject(arg1);
  6070. xmlXPathFreeObject(arg2);
  6071. return(0);
  6072. }
  6073. ns1 = arg1->nodesetval;
  6074. ns2 = arg2->nodesetval;
  6075. if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
  6076. xmlXPathFreeObject(arg1);
  6077. xmlXPathFreeObject(arg2);
  6078. return(0);
  6079. }
  6080. if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
  6081. xmlXPathFreeObject(arg1);
  6082. xmlXPathFreeObject(arg2);
  6083. return(0);
  6084. }
  6085. values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
  6086. if (values2 == NULL) {
  6087. /* TODO: Propagate memory error. */
  6088. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  6089. xmlXPathFreeObject(arg1);
  6090. xmlXPathFreeObject(arg2);
  6091. return(0);
  6092. }
  6093. for (i = 0;i < ns1->nodeNr;i++) {
  6094. val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
  6095. if (xmlXPathIsNaN(val1))
  6096. continue;
  6097. for (j = 0;j < ns2->nodeNr;j++) {
  6098. if (init == 0) {
  6099. values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
  6100. }
  6101. if (xmlXPathIsNaN(values2[j]))
  6102. continue;
  6103. if (inf && strict)
  6104. ret = (val1 < values2[j]);
  6105. else if (inf && !strict)
  6106. ret = (val1 <= values2[j]);
  6107. else if (!inf && strict)
  6108. ret = (val1 > values2[j]);
  6109. else if (!inf && !strict)
  6110. ret = (val1 >= values2[j]);
  6111. if (ret)
  6112. break;
  6113. }
  6114. if (ret)
  6115. break;
  6116. init = 1;
  6117. }
  6118. xmlFree(values2);
  6119. xmlXPathFreeObject(arg1);
  6120. xmlXPathFreeObject(arg2);
  6121. return(ret);
  6122. }
  6123. /**
  6124. * xmlXPathCompareNodeSetValue:
  6125. * @ctxt: the XPath Parser context
  6126. * @inf: less than (1) or greater than (0)
  6127. * @strict: is the comparison strict
  6128. * @arg: the node set
  6129. * @val: the value
  6130. *
  6131. * Implement the compare operation between a nodeset and a value
  6132. * @ns < @val (1, 1, ...
  6133. * @ns <= @val (1, 0, ...
  6134. * @ns > @val (0, 1, ...
  6135. * @ns >= @val (0, 0, ...
  6136. *
  6137. * If one object to be compared is a node-set and the other is a boolean,
  6138. * then the comparison will be true if and only if the result of performing
  6139. * the comparison on the boolean and on the result of converting
  6140. * the node-set to a boolean using the boolean function is true.
  6141. *
  6142. * Returns 0 or 1 depending on the results of the test.
  6143. */
  6144. static int
  6145. xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
  6146. xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
  6147. if ((val == NULL) || (arg == NULL) ||
  6148. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
  6149. return(0);
  6150. switch(val->type) {
  6151. case XPATH_NUMBER:
  6152. return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
  6153. case XPATH_NODESET:
  6154. case XPATH_XSLT_TREE:
  6155. return(xmlXPathCompareNodeSets(inf, strict, arg, val));
  6156. case XPATH_STRING:
  6157. return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
  6158. case XPATH_BOOLEAN:
  6159. valuePush(ctxt, arg);
  6160. xmlXPathBooleanFunction(ctxt, 1);
  6161. valuePush(ctxt, val);
  6162. return(xmlXPathCompareValues(ctxt, inf, strict));
  6163. default:
  6164. xmlGenericError(xmlGenericErrorContext,
  6165. "xmlXPathCompareNodeSetValue: Can't compare node set "
  6166. "and object of type %d\n",
  6167. val->type);
  6168. xmlXPathReleaseObject(ctxt->context, arg);
  6169. xmlXPathReleaseObject(ctxt->context, val);
  6170. XP_ERROR0(XPATH_INVALID_TYPE);
  6171. }
  6172. return(0);
  6173. }
  6174. /**
  6175. * xmlXPathEqualNodeSetString:
  6176. * @arg: the nodeset object argument
  6177. * @str: the string to compare to.
  6178. * @neq: flag to show whether for '=' (0) or '!=' (1)
  6179. *
  6180. * Implement the equal operation on XPath objects content: @arg1 == @arg2
  6181. * If one object to be compared is a node-set and the other is a string,
  6182. * then the comparison will be true if and only if there is a node in
  6183. * the node-set such that the result of performing the comparison on the
  6184. * string-value of the node and the other string is true.
  6185. *
  6186. * Returns 0 or 1 depending on the results of the test.
  6187. */
  6188. static int
  6189. xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
  6190. {
  6191. int i;
  6192. xmlNodeSetPtr ns;
  6193. xmlChar *str2;
  6194. unsigned int hash;
  6195. if ((str == NULL) || (arg == NULL) ||
  6196. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
  6197. return (0);
  6198. ns = arg->nodesetval;
  6199. /*
  6200. * A NULL nodeset compared with a string is always false
  6201. * (since there is no node equal, and no node not equal)
  6202. */
  6203. if ((ns == NULL) || (ns->nodeNr <= 0) )
  6204. return (0);
  6205. hash = xmlXPathStringHash(str);
  6206. for (i = 0; i < ns->nodeNr; i++) {
  6207. if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
  6208. str2 = xmlNodeGetContent(ns->nodeTab[i]);
  6209. if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
  6210. xmlFree(str2);
  6211. if (neq)
  6212. continue;
  6213. return (1);
  6214. } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
  6215. if (neq)
  6216. continue;
  6217. return (1);
  6218. } else if (neq) {
  6219. if (str2 != NULL)
  6220. xmlFree(str2);
  6221. return (1);
  6222. }
  6223. if (str2 != NULL)
  6224. xmlFree(str2);
  6225. } else if (neq)
  6226. return (1);
  6227. }
  6228. return (0);
  6229. }
  6230. /**
  6231. * xmlXPathEqualNodeSetFloat:
  6232. * @arg: the nodeset object argument
  6233. * @f: the float to compare to
  6234. * @neq: flag to show whether to compare '=' (0) or '!=' (1)
  6235. *
  6236. * Implement the equal operation on XPath objects content: @arg1 == @arg2
  6237. * If one object to be compared is a node-set and the other is a number,
  6238. * then the comparison will be true if and only if there is a node in
  6239. * the node-set such that the result of performing the comparison on the
  6240. * number to be compared and on the result of converting the string-value
  6241. * of that node to a number using the number function is true.
  6242. *
  6243. * Returns 0 or 1 depending on the results of the test.
  6244. */
  6245. static int
  6246. xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
  6247. xmlXPathObjectPtr arg, double f, int neq) {
  6248. int i, ret=0;
  6249. xmlNodeSetPtr ns;
  6250. xmlChar *str2;
  6251. xmlXPathObjectPtr val;
  6252. double v;
  6253. if ((arg == NULL) ||
  6254. ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
  6255. return(0);
  6256. ns = arg->nodesetval;
  6257. if (ns != NULL) {
  6258. for (i=0;i<ns->nodeNr;i++) {
  6259. str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
  6260. if (str2 != NULL) {
  6261. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
  6262. xmlFree(str2);
  6263. xmlXPathNumberFunction(ctxt, 1);
  6264. val = valuePop(ctxt);
  6265. v = val->floatval;
  6266. xmlXPathReleaseObject(ctxt->context, val);
  6267. if (!xmlXPathIsNaN(v)) {
  6268. if ((!neq) && (v==f)) {
  6269. ret = 1;
  6270. break;
  6271. } else if ((neq) && (v!=f)) {
  6272. ret = 1;
  6273. break;
  6274. }
  6275. } else { /* NaN is unequal to any value */
  6276. if (neq)
  6277. ret = 1;
  6278. }
  6279. }
  6280. }
  6281. }
  6282. return(ret);
  6283. }
  6284. /**
  6285. * xmlXPathEqualNodeSets:
  6286. * @arg1: first nodeset object argument
  6287. * @arg2: second nodeset object argument
  6288. * @neq: flag to show whether to test '=' (0) or '!=' (1)
  6289. *
  6290. * Implement the equal / not equal operation on XPath nodesets:
  6291. * @arg1 == @arg2 or @arg1 != @arg2
  6292. * If both objects to be compared are node-sets, then the comparison
  6293. * will be true if and only if there is a node in the first node-set and
  6294. * a node in the second node-set such that the result of performing the
  6295. * comparison on the string-values of the two nodes is true.
  6296. *
  6297. * (needless to say, this is a costly operation)
  6298. *
  6299. * Returns 0 or 1 depending on the results of the test.
  6300. */
  6301. static int
  6302. xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
  6303. int i, j;
  6304. unsigned int *hashs1;
  6305. unsigned int *hashs2;
  6306. xmlChar **values1;
  6307. xmlChar **values2;
  6308. int ret = 0;
  6309. xmlNodeSetPtr ns1;
  6310. xmlNodeSetPtr ns2;
  6311. if ((arg1 == NULL) ||
  6312. ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
  6313. return(0);
  6314. if ((arg2 == NULL) ||
  6315. ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
  6316. return(0);
  6317. ns1 = arg1->nodesetval;
  6318. ns2 = arg2->nodesetval;
  6319. if ((ns1 == NULL) || (ns1->nodeNr <= 0))
  6320. return(0);
  6321. if ((ns2 == NULL) || (ns2->nodeNr <= 0))
  6322. return(0);
  6323. /*
  6324. * for equal, check if there is a node pertaining to both sets
  6325. */
  6326. if (neq == 0)
  6327. for (i = 0;i < ns1->nodeNr;i++)
  6328. for (j = 0;j < ns2->nodeNr;j++)
  6329. if (ns1->nodeTab[i] == ns2->nodeTab[j])
  6330. return(1);
  6331. values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
  6332. if (values1 == NULL) {
  6333. /* TODO: Propagate memory error. */
  6334. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  6335. return(0);
  6336. }
  6337. hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
  6338. if (hashs1 == NULL) {
  6339. /* TODO: Propagate memory error. */
  6340. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  6341. xmlFree(values1);
  6342. return(0);
  6343. }
  6344. memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
  6345. values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
  6346. if (values2 == NULL) {
  6347. /* TODO: Propagate memory error. */
  6348. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  6349. xmlFree(hashs1);
  6350. xmlFree(values1);
  6351. return(0);
  6352. }
  6353. hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
  6354. if (hashs2 == NULL) {
  6355. /* TODO: Propagate memory error. */
  6356. xmlXPathErrMemory(NULL, "comparing nodesets\n");
  6357. xmlFree(hashs1);
  6358. xmlFree(values1);
  6359. xmlFree(values2);
  6360. return(0);
  6361. }
  6362. memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
  6363. for (i = 0;i < ns1->nodeNr;i++) {
  6364. hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
  6365. for (j = 0;j < ns2->nodeNr;j++) {
  6366. if (i == 0)
  6367. hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
  6368. if (hashs1[i] != hashs2[j]) {
  6369. if (neq) {
  6370. ret = 1;
  6371. break;
  6372. }
  6373. }
  6374. else {
  6375. if (values1[i] == NULL)
  6376. values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
  6377. if (values2[j] == NULL)
  6378. values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
  6379. ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
  6380. if (ret)
  6381. break;
  6382. }
  6383. }
  6384. if (ret)
  6385. break;
  6386. }
  6387. for (i = 0;i < ns1->nodeNr;i++)
  6388. if (values1[i] != NULL)
  6389. xmlFree(values1[i]);
  6390. for (j = 0;j < ns2->nodeNr;j++)
  6391. if (values2[j] != NULL)
  6392. xmlFree(values2[j]);
  6393. xmlFree(values1);
  6394. xmlFree(values2);
  6395. xmlFree(hashs1);
  6396. xmlFree(hashs2);
  6397. return(ret);
  6398. }
  6399. static int
  6400. xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
  6401. xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
  6402. int ret = 0;
  6403. /*
  6404. *At this point we are assured neither arg1 nor arg2
  6405. *is a nodeset, so we can just pick the appropriate routine.
  6406. */
  6407. switch (arg1->type) {
  6408. case XPATH_UNDEFINED:
  6409. #ifdef DEBUG_EXPR
  6410. xmlGenericError(xmlGenericErrorContext,
  6411. "Equal: undefined\n");
  6412. #endif
  6413. break;
  6414. case XPATH_BOOLEAN:
  6415. switch (arg2->type) {
  6416. case XPATH_UNDEFINED:
  6417. #ifdef DEBUG_EXPR
  6418. xmlGenericError(xmlGenericErrorContext,
  6419. "Equal: undefined\n");
  6420. #endif
  6421. break;
  6422. case XPATH_BOOLEAN:
  6423. #ifdef DEBUG_EXPR
  6424. xmlGenericError(xmlGenericErrorContext,
  6425. "Equal: %d boolean %d \n",
  6426. arg1->boolval, arg2->boolval);
  6427. #endif
  6428. ret = (arg1->boolval == arg2->boolval);
  6429. break;
  6430. case XPATH_NUMBER:
  6431. ret = (arg1->boolval ==
  6432. xmlXPathCastNumberToBoolean(arg2->floatval));
  6433. break;
  6434. case XPATH_STRING:
  6435. if ((arg2->stringval == NULL) ||
  6436. (arg2->stringval[0] == 0)) ret = 0;
  6437. else
  6438. ret = 1;
  6439. ret = (arg1->boolval == ret);
  6440. break;
  6441. case XPATH_USERS:
  6442. case XPATH_POINT:
  6443. case XPATH_RANGE:
  6444. case XPATH_LOCATIONSET:
  6445. TODO
  6446. break;
  6447. case XPATH_NODESET:
  6448. case XPATH_XSLT_TREE:
  6449. break;
  6450. }
  6451. break;
  6452. case XPATH_NUMBER:
  6453. switch (arg2->type) {
  6454. case XPATH_UNDEFINED:
  6455. #ifdef DEBUG_EXPR
  6456. xmlGenericError(xmlGenericErrorContext,
  6457. "Equal: undefined\n");
  6458. #endif
  6459. break;
  6460. case XPATH_BOOLEAN:
  6461. ret = (arg2->boolval==
  6462. xmlXPathCastNumberToBoolean(arg1->floatval));
  6463. break;
  6464. case XPATH_STRING:
  6465. valuePush(ctxt, arg2);
  6466. xmlXPathNumberFunction(ctxt, 1);
  6467. arg2 = valuePop(ctxt);
  6468. /* Falls through. */
  6469. case XPATH_NUMBER:
  6470. /* Hand check NaN and Infinity equalities */
  6471. if (xmlXPathIsNaN(arg1->floatval) ||
  6472. xmlXPathIsNaN(arg2->floatval)) {
  6473. ret = 0;
  6474. } else if (xmlXPathIsInf(arg1->floatval) == 1) {
  6475. if (xmlXPathIsInf(arg2->floatval) == 1)
  6476. ret = 1;
  6477. else
  6478. ret = 0;
  6479. } else if (xmlXPathIsInf(arg1->floatval) == -1) {
  6480. if (xmlXPathIsInf(arg2->floatval) == -1)
  6481. ret = 1;
  6482. else
  6483. ret = 0;
  6484. } else if (xmlXPathIsInf(arg2->floatval) == 1) {
  6485. if (xmlXPathIsInf(arg1->floatval) == 1)
  6486. ret = 1;
  6487. else
  6488. ret = 0;
  6489. } else if (xmlXPathIsInf(arg2->floatval) == -1) {
  6490. if (xmlXPathIsInf(arg1->floatval) == -1)
  6491. ret = 1;
  6492. else
  6493. ret = 0;
  6494. } else {
  6495. ret = (arg1->floatval == arg2->floatval);
  6496. }
  6497. break;
  6498. case XPATH_USERS:
  6499. case XPATH_POINT:
  6500. case XPATH_RANGE:
  6501. case XPATH_LOCATIONSET:
  6502. TODO
  6503. break;
  6504. case XPATH_NODESET:
  6505. case XPATH_XSLT_TREE:
  6506. break;
  6507. }
  6508. break;
  6509. case XPATH_STRING:
  6510. switch (arg2->type) {
  6511. case XPATH_UNDEFINED:
  6512. #ifdef DEBUG_EXPR
  6513. xmlGenericError(xmlGenericErrorContext,
  6514. "Equal: undefined\n");
  6515. #endif
  6516. break;
  6517. case XPATH_BOOLEAN:
  6518. if ((arg1->stringval == NULL) ||
  6519. (arg1->stringval[0] == 0)) ret = 0;
  6520. else
  6521. ret = 1;
  6522. ret = (arg2->boolval == ret);
  6523. break;
  6524. case XPATH_STRING:
  6525. ret = xmlStrEqual(arg1->stringval, arg2->stringval);
  6526. break;
  6527. case XPATH_NUMBER:
  6528. valuePush(ctxt, arg1);
  6529. xmlXPathNumberFunction(ctxt, 1);
  6530. arg1 = valuePop(ctxt);
  6531. /* Hand check NaN and Infinity equalities */
  6532. if (xmlXPathIsNaN(arg1->floatval) ||
  6533. xmlXPathIsNaN(arg2->floatval)) {
  6534. ret = 0;
  6535. } else if (xmlXPathIsInf(arg1->floatval) == 1) {
  6536. if (xmlXPathIsInf(arg2->floatval) == 1)
  6537. ret = 1;
  6538. else
  6539. ret = 0;
  6540. } else if (xmlXPathIsInf(arg1->floatval) == -1) {
  6541. if (xmlXPathIsInf(arg2->floatval) == -1)
  6542. ret = 1;
  6543. else
  6544. ret = 0;
  6545. } else if (xmlXPathIsInf(arg2->floatval) == 1) {
  6546. if (xmlXPathIsInf(arg1->floatval) == 1)
  6547. ret = 1;
  6548. else
  6549. ret = 0;
  6550. } else if (xmlXPathIsInf(arg2->floatval) == -1) {
  6551. if (xmlXPathIsInf(arg1->floatval) == -1)
  6552. ret = 1;
  6553. else
  6554. ret = 0;
  6555. } else {
  6556. ret = (arg1->floatval == arg2->floatval);
  6557. }
  6558. break;
  6559. case XPATH_USERS:
  6560. case XPATH_POINT:
  6561. case XPATH_RANGE:
  6562. case XPATH_LOCATIONSET:
  6563. TODO
  6564. break;
  6565. case XPATH_NODESET:
  6566. case XPATH_XSLT_TREE:
  6567. break;
  6568. }
  6569. break;
  6570. case XPATH_USERS:
  6571. case XPATH_POINT:
  6572. case XPATH_RANGE:
  6573. case XPATH_LOCATIONSET:
  6574. TODO
  6575. break;
  6576. case XPATH_NODESET:
  6577. case XPATH_XSLT_TREE:
  6578. break;
  6579. }
  6580. xmlXPathReleaseObject(ctxt->context, arg1);
  6581. xmlXPathReleaseObject(ctxt->context, arg2);
  6582. return(ret);
  6583. }
  6584. /**
  6585. * xmlXPathEqualValues:
  6586. * @ctxt: the XPath Parser context
  6587. *
  6588. * Implement the equal operation on XPath objects content: @arg1 == @arg2
  6589. *
  6590. * Returns 0 or 1 depending on the results of the test.
  6591. */
  6592. int
  6593. xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
  6594. xmlXPathObjectPtr arg1, arg2, argtmp;
  6595. int ret = 0;
  6596. if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
  6597. arg2 = valuePop(ctxt);
  6598. arg1 = valuePop(ctxt);
  6599. if ((arg1 == NULL) || (arg2 == NULL)) {
  6600. if (arg1 != NULL)
  6601. xmlXPathReleaseObject(ctxt->context, arg1);
  6602. else
  6603. xmlXPathReleaseObject(ctxt->context, arg2);
  6604. XP_ERROR0(XPATH_INVALID_OPERAND);
  6605. }
  6606. if (arg1 == arg2) {
  6607. #ifdef DEBUG_EXPR
  6608. xmlGenericError(xmlGenericErrorContext,
  6609. "Equal: by pointer\n");
  6610. #endif
  6611. xmlXPathFreeObject(arg1);
  6612. return(1);
  6613. }
  6614. /*
  6615. *If either argument is a nodeset, it's a 'special case'
  6616. */
  6617. if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
  6618. (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
  6619. /*
  6620. *Hack it to assure arg1 is the nodeset
  6621. */
  6622. if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
  6623. argtmp = arg2;
  6624. arg2 = arg1;
  6625. arg1 = argtmp;
  6626. }
  6627. switch (arg2->type) {
  6628. case XPATH_UNDEFINED:
  6629. #ifdef DEBUG_EXPR
  6630. xmlGenericError(xmlGenericErrorContext,
  6631. "Equal: undefined\n");
  6632. #endif
  6633. break;
  6634. case XPATH_NODESET:
  6635. case XPATH_XSLT_TREE:
  6636. ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
  6637. break;
  6638. case XPATH_BOOLEAN:
  6639. if ((arg1->nodesetval == NULL) ||
  6640. (arg1->nodesetval->nodeNr == 0)) ret = 0;
  6641. else
  6642. ret = 1;
  6643. ret = (ret == arg2->boolval);
  6644. break;
  6645. case XPATH_NUMBER:
  6646. ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
  6647. break;
  6648. case XPATH_STRING:
  6649. ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
  6650. break;
  6651. case XPATH_USERS:
  6652. case XPATH_POINT:
  6653. case XPATH_RANGE:
  6654. case XPATH_LOCATIONSET:
  6655. TODO
  6656. break;
  6657. }
  6658. xmlXPathReleaseObject(ctxt->context, arg1);
  6659. xmlXPathReleaseObject(ctxt->context, arg2);
  6660. return(ret);
  6661. }
  6662. return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
  6663. }
  6664. /**
  6665. * xmlXPathNotEqualValues:
  6666. * @ctxt: the XPath Parser context
  6667. *
  6668. * Implement the equal operation on XPath objects content: @arg1 == @arg2
  6669. *
  6670. * Returns 0 or 1 depending on the results of the test.
  6671. */
  6672. int
  6673. xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
  6674. xmlXPathObjectPtr arg1, arg2, argtmp;
  6675. int ret = 0;
  6676. if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
  6677. arg2 = valuePop(ctxt);
  6678. arg1 = valuePop(ctxt);
  6679. if ((arg1 == NULL) || (arg2 == NULL)) {
  6680. if (arg1 != NULL)
  6681. xmlXPathReleaseObject(ctxt->context, arg1);
  6682. else
  6683. xmlXPathReleaseObject(ctxt->context, arg2);
  6684. XP_ERROR0(XPATH_INVALID_OPERAND);
  6685. }
  6686. if (arg1 == arg2) {
  6687. #ifdef DEBUG_EXPR
  6688. xmlGenericError(xmlGenericErrorContext,
  6689. "NotEqual: by pointer\n");
  6690. #endif
  6691. xmlXPathReleaseObject(ctxt->context, arg1);
  6692. return(0);
  6693. }
  6694. /*
  6695. *If either argument is a nodeset, it's a 'special case'
  6696. */
  6697. if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
  6698. (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
  6699. /*
  6700. *Hack it to assure arg1 is the nodeset
  6701. */
  6702. if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
  6703. argtmp = arg2;
  6704. arg2 = arg1;
  6705. arg1 = argtmp;
  6706. }
  6707. switch (arg2->type) {
  6708. case XPATH_UNDEFINED:
  6709. #ifdef DEBUG_EXPR
  6710. xmlGenericError(xmlGenericErrorContext,
  6711. "NotEqual: undefined\n");
  6712. #endif
  6713. break;
  6714. case XPATH_NODESET:
  6715. case XPATH_XSLT_TREE:
  6716. ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
  6717. break;
  6718. case XPATH_BOOLEAN:
  6719. if ((arg1->nodesetval == NULL) ||
  6720. (arg1->nodesetval->nodeNr == 0)) ret = 0;
  6721. else
  6722. ret = 1;
  6723. ret = (ret != arg2->boolval);
  6724. break;
  6725. case XPATH_NUMBER:
  6726. ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
  6727. break;
  6728. case XPATH_STRING:
  6729. ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
  6730. break;
  6731. case XPATH_USERS:
  6732. case XPATH_POINT:
  6733. case XPATH_RANGE:
  6734. case XPATH_LOCATIONSET:
  6735. TODO
  6736. break;
  6737. }
  6738. xmlXPathReleaseObject(ctxt->context, arg1);
  6739. xmlXPathReleaseObject(ctxt->context, arg2);
  6740. return(ret);
  6741. }
  6742. return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
  6743. }
  6744. /**
  6745. * xmlXPathCompareValues:
  6746. * @ctxt: the XPath Parser context
  6747. * @inf: less than (1) or greater than (0)
  6748. * @strict: is the comparison strict
  6749. *
  6750. * Implement the compare operation on XPath objects:
  6751. * @arg1 < @arg2 (1, 1, ...
  6752. * @arg1 <= @arg2 (1, 0, ...
  6753. * @arg1 > @arg2 (0, 1, ...
  6754. * @arg1 >= @arg2 (0, 0, ...
  6755. *
  6756. * When neither object to be compared is a node-set and the operator is
  6757. * <=, <, >=, >, then the objects are compared by converted both objects
  6758. * to numbers and comparing the numbers according to IEEE 754. The <
  6759. * comparison will be true if and only if the first number is less than the
  6760. * second number. The <= comparison will be true if and only if the first
  6761. * number is less than or equal to the second number. The > comparison
  6762. * will be true if and only if the first number is greater than the second
  6763. * number. The >= comparison will be true if and only if the first number
  6764. * is greater than or equal to the second number.
  6765. *
  6766. * Returns 1 if the comparison succeeded, 0 if it failed
  6767. */
  6768. int
  6769. xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
  6770. int ret = 0, arg1i = 0, arg2i = 0;
  6771. xmlXPathObjectPtr arg1, arg2;
  6772. if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
  6773. arg2 = valuePop(ctxt);
  6774. arg1 = valuePop(ctxt);
  6775. if ((arg1 == NULL) || (arg2 == NULL)) {
  6776. if (arg1 != NULL)
  6777. xmlXPathReleaseObject(ctxt->context, arg1);
  6778. else
  6779. xmlXPathReleaseObject(ctxt->context, arg2);
  6780. XP_ERROR0(XPATH_INVALID_OPERAND);
  6781. }
  6782. if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
  6783. (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
  6784. /*
  6785. * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
  6786. * are not freed from within this routine; they will be freed from the
  6787. * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
  6788. */
  6789. if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
  6790. ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
  6791. ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
  6792. } else {
  6793. if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
  6794. ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
  6795. arg1, arg2);
  6796. } else {
  6797. ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
  6798. arg2, arg1);
  6799. }
  6800. }
  6801. return(ret);
  6802. }
  6803. if (arg1->type != XPATH_NUMBER) {
  6804. valuePush(ctxt, arg1);
  6805. xmlXPathNumberFunction(ctxt, 1);
  6806. arg1 = valuePop(ctxt);
  6807. }
  6808. if (arg1->type != XPATH_NUMBER) {
  6809. xmlXPathFreeObject(arg1);
  6810. xmlXPathFreeObject(arg2);
  6811. XP_ERROR0(XPATH_INVALID_OPERAND);
  6812. }
  6813. if (arg2->type != XPATH_NUMBER) {
  6814. valuePush(ctxt, arg2);
  6815. xmlXPathNumberFunction(ctxt, 1);
  6816. arg2 = valuePop(ctxt);
  6817. }
  6818. if (arg2->type != XPATH_NUMBER) {
  6819. xmlXPathReleaseObject(ctxt->context, arg1);
  6820. xmlXPathReleaseObject(ctxt->context, arg2);
  6821. XP_ERROR0(XPATH_INVALID_OPERAND);
  6822. }
  6823. /*
  6824. * Add tests for infinity and nan
  6825. * => feedback on 3.4 for Inf and NaN
  6826. */
  6827. /* Hand check NaN and Infinity comparisons */
  6828. if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
  6829. ret=0;
  6830. } else {
  6831. arg1i=xmlXPathIsInf(arg1->floatval);
  6832. arg2i=xmlXPathIsInf(arg2->floatval);
  6833. if (inf && strict) {
  6834. if ((arg1i == -1 && arg2i != -1) ||
  6835. (arg2i == 1 && arg1i != 1)) {
  6836. ret = 1;
  6837. } else if (arg1i == 0 && arg2i == 0) {
  6838. ret = (arg1->floatval < arg2->floatval);
  6839. } else {
  6840. ret = 0;
  6841. }
  6842. }
  6843. else if (inf && !strict) {
  6844. if (arg1i == -1 || arg2i == 1) {
  6845. ret = 1;
  6846. } else if (arg1i == 0 && arg2i == 0) {
  6847. ret = (arg1->floatval <= arg2->floatval);
  6848. } else {
  6849. ret = 0;
  6850. }
  6851. }
  6852. else if (!inf && strict) {
  6853. if ((arg1i == 1 && arg2i != 1) ||
  6854. (arg2i == -1 && arg1i != -1)) {
  6855. ret = 1;
  6856. } else if (arg1i == 0 && arg2i == 0) {
  6857. ret = (arg1->floatval > arg2->floatval);
  6858. } else {
  6859. ret = 0;
  6860. }
  6861. }
  6862. else if (!inf && !strict) {
  6863. if (arg1i == 1 || arg2i == -1) {
  6864. ret = 1;
  6865. } else if (arg1i == 0 && arg2i == 0) {
  6866. ret = (arg1->floatval >= arg2->floatval);
  6867. } else {
  6868. ret = 0;
  6869. }
  6870. }
  6871. }
  6872. xmlXPathReleaseObject(ctxt->context, arg1);
  6873. xmlXPathReleaseObject(ctxt->context, arg2);
  6874. return(ret);
  6875. }
  6876. /**
  6877. * xmlXPathValueFlipSign:
  6878. * @ctxt: the XPath Parser context
  6879. *
  6880. * Implement the unary - operation on an XPath object
  6881. * The numeric operators convert their operands to numbers as if
  6882. * by calling the number function.
  6883. */
  6884. void
  6885. xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
  6886. if ((ctxt == NULL) || (ctxt->context == NULL)) return;
  6887. CAST_TO_NUMBER;
  6888. CHECK_TYPE(XPATH_NUMBER);
  6889. ctxt->value->floatval = -ctxt->value->floatval;
  6890. }
  6891. /**
  6892. * xmlXPathAddValues:
  6893. * @ctxt: the XPath Parser context
  6894. *
  6895. * Implement the add operation on XPath objects:
  6896. * The numeric operators convert their operands to numbers as if
  6897. * by calling the number function.
  6898. */
  6899. void
  6900. xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
  6901. xmlXPathObjectPtr arg;
  6902. double val;
  6903. arg = valuePop(ctxt);
  6904. if (arg == NULL)
  6905. XP_ERROR(XPATH_INVALID_OPERAND);
  6906. val = xmlXPathCastToNumber(arg);
  6907. xmlXPathReleaseObject(ctxt->context, arg);
  6908. CAST_TO_NUMBER;
  6909. CHECK_TYPE(XPATH_NUMBER);
  6910. ctxt->value->floatval += val;
  6911. }
  6912. /**
  6913. * xmlXPathSubValues:
  6914. * @ctxt: the XPath Parser context
  6915. *
  6916. * Implement the subtraction operation on XPath objects:
  6917. * The numeric operators convert their operands to numbers as if
  6918. * by calling the number function.
  6919. */
  6920. void
  6921. xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
  6922. xmlXPathObjectPtr arg;
  6923. double val;
  6924. arg = valuePop(ctxt);
  6925. if (arg == NULL)
  6926. XP_ERROR(XPATH_INVALID_OPERAND);
  6927. val = xmlXPathCastToNumber(arg);
  6928. xmlXPathReleaseObject(ctxt->context, arg);
  6929. CAST_TO_NUMBER;
  6930. CHECK_TYPE(XPATH_NUMBER);
  6931. ctxt->value->floatval -= val;
  6932. }
  6933. /**
  6934. * xmlXPathMultValues:
  6935. * @ctxt: the XPath Parser context
  6936. *
  6937. * Implement the multiply operation on XPath objects:
  6938. * The numeric operators convert their operands to numbers as if
  6939. * by calling the number function.
  6940. */
  6941. void
  6942. xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
  6943. xmlXPathObjectPtr arg;
  6944. double val;
  6945. arg = valuePop(ctxt);
  6946. if (arg == NULL)
  6947. XP_ERROR(XPATH_INVALID_OPERAND);
  6948. val = xmlXPathCastToNumber(arg);
  6949. xmlXPathReleaseObject(ctxt->context, arg);
  6950. CAST_TO_NUMBER;
  6951. CHECK_TYPE(XPATH_NUMBER);
  6952. ctxt->value->floatval *= val;
  6953. }
  6954. /**
  6955. * xmlXPathDivValues:
  6956. * @ctxt: the XPath Parser context
  6957. *
  6958. * Implement the div operation on XPath objects @arg1 / @arg2:
  6959. * The numeric operators convert their operands to numbers as if
  6960. * by calling the number function.
  6961. */
  6962. ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
  6963. void
  6964. xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
  6965. xmlXPathObjectPtr arg;
  6966. double val;
  6967. arg = valuePop(ctxt);
  6968. if (arg == NULL)
  6969. XP_ERROR(XPATH_INVALID_OPERAND);
  6970. val = xmlXPathCastToNumber(arg);
  6971. xmlXPathReleaseObject(ctxt->context, arg);
  6972. CAST_TO_NUMBER;
  6973. CHECK_TYPE(XPATH_NUMBER);
  6974. ctxt->value->floatval /= val;
  6975. }
  6976. /**
  6977. * xmlXPathModValues:
  6978. * @ctxt: the XPath Parser context
  6979. *
  6980. * Implement the mod operation on XPath objects: @arg1 / @arg2
  6981. * The numeric operators convert their operands to numbers as if
  6982. * by calling the number function.
  6983. */
  6984. void
  6985. xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
  6986. xmlXPathObjectPtr arg;
  6987. double arg1, arg2;
  6988. arg = valuePop(ctxt);
  6989. if (arg == NULL)
  6990. XP_ERROR(XPATH_INVALID_OPERAND);
  6991. arg2 = xmlXPathCastToNumber(arg);
  6992. xmlXPathReleaseObject(ctxt->context, arg);
  6993. CAST_TO_NUMBER;
  6994. CHECK_TYPE(XPATH_NUMBER);
  6995. arg1 = ctxt->value->floatval;
  6996. if (arg2 == 0)
  6997. ctxt->value->floatval = xmlXPathNAN;
  6998. else {
  6999. ctxt->value->floatval = fmod(arg1, arg2);
  7000. }
  7001. }
  7002. /************************************************************************
  7003. * *
  7004. * The traversal functions *
  7005. * *
  7006. ************************************************************************/
  7007. /*
  7008. * A traversal function enumerates nodes along an axis.
  7009. * Initially it must be called with NULL, and it indicates
  7010. * termination on the axis by returning NULL.
  7011. */
  7012. typedef xmlNodePtr (*xmlXPathTraversalFunction)
  7013. (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
  7014. /*
  7015. * xmlXPathTraversalFunctionExt:
  7016. * A traversal function enumerates nodes along an axis.
  7017. * Initially it must be called with NULL, and it indicates
  7018. * termination on the axis by returning NULL.
  7019. * The context node of the traversal is specified via @contextNode.
  7020. */
  7021. typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
  7022. (xmlNodePtr cur, xmlNodePtr contextNode);
  7023. /*
  7024. * xmlXPathNodeSetMergeFunction:
  7025. * Used for merging node sets in xmlXPathCollectAndTest().
  7026. */
  7027. typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
  7028. (xmlNodeSetPtr, xmlNodeSetPtr);
  7029. /**
  7030. * xmlXPathNextSelf:
  7031. * @ctxt: the XPath Parser context
  7032. * @cur: the current node in the traversal
  7033. *
  7034. * Traversal function for the "self" direction
  7035. * The self axis contains just the context node itself
  7036. *
  7037. * Returns the next element following that axis
  7038. */
  7039. xmlNodePtr
  7040. xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7041. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7042. if (cur == NULL)
  7043. return(ctxt->context->node);
  7044. return(NULL);
  7045. }
  7046. /**
  7047. * xmlXPathNextChild:
  7048. * @ctxt: the XPath Parser context
  7049. * @cur: the current node in the traversal
  7050. *
  7051. * Traversal function for the "child" direction
  7052. * The child axis contains the children of the context node in document order.
  7053. *
  7054. * Returns the next element following that axis
  7055. */
  7056. xmlNodePtr
  7057. xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7058. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7059. if (cur == NULL) {
  7060. if (ctxt->context->node == NULL) return(NULL);
  7061. switch (ctxt->context->node->type) {
  7062. case XML_ELEMENT_NODE:
  7063. case XML_TEXT_NODE:
  7064. case XML_CDATA_SECTION_NODE:
  7065. case XML_ENTITY_REF_NODE:
  7066. case XML_ENTITY_NODE:
  7067. case XML_PI_NODE:
  7068. case XML_COMMENT_NODE:
  7069. case XML_NOTATION_NODE:
  7070. case XML_DTD_NODE:
  7071. return(ctxt->context->node->children);
  7072. case XML_DOCUMENT_NODE:
  7073. case XML_DOCUMENT_TYPE_NODE:
  7074. case XML_DOCUMENT_FRAG_NODE:
  7075. case XML_HTML_DOCUMENT_NODE:
  7076. #ifdef LIBXML_DOCB_ENABLED
  7077. case XML_DOCB_DOCUMENT_NODE:
  7078. #endif
  7079. return(((xmlDocPtr) ctxt->context->node)->children);
  7080. case XML_ELEMENT_DECL:
  7081. case XML_ATTRIBUTE_DECL:
  7082. case XML_ENTITY_DECL:
  7083. case XML_ATTRIBUTE_NODE:
  7084. case XML_NAMESPACE_DECL:
  7085. case XML_XINCLUDE_START:
  7086. case XML_XINCLUDE_END:
  7087. return(NULL);
  7088. }
  7089. return(NULL);
  7090. }
  7091. if ((cur->type == XML_DOCUMENT_NODE) ||
  7092. (cur->type == XML_HTML_DOCUMENT_NODE))
  7093. return(NULL);
  7094. return(cur->next);
  7095. }
  7096. /**
  7097. * xmlXPathNextChildElement:
  7098. * @ctxt: the XPath Parser context
  7099. * @cur: the current node in the traversal
  7100. *
  7101. * Traversal function for the "child" direction and nodes of type element.
  7102. * The child axis contains the children of the context node in document order.
  7103. *
  7104. * Returns the next element following that axis
  7105. */
  7106. static xmlNodePtr
  7107. xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7108. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7109. if (cur == NULL) {
  7110. cur = ctxt->context->node;
  7111. if (cur == NULL) return(NULL);
  7112. /*
  7113. * Get the first element child.
  7114. */
  7115. switch (cur->type) {
  7116. case XML_ELEMENT_NODE:
  7117. case XML_DOCUMENT_FRAG_NODE:
  7118. case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
  7119. case XML_ENTITY_NODE:
  7120. cur = cur->children;
  7121. if (cur != NULL) {
  7122. if (cur->type == XML_ELEMENT_NODE)
  7123. return(cur);
  7124. do {
  7125. cur = cur->next;
  7126. } while ((cur != NULL) &&
  7127. (cur->type != XML_ELEMENT_NODE));
  7128. return(cur);
  7129. }
  7130. return(NULL);
  7131. case XML_DOCUMENT_NODE:
  7132. case XML_HTML_DOCUMENT_NODE:
  7133. #ifdef LIBXML_DOCB_ENABLED
  7134. case XML_DOCB_DOCUMENT_NODE:
  7135. #endif
  7136. return(xmlDocGetRootElement((xmlDocPtr) cur));
  7137. default:
  7138. return(NULL);
  7139. }
  7140. return(NULL);
  7141. }
  7142. /*
  7143. * Get the next sibling element node.
  7144. */
  7145. switch (cur->type) {
  7146. case XML_ELEMENT_NODE:
  7147. case XML_TEXT_NODE:
  7148. case XML_ENTITY_REF_NODE:
  7149. case XML_ENTITY_NODE:
  7150. case XML_CDATA_SECTION_NODE:
  7151. case XML_PI_NODE:
  7152. case XML_COMMENT_NODE:
  7153. case XML_XINCLUDE_END:
  7154. break;
  7155. /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
  7156. default:
  7157. return(NULL);
  7158. }
  7159. if (cur->next != NULL) {
  7160. if (cur->next->type == XML_ELEMENT_NODE)
  7161. return(cur->next);
  7162. cur = cur->next;
  7163. do {
  7164. cur = cur->next;
  7165. } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
  7166. return(cur);
  7167. }
  7168. return(NULL);
  7169. }
  7170. #if 0
  7171. /**
  7172. * xmlXPathNextDescendantOrSelfElemParent:
  7173. * @ctxt: the XPath Parser context
  7174. * @cur: the current node in the traversal
  7175. *
  7176. * Traversal function for the "descendant-or-self" axis.
  7177. * Additionally it returns only nodes which can be parents of
  7178. * element nodes.
  7179. *
  7180. *
  7181. * Returns the next element following that axis
  7182. */
  7183. static xmlNodePtr
  7184. xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
  7185. xmlNodePtr contextNode)
  7186. {
  7187. if (cur == NULL) {
  7188. if (contextNode == NULL)
  7189. return(NULL);
  7190. switch (contextNode->type) {
  7191. case XML_ELEMENT_NODE:
  7192. case XML_XINCLUDE_START:
  7193. case XML_DOCUMENT_FRAG_NODE:
  7194. case XML_DOCUMENT_NODE:
  7195. #ifdef LIBXML_DOCB_ENABLED
  7196. case XML_DOCB_DOCUMENT_NODE:
  7197. #endif
  7198. case XML_HTML_DOCUMENT_NODE:
  7199. return(contextNode);
  7200. default:
  7201. return(NULL);
  7202. }
  7203. return(NULL);
  7204. } else {
  7205. xmlNodePtr start = cur;
  7206. while (cur != NULL) {
  7207. switch (cur->type) {
  7208. case XML_ELEMENT_NODE:
  7209. /* TODO: OK to have XInclude here? */
  7210. case XML_XINCLUDE_START:
  7211. case XML_DOCUMENT_FRAG_NODE:
  7212. if (cur != start)
  7213. return(cur);
  7214. if (cur->children != NULL) {
  7215. cur = cur->children;
  7216. continue;
  7217. }
  7218. break;
  7219. /* Not sure if we need those here. */
  7220. case XML_DOCUMENT_NODE:
  7221. #ifdef LIBXML_DOCB_ENABLED
  7222. case XML_DOCB_DOCUMENT_NODE:
  7223. #endif
  7224. case XML_HTML_DOCUMENT_NODE:
  7225. if (cur != start)
  7226. return(cur);
  7227. return(xmlDocGetRootElement((xmlDocPtr) cur));
  7228. default:
  7229. break;
  7230. }
  7231. next_sibling:
  7232. if ((cur == NULL) || (cur == contextNode))
  7233. return(NULL);
  7234. if (cur->next != NULL) {
  7235. cur = cur->next;
  7236. } else {
  7237. cur = cur->parent;
  7238. goto next_sibling;
  7239. }
  7240. }
  7241. }
  7242. return(NULL);
  7243. }
  7244. #endif
  7245. /**
  7246. * xmlXPathNextDescendant:
  7247. * @ctxt: the XPath Parser context
  7248. * @cur: the current node in the traversal
  7249. *
  7250. * Traversal function for the "descendant" direction
  7251. * the descendant axis contains the descendants of the context node in document
  7252. * order; a descendant is a child or a child of a child and so on.
  7253. *
  7254. * Returns the next element following that axis
  7255. */
  7256. xmlNodePtr
  7257. xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7258. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7259. if (cur == NULL) {
  7260. if (ctxt->context->node == NULL)
  7261. return(NULL);
  7262. if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
  7263. (ctxt->context->node->type == XML_NAMESPACE_DECL))
  7264. return(NULL);
  7265. if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
  7266. return(ctxt->context->doc->children);
  7267. return(ctxt->context->node->children);
  7268. }
  7269. if (cur->type == XML_NAMESPACE_DECL)
  7270. return(NULL);
  7271. if (cur->children != NULL) {
  7272. /*
  7273. * Do not descend on entities declarations
  7274. */
  7275. if (cur->children->type != XML_ENTITY_DECL) {
  7276. cur = cur->children;
  7277. /*
  7278. * Skip DTDs
  7279. */
  7280. if (cur->type != XML_DTD_NODE)
  7281. return(cur);
  7282. }
  7283. }
  7284. if (cur == ctxt->context->node) return(NULL);
  7285. while (cur->next != NULL) {
  7286. cur = cur->next;
  7287. if ((cur->type != XML_ENTITY_DECL) &&
  7288. (cur->type != XML_DTD_NODE))
  7289. return(cur);
  7290. }
  7291. do {
  7292. cur = cur->parent;
  7293. if (cur == NULL) break;
  7294. if (cur == ctxt->context->node) return(NULL);
  7295. if (cur->next != NULL) {
  7296. cur = cur->next;
  7297. return(cur);
  7298. }
  7299. } while (cur != NULL);
  7300. return(cur);
  7301. }
  7302. /**
  7303. * xmlXPathNextDescendantOrSelf:
  7304. * @ctxt: the XPath Parser context
  7305. * @cur: the current node in the traversal
  7306. *
  7307. * Traversal function for the "descendant-or-self" direction
  7308. * the descendant-or-self axis contains the context node and the descendants
  7309. * of the context node in document order; thus the context node is the first
  7310. * node on the axis, and the first child of the context node is the second node
  7311. * on the axis
  7312. *
  7313. * Returns the next element following that axis
  7314. */
  7315. xmlNodePtr
  7316. xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7317. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7318. if (cur == NULL)
  7319. return(ctxt->context->node);
  7320. if (ctxt->context->node == NULL)
  7321. return(NULL);
  7322. if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
  7323. (ctxt->context->node->type == XML_NAMESPACE_DECL))
  7324. return(NULL);
  7325. return(xmlXPathNextDescendant(ctxt, cur));
  7326. }
  7327. /**
  7328. * xmlXPathNextParent:
  7329. * @ctxt: the XPath Parser context
  7330. * @cur: the current node in the traversal
  7331. *
  7332. * Traversal function for the "parent" direction
  7333. * The parent axis contains the parent of the context node, if there is one.
  7334. *
  7335. * Returns the next element following that axis
  7336. */
  7337. xmlNodePtr
  7338. xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7339. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7340. /*
  7341. * the parent of an attribute or namespace node is the element
  7342. * to which the attribute or namespace node is attached
  7343. * Namespace handling !!!
  7344. */
  7345. if (cur == NULL) {
  7346. if (ctxt->context->node == NULL) return(NULL);
  7347. switch (ctxt->context->node->type) {
  7348. case XML_ELEMENT_NODE:
  7349. case XML_TEXT_NODE:
  7350. case XML_CDATA_SECTION_NODE:
  7351. case XML_ENTITY_REF_NODE:
  7352. case XML_ENTITY_NODE:
  7353. case XML_PI_NODE:
  7354. case XML_COMMENT_NODE:
  7355. case XML_NOTATION_NODE:
  7356. case XML_DTD_NODE:
  7357. case XML_ELEMENT_DECL:
  7358. case XML_ATTRIBUTE_DECL:
  7359. case XML_XINCLUDE_START:
  7360. case XML_XINCLUDE_END:
  7361. case XML_ENTITY_DECL:
  7362. if (ctxt->context->node->parent == NULL)
  7363. return((xmlNodePtr) ctxt->context->doc);
  7364. if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
  7365. ((ctxt->context->node->parent->name[0] == ' ') ||
  7366. (xmlStrEqual(ctxt->context->node->parent->name,
  7367. BAD_CAST "fake node libxslt"))))
  7368. return(NULL);
  7369. return(ctxt->context->node->parent);
  7370. case XML_ATTRIBUTE_NODE: {
  7371. xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
  7372. return(att->parent);
  7373. }
  7374. case XML_DOCUMENT_NODE:
  7375. case XML_DOCUMENT_TYPE_NODE:
  7376. case XML_DOCUMENT_FRAG_NODE:
  7377. case XML_HTML_DOCUMENT_NODE:
  7378. #ifdef LIBXML_DOCB_ENABLED
  7379. case XML_DOCB_DOCUMENT_NODE:
  7380. #endif
  7381. return(NULL);
  7382. case XML_NAMESPACE_DECL: {
  7383. xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
  7384. if ((ns->next != NULL) &&
  7385. (ns->next->type != XML_NAMESPACE_DECL))
  7386. return((xmlNodePtr) ns->next);
  7387. return(NULL);
  7388. }
  7389. }
  7390. }
  7391. return(NULL);
  7392. }
  7393. /**
  7394. * xmlXPathNextAncestor:
  7395. * @ctxt: the XPath Parser context
  7396. * @cur: the current node in the traversal
  7397. *
  7398. * Traversal function for the "ancestor" direction
  7399. * the ancestor axis contains the ancestors of the context node; the ancestors
  7400. * of the context node consist of the parent of context node and the parent's
  7401. * parent and so on; the nodes are ordered in reverse document order; thus the
  7402. * parent is the first node on the axis, and the parent's parent is the second
  7403. * node on the axis
  7404. *
  7405. * Returns the next element following that axis
  7406. */
  7407. xmlNodePtr
  7408. xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7409. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7410. /*
  7411. * the parent of an attribute or namespace node is the element
  7412. * to which the attribute or namespace node is attached
  7413. * !!!!!!!!!!!!!
  7414. */
  7415. if (cur == NULL) {
  7416. if (ctxt->context->node == NULL) return(NULL);
  7417. switch (ctxt->context->node->type) {
  7418. case XML_ELEMENT_NODE:
  7419. case XML_TEXT_NODE:
  7420. case XML_CDATA_SECTION_NODE:
  7421. case XML_ENTITY_REF_NODE:
  7422. case XML_ENTITY_NODE:
  7423. case XML_PI_NODE:
  7424. case XML_COMMENT_NODE:
  7425. case XML_DTD_NODE:
  7426. case XML_ELEMENT_DECL:
  7427. case XML_ATTRIBUTE_DECL:
  7428. case XML_ENTITY_DECL:
  7429. case XML_NOTATION_NODE:
  7430. case XML_XINCLUDE_START:
  7431. case XML_XINCLUDE_END:
  7432. if (ctxt->context->node->parent == NULL)
  7433. return((xmlNodePtr) ctxt->context->doc);
  7434. if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
  7435. ((ctxt->context->node->parent->name[0] == ' ') ||
  7436. (xmlStrEqual(ctxt->context->node->parent->name,
  7437. BAD_CAST "fake node libxslt"))))
  7438. return(NULL);
  7439. return(ctxt->context->node->parent);
  7440. case XML_ATTRIBUTE_NODE: {
  7441. xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
  7442. return(tmp->parent);
  7443. }
  7444. case XML_DOCUMENT_NODE:
  7445. case XML_DOCUMENT_TYPE_NODE:
  7446. case XML_DOCUMENT_FRAG_NODE:
  7447. case XML_HTML_DOCUMENT_NODE:
  7448. #ifdef LIBXML_DOCB_ENABLED
  7449. case XML_DOCB_DOCUMENT_NODE:
  7450. #endif
  7451. return(NULL);
  7452. case XML_NAMESPACE_DECL: {
  7453. xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
  7454. if ((ns->next != NULL) &&
  7455. (ns->next->type != XML_NAMESPACE_DECL))
  7456. return((xmlNodePtr) ns->next);
  7457. /* Bad, how did that namespace end up here ? */
  7458. return(NULL);
  7459. }
  7460. }
  7461. return(NULL);
  7462. }
  7463. if (cur == ctxt->context->doc->children)
  7464. return((xmlNodePtr) ctxt->context->doc);
  7465. if (cur == (xmlNodePtr) ctxt->context->doc)
  7466. return(NULL);
  7467. switch (cur->type) {
  7468. case XML_ELEMENT_NODE:
  7469. case XML_TEXT_NODE:
  7470. case XML_CDATA_SECTION_NODE:
  7471. case XML_ENTITY_REF_NODE:
  7472. case XML_ENTITY_NODE:
  7473. case XML_PI_NODE:
  7474. case XML_COMMENT_NODE:
  7475. case XML_NOTATION_NODE:
  7476. case XML_DTD_NODE:
  7477. case XML_ELEMENT_DECL:
  7478. case XML_ATTRIBUTE_DECL:
  7479. case XML_ENTITY_DECL:
  7480. case XML_XINCLUDE_START:
  7481. case XML_XINCLUDE_END:
  7482. if (cur->parent == NULL)
  7483. return(NULL);
  7484. if ((cur->parent->type == XML_ELEMENT_NODE) &&
  7485. ((cur->parent->name[0] == ' ') ||
  7486. (xmlStrEqual(cur->parent->name,
  7487. BAD_CAST "fake node libxslt"))))
  7488. return(NULL);
  7489. return(cur->parent);
  7490. case XML_ATTRIBUTE_NODE: {
  7491. xmlAttrPtr att = (xmlAttrPtr) cur;
  7492. return(att->parent);
  7493. }
  7494. case XML_NAMESPACE_DECL: {
  7495. xmlNsPtr ns = (xmlNsPtr) cur;
  7496. if ((ns->next != NULL) &&
  7497. (ns->next->type != XML_NAMESPACE_DECL))
  7498. return((xmlNodePtr) ns->next);
  7499. /* Bad, how did that namespace end up here ? */
  7500. return(NULL);
  7501. }
  7502. case XML_DOCUMENT_NODE:
  7503. case XML_DOCUMENT_TYPE_NODE:
  7504. case XML_DOCUMENT_FRAG_NODE:
  7505. case XML_HTML_DOCUMENT_NODE:
  7506. #ifdef LIBXML_DOCB_ENABLED
  7507. case XML_DOCB_DOCUMENT_NODE:
  7508. #endif
  7509. return(NULL);
  7510. }
  7511. return(NULL);
  7512. }
  7513. /**
  7514. * xmlXPathNextAncestorOrSelf:
  7515. * @ctxt: the XPath Parser context
  7516. * @cur: the current node in the traversal
  7517. *
  7518. * Traversal function for the "ancestor-or-self" direction
  7519. * he ancestor-or-self axis contains the context node and ancestors of
  7520. * the context node in reverse document order; thus the context node is
  7521. * the first node on the axis, and the context node's parent the second;
  7522. * parent here is defined the same as with the parent axis.
  7523. *
  7524. * Returns the next element following that axis
  7525. */
  7526. xmlNodePtr
  7527. xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7528. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7529. if (cur == NULL)
  7530. return(ctxt->context->node);
  7531. return(xmlXPathNextAncestor(ctxt, cur));
  7532. }
  7533. /**
  7534. * xmlXPathNextFollowingSibling:
  7535. * @ctxt: the XPath Parser context
  7536. * @cur: the current node in the traversal
  7537. *
  7538. * Traversal function for the "following-sibling" direction
  7539. * The following-sibling axis contains the following siblings of the context
  7540. * node in document order.
  7541. *
  7542. * Returns the next element following that axis
  7543. */
  7544. xmlNodePtr
  7545. xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7546. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7547. if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
  7548. (ctxt->context->node->type == XML_NAMESPACE_DECL))
  7549. return(NULL);
  7550. if (cur == (xmlNodePtr) ctxt->context->doc)
  7551. return(NULL);
  7552. if (cur == NULL)
  7553. return(ctxt->context->node->next);
  7554. return(cur->next);
  7555. }
  7556. /**
  7557. * xmlXPathNextPrecedingSibling:
  7558. * @ctxt: the XPath Parser context
  7559. * @cur: the current node in the traversal
  7560. *
  7561. * Traversal function for the "preceding-sibling" direction
  7562. * The preceding-sibling axis contains the preceding siblings of the context
  7563. * node in reverse document order; the first preceding sibling is first on the
  7564. * axis; the sibling preceding that node is the second on the axis and so on.
  7565. *
  7566. * Returns the next element following that axis
  7567. */
  7568. xmlNodePtr
  7569. xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7570. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7571. if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
  7572. (ctxt->context->node->type == XML_NAMESPACE_DECL))
  7573. return(NULL);
  7574. if (cur == (xmlNodePtr) ctxt->context->doc)
  7575. return(NULL);
  7576. if (cur == NULL)
  7577. return(ctxt->context->node->prev);
  7578. if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
  7579. cur = cur->prev;
  7580. if (cur == NULL)
  7581. return(ctxt->context->node->prev);
  7582. }
  7583. return(cur->prev);
  7584. }
  7585. /**
  7586. * xmlXPathNextFollowing:
  7587. * @ctxt: the XPath Parser context
  7588. * @cur: the current node in the traversal
  7589. *
  7590. * Traversal function for the "following" direction
  7591. * The following axis contains all nodes in the same document as the context
  7592. * node that are after the context node in document order, excluding any
  7593. * descendants and excluding attribute nodes and namespace nodes; the nodes
  7594. * are ordered in document order
  7595. *
  7596. * Returns the next element following that axis
  7597. */
  7598. xmlNodePtr
  7599. xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7600. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7601. if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
  7602. (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
  7603. return(cur->children);
  7604. if (cur == NULL) {
  7605. cur = ctxt->context->node;
  7606. if (cur->type == XML_ATTRIBUTE_NODE) {
  7607. cur = cur->parent;
  7608. } else if (cur->type == XML_NAMESPACE_DECL) {
  7609. xmlNsPtr ns = (xmlNsPtr) cur;
  7610. if ((ns->next == NULL) ||
  7611. (ns->next->type == XML_NAMESPACE_DECL))
  7612. return (NULL);
  7613. cur = (xmlNodePtr) ns->next;
  7614. }
  7615. }
  7616. if (cur == NULL) return(NULL) ; /* ERROR */
  7617. if (cur->next != NULL) return(cur->next) ;
  7618. do {
  7619. cur = cur->parent;
  7620. if (cur == NULL) break;
  7621. if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
  7622. if (cur->next != NULL) return(cur->next);
  7623. } while (cur != NULL);
  7624. return(cur);
  7625. }
  7626. /*
  7627. * xmlXPathIsAncestor:
  7628. * @ancestor: the ancestor node
  7629. * @node: the current node
  7630. *
  7631. * Check that @ancestor is a @node's ancestor
  7632. *
  7633. * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
  7634. */
  7635. static int
  7636. xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
  7637. if ((ancestor == NULL) || (node == NULL)) return(0);
  7638. if (node->type == XML_NAMESPACE_DECL)
  7639. return(0);
  7640. if (ancestor->type == XML_NAMESPACE_DECL)
  7641. return(0);
  7642. /* nodes need to be in the same document */
  7643. if (ancestor->doc != node->doc) return(0);
  7644. /* avoid searching if ancestor or node is the root node */
  7645. if (ancestor == (xmlNodePtr) node->doc) return(1);
  7646. if (node == (xmlNodePtr) ancestor->doc) return(0);
  7647. while (node->parent != NULL) {
  7648. if (node->parent == ancestor)
  7649. return(1);
  7650. node = node->parent;
  7651. }
  7652. return(0);
  7653. }
  7654. /**
  7655. * xmlXPathNextPreceding:
  7656. * @ctxt: the XPath Parser context
  7657. * @cur: the current node in the traversal
  7658. *
  7659. * Traversal function for the "preceding" direction
  7660. * the preceding axis contains all nodes in the same document as the context
  7661. * node that are before the context node in document order, excluding any
  7662. * ancestors and excluding attribute nodes and namespace nodes; the nodes are
  7663. * ordered in reverse document order
  7664. *
  7665. * Returns the next element following that axis
  7666. */
  7667. xmlNodePtr
  7668. xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
  7669. {
  7670. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7671. if (cur == NULL) {
  7672. cur = ctxt->context->node;
  7673. if (cur->type == XML_ATTRIBUTE_NODE) {
  7674. cur = cur->parent;
  7675. } else if (cur->type == XML_NAMESPACE_DECL) {
  7676. xmlNsPtr ns = (xmlNsPtr) cur;
  7677. if ((ns->next == NULL) ||
  7678. (ns->next->type == XML_NAMESPACE_DECL))
  7679. return (NULL);
  7680. cur = (xmlNodePtr) ns->next;
  7681. }
  7682. }
  7683. if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
  7684. return (NULL);
  7685. if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
  7686. cur = cur->prev;
  7687. do {
  7688. if (cur->prev != NULL) {
  7689. for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
  7690. return (cur);
  7691. }
  7692. cur = cur->parent;
  7693. if (cur == NULL)
  7694. return (NULL);
  7695. if (cur == ctxt->context->doc->children)
  7696. return (NULL);
  7697. } while (xmlXPathIsAncestor(cur, ctxt->context->node));
  7698. return (cur);
  7699. }
  7700. /**
  7701. * xmlXPathNextPrecedingInternal:
  7702. * @ctxt: the XPath Parser context
  7703. * @cur: the current node in the traversal
  7704. *
  7705. * Traversal function for the "preceding" direction
  7706. * the preceding axis contains all nodes in the same document as the context
  7707. * node that are before the context node in document order, excluding any
  7708. * ancestors and excluding attribute nodes and namespace nodes; the nodes are
  7709. * ordered in reverse document order
  7710. * This is a faster implementation but internal only since it requires a
  7711. * state kept in the parser context: ctxt->ancestor.
  7712. *
  7713. * Returns the next element following that axis
  7714. */
  7715. static xmlNodePtr
  7716. xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
  7717. xmlNodePtr cur)
  7718. {
  7719. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7720. if (cur == NULL) {
  7721. cur = ctxt->context->node;
  7722. if (cur == NULL)
  7723. return (NULL);
  7724. if (cur->type == XML_ATTRIBUTE_NODE) {
  7725. cur = cur->parent;
  7726. } else if (cur->type == XML_NAMESPACE_DECL) {
  7727. xmlNsPtr ns = (xmlNsPtr) cur;
  7728. if ((ns->next == NULL) ||
  7729. (ns->next->type == XML_NAMESPACE_DECL))
  7730. return (NULL);
  7731. cur = (xmlNodePtr) ns->next;
  7732. }
  7733. ctxt->ancestor = cur->parent;
  7734. }
  7735. if (cur->type == XML_NAMESPACE_DECL)
  7736. return(NULL);
  7737. if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
  7738. cur = cur->prev;
  7739. while (cur->prev == NULL) {
  7740. cur = cur->parent;
  7741. if (cur == NULL)
  7742. return (NULL);
  7743. if (cur == ctxt->context->doc->children)
  7744. return (NULL);
  7745. if (cur != ctxt->ancestor)
  7746. return (cur);
  7747. ctxt->ancestor = cur->parent;
  7748. }
  7749. cur = cur->prev;
  7750. while (cur->last != NULL)
  7751. cur = cur->last;
  7752. return (cur);
  7753. }
  7754. /**
  7755. * xmlXPathNextNamespace:
  7756. * @ctxt: the XPath Parser context
  7757. * @cur: the current attribute in the traversal
  7758. *
  7759. * Traversal function for the "namespace" direction
  7760. * the namespace axis contains the namespace nodes of the context node;
  7761. * the order of nodes on this axis is implementation-defined; the axis will
  7762. * be empty unless the context node is an element
  7763. *
  7764. * We keep the XML namespace node at the end of the list.
  7765. *
  7766. * Returns the next element following that axis
  7767. */
  7768. xmlNodePtr
  7769. xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7770. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7771. if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
  7772. if (cur == NULL) {
  7773. if (ctxt->context->tmpNsList != NULL)
  7774. xmlFree(ctxt->context->tmpNsList);
  7775. ctxt->context->tmpNsList =
  7776. xmlGetNsList(ctxt->context->doc, ctxt->context->node);
  7777. ctxt->context->tmpNsNr = 0;
  7778. if (ctxt->context->tmpNsList != NULL) {
  7779. while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
  7780. ctxt->context->tmpNsNr++;
  7781. }
  7782. }
  7783. return((xmlNodePtr) xmlXPathXMLNamespace);
  7784. }
  7785. if (ctxt->context->tmpNsNr > 0) {
  7786. return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
  7787. } else {
  7788. if (ctxt->context->tmpNsList != NULL)
  7789. xmlFree(ctxt->context->tmpNsList);
  7790. ctxt->context->tmpNsList = NULL;
  7791. return(NULL);
  7792. }
  7793. }
  7794. /**
  7795. * xmlXPathNextAttribute:
  7796. * @ctxt: the XPath Parser context
  7797. * @cur: the current attribute in the traversal
  7798. *
  7799. * Traversal function for the "attribute" direction
  7800. * TODO: support DTD inherited default attributes
  7801. *
  7802. * Returns the next element following that axis
  7803. */
  7804. xmlNodePtr
  7805. xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
  7806. if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
  7807. if (ctxt->context->node == NULL)
  7808. return(NULL);
  7809. if (ctxt->context->node->type != XML_ELEMENT_NODE)
  7810. return(NULL);
  7811. if (cur == NULL) {
  7812. if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
  7813. return(NULL);
  7814. return((xmlNodePtr)ctxt->context->node->properties);
  7815. }
  7816. return((xmlNodePtr)cur->next);
  7817. }
  7818. /************************************************************************
  7819. * *
  7820. * NodeTest Functions *
  7821. * *
  7822. ************************************************************************/
  7823. #define IS_FUNCTION 200
  7824. /************************************************************************
  7825. * *
  7826. * Implicit tree core function library *
  7827. * *
  7828. ************************************************************************/
  7829. /**
  7830. * xmlXPathRoot:
  7831. * @ctxt: the XPath Parser context
  7832. *
  7833. * Initialize the context to the root of the document
  7834. */
  7835. void
  7836. xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
  7837. if ((ctxt == NULL) || (ctxt->context == NULL))
  7838. return;
  7839. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  7840. (xmlNodePtr) ctxt->context->doc));
  7841. }
  7842. /************************************************************************
  7843. * *
  7844. * The explicit core function library *
  7845. *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
  7846. * *
  7847. ************************************************************************/
  7848. /**
  7849. * xmlXPathLastFunction:
  7850. * @ctxt: the XPath Parser context
  7851. * @nargs: the number of arguments
  7852. *
  7853. * Implement the last() XPath function
  7854. * number last()
  7855. * The last function returns the number of nodes in the context node list.
  7856. */
  7857. void
  7858. xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7859. CHECK_ARITY(0);
  7860. if (ctxt->context->contextSize >= 0) {
  7861. valuePush(ctxt,
  7862. xmlXPathCacheNewFloat(ctxt->context,
  7863. (double) ctxt->context->contextSize));
  7864. #ifdef DEBUG_EXPR
  7865. xmlGenericError(xmlGenericErrorContext,
  7866. "last() : %d\n", ctxt->context->contextSize);
  7867. #endif
  7868. } else {
  7869. XP_ERROR(XPATH_INVALID_CTXT_SIZE);
  7870. }
  7871. }
  7872. /**
  7873. * xmlXPathPositionFunction:
  7874. * @ctxt: the XPath Parser context
  7875. * @nargs: the number of arguments
  7876. *
  7877. * Implement the position() XPath function
  7878. * number position()
  7879. * The position function returns the position of the context node in the
  7880. * context node list. The first position is 1, and so the last position
  7881. * will be equal to last().
  7882. */
  7883. void
  7884. xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7885. CHECK_ARITY(0);
  7886. if (ctxt->context->proximityPosition >= 0) {
  7887. valuePush(ctxt,
  7888. xmlXPathCacheNewFloat(ctxt->context,
  7889. (double) ctxt->context->proximityPosition));
  7890. #ifdef DEBUG_EXPR
  7891. xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
  7892. ctxt->context->proximityPosition);
  7893. #endif
  7894. } else {
  7895. XP_ERROR(XPATH_INVALID_CTXT_POSITION);
  7896. }
  7897. }
  7898. /**
  7899. * xmlXPathCountFunction:
  7900. * @ctxt: the XPath Parser context
  7901. * @nargs: the number of arguments
  7902. *
  7903. * Implement the count() XPath function
  7904. * number count(node-set)
  7905. */
  7906. void
  7907. xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7908. xmlXPathObjectPtr cur;
  7909. CHECK_ARITY(1);
  7910. if ((ctxt->value == NULL) ||
  7911. ((ctxt->value->type != XPATH_NODESET) &&
  7912. (ctxt->value->type != XPATH_XSLT_TREE)))
  7913. XP_ERROR(XPATH_INVALID_TYPE);
  7914. cur = valuePop(ctxt);
  7915. if ((cur == NULL) || (cur->nodesetval == NULL))
  7916. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
  7917. else
  7918. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
  7919. (double) cur->nodesetval->nodeNr));
  7920. xmlXPathReleaseObject(ctxt->context, cur);
  7921. }
  7922. /**
  7923. * xmlXPathGetElementsByIds:
  7924. * @doc: the document
  7925. * @ids: a whitespace separated list of IDs
  7926. *
  7927. * Selects elements by their unique ID.
  7928. *
  7929. * Returns a node-set of selected elements.
  7930. */
  7931. static xmlNodeSetPtr
  7932. xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
  7933. xmlNodeSetPtr ret;
  7934. const xmlChar *cur = ids;
  7935. xmlChar *ID;
  7936. xmlAttrPtr attr;
  7937. xmlNodePtr elem = NULL;
  7938. if (ids == NULL) return(NULL);
  7939. ret = xmlXPathNodeSetCreate(NULL);
  7940. if (ret == NULL)
  7941. return(ret);
  7942. while (IS_BLANK_CH(*cur)) cur++;
  7943. while (*cur != 0) {
  7944. while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
  7945. cur++;
  7946. ID = xmlStrndup(ids, cur - ids);
  7947. if (ID != NULL) {
  7948. /*
  7949. * We used to check the fact that the value passed
  7950. * was an NCName, but this generated much troubles for
  7951. * me and Aleksey Sanin, people blatantly violated that
  7952. * constraint, like Visa3D spec.
  7953. * if (xmlValidateNCName(ID, 1) == 0)
  7954. */
  7955. attr = xmlGetID(doc, ID);
  7956. if (attr != NULL) {
  7957. if (attr->type == XML_ATTRIBUTE_NODE)
  7958. elem = attr->parent;
  7959. else if (attr->type == XML_ELEMENT_NODE)
  7960. elem = (xmlNodePtr) attr;
  7961. else
  7962. elem = NULL;
  7963. /* TODO: Check memory error. */
  7964. if (elem != NULL)
  7965. xmlXPathNodeSetAdd(ret, elem);
  7966. }
  7967. xmlFree(ID);
  7968. }
  7969. while (IS_BLANK_CH(*cur)) cur++;
  7970. ids = cur;
  7971. }
  7972. return(ret);
  7973. }
  7974. /**
  7975. * xmlXPathIdFunction:
  7976. * @ctxt: the XPath Parser context
  7977. * @nargs: the number of arguments
  7978. *
  7979. * Implement the id() XPath function
  7980. * node-set id(object)
  7981. * The id function selects elements by their unique ID
  7982. * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
  7983. * then the result is the union of the result of applying id to the
  7984. * string value of each of the nodes in the argument node-set. When the
  7985. * argument to id is of any other type, the argument is converted to a
  7986. * string as if by a call to the string function; the string is split
  7987. * into a whitespace-separated list of tokens (whitespace is any sequence
  7988. * of characters matching the production S); the result is a node-set
  7989. * containing the elements in the same document as the context node that
  7990. * have a unique ID equal to any of the tokens in the list.
  7991. */
  7992. void
  7993. xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  7994. xmlChar *tokens;
  7995. xmlNodeSetPtr ret;
  7996. xmlXPathObjectPtr obj;
  7997. CHECK_ARITY(1);
  7998. obj = valuePop(ctxt);
  7999. if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
  8000. if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
  8001. xmlNodeSetPtr ns;
  8002. int i;
  8003. /* TODO: Check memory error. */
  8004. ret = xmlXPathNodeSetCreate(NULL);
  8005. if (obj->nodesetval != NULL) {
  8006. for (i = 0; i < obj->nodesetval->nodeNr; i++) {
  8007. tokens =
  8008. xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
  8009. ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
  8010. /* TODO: Check memory error. */
  8011. ret = xmlXPathNodeSetMerge(ret, ns);
  8012. xmlXPathFreeNodeSet(ns);
  8013. if (tokens != NULL)
  8014. xmlFree(tokens);
  8015. }
  8016. }
  8017. xmlXPathReleaseObject(ctxt->context, obj);
  8018. valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
  8019. return;
  8020. }
  8021. obj = xmlXPathCacheConvertString(ctxt->context, obj);
  8022. if (obj == NULL) return;
  8023. ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
  8024. valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
  8025. xmlXPathReleaseObject(ctxt->context, obj);
  8026. return;
  8027. }
  8028. /**
  8029. * xmlXPathLocalNameFunction:
  8030. * @ctxt: the XPath Parser context
  8031. * @nargs: the number of arguments
  8032. *
  8033. * Implement the local-name() XPath function
  8034. * string local-name(node-set?)
  8035. * The local-name function returns a string containing the local part
  8036. * of the name of the node in the argument node-set that is first in
  8037. * document order. If the node-set is empty or the first node has no
  8038. * name, an empty string is returned. If the argument is omitted it
  8039. * defaults to the context node.
  8040. */
  8041. void
  8042. xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8043. xmlXPathObjectPtr cur;
  8044. if (ctxt == NULL) return;
  8045. if (nargs == 0) {
  8046. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  8047. ctxt->context->node));
  8048. nargs = 1;
  8049. }
  8050. CHECK_ARITY(1);
  8051. if ((ctxt->value == NULL) ||
  8052. ((ctxt->value->type != XPATH_NODESET) &&
  8053. (ctxt->value->type != XPATH_XSLT_TREE)))
  8054. XP_ERROR(XPATH_INVALID_TYPE);
  8055. cur = valuePop(ctxt);
  8056. if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
  8057. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8058. } else {
  8059. int i = 0; /* Should be first in document order !!!!! */
  8060. switch (cur->nodesetval->nodeTab[i]->type) {
  8061. case XML_ELEMENT_NODE:
  8062. case XML_ATTRIBUTE_NODE:
  8063. case XML_PI_NODE:
  8064. if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
  8065. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8066. else
  8067. valuePush(ctxt,
  8068. xmlXPathCacheNewString(ctxt->context,
  8069. cur->nodesetval->nodeTab[i]->name));
  8070. break;
  8071. case XML_NAMESPACE_DECL:
  8072. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  8073. ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
  8074. break;
  8075. default:
  8076. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8077. }
  8078. }
  8079. xmlXPathReleaseObject(ctxt->context, cur);
  8080. }
  8081. /**
  8082. * xmlXPathNamespaceURIFunction:
  8083. * @ctxt: the XPath Parser context
  8084. * @nargs: the number of arguments
  8085. *
  8086. * Implement the namespace-uri() XPath function
  8087. * string namespace-uri(node-set?)
  8088. * The namespace-uri function returns a string containing the
  8089. * namespace URI of the expanded name of the node in the argument
  8090. * node-set that is first in document order. If the node-set is empty,
  8091. * the first node has no name, or the expanded name has no namespace
  8092. * URI, an empty string is returned. If the argument is omitted it
  8093. * defaults to the context node.
  8094. */
  8095. void
  8096. xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8097. xmlXPathObjectPtr cur;
  8098. if (ctxt == NULL) return;
  8099. if (nargs == 0) {
  8100. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  8101. ctxt->context->node));
  8102. nargs = 1;
  8103. }
  8104. CHECK_ARITY(1);
  8105. if ((ctxt->value == NULL) ||
  8106. ((ctxt->value->type != XPATH_NODESET) &&
  8107. (ctxt->value->type != XPATH_XSLT_TREE)))
  8108. XP_ERROR(XPATH_INVALID_TYPE);
  8109. cur = valuePop(ctxt);
  8110. if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
  8111. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8112. } else {
  8113. int i = 0; /* Should be first in document order !!!!! */
  8114. switch (cur->nodesetval->nodeTab[i]->type) {
  8115. case XML_ELEMENT_NODE:
  8116. case XML_ATTRIBUTE_NODE:
  8117. if (cur->nodesetval->nodeTab[i]->ns == NULL)
  8118. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8119. else
  8120. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  8121. cur->nodesetval->nodeTab[i]->ns->href));
  8122. break;
  8123. default:
  8124. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8125. }
  8126. }
  8127. xmlXPathReleaseObject(ctxt->context, cur);
  8128. }
  8129. /**
  8130. * xmlXPathNameFunction:
  8131. * @ctxt: the XPath Parser context
  8132. * @nargs: the number of arguments
  8133. *
  8134. * Implement the name() XPath function
  8135. * string name(node-set?)
  8136. * The name function returns a string containing a QName representing
  8137. * the name of the node in the argument node-set that is first in document
  8138. * order. The QName must represent the name with respect to the namespace
  8139. * declarations in effect on the node whose name is being represented.
  8140. * Typically, this will be the form in which the name occurred in the XML
  8141. * source. This need not be the case if there are namespace declarations
  8142. * in effect on the node that associate multiple prefixes with the same
  8143. * namespace. However, an implementation may include information about
  8144. * the original prefix in its representation of nodes; in this case, an
  8145. * implementation can ensure that the returned string is always the same
  8146. * as the QName used in the XML source. If the argument it omitted it
  8147. * defaults to the context node.
  8148. * Libxml keep the original prefix so the "real qualified name" used is
  8149. * returned.
  8150. */
  8151. static void
  8152. xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
  8153. {
  8154. xmlXPathObjectPtr cur;
  8155. if (nargs == 0) {
  8156. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  8157. ctxt->context->node));
  8158. nargs = 1;
  8159. }
  8160. CHECK_ARITY(1);
  8161. if ((ctxt->value == NULL) ||
  8162. ((ctxt->value->type != XPATH_NODESET) &&
  8163. (ctxt->value->type != XPATH_XSLT_TREE)))
  8164. XP_ERROR(XPATH_INVALID_TYPE);
  8165. cur = valuePop(ctxt);
  8166. if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
  8167. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8168. } else {
  8169. int i = 0; /* Should be first in document order !!!!! */
  8170. switch (cur->nodesetval->nodeTab[i]->type) {
  8171. case XML_ELEMENT_NODE:
  8172. case XML_ATTRIBUTE_NODE:
  8173. if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
  8174. valuePush(ctxt,
  8175. xmlXPathCacheNewCString(ctxt->context, ""));
  8176. else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
  8177. (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
  8178. valuePush(ctxt,
  8179. xmlXPathCacheNewString(ctxt->context,
  8180. cur->nodesetval->nodeTab[i]->name));
  8181. } else {
  8182. xmlChar *fullname;
  8183. fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
  8184. cur->nodesetval->nodeTab[i]->ns->prefix,
  8185. NULL, 0);
  8186. if (fullname == cur->nodesetval->nodeTab[i]->name)
  8187. fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
  8188. if (fullname == NULL) {
  8189. XP_ERROR(XPATH_MEMORY_ERROR);
  8190. }
  8191. valuePush(ctxt, xmlXPathCacheWrapString(
  8192. ctxt->context, fullname));
  8193. }
  8194. break;
  8195. default:
  8196. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  8197. cur->nodesetval->nodeTab[i]));
  8198. xmlXPathLocalNameFunction(ctxt, 1);
  8199. }
  8200. }
  8201. xmlXPathReleaseObject(ctxt->context, cur);
  8202. }
  8203. /**
  8204. * xmlXPathStringFunction:
  8205. * @ctxt: the XPath Parser context
  8206. * @nargs: the number of arguments
  8207. *
  8208. * Implement the string() XPath function
  8209. * string string(object?)
  8210. * The string function converts an object to a string as follows:
  8211. * - A node-set is converted to a string by returning the value of
  8212. * the node in the node-set that is first in document order.
  8213. * If the node-set is empty, an empty string is returned.
  8214. * - A number is converted to a string as follows
  8215. * + NaN is converted to the string NaN
  8216. * + positive zero is converted to the string 0
  8217. * + negative zero is converted to the string 0
  8218. * + positive infinity is converted to the string Infinity
  8219. * + negative infinity is converted to the string -Infinity
  8220. * + if the number is an integer, the number is represented in
  8221. * decimal form as a Number with no decimal point and no leading
  8222. * zeros, preceded by a minus sign (-) if the number is negative
  8223. * + otherwise, the number is represented in decimal form as a
  8224. * Number including a decimal point with at least one digit
  8225. * before the decimal point and at least one digit after the
  8226. * decimal point, preceded by a minus sign (-) if the number
  8227. * is negative; there must be no leading zeros before the decimal
  8228. * point apart possibly from the one required digit immediately
  8229. * before the decimal point; beyond the one required digit
  8230. * after the decimal point there must be as many, but only as
  8231. * many, more digits as are needed to uniquely distinguish the
  8232. * number from all other IEEE 754 numeric values.
  8233. * - The boolean false value is converted to the string false.
  8234. * The boolean true value is converted to the string true.
  8235. *
  8236. * If the argument is omitted, it defaults to a node-set with the
  8237. * context node as its only member.
  8238. */
  8239. void
  8240. xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8241. xmlXPathObjectPtr cur;
  8242. if (ctxt == NULL) return;
  8243. if (nargs == 0) {
  8244. valuePush(ctxt,
  8245. xmlXPathCacheWrapString(ctxt->context,
  8246. xmlXPathCastNodeToString(ctxt->context->node)));
  8247. return;
  8248. }
  8249. CHECK_ARITY(1);
  8250. cur = valuePop(ctxt);
  8251. if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
  8252. valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
  8253. }
  8254. /**
  8255. * xmlXPathStringLengthFunction:
  8256. * @ctxt: the XPath Parser context
  8257. * @nargs: the number of arguments
  8258. *
  8259. * Implement the string-length() XPath function
  8260. * number string-length(string?)
  8261. * The string-length returns the number of characters in the string
  8262. * (see [3.6 Strings]). If the argument is omitted, it defaults to
  8263. * the context node converted to a string, in other words the value
  8264. * of the context node.
  8265. */
  8266. void
  8267. xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8268. xmlXPathObjectPtr cur;
  8269. if (nargs == 0) {
  8270. if ((ctxt == NULL) || (ctxt->context == NULL))
  8271. return;
  8272. if (ctxt->context->node == NULL) {
  8273. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
  8274. } else {
  8275. xmlChar *content;
  8276. content = xmlXPathCastNodeToString(ctxt->context->node);
  8277. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
  8278. xmlUTF8Strlen(content)));
  8279. xmlFree(content);
  8280. }
  8281. return;
  8282. }
  8283. CHECK_ARITY(1);
  8284. CAST_TO_STRING;
  8285. CHECK_TYPE(XPATH_STRING);
  8286. cur = valuePop(ctxt);
  8287. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
  8288. xmlUTF8Strlen(cur->stringval)));
  8289. xmlXPathReleaseObject(ctxt->context, cur);
  8290. }
  8291. /**
  8292. * xmlXPathConcatFunction:
  8293. * @ctxt: the XPath Parser context
  8294. * @nargs: the number of arguments
  8295. *
  8296. * Implement the concat() XPath function
  8297. * string concat(string, string, string*)
  8298. * The concat function returns the concatenation of its arguments.
  8299. */
  8300. void
  8301. xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8302. xmlXPathObjectPtr cur, newobj;
  8303. xmlChar *tmp;
  8304. if (ctxt == NULL) return;
  8305. if (nargs < 2) {
  8306. CHECK_ARITY(2);
  8307. }
  8308. CAST_TO_STRING;
  8309. cur = valuePop(ctxt);
  8310. if ((cur == NULL) || (cur->type != XPATH_STRING)) {
  8311. xmlXPathReleaseObject(ctxt->context, cur);
  8312. return;
  8313. }
  8314. nargs--;
  8315. while (nargs > 0) {
  8316. CAST_TO_STRING;
  8317. newobj = valuePop(ctxt);
  8318. if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
  8319. xmlXPathReleaseObject(ctxt->context, newobj);
  8320. xmlXPathReleaseObject(ctxt->context, cur);
  8321. XP_ERROR(XPATH_INVALID_TYPE);
  8322. }
  8323. tmp = xmlStrcat(newobj->stringval, cur->stringval);
  8324. newobj->stringval = cur->stringval;
  8325. cur->stringval = tmp;
  8326. xmlXPathReleaseObject(ctxt->context, newobj);
  8327. nargs--;
  8328. }
  8329. valuePush(ctxt, cur);
  8330. }
  8331. /**
  8332. * xmlXPathContainsFunction:
  8333. * @ctxt: the XPath Parser context
  8334. * @nargs: the number of arguments
  8335. *
  8336. * Implement the contains() XPath function
  8337. * boolean contains(string, string)
  8338. * The contains function returns true if the first argument string
  8339. * contains the second argument string, and otherwise returns false.
  8340. */
  8341. void
  8342. xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8343. xmlXPathObjectPtr hay, needle;
  8344. CHECK_ARITY(2);
  8345. CAST_TO_STRING;
  8346. CHECK_TYPE(XPATH_STRING);
  8347. needle = valuePop(ctxt);
  8348. CAST_TO_STRING;
  8349. hay = valuePop(ctxt);
  8350. if ((hay == NULL) || (hay->type != XPATH_STRING)) {
  8351. xmlXPathReleaseObject(ctxt->context, hay);
  8352. xmlXPathReleaseObject(ctxt->context, needle);
  8353. XP_ERROR(XPATH_INVALID_TYPE);
  8354. }
  8355. if (xmlStrstr(hay->stringval, needle->stringval))
  8356. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
  8357. else
  8358. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
  8359. xmlXPathReleaseObject(ctxt->context, hay);
  8360. xmlXPathReleaseObject(ctxt->context, needle);
  8361. }
  8362. /**
  8363. * xmlXPathStartsWithFunction:
  8364. * @ctxt: the XPath Parser context
  8365. * @nargs: the number of arguments
  8366. *
  8367. * Implement the starts-with() XPath function
  8368. * boolean starts-with(string, string)
  8369. * The starts-with function returns true if the first argument string
  8370. * starts with the second argument string, and otherwise returns false.
  8371. */
  8372. void
  8373. xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8374. xmlXPathObjectPtr hay, needle;
  8375. int n;
  8376. CHECK_ARITY(2);
  8377. CAST_TO_STRING;
  8378. CHECK_TYPE(XPATH_STRING);
  8379. needle = valuePop(ctxt);
  8380. CAST_TO_STRING;
  8381. hay = valuePop(ctxt);
  8382. if ((hay == NULL) || (hay->type != XPATH_STRING)) {
  8383. xmlXPathReleaseObject(ctxt->context, hay);
  8384. xmlXPathReleaseObject(ctxt->context, needle);
  8385. XP_ERROR(XPATH_INVALID_TYPE);
  8386. }
  8387. n = xmlStrlen(needle->stringval);
  8388. if (xmlStrncmp(hay->stringval, needle->stringval, n))
  8389. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
  8390. else
  8391. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
  8392. xmlXPathReleaseObject(ctxt->context, hay);
  8393. xmlXPathReleaseObject(ctxt->context, needle);
  8394. }
  8395. /**
  8396. * xmlXPathSubstringFunction:
  8397. * @ctxt: the XPath Parser context
  8398. * @nargs: the number of arguments
  8399. *
  8400. * Implement the substring() XPath function
  8401. * string substring(string, number, number?)
  8402. * The substring function returns the substring of the first argument
  8403. * starting at the position specified in the second argument with
  8404. * length specified in the third argument. For example,
  8405. * substring("12345",2,3) returns "234". If the third argument is not
  8406. * specified, it returns the substring starting at the position specified
  8407. * in the second argument and continuing to the end of the string. For
  8408. * example, substring("12345",2) returns "2345". More precisely, each
  8409. * character in the string (see [3.6 Strings]) is considered to have a
  8410. * numeric position: the position of the first character is 1, the position
  8411. * of the second character is 2 and so on. The returned substring contains
  8412. * those characters for which the position of the character is greater than
  8413. * or equal to the second argument and, if the third argument is specified,
  8414. * less than the sum of the second and third arguments; the comparisons
  8415. * and addition used for the above follow the standard IEEE 754 rules. Thus:
  8416. * - substring("12345", 1.5, 2.6) returns "234"
  8417. * - substring("12345", 0, 3) returns "12"
  8418. * - substring("12345", 0 div 0, 3) returns ""
  8419. * - substring("12345", 1, 0 div 0) returns ""
  8420. * - substring("12345", -42, 1 div 0) returns "12345"
  8421. * - substring("12345", -1 div 0, 1 div 0) returns ""
  8422. */
  8423. void
  8424. xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8425. xmlXPathObjectPtr str, start, len;
  8426. double le=0, in;
  8427. int i = 1, j = INT_MAX;
  8428. if (nargs < 2) {
  8429. CHECK_ARITY(2);
  8430. }
  8431. if (nargs > 3) {
  8432. CHECK_ARITY(3);
  8433. }
  8434. /*
  8435. * take care of possible last (position) argument
  8436. */
  8437. if (nargs == 3) {
  8438. CAST_TO_NUMBER;
  8439. CHECK_TYPE(XPATH_NUMBER);
  8440. len = valuePop(ctxt);
  8441. le = len->floatval;
  8442. xmlXPathReleaseObject(ctxt->context, len);
  8443. }
  8444. CAST_TO_NUMBER;
  8445. CHECK_TYPE(XPATH_NUMBER);
  8446. start = valuePop(ctxt);
  8447. in = start->floatval;
  8448. xmlXPathReleaseObject(ctxt->context, start);
  8449. CAST_TO_STRING;
  8450. CHECK_TYPE(XPATH_STRING);
  8451. str = valuePop(ctxt);
  8452. if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
  8453. i = INT_MAX;
  8454. } else if (in >= 1.0) {
  8455. i = (int)in;
  8456. if (in - floor(in) >= 0.5)
  8457. i += 1;
  8458. }
  8459. if (nargs == 3) {
  8460. double rin, rle, end;
  8461. rin = floor(in);
  8462. if (in - rin >= 0.5)
  8463. rin += 1.0;
  8464. rle = floor(le);
  8465. if (le - rle >= 0.5)
  8466. rle += 1.0;
  8467. end = rin + rle;
  8468. if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
  8469. j = 1;
  8470. } else if (end < INT_MAX) {
  8471. j = (int)end;
  8472. }
  8473. }
  8474. if (i < j) {
  8475. xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
  8476. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
  8477. xmlFree(ret);
  8478. } else {
  8479. valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
  8480. }
  8481. xmlXPathReleaseObject(ctxt->context, str);
  8482. }
  8483. /**
  8484. * xmlXPathSubstringBeforeFunction:
  8485. * @ctxt: the XPath Parser context
  8486. * @nargs: the number of arguments
  8487. *
  8488. * Implement the substring-before() XPath function
  8489. * string substring-before(string, string)
  8490. * The substring-before function returns the substring of the first
  8491. * argument string that precedes the first occurrence of the second
  8492. * argument string in the first argument string, or the empty string
  8493. * if the first argument string does not contain the second argument
  8494. * string. For example, substring-before("1999/04/01","/") returns 1999.
  8495. */
  8496. void
  8497. xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8498. xmlXPathObjectPtr str;
  8499. xmlXPathObjectPtr find;
  8500. xmlBufPtr target;
  8501. const xmlChar *point;
  8502. int offset;
  8503. CHECK_ARITY(2);
  8504. CAST_TO_STRING;
  8505. find = valuePop(ctxt);
  8506. CAST_TO_STRING;
  8507. str = valuePop(ctxt);
  8508. target = xmlBufCreate();
  8509. if (target) {
  8510. point = xmlStrstr(str->stringval, find->stringval);
  8511. if (point) {
  8512. offset = (int)(point - str->stringval);
  8513. xmlBufAdd(target, str->stringval, offset);
  8514. }
  8515. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  8516. xmlBufContent(target)));
  8517. xmlBufFree(target);
  8518. }
  8519. xmlXPathReleaseObject(ctxt->context, str);
  8520. xmlXPathReleaseObject(ctxt->context, find);
  8521. }
  8522. /**
  8523. * xmlXPathSubstringAfterFunction:
  8524. * @ctxt: the XPath Parser context
  8525. * @nargs: the number of arguments
  8526. *
  8527. * Implement the substring-after() XPath function
  8528. * string substring-after(string, string)
  8529. * The substring-after function returns the substring of the first
  8530. * argument string that follows the first occurrence of the second
  8531. * argument string in the first argument string, or the empty stringi
  8532. * if the first argument string does not contain the second argument
  8533. * string. For example, substring-after("1999/04/01","/") returns 04/01,
  8534. * and substring-after("1999/04/01","19") returns 99/04/01.
  8535. */
  8536. void
  8537. xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8538. xmlXPathObjectPtr str;
  8539. xmlXPathObjectPtr find;
  8540. xmlBufPtr target;
  8541. const xmlChar *point;
  8542. int offset;
  8543. CHECK_ARITY(2);
  8544. CAST_TO_STRING;
  8545. find = valuePop(ctxt);
  8546. CAST_TO_STRING;
  8547. str = valuePop(ctxt);
  8548. target = xmlBufCreate();
  8549. if (target) {
  8550. point = xmlStrstr(str->stringval, find->stringval);
  8551. if (point) {
  8552. offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
  8553. xmlBufAdd(target, &str->stringval[offset],
  8554. xmlStrlen(str->stringval) - offset);
  8555. }
  8556. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  8557. xmlBufContent(target)));
  8558. xmlBufFree(target);
  8559. }
  8560. xmlXPathReleaseObject(ctxt->context, str);
  8561. xmlXPathReleaseObject(ctxt->context, find);
  8562. }
  8563. /**
  8564. * xmlXPathNormalizeFunction:
  8565. * @ctxt: the XPath Parser context
  8566. * @nargs: the number of arguments
  8567. *
  8568. * Implement the normalize-space() XPath function
  8569. * string normalize-space(string?)
  8570. * The normalize-space function returns the argument string with white
  8571. * space normalized by stripping leading and trailing whitespace
  8572. * and replacing sequences of whitespace characters by a single
  8573. * space. Whitespace characters are the same allowed by the S production
  8574. * in XML. If the argument is omitted, it defaults to the context
  8575. * node converted to a string, in other words the value of the context node.
  8576. */
  8577. void
  8578. xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8579. xmlXPathObjectPtr obj = NULL;
  8580. xmlChar *source = NULL;
  8581. xmlBufPtr target;
  8582. xmlChar blank;
  8583. if (ctxt == NULL) return;
  8584. if (nargs == 0) {
  8585. /* Use current context node */
  8586. valuePush(ctxt,
  8587. xmlXPathCacheWrapString(ctxt->context,
  8588. xmlXPathCastNodeToString(ctxt->context->node)));
  8589. nargs = 1;
  8590. }
  8591. CHECK_ARITY(1);
  8592. CAST_TO_STRING;
  8593. CHECK_TYPE(XPATH_STRING);
  8594. obj = valuePop(ctxt);
  8595. source = obj->stringval;
  8596. target = xmlBufCreate();
  8597. if (target && source) {
  8598. /* Skip leading whitespaces */
  8599. while (IS_BLANK_CH(*source))
  8600. source++;
  8601. /* Collapse intermediate whitespaces, and skip trailing whitespaces */
  8602. blank = 0;
  8603. while (*source) {
  8604. if (IS_BLANK_CH(*source)) {
  8605. blank = 0x20;
  8606. } else {
  8607. if (blank) {
  8608. xmlBufAdd(target, &blank, 1);
  8609. blank = 0;
  8610. }
  8611. xmlBufAdd(target, source, 1);
  8612. }
  8613. source++;
  8614. }
  8615. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  8616. xmlBufContent(target)));
  8617. xmlBufFree(target);
  8618. }
  8619. xmlXPathReleaseObject(ctxt->context, obj);
  8620. }
  8621. /**
  8622. * xmlXPathTranslateFunction:
  8623. * @ctxt: the XPath Parser context
  8624. * @nargs: the number of arguments
  8625. *
  8626. * Implement the translate() XPath function
  8627. * string translate(string, string, string)
  8628. * The translate function returns the first argument string with
  8629. * occurrences of characters in the second argument string replaced
  8630. * by the character at the corresponding position in the third argument
  8631. * string. For example, translate("bar","abc","ABC") returns the string
  8632. * BAr. If there is a character in the second argument string with no
  8633. * character at a corresponding position in the third argument string
  8634. * (because the second argument string is longer than the third argument
  8635. * string), then occurrences of that character in the first argument
  8636. * string are removed. For example, translate("--aaa--","abc-","ABC")
  8637. * returns "AAA". If a character occurs more than once in second
  8638. * argument string, then the first occurrence determines the replacement
  8639. * character. If the third argument string is longer than the second
  8640. * argument string, then excess characters are ignored.
  8641. */
  8642. void
  8643. xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8644. xmlXPathObjectPtr str;
  8645. xmlXPathObjectPtr from;
  8646. xmlXPathObjectPtr to;
  8647. xmlBufPtr target;
  8648. int offset, max;
  8649. xmlChar ch;
  8650. const xmlChar *point;
  8651. xmlChar *cptr;
  8652. CHECK_ARITY(3);
  8653. CAST_TO_STRING;
  8654. to = valuePop(ctxt);
  8655. CAST_TO_STRING;
  8656. from = valuePop(ctxt);
  8657. CAST_TO_STRING;
  8658. str = valuePop(ctxt);
  8659. target = xmlBufCreate();
  8660. if (target) {
  8661. max = xmlUTF8Strlen(to->stringval);
  8662. for (cptr = str->stringval; (ch=*cptr); ) {
  8663. offset = xmlUTF8Strloc(from->stringval, cptr);
  8664. if (offset >= 0) {
  8665. if (offset < max) {
  8666. point = xmlUTF8Strpos(to->stringval, offset);
  8667. if (point)
  8668. xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
  8669. }
  8670. } else
  8671. xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
  8672. /* Step to next character in input */
  8673. cptr++;
  8674. if ( ch & 0x80 ) {
  8675. /* if not simple ascii, verify proper format */
  8676. if ( (ch & 0xc0) != 0xc0 ) {
  8677. xmlGenericError(xmlGenericErrorContext,
  8678. "xmlXPathTranslateFunction: Invalid UTF8 string\n");
  8679. /* not asserting an XPath error is probably better */
  8680. break;
  8681. }
  8682. /* then skip over remaining bytes for this char */
  8683. while ( (ch <<= 1) & 0x80 )
  8684. if ( (*cptr++ & 0xc0) != 0x80 ) {
  8685. xmlGenericError(xmlGenericErrorContext,
  8686. "xmlXPathTranslateFunction: Invalid UTF8 string\n");
  8687. /* not asserting an XPath error is probably better */
  8688. break;
  8689. }
  8690. if (ch & 0x80) /* must have had error encountered */
  8691. break;
  8692. }
  8693. }
  8694. }
  8695. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  8696. xmlBufContent(target)));
  8697. xmlBufFree(target);
  8698. xmlXPathReleaseObject(ctxt->context, str);
  8699. xmlXPathReleaseObject(ctxt->context, from);
  8700. xmlXPathReleaseObject(ctxt->context, to);
  8701. }
  8702. /**
  8703. * xmlXPathBooleanFunction:
  8704. * @ctxt: the XPath Parser context
  8705. * @nargs: the number of arguments
  8706. *
  8707. * Implement the boolean() XPath function
  8708. * boolean boolean(object)
  8709. * The boolean function converts its argument to a boolean as follows:
  8710. * - a number is true if and only if it is neither positive or
  8711. * negative zero nor NaN
  8712. * - a node-set is true if and only if it is non-empty
  8713. * - a string is true if and only if its length is non-zero
  8714. */
  8715. void
  8716. xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8717. xmlXPathObjectPtr cur;
  8718. CHECK_ARITY(1);
  8719. cur = valuePop(ctxt);
  8720. if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
  8721. cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
  8722. valuePush(ctxt, cur);
  8723. }
  8724. /**
  8725. * xmlXPathNotFunction:
  8726. * @ctxt: the XPath Parser context
  8727. * @nargs: the number of arguments
  8728. *
  8729. * Implement the not() XPath function
  8730. * boolean not(boolean)
  8731. * The not function returns true if its argument is false,
  8732. * and false otherwise.
  8733. */
  8734. void
  8735. xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8736. CHECK_ARITY(1);
  8737. CAST_TO_BOOLEAN;
  8738. CHECK_TYPE(XPATH_BOOLEAN);
  8739. ctxt->value->boolval = ! ctxt->value->boolval;
  8740. }
  8741. /**
  8742. * xmlXPathTrueFunction:
  8743. * @ctxt: the XPath Parser context
  8744. * @nargs: the number of arguments
  8745. *
  8746. * Implement the true() XPath function
  8747. * boolean true()
  8748. */
  8749. void
  8750. xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8751. CHECK_ARITY(0);
  8752. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
  8753. }
  8754. /**
  8755. * xmlXPathFalseFunction:
  8756. * @ctxt: the XPath Parser context
  8757. * @nargs: the number of arguments
  8758. *
  8759. * Implement the false() XPath function
  8760. * boolean false()
  8761. */
  8762. void
  8763. xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8764. CHECK_ARITY(0);
  8765. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
  8766. }
  8767. /**
  8768. * xmlXPathLangFunction:
  8769. * @ctxt: the XPath Parser context
  8770. * @nargs: the number of arguments
  8771. *
  8772. * Implement the lang() XPath function
  8773. * boolean lang(string)
  8774. * The lang function returns true or false depending on whether the
  8775. * language of the context node as specified by xml:lang attributes
  8776. * is the same as or is a sublanguage of the language specified by
  8777. * the argument string. The language of the context node is determined
  8778. * by the value of the xml:lang attribute on the context node, or, if
  8779. * the context node has no xml:lang attribute, by the value of the
  8780. * xml:lang attribute on the nearest ancestor of the context node that
  8781. * has an xml:lang attribute. If there is no such attribute, then lang
  8782. * returns false. If there is such an attribute, then lang returns
  8783. * true if the attribute value is equal to the argument ignoring case,
  8784. * or if there is some suffix starting with - such that the attribute
  8785. * value is equal to the argument ignoring that suffix of the attribute
  8786. * value and ignoring case.
  8787. */
  8788. void
  8789. xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8790. xmlXPathObjectPtr val = NULL;
  8791. const xmlChar *theLang = NULL;
  8792. const xmlChar *lang;
  8793. int ret = 0;
  8794. int i;
  8795. CHECK_ARITY(1);
  8796. CAST_TO_STRING;
  8797. CHECK_TYPE(XPATH_STRING);
  8798. val = valuePop(ctxt);
  8799. lang = val->stringval;
  8800. theLang = xmlNodeGetLang(ctxt->context->node);
  8801. if ((theLang != NULL) && (lang != NULL)) {
  8802. for (i = 0;lang[i] != 0;i++)
  8803. if (toupper(lang[i]) != toupper(theLang[i]))
  8804. goto not_equal;
  8805. if ((theLang[i] == 0) || (theLang[i] == '-'))
  8806. ret = 1;
  8807. }
  8808. not_equal:
  8809. if (theLang != NULL)
  8810. xmlFree((void *)theLang);
  8811. xmlXPathReleaseObject(ctxt->context, val);
  8812. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
  8813. }
  8814. /**
  8815. * xmlXPathNumberFunction:
  8816. * @ctxt: the XPath Parser context
  8817. * @nargs: the number of arguments
  8818. *
  8819. * Implement the number() XPath function
  8820. * number number(object?)
  8821. */
  8822. void
  8823. xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8824. xmlXPathObjectPtr cur;
  8825. double res;
  8826. if (ctxt == NULL) return;
  8827. if (nargs == 0) {
  8828. if (ctxt->context->node == NULL) {
  8829. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
  8830. } else {
  8831. xmlChar* content = xmlNodeGetContent(ctxt->context->node);
  8832. res = xmlXPathStringEvalNumber(content);
  8833. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
  8834. xmlFree(content);
  8835. }
  8836. return;
  8837. }
  8838. CHECK_ARITY(1);
  8839. cur = valuePop(ctxt);
  8840. valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
  8841. }
  8842. /**
  8843. * xmlXPathSumFunction:
  8844. * @ctxt: the XPath Parser context
  8845. * @nargs: the number of arguments
  8846. *
  8847. * Implement the sum() XPath function
  8848. * number sum(node-set)
  8849. * The sum function returns the sum of the values of the nodes in
  8850. * the argument node-set.
  8851. */
  8852. void
  8853. xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8854. xmlXPathObjectPtr cur;
  8855. int i;
  8856. double res = 0.0;
  8857. CHECK_ARITY(1);
  8858. if ((ctxt->value == NULL) ||
  8859. ((ctxt->value->type != XPATH_NODESET) &&
  8860. (ctxt->value->type != XPATH_XSLT_TREE)))
  8861. XP_ERROR(XPATH_INVALID_TYPE);
  8862. cur = valuePop(ctxt);
  8863. if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
  8864. for (i = 0; i < cur->nodesetval->nodeNr; i++) {
  8865. res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
  8866. }
  8867. }
  8868. valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
  8869. xmlXPathReleaseObject(ctxt->context, cur);
  8870. }
  8871. /**
  8872. * xmlXPathFloorFunction:
  8873. * @ctxt: the XPath Parser context
  8874. * @nargs: the number of arguments
  8875. *
  8876. * Implement the floor() XPath function
  8877. * number floor(number)
  8878. * The floor function returns the largest (closest to positive infinity)
  8879. * number that is not greater than the argument and that is an integer.
  8880. */
  8881. void
  8882. xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8883. CHECK_ARITY(1);
  8884. CAST_TO_NUMBER;
  8885. CHECK_TYPE(XPATH_NUMBER);
  8886. ctxt->value->floatval = floor(ctxt->value->floatval);
  8887. }
  8888. /**
  8889. * xmlXPathCeilingFunction:
  8890. * @ctxt: the XPath Parser context
  8891. * @nargs: the number of arguments
  8892. *
  8893. * Implement the ceiling() XPath function
  8894. * number ceiling(number)
  8895. * The ceiling function returns the smallest (closest to negative infinity)
  8896. * number that is not less than the argument and that is an integer.
  8897. */
  8898. void
  8899. xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8900. CHECK_ARITY(1);
  8901. CAST_TO_NUMBER;
  8902. CHECK_TYPE(XPATH_NUMBER);
  8903. #ifdef _AIX
  8904. /* Work around buggy ceil() function on AIX */
  8905. ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
  8906. #else
  8907. ctxt->value->floatval = ceil(ctxt->value->floatval);
  8908. #endif
  8909. }
  8910. /**
  8911. * xmlXPathRoundFunction:
  8912. * @ctxt: the XPath Parser context
  8913. * @nargs: the number of arguments
  8914. *
  8915. * Implement the round() XPath function
  8916. * number round(number)
  8917. * The round function returns the number that is closest to the
  8918. * argument and that is an integer. If there are two such numbers,
  8919. * then the one that is closest to positive infinity is returned.
  8920. */
  8921. void
  8922. xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  8923. double f;
  8924. CHECK_ARITY(1);
  8925. CAST_TO_NUMBER;
  8926. CHECK_TYPE(XPATH_NUMBER);
  8927. f = ctxt->value->floatval;
  8928. if ((f >= -0.5) && (f < 0.5)) {
  8929. /* Handles negative zero. */
  8930. ctxt->value->floatval *= 0.0;
  8931. }
  8932. else {
  8933. double rounded = floor(f);
  8934. if (f - rounded >= 0.5)
  8935. rounded += 1.0;
  8936. ctxt->value->floatval = rounded;
  8937. }
  8938. }
  8939. /************************************************************************
  8940. * *
  8941. * The Parser *
  8942. * *
  8943. ************************************************************************/
  8944. /*
  8945. * a few forward declarations since we use a recursive call based
  8946. * implementation.
  8947. */
  8948. static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
  8949. static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
  8950. static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
  8951. static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
  8952. static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
  8953. int qualified);
  8954. /**
  8955. * xmlXPathCurrentChar:
  8956. * @ctxt: the XPath parser context
  8957. * @cur: pointer to the beginning of the char
  8958. * @len: pointer to the length of the char read
  8959. *
  8960. * The current char value, if using UTF-8 this may actually span multiple
  8961. * bytes in the input buffer.
  8962. *
  8963. * Returns the current char value and its length
  8964. */
  8965. static int
  8966. xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
  8967. unsigned char c;
  8968. unsigned int val;
  8969. const xmlChar *cur;
  8970. if (ctxt == NULL)
  8971. return(0);
  8972. cur = ctxt->cur;
  8973. /*
  8974. * We are supposed to handle UTF8, check it's valid
  8975. * From rfc2044: encoding of the Unicode values on UTF-8:
  8976. *
  8977. * UCS-4 range (hex.) UTF-8 octet sequence (binary)
  8978. * 0000 0000-0000 007F 0xxxxxxx
  8979. * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
  8980. * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
  8981. *
  8982. * Check for the 0x110000 limit too
  8983. */
  8984. c = *cur;
  8985. if (c & 0x80) {
  8986. if ((cur[1] & 0xc0) != 0x80)
  8987. goto encoding_error;
  8988. if ((c & 0xe0) == 0xe0) {
  8989. if ((cur[2] & 0xc0) != 0x80)
  8990. goto encoding_error;
  8991. if ((c & 0xf0) == 0xf0) {
  8992. if (((c & 0xf8) != 0xf0) ||
  8993. ((cur[3] & 0xc0) != 0x80))
  8994. goto encoding_error;
  8995. /* 4-byte code */
  8996. *len = 4;
  8997. val = (cur[0] & 0x7) << 18;
  8998. val |= (cur[1] & 0x3f) << 12;
  8999. val |= (cur[2] & 0x3f) << 6;
  9000. val |= cur[3] & 0x3f;
  9001. } else {
  9002. /* 3-byte code */
  9003. *len = 3;
  9004. val = (cur[0] & 0xf) << 12;
  9005. val |= (cur[1] & 0x3f) << 6;
  9006. val |= cur[2] & 0x3f;
  9007. }
  9008. } else {
  9009. /* 2-byte code */
  9010. *len = 2;
  9011. val = (cur[0] & 0x1f) << 6;
  9012. val |= cur[1] & 0x3f;
  9013. }
  9014. if (!IS_CHAR(val)) {
  9015. XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
  9016. }
  9017. return(val);
  9018. } else {
  9019. /* 1-byte code */
  9020. *len = 1;
  9021. return((int) *cur);
  9022. }
  9023. encoding_error:
  9024. /*
  9025. * If we detect an UTF8 error that probably means that the
  9026. * input encoding didn't get properly advertised in the
  9027. * declaration header. Report the error and switch the encoding
  9028. * to ISO-Latin-1 (if you don't like this policy, just declare the
  9029. * encoding !)
  9030. */
  9031. *len = 0;
  9032. XP_ERROR0(XPATH_ENCODING_ERROR);
  9033. }
  9034. /**
  9035. * xmlXPathParseNCName:
  9036. * @ctxt: the XPath Parser context
  9037. *
  9038. * parse an XML namespace non qualified name.
  9039. *
  9040. * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
  9041. *
  9042. * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
  9043. * CombiningChar | Extender
  9044. *
  9045. * Returns the namespace name or NULL
  9046. */
  9047. xmlChar *
  9048. xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
  9049. const xmlChar *in;
  9050. xmlChar *ret;
  9051. int count = 0;
  9052. if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
  9053. /*
  9054. * Accelerator for simple ASCII names
  9055. */
  9056. in = ctxt->cur;
  9057. if (((*in >= 0x61) && (*in <= 0x7A)) ||
  9058. ((*in >= 0x41) && (*in <= 0x5A)) ||
  9059. (*in == '_')) {
  9060. in++;
  9061. while (((*in >= 0x61) && (*in <= 0x7A)) ||
  9062. ((*in >= 0x41) && (*in <= 0x5A)) ||
  9063. ((*in >= 0x30) && (*in <= 0x39)) ||
  9064. (*in == '_') || (*in == '.') ||
  9065. (*in == '-'))
  9066. in++;
  9067. if ((*in == ' ') || (*in == '>') || (*in == '/') ||
  9068. (*in == '[') || (*in == ']') || (*in == ':') ||
  9069. (*in == '@') || (*in == '*')) {
  9070. count = in - ctxt->cur;
  9071. if (count == 0)
  9072. return(NULL);
  9073. ret = xmlStrndup(ctxt->cur, count);
  9074. ctxt->cur = in;
  9075. return(ret);
  9076. }
  9077. }
  9078. return(xmlXPathParseNameComplex(ctxt, 0));
  9079. }
  9080. /**
  9081. * xmlXPathParseQName:
  9082. * @ctxt: the XPath Parser context
  9083. * @prefix: a xmlChar **
  9084. *
  9085. * parse an XML qualified name
  9086. *
  9087. * [NS 5] QName ::= (Prefix ':')? LocalPart
  9088. *
  9089. * [NS 6] Prefix ::= NCName
  9090. *
  9091. * [NS 7] LocalPart ::= NCName
  9092. *
  9093. * Returns the function returns the local part, and prefix is updated
  9094. * to get the Prefix if any.
  9095. */
  9096. static xmlChar *
  9097. xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
  9098. xmlChar *ret = NULL;
  9099. *prefix = NULL;
  9100. ret = xmlXPathParseNCName(ctxt);
  9101. if (ret && CUR == ':') {
  9102. *prefix = ret;
  9103. NEXT;
  9104. ret = xmlXPathParseNCName(ctxt);
  9105. }
  9106. return(ret);
  9107. }
  9108. /**
  9109. * xmlXPathParseName:
  9110. * @ctxt: the XPath Parser context
  9111. *
  9112. * parse an XML name
  9113. *
  9114. * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
  9115. * CombiningChar | Extender
  9116. *
  9117. * [5] Name ::= (Letter | '_' | ':') (NameChar)*
  9118. *
  9119. * Returns the namespace name or NULL
  9120. */
  9121. xmlChar *
  9122. xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
  9123. const xmlChar *in;
  9124. xmlChar *ret;
  9125. size_t count = 0;
  9126. if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
  9127. /*
  9128. * Accelerator for simple ASCII names
  9129. */
  9130. in = ctxt->cur;
  9131. if (((*in >= 0x61) && (*in <= 0x7A)) ||
  9132. ((*in >= 0x41) && (*in <= 0x5A)) ||
  9133. (*in == '_') || (*in == ':')) {
  9134. in++;
  9135. while (((*in >= 0x61) && (*in <= 0x7A)) ||
  9136. ((*in >= 0x41) && (*in <= 0x5A)) ||
  9137. ((*in >= 0x30) && (*in <= 0x39)) ||
  9138. (*in == '_') || (*in == '-') ||
  9139. (*in == ':') || (*in == '.'))
  9140. in++;
  9141. if ((*in > 0) && (*in < 0x80)) {
  9142. count = in - ctxt->cur;
  9143. if (count > XML_MAX_NAME_LENGTH) {
  9144. ctxt->cur = in;
  9145. XP_ERRORNULL(XPATH_EXPR_ERROR);
  9146. }
  9147. ret = xmlStrndup(ctxt->cur, count);
  9148. ctxt->cur = in;
  9149. return(ret);
  9150. }
  9151. }
  9152. return(xmlXPathParseNameComplex(ctxt, 1));
  9153. }
  9154. static xmlChar *
  9155. xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
  9156. xmlChar buf[XML_MAX_NAMELEN + 5];
  9157. int len = 0, l;
  9158. int c;
  9159. /*
  9160. * Handler for more complex cases
  9161. */
  9162. c = CUR_CHAR(l);
  9163. if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
  9164. (c == '[') || (c == ']') || (c == '@') || /* accelerators */
  9165. (c == '*') || /* accelerators */
  9166. (!IS_LETTER(c) && (c != '_') &&
  9167. ((!qualified) || (c != ':')))) {
  9168. return(NULL);
  9169. }
  9170. while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
  9171. ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
  9172. (c == '.') || (c == '-') ||
  9173. (c == '_') || ((qualified) && (c == ':')) ||
  9174. (IS_COMBINING(c)) ||
  9175. (IS_EXTENDER(c)))) {
  9176. COPY_BUF(l,buf,len,c);
  9177. NEXTL(l);
  9178. c = CUR_CHAR(l);
  9179. if (len >= XML_MAX_NAMELEN) {
  9180. /*
  9181. * Okay someone managed to make a huge name, so he's ready to pay
  9182. * for the processing speed.
  9183. */
  9184. xmlChar *buffer;
  9185. int max = len * 2;
  9186. if (len > XML_MAX_NAME_LENGTH) {
  9187. XP_ERRORNULL(XPATH_EXPR_ERROR);
  9188. }
  9189. buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
  9190. if (buffer == NULL) {
  9191. XP_ERRORNULL(XPATH_MEMORY_ERROR);
  9192. }
  9193. memcpy(buffer, buf, len);
  9194. while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
  9195. (c == '.') || (c == '-') ||
  9196. (c == '_') || ((qualified) && (c == ':')) ||
  9197. (IS_COMBINING(c)) ||
  9198. (IS_EXTENDER(c))) {
  9199. if (len + 10 > max) {
  9200. xmlChar *tmp;
  9201. if (max > XML_MAX_NAME_LENGTH) {
  9202. xmlFree(buffer);
  9203. XP_ERRORNULL(XPATH_EXPR_ERROR);
  9204. }
  9205. max *= 2;
  9206. tmp = (xmlChar *) xmlRealloc(buffer,
  9207. max * sizeof(xmlChar));
  9208. if (tmp == NULL) {
  9209. xmlFree(buffer);
  9210. XP_ERRORNULL(XPATH_MEMORY_ERROR);
  9211. }
  9212. buffer = tmp;
  9213. }
  9214. COPY_BUF(l,buffer,len,c);
  9215. NEXTL(l);
  9216. c = CUR_CHAR(l);
  9217. }
  9218. buffer[len] = 0;
  9219. return(buffer);
  9220. }
  9221. }
  9222. if (len == 0)
  9223. return(NULL);
  9224. return(xmlStrndup(buf, len));
  9225. }
  9226. #define MAX_FRAC 20
  9227. /**
  9228. * xmlXPathStringEvalNumber:
  9229. * @str: A string to scan
  9230. *
  9231. * [30a] Float ::= Number ('e' Digits?)?
  9232. *
  9233. * [30] Number ::= Digits ('.' Digits?)?
  9234. * | '.' Digits
  9235. * [31] Digits ::= [0-9]+
  9236. *
  9237. * Compile a Number in the string
  9238. * In complement of the Number expression, this function also handles
  9239. * negative values : '-' Number.
  9240. *
  9241. * Returns the double value.
  9242. */
  9243. double
  9244. xmlXPathStringEvalNumber(const xmlChar *str) {
  9245. const xmlChar *cur = str;
  9246. double ret;
  9247. int ok = 0;
  9248. int isneg = 0;
  9249. int exponent = 0;
  9250. int is_exponent_negative = 0;
  9251. #ifdef __GNUC__
  9252. unsigned long tmp = 0;
  9253. double temp;
  9254. #endif
  9255. if (cur == NULL) return(0);
  9256. while (IS_BLANK_CH(*cur)) cur++;
  9257. if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
  9258. return(xmlXPathNAN);
  9259. }
  9260. if (*cur == '-') {
  9261. isneg = 1;
  9262. cur++;
  9263. }
  9264. #ifdef __GNUC__
  9265. /*
  9266. * tmp/temp is a workaround against a gcc compiler bug
  9267. * http://veillard.com/gcc.bug
  9268. */
  9269. ret = 0;
  9270. while ((*cur >= '0') && (*cur <= '9')) {
  9271. ret = ret * 10;
  9272. tmp = (*cur - '0');
  9273. ok = 1;
  9274. cur++;
  9275. temp = (double) tmp;
  9276. ret = ret + temp;
  9277. }
  9278. #else
  9279. ret = 0;
  9280. while ((*cur >= '0') && (*cur <= '9')) {
  9281. ret = ret * 10 + (*cur - '0');
  9282. ok = 1;
  9283. cur++;
  9284. }
  9285. #endif
  9286. if (*cur == '.') {
  9287. int v, frac = 0, max;
  9288. double fraction = 0;
  9289. cur++;
  9290. if (((*cur < '0') || (*cur > '9')) && (!ok)) {
  9291. return(xmlXPathNAN);
  9292. }
  9293. while (*cur == '0') {
  9294. frac = frac + 1;
  9295. cur++;
  9296. }
  9297. max = frac + MAX_FRAC;
  9298. while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
  9299. v = (*cur - '0');
  9300. fraction = fraction * 10 + v;
  9301. frac = frac + 1;
  9302. cur++;
  9303. }
  9304. fraction /= pow(10.0, frac);
  9305. ret = ret + fraction;
  9306. while ((*cur >= '0') && (*cur <= '9'))
  9307. cur++;
  9308. }
  9309. if ((*cur == 'e') || (*cur == 'E')) {
  9310. cur++;
  9311. if (*cur == '-') {
  9312. is_exponent_negative = 1;
  9313. cur++;
  9314. } else if (*cur == '+') {
  9315. cur++;
  9316. }
  9317. while ((*cur >= '0') && (*cur <= '9')) {
  9318. if (exponent < 1000000)
  9319. exponent = exponent * 10 + (*cur - '0');
  9320. cur++;
  9321. }
  9322. }
  9323. while (IS_BLANK_CH(*cur)) cur++;
  9324. if (*cur != 0) return(xmlXPathNAN);
  9325. if (isneg) ret = -ret;
  9326. if (is_exponent_negative) exponent = -exponent;
  9327. ret *= pow(10.0, (double)exponent);
  9328. return(ret);
  9329. }
  9330. /**
  9331. * xmlXPathCompNumber:
  9332. * @ctxt: the XPath Parser context
  9333. *
  9334. * [30] Number ::= Digits ('.' Digits?)?
  9335. * | '.' Digits
  9336. * [31] Digits ::= [0-9]+
  9337. *
  9338. * Compile a Number, then push it on the stack
  9339. *
  9340. */
  9341. static void
  9342. xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
  9343. {
  9344. double ret = 0.0;
  9345. int ok = 0;
  9346. int exponent = 0;
  9347. int is_exponent_negative = 0;
  9348. xmlXPathObjectPtr num;
  9349. #ifdef __GNUC__
  9350. unsigned long tmp = 0;
  9351. double temp;
  9352. #endif
  9353. CHECK_ERROR;
  9354. if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
  9355. XP_ERROR(XPATH_NUMBER_ERROR);
  9356. }
  9357. #ifdef __GNUC__
  9358. /*
  9359. * tmp/temp is a workaround against a gcc compiler bug
  9360. * http://veillard.com/gcc.bug
  9361. */
  9362. ret = 0;
  9363. while ((CUR >= '0') && (CUR <= '9')) {
  9364. ret = ret * 10;
  9365. tmp = (CUR - '0');
  9366. ok = 1;
  9367. NEXT;
  9368. temp = (double) tmp;
  9369. ret = ret + temp;
  9370. }
  9371. #else
  9372. ret = 0;
  9373. while ((CUR >= '0') && (CUR <= '9')) {
  9374. ret = ret * 10 + (CUR - '0');
  9375. ok = 1;
  9376. NEXT;
  9377. }
  9378. #endif
  9379. if (CUR == '.') {
  9380. int v, frac = 0, max;
  9381. double fraction = 0;
  9382. NEXT;
  9383. if (((CUR < '0') || (CUR > '9')) && (!ok)) {
  9384. XP_ERROR(XPATH_NUMBER_ERROR);
  9385. }
  9386. while (CUR == '0') {
  9387. frac = frac + 1;
  9388. NEXT;
  9389. }
  9390. max = frac + MAX_FRAC;
  9391. while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
  9392. v = (CUR - '0');
  9393. fraction = fraction * 10 + v;
  9394. frac = frac + 1;
  9395. NEXT;
  9396. }
  9397. fraction /= pow(10.0, frac);
  9398. ret = ret + fraction;
  9399. while ((CUR >= '0') && (CUR <= '9'))
  9400. NEXT;
  9401. }
  9402. if ((CUR == 'e') || (CUR == 'E')) {
  9403. NEXT;
  9404. if (CUR == '-') {
  9405. is_exponent_negative = 1;
  9406. NEXT;
  9407. } else if (CUR == '+') {
  9408. NEXT;
  9409. }
  9410. while ((CUR >= '0') && (CUR <= '9')) {
  9411. if (exponent < 1000000)
  9412. exponent = exponent * 10 + (CUR - '0');
  9413. NEXT;
  9414. }
  9415. if (is_exponent_negative)
  9416. exponent = -exponent;
  9417. ret *= pow(10.0, (double) exponent);
  9418. }
  9419. num = xmlXPathCacheNewFloat(ctxt->context, ret);
  9420. if (num == NULL) {
  9421. ctxt->error = XPATH_MEMORY_ERROR;
  9422. } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
  9423. NULL) == -1) {
  9424. xmlXPathReleaseObject(ctxt->context, num);
  9425. }
  9426. }
  9427. /**
  9428. * xmlXPathParseLiteral:
  9429. * @ctxt: the XPath Parser context
  9430. *
  9431. * Parse a Literal
  9432. *
  9433. * [29] Literal ::= '"' [^"]* '"'
  9434. * | "'" [^']* "'"
  9435. *
  9436. * Returns the value found or NULL in case of error
  9437. */
  9438. static xmlChar *
  9439. xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
  9440. const xmlChar *q;
  9441. xmlChar *ret = NULL;
  9442. if (CUR == '"') {
  9443. NEXT;
  9444. q = CUR_PTR;
  9445. while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
  9446. NEXT;
  9447. if (!IS_CHAR_CH(CUR)) {
  9448. XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
  9449. } else {
  9450. ret = xmlStrndup(q, CUR_PTR - q);
  9451. NEXT;
  9452. }
  9453. } else if (CUR == '\'') {
  9454. NEXT;
  9455. q = CUR_PTR;
  9456. while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
  9457. NEXT;
  9458. if (!IS_CHAR_CH(CUR)) {
  9459. XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
  9460. } else {
  9461. ret = xmlStrndup(q, CUR_PTR - q);
  9462. NEXT;
  9463. }
  9464. } else {
  9465. XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
  9466. }
  9467. return(ret);
  9468. }
  9469. /**
  9470. * xmlXPathCompLiteral:
  9471. * @ctxt: the XPath Parser context
  9472. *
  9473. * Parse a Literal and push it on the stack.
  9474. *
  9475. * [29] Literal ::= '"' [^"]* '"'
  9476. * | "'" [^']* "'"
  9477. *
  9478. * TODO: xmlXPathCompLiteral memory allocation could be improved.
  9479. */
  9480. static void
  9481. xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
  9482. const xmlChar *q;
  9483. xmlChar *ret = NULL;
  9484. xmlXPathObjectPtr lit;
  9485. if (CUR == '"') {
  9486. NEXT;
  9487. q = CUR_PTR;
  9488. while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
  9489. NEXT;
  9490. if (!IS_CHAR_CH(CUR)) {
  9491. XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
  9492. } else {
  9493. ret = xmlStrndup(q, CUR_PTR - q);
  9494. NEXT;
  9495. }
  9496. } else if (CUR == '\'') {
  9497. NEXT;
  9498. q = CUR_PTR;
  9499. while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
  9500. NEXT;
  9501. if (!IS_CHAR_CH(CUR)) {
  9502. XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
  9503. } else {
  9504. ret = xmlStrndup(q, CUR_PTR - q);
  9505. NEXT;
  9506. }
  9507. } else {
  9508. XP_ERROR(XPATH_START_LITERAL_ERROR);
  9509. }
  9510. if (ret == NULL) return;
  9511. lit = xmlXPathCacheNewString(ctxt->context, ret);
  9512. if (lit == NULL) {
  9513. ctxt->error = XPATH_MEMORY_ERROR;
  9514. } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
  9515. NULL) == -1) {
  9516. xmlXPathReleaseObject(ctxt->context, lit);
  9517. }
  9518. xmlFree(ret);
  9519. }
  9520. /**
  9521. * xmlXPathCompVariableReference:
  9522. * @ctxt: the XPath Parser context
  9523. *
  9524. * Parse a VariableReference, evaluate it and push it on the stack.
  9525. *
  9526. * The variable bindings consist of a mapping from variable names
  9527. * to variable values. The value of a variable is an object, which can be
  9528. * of any of the types that are possible for the value of an expression,
  9529. * and may also be of additional types not specified here.
  9530. *
  9531. * Early evaluation is possible since:
  9532. * The variable bindings [...] used to evaluate a subexpression are
  9533. * always the same as those used to evaluate the containing expression.
  9534. *
  9535. * [36] VariableReference ::= '$' QName
  9536. */
  9537. static void
  9538. xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
  9539. xmlChar *name;
  9540. xmlChar *prefix;
  9541. SKIP_BLANKS;
  9542. if (CUR != '$') {
  9543. XP_ERROR(XPATH_VARIABLE_REF_ERROR);
  9544. }
  9545. NEXT;
  9546. name = xmlXPathParseQName(ctxt, &prefix);
  9547. if (name == NULL) {
  9548. xmlFree(prefix);
  9549. XP_ERROR(XPATH_VARIABLE_REF_ERROR);
  9550. }
  9551. ctxt->comp->last = -1;
  9552. if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
  9553. xmlFree(prefix);
  9554. xmlFree(name);
  9555. }
  9556. SKIP_BLANKS;
  9557. if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
  9558. XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
  9559. }
  9560. }
  9561. /**
  9562. * xmlXPathIsNodeType:
  9563. * @name: a name string
  9564. *
  9565. * Is the name given a NodeType one.
  9566. *
  9567. * [38] NodeType ::= 'comment'
  9568. * | 'text'
  9569. * | 'processing-instruction'
  9570. * | 'node'
  9571. *
  9572. * Returns 1 if true 0 otherwise
  9573. */
  9574. int
  9575. xmlXPathIsNodeType(const xmlChar *name) {
  9576. if (name == NULL)
  9577. return(0);
  9578. if (xmlStrEqual(name, BAD_CAST "node"))
  9579. return(1);
  9580. if (xmlStrEqual(name, BAD_CAST "text"))
  9581. return(1);
  9582. if (xmlStrEqual(name, BAD_CAST "comment"))
  9583. return(1);
  9584. if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
  9585. return(1);
  9586. return(0);
  9587. }
  9588. /**
  9589. * xmlXPathCompFunctionCall:
  9590. * @ctxt: the XPath Parser context
  9591. *
  9592. * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
  9593. * [17] Argument ::= Expr
  9594. *
  9595. * Compile a function call, the evaluation of all arguments are
  9596. * pushed on the stack
  9597. */
  9598. static void
  9599. xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
  9600. xmlChar *name;
  9601. xmlChar *prefix;
  9602. int nbargs = 0;
  9603. int sort = 1;
  9604. name = xmlXPathParseQName(ctxt, &prefix);
  9605. if (name == NULL) {
  9606. xmlFree(prefix);
  9607. XP_ERROR(XPATH_EXPR_ERROR);
  9608. }
  9609. SKIP_BLANKS;
  9610. #ifdef DEBUG_EXPR
  9611. if (prefix == NULL)
  9612. xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
  9613. name);
  9614. else
  9615. xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
  9616. prefix, name);
  9617. #endif
  9618. if (CUR != '(') {
  9619. xmlFree(name);
  9620. xmlFree(prefix);
  9621. XP_ERROR(XPATH_EXPR_ERROR);
  9622. }
  9623. NEXT;
  9624. SKIP_BLANKS;
  9625. /*
  9626. * Optimization for count(): we don't need the node-set to be sorted.
  9627. */
  9628. if ((prefix == NULL) && (name[0] == 'c') &&
  9629. xmlStrEqual(name, BAD_CAST "count"))
  9630. {
  9631. sort = 0;
  9632. }
  9633. ctxt->comp->last = -1;
  9634. if (CUR != ')') {
  9635. while (CUR != 0) {
  9636. int op1 = ctxt->comp->last;
  9637. ctxt->comp->last = -1;
  9638. xmlXPathCompileExpr(ctxt, sort);
  9639. if (ctxt->error != XPATH_EXPRESSION_OK) {
  9640. xmlFree(name);
  9641. xmlFree(prefix);
  9642. return;
  9643. }
  9644. PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
  9645. nbargs++;
  9646. if (CUR == ')') break;
  9647. if (CUR != ',') {
  9648. xmlFree(name);
  9649. xmlFree(prefix);
  9650. XP_ERROR(XPATH_EXPR_ERROR);
  9651. }
  9652. NEXT;
  9653. SKIP_BLANKS;
  9654. }
  9655. }
  9656. if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
  9657. xmlFree(prefix);
  9658. xmlFree(name);
  9659. }
  9660. NEXT;
  9661. SKIP_BLANKS;
  9662. }
  9663. /**
  9664. * xmlXPathCompPrimaryExpr:
  9665. * @ctxt: the XPath Parser context
  9666. *
  9667. * [15] PrimaryExpr ::= VariableReference
  9668. * | '(' Expr ')'
  9669. * | Literal
  9670. * | Number
  9671. * | FunctionCall
  9672. *
  9673. * Compile a primary expression.
  9674. */
  9675. static void
  9676. xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
  9677. SKIP_BLANKS;
  9678. if (CUR == '$') xmlXPathCompVariableReference(ctxt);
  9679. else if (CUR == '(') {
  9680. NEXT;
  9681. SKIP_BLANKS;
  9682. xmlXPathCompileExpr(ctxt, 1);
  9683. CHECK_ERROR;
  9684. if (CUR != ')') {
  9685. XP_ERROR(XPATH_EXPR_ERROR);
  9686. }
  9687. NEXT;
  9688. SKIP_BLANKS;
  9689. } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
  9690. xmlXPathCompNumber(ctxt);
  9691. } else if ((CUR == '\'') || (CUR == '"')) {
  9692. xmlXPathCompLiteral(ctxt);
  9693. } else {
  9694. xmlXPathCompFunctionCall(ctxt);
  9695. }
  9696. SKIP_BLANKS;
  9697. }
  9698. /**
  9699. * xmlXPathCompFilterExpr:
  9700. * @ctxt: the XPath Parser context
  9701. *
  9702. * [20] FilterExpr ::= PrimaryExpr
  9703. * | FilterExpr Predicate
  9704. *
  9705. * Compile a filter expression.
  9706. * Square brackets are used to filter expressions in the same way that
  9707. * they are used in location paths. It is an error if the expression to
  9708. * be filtered does not evaluate to a node-set. The context node list
  9709. * used for evaluating the expression in square brackets is the node-set
  9710. * to be filtered listed in document order.
  9711. */
  9712. static void
  9713. xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
  9714. xmlXPathCompPrimaryExpr(ctxt);
  9715. CHECK_ERROR;
  9716. SKIP_BLANKS;
  9717. while (CUR == '[') {
  9718. xmlXPathCompPredicate(ctxt, 1);
  9719. SKIP_BLANKS;
  9720. }
  9721. }
  9722. /**
  9723. * xmlXPathScanName:
  9724. * @ctxt: the XPath Parser context
  9725. *
  9726. * Trickery: parse an XML name but without consuming the input flow
  9727. * Needed to avoid insanity in the parser state.
  9728. *
  9729. * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
  9730. * CombiningChar | Extender
  9731. *
  9732. * [5] Name ::= (Letter | '_' | ':') (NameChar)*
  9733. *
  9734. * [6] Names ::= Name (S Name)*
  9735. *
  9736. * Returns the Name parsed or NULL
  9737. */
  9738. static xmlChar *
  9739. xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
  9740. int len = 0, l;
  9741. int c;
  9742. const xmlChar *cur;
  9743. xmlChar *ret;
  9744. cur = ctxt->cur;
  9745. c = CUR_CHAR(l);
  9746. if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
  9747. (!IS_LETTER(c) && (c != '_') &&
  9748. (c != ':'))) {
  9749. return(NULL);
  9750. }
  9751. while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
  9752. ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
  9753. (c == '.') || (c == '-') ||
  9754. (c == '_') || (c == ':') ||
  9755. (IS_COMBINING(c)) ||
  9756. (IS_EXTENDER(c)))) {
  9757. len += l;
  9758. NEXTL(l);
  9759. c = CUR_CHAR(l);
  9760. }
  9761. ret = xmlStrndup(cur, ctxt->cur - cur);
  9762. ctxt->cur = cur;
  9763. return(ret);
  9764. }
  9765. /**
  9766. * xmlXPathCompPathExpr:
  9767. * @ctxt: the XPath Parser context
  9768. *
  9769. * [19] PathExpr ::= LocationPath
  9770. * | FilterExpr
  9771. * | FilterExpr '/' RelativeLocationPath
  9772. * | FilterExpr '//' RelativeLocationPath
  9773. *
  9774. * Compile a path expression.
  9775. * The / operator and // operators combine an arbitrary expression
  9776. * and a relative location path. It is an error if the expression
  9777. * does not evaluate to a node-set.
  9778. * The / operator does composition in the same way as when / is
  9779. * used in a location path. As in location paths, // is short for
  9780. * /descendant-or-self::node()/.
  9781. */
  9782. static void
  9783. xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
  9784. int lc = 1; /* Should we branch to LocationPath ? */
  9785. xmlChar *name = NULL; /* we may have to preparse a name to find out */
  9786. SKIP_BLANKS;
  9787. if ((CUR == '$') || (CUR == '(') ||
  9788. (IS_ASCII_DIGIT(CUR)) ||
  9789. (CUR == '\'') || (CUR == '"') ||
  9790. (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
  9791. lc = 0;
  9792. } else if (CUR == '*') {
  9793. /* relative or absolute location path */
  9794. lc = 1;
  9795. } else if (CUR == '/') {
  9796. /* relative or absolute location path */
  9797. lc = 1;
  9798. } else if (CUR == '@') {
  9799. /* relative abbreviated attribute location path */
  9800. lc = 1;
  9801. } else if (CUR == '.') {
  9802. /* relative abbreviated attribute location path */
  9803. lc = 1;
  9804. } else {
  9805. /*
  9806. * Problem is finding if we have a name here whether it's:
  9807. * - a nodetype
  9808. * - a function call in which case it's followed by '('
  9809. * - an axis in which case it's followed by ':'
  9810. * - a element name
  9811. * We do an a priori analysis here rather than having to
  9812. * maintain parsed token content through the recursive function
  9813. * calls. This looks uglier but makes the code easier to
  9814. * read/write/debug.
  9815. */
  9816. SKIP_BLANKS;
  9817. name = xmlXPathScanName(ctxt);
  9818. if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
  9819. #ifdef DEBUG_STEP
  9820. xmlGenericError(xmlGenericErrorContext,
  9821. "PathExpr: Axis\n");
  9822. #endif
  9823. lc = 1;
  9824. xmlFree(name);
  9825. } else if (name != NULL) {
  9826. int len =xmlStrlen(name);
  9827. while (NXT(len) != 0) {
  9828. if (NXT(len) == '/') {
  9829. /* element name */
  9830. #ifdef DEBUG_STEP
  9831. xmlGenericError(xmlGenericErrorContext,
  9832. "PathExpr: AbbrRelLocation\n");
  9833. #endif
  9834. lc = 1;
  9835. break;
  9836. } else if (IS_BLANK_CH(NXT(len))) {
  9837. /* ignore blanks */
  9838. ;
  9839. } else if (NXT(len) == ':') {
  9840. #ifdef DEBUG_STEP
  9841. xmlGenericError(xmlGenericErrorContext,
  9842. "PathExpr: AbbrRelLocation\n");
  9843. #endif
  9844. lc = 1;
  9845. break;
  9846. } else if ((NXT(len) == '(')) {
  9847. /* Node Type or Function */
  9848. if (xmlXPathIsNodeType(name)) {
  9849. #ifdef DEBUG_STEP
  9850. xmlGenericError(xmlGenericErrorContext,
  9851. "PathExpr: Type search\n");
  9852. #endif
  9853. lc = 1;
  9854. #ifdef LIBXML_XPTR_ENABLED
  9855. } else if (ctxt->xptr &&
  9856. xmlStrEqual(name, BAD_CAST "range-to")) {
  9857. lc = 1;
  9858. #endif
  9859. } else {
  9860. #ifdef DEBUG_STEP
  9861. xmlGenericError(xmlGenericErrorContext,
  9862. "PathExpr: function call\n");
  9863. #endif
  9864. lc = 0;
  9865. }
  9866. break;
  9867. } else if ((NXT(len) == '[')) {
  9868. /* element name */
  9869. #ifdef DEBUG_STEP
  9870. xmlGenericError(xmlGenericErrorContext,
  9871. "PathExpr: AbbrRelLocation\n");
  9872. #endif
  9873. lc = 1;
  9874. break;
  9875. } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
  9876. (NXT(len) == '=')) {
  9877. lc = 1;
  9878. break;
  9879. } else {
  9880. lc = 1;
  9881. break;
  9882. }
  9883. len++;
  9884. }
  9885. if (NXT(len) == 0) {
  9886. #ifdef DEBUG_STEP
  9887. xmlGenericError(xmlGenericErrorContext,
  9888. "PathExpr: AbbrRelLocation\n");
  9889. #endif
  9890. /* element name */
  9891. lc = 1;
  9892. }
  9893. xmlFree(name);
  9894. } else {
  9895. /* make sure all cases are covered explicitly */
  9896. XP_ERROR(XPATH_EXPR_ERROR);
  9897. }
  9898. }
  9899. if (lc) {
  9900. if (CUR == '/') {
  9901. PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
  9902. } else {
  9903. PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
  9904. }
  9905. xmlXPathCompLocationPath(ctxt);
  9906. } else {
  9907. xmlXPathCompFilterExpr(ctxt);
  9908. CHECK_ERROR;
  9909. if ((CUR == '/') && (NXT(1) == '/')) {
  9910. SKIP(2);
  9911. SKIP_BLANKS;
  9912. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
  9913. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  9914. xmlXPathCompRelativeLocationPath(ctxt);
  9915. } else if (CUR == '/') {
  9916. xmlXPathCompRelativeLocationPath(ctxt);
  9917. }
  9918. }
  9919. SKIP_BLANKS;
  9920. }
  9921. /**
  9922. * xmlXPathCompUnionExpr:
  9923. * @ctxt: the XPath Parser context
  9924. *
  9925. * [18] UnionExpr ::= PathExpr
  9926. * | UnionExpr '|' PathExpr
  9927. *
  9928. * Compile an union expression.
  9929. */
  9930. static void
  9931. xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
  9932. xmlXPathCompPathExpr(ctxt);
  9933. CHECK_ERROR;
  9934. SKIP_BLANKS;
  9935. while (CUR == '|') {
  9936. int op1 = ctxt->comp->last;
  9937. PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
  9938. NEXT;
  9939. SKIP_BLANKS;
  9940. xmlXPathCompPathExpr(ctxt);
  9941. PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
  9942. SKIP_BLANKS;
  9943. }
  9944. }
  9945. /**
  9946. * xmlXPathCompUnaryExpr:
  9947. * @ctxt: the XPath Parser context
  9948. *
  9949. * [27] UnaryExpr ::= UnionExpr
  9950. * | '-' UnaryExpr
  9951. *
  9952. * Compile an unary expression.
  9953. */
  9954. static void
  9955. xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
  9956. int minus = 0;
  9957. int found = 0;
  9958. SKIP_BLANKS;
  9959. while (CUR == '-') {
  9960. minus = 1 - minus;
  9961. found = 1;
  9962. NEXT;
  9963. SKIP_BLANKS;
  9964. }
  9965. xmlXPathCompUnionExpr(ctxt);
  9966. CHECK_ERROR;
  9967. if (found) {
  9968. if (minus)
  9969. PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
  9970. else
  9971. PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
  9972. }
  9973. }
  9974. /**
  9975. * xmlXPathCompMultiplicativeExpr:
  9976. * @ctxt: the XPath Parser context
  9977. *
  9978. * [26] MultiplicativeExpr ::= UnaryExpr
  9979. * | MultiplicativeExpr MultiplyOperator UnaryExpr
  9980. * | MultiplicativeExpr 'div' UnaryExpr
  9981. * | MultiplicativeExpr 'mod' UnaryExpr
  9982. * [34] MultiplyOperator ::= '*'
  9983. *
  9984. * Compile an Additive expression.
  9985. */
  9986. static void
  9987. xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
  9988. xmlXPathCompUnaryExpr(ctxt);
  9989. CHECK_ERROR;
  9990. SKIP_BLANKS;
  9991. while ((CUR == '*') ||
  9992. ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
  9993. ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
  9994. int op = -1;
  9995. int op1 = ctxt->comp->last;
  9996. if (CUR == '*') {
  9997. op = 0;
  9998. NEXT;
  9999. } else if (CUR == 'd') {
  10000. op = 1;
  10001. SKIP(3);
  10002. } else if (CUR == 'm') {
  10003. op = 2;
  10004. SKIP(3);
  10005. }
  10006. SKIP_BLANKS;
  10007. xmlXPathCompUnaryExpr(ctxt);
  10008. CHECK_ERROR;
  10009. PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
  10010. SKIP_BLANKS;
  10011. }
  10012. }
  10013. /**
  10014. * xmlXPathCompAdditiveExpr:
  10015. * @ctxt: the XPath Parser context
  10016. *
  10017. * [25] AdditiveExpr ::= MultiplicativeExpr
  10018. * | AdditiveExpr '+' MultiplicativeExpr
  10019. * | AdditiveExpr '-' MultiplicativeExpr
  10020. *
  10021. * Compile an Additive expression.
  10022. */
  10023. static void
  10024. xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
  10025. xmlXPathCompMultiplicativeExpr(ctxt);
  10026. CHECK_ERROR;
  10027. SKIP_BLANKS;
  10028. while ((CUR == '+') || (CUR == '-')) {
  10029. int plus;
  10030. int op1 = ctxt->comp->last;
  10031. if (CUR == '+') plus = 1;
  10032. else plus = 0;
  10033. NEXT;
  10034. SKIP_BLANKS;
  10035. xmlXPathCompMultiplicativeExpr(ctxt);
  10036. CHECK_ERROR;
  10037. PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
  10038. SKIP_BLANKS;
  10039. }
  10040. }
  10041. /**
  10042. * xmlXPathCompRelationalExpr:
  10043. * @ctxt: the XPath Parser context
  10044. *
  10045. * [24] RelationalExpr ::= AdditiveExpr
  10046. * | RelationalExpr '<' AdditiveExpr
  10047. * | RelationalExpr '>' AdditiveExpr
  10048. * | RelationalExpr '<=' AdditiveExpr
  10049. * | RelationalExpr '>=' AdditiveExpr
  10050. *
  10051. * A <= B > C is allowed ? Answer from James, yes with
  10052. * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
  10053. * which is basically what got implemented.
  10054. *
  10055. * Compile a Relational expression, then push the result
  10056. * on the stack
  10057. */
  10058. static void
  10059. xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
  10060. xmlXPathCompAdditiveExpr(ctxt);
  10061. CHECK_ERROR;
  10062. SKIP_BLANKS;
  10063. while ((CUR == '<') || (CUR == '>')) {
  10064. int inf, strict;
  10065. int op1 = ctxt->comp->last;
  10066. if (CUR == '<') inf = 1;
  10067. else inf = 0;
  10068. if (NXT(1) == '=') strict = 0;
  10069. else strict = 1;
  10070. NEXT;
  10071. if (!strict) NEXT;
  10072. SKIP_BLANKS;
  10073. xmlXPathCompAdditiveExpr(ctxt);
  10074. CHECK_ERROR;
  10075. PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
  10076. SKIP_BLANKS;
  10077. }
  10078. }
  10079. /**
  10080. * xmlXPathCompEqualityExpr:
  10081. * @ctxt: the XPath Parser context
  10082. *
  10083. * [23] EqualityExpr ::= RelationalExpr
  10084. * | EqualityExpr '=' RelationalExpr
  10085. * | EqualityExpr '!=' RelationalExpr
  10086. *
  10087. * A != B != C is allowed ? Answer from James, yes with
  10088. * (RelationalExpr = RelationalExpr) = RelationalExpr
  10089. * (RelationalExpr != RelationalExpr) != RelationalExpr
  10090. * which is basically what got implemented.
  10091. *
  10092. * Compile an Equality expression.
  10093. *
  10094. */
  10095. static void
  10096. xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
  10097. xmlXPathCompRelationalExpr(ctxt);
  10098. CHECK_ERROR;
  10099. SKIP_BLANKS;
  10100. while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
  10101. int eq;
  10102. int op1 = ctxt->comp->last;
  10103. if (CUR == '=') eq = 1;
  10104. else eq = 0;
  10105. NEXT;
  10106. if (!eq) NEXT;
  10107. SKIP_BLANKS;
  10108. xmlXPathCompRelationalExpr(ctxt);
  10109. CHECK_ERROR;
  10110. PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
  10111. SKIP_BLANKS;
  10112. }
  10113. }
  10114. /**
  10115. * xmlXPathCompAndExpr:
  10116. * @ctxt: the XPath Parser context
  10117. *
  10118. * [22] AndExpr ::= EqualityExpr
  10119. * | AndExpr 'and' EqualityExpr
  10120. *
  10121. * Compile an AND expression.
  10122. *
  10123. */
  10124. static void
  10125. xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
  10126. xmlXPathCompEqualityExpr(ctxt);
  10127. CHECK_ERROR;
  10128. SKIP_BLANKS;
  10129. while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
  10130. int op1 = ctxt->comp->last;
  10131. SKIP(3);
  10132. SKIP_BLANKS;
  10133. xmlXPathCompEqualityExpr(ctxt);
  10134. CHECK_ERROR;
  10135. PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
  10136. SKIP_BLANKS;
  10137. }
  10138. }
  10139. /**
  10140. * xmlXPathCompileExpr:
  10141. * @ctxt: the XPath Parser context
  10142. *
  10143. * [14] Expr ::= OrExpr
  10144. * [21] OrExpr ::= AndExpr
  10145. * | OrExpr 'or' AndExpr
  10146. *
  10147. * Parse and compile an expression
  10148. */
  10149. static void
  10150. xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
  10151. xmlXPathContextPtr xpctxt = ctxt->context;
  10152. if (xpctxt != NULL) {
  10153. if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
  10154. XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
  10155. /*
  10156. * Parsing a single '(' pushes about 10 functions on the call stack
  10157. * before recursing!
  10158. */
  10159. xpctxt->depth += 10;
  10160. }
  10161. xmlXPathCompAndExpr(ctxt);
  10162. CHECK_ERROR;
  10163. SKIP_BLANKS;
  10164. while ((CUR == 'o') && (NXT(1) == 'r')) {
  10165. int op1 = ctxt->comp->last;
  10166. SKIP(2);
  10167. SKIP_BLANKS;
  10168. xmlXPathCompAndExpr(ctxt);
  10169. CHECK_ERROR;
  10170. PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
  10171. SKIP_BLANKS;
  10172. }
  10173. if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
  10174. /* more ops could be optimized too */
  10175. /*
  10176. * This is the main place to eliminate sorting for
  10177. * operations which don't require a sorted node-set.
  10178. * E.g. count().
  10179. */
  10180. PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
  10181. }
  10182. if (xpctxt != NULL)
  10183. xpctxt->depth -= 10;
  10184. }
  10185. /**
  10186. * xmlXPathCompPredicate:
  10187. * @ctxt: the XPath Parser context
  10188. * @filter: act as a filter
  10189. *
  10190. * [8] Predicate ::= '[' PredicateExpr ']'
  10191. * [9] PredicateExpr ::= Expr
  10192. *
  10193. * Compile a predicate expression
  10194. */
  10195. static void
  10196. xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
  10197. int op1 = ctxt->comp->last;
  10198. SKIP_BLANKS;
  10199. if (CUR != '[') {
  10200. XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
  10201. }
  10202. NEXT;
  10203. SKIP_BLANKS;
  10204. ctxt->comp->last = -1;
  10205. /*
  10206. * This call to xmlXPathCompileExpr() will deactivate sorting
  10207. * of the predicate result.
  10208. * TODO: Sorting is still activated for filters, since I'm not
  10209. * sure if needed. Normally sorting should not be needed, since
  10210. * a filter can only diminish the number of items in a sequence,
  10211. * but won't change its order; so if the initial sequence is sorted,
  10212. * subsequent sorting is not needed.
  10213. */
  10214. if (! filter)
  10215. xmlXPathCompileExpr(ctxt, 0);
  10216. else
  10217. xmlXPathCompileExpr(ctxt, 1);
  10218. CHECK_ERROR;
  10219. if (CUR != ']') {
  10220. XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
  10221. }
  10222. if (filter)
  10223. PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
  10224. else
  10225. PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
  10226. NEXT;
  10227. SKIP_BLANKS;
  10228. }
  10229. /**
  10230. * xmlXPathCompNodeTest:
  10231. * @ctxt: the XPath Parser context
  10232. * @test: pointer to a xmlXPathTestVal
  10233. * @type: pointer to a xmlXPathTypeVal
  10234. * @prefix: placeholder for a possible name prefix
  10235. *
  10236. * [7] NodeTest ::= NameTest
  10237. * | NodeType '(' ')'
  10238. * | 'processing-instruction' '(' Literal ')'
  10239. *
  10240. * [37] NameTest ::= '*'
  10241. * | NCName ':' '*'
  10242. * | QName
  10243. * [38] NodeType ::= 'comment'
  10244. * | 'text'
  10245. * | 'processing-instruction'
  10246. * | 'node'
  10247. *
  10248. * Returns the name found and updates @test, @type and @prefix appropriately
  10249. */
  10250. static xmlChar *
  10251. xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
  10252. xmlXPathTypeVal *type, xmlChar **prefix,
  10253. xmlChar *name) {
  10254. int blanks;
  10255. if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
  10256. STRANGE;
  10257. return(NULL);
  10258. }
  10259. *type = (xmlXPathTypeVal) 0;
  10260. *test = (xmlXPathTestVal) 0;
  10261. *prefix = NULL;
  10262. SKIP_BLANKS;
  10263. if ((name == NULL) && (CUR == '*')) {
  10264. /*
  10265. * All elements
  10266. */
  10267. NEXT;
  10268. *test = NODE_TEST_ALL;
  10269. return(NULL);
  10270. }
  10271. if (name == NULL)
  10272. name = xmlXPathParseNCName(ctxt);
  10273. if (name == NULL) {
  10274. XP_ERRORNULL(XPATH_EXPR_ERROR);
  10275. }
  10276. blanks = IS_BLANK_CH(CUR);
  10277. SKIP_BLANKS;
  10278. if (CUR == '(') {
  10279. NEXT;
  10280. /*
  10281. * NodeType or PI search
  10282. */
  10283. if (xmlStrEqual(name, BAD_CAST "comment"))
  10284. *type = NODE_TYPE_COMMENT;
  10285. else if (xmlStrEqual(name, BAD_CAST "node"))
  10286. *type = NODE_TYPE_NODE;
  10287. else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
  10288. *type = NODE_TYPE_PI;
  10289. else if (xmlStrEqual(name, BAD_CAST "text"))
  10290. *type = NODE_TYPE_TEXT;
  10291. else {
  10292. if (name != NULL)
  10293. xmlFree(name);
  10294. XP_ERRORNULL(XPATH_EXPR_ERROR);
  10295. }
  10296. *test = NODE_TEST_TYPE;
  10297. SKIP_BLANKS;
  10298. if (*type == NODE_TYPE_PI) {
  10299. /*
  10300. * Specific case: search a PI by name.
  10301. */
  10302. if (name != NULL)
  10303. xmlFree(name);
  10304. name = NULL;
  10305. if (CUR != ')') {
  10306. name = xmlXPathParseLiteral(ctxt);
  10307. if (name == NULL) {
  10308. XP_ERRORNULL(XPATH_EXPR_ERROR);
  10309. }
  10310. *test = NODE_TEST_PI;
  10311. SKIP_BLANKS;
  10312. }
  10313. }
  10314. if (CUR != ')') {
  10315. if (name != NULL)
  10316. xmlFree(name);
  10317. XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
  10318. }
  10319. NEXT;
  10320. return(name);
  10321. }
  10322. *test = NODE_TEST_NAME;
  10323. if ((!blanks) && (CUR == ':')) {
  10324. NEXT;
  10325. /*
  10326. * Since currently the parser context don't have a
  10327. * namespace list associated:
  10328. * The namespace name for this prefix can be computed
  10329. * only at evaluation time. The compilation is done
  10330. * outside of any context.
  10331. */
  10332. #if 0
  10333. *prefix = xmlXPathNsLookup(ctxt->context, name);
  10334. if (name != NULL)
  10335. xmlFree(name);
  10336. if (*prefix == NULL) {
  10337. XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
  10338. }
  10339. #else
  10340. *prefix = name;
  10341. #endif
  10342. if (CUR == '*') {
  10343. /*
  10344. * All elements
  10345. */
  10346. NEXT;
  10347. *test = NODE_TEST_ALL;
  10348. return(NULL);
  10349. }
  10350. name = xmlXPathParseNCName(ctxt);
  10351. if (name == NULL) {
  10352. XP_ERRORNULL(XPATH_EXPR_ERROR);
  10353. }
  10354. }
  10355. return(name);
  10356. }
  10357. /**
  10358. * xmlXPathIsAxisName:
  10359. * @name: a preparsed name token
  10360. *
  10361. * [6] AxisName ::= 'ancestor'
  10362. * | 'ancestor-or-self'
  10363. * | 'attribute'
  10364. * | 'child'
  10365. * | 'descendant'
  10366. * | 'descendant-or-self'
  10367. * | 'following'
  10368. * | 'following-sibling'
  10369. * | 'namespace'
  10370. * | 'parent'
  10371. * | 'preceding'
  10372. * | 'preceding-sibling'
  10373. * | 'self'
  10374. *
  10375. * Returns the axis or 0
  10376. */
  10377. static xmlXPathAxisVal
  10378. xmlXPathIsAxisName(const xmlChar *name) {
  10379. xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
  10380. switch (name[0]) {
  10381. case 'a':
  10382. if (xmlStrEqual(name, BAD_CAST "ancestor"))
  10383. ret = AXIS_ANCESTOR;
  10384. if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
  10385. ret = AXIS_ANCESTOR_OR_SELF;
  10386. if (xmlStrEqual(name, BAD_CAST "attribute"))
  10387. ret = AXIS_ATTRIBUTE;
  10388. break;
  10389. case 'c':
  10390. if (xmlStrEqual(name, BAD_CAST "child"))
  10391. ret = AXIS_CHILD;
  10392. break;
  10393. case 'd':
  10394. if (xmlStrEqual(name, BAD_CAST "descendant"))
  10395. ret = AXIS_DESCENDANT;
  10396. if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
  10397. ret = AXIS_DESCENDANT_OR_SELF;
  10398. break;
  10399. case 'f':
  10400. if (xmlStrEqual(name, BAD_CAST "following"))
  10401. ret = AXIS_FOLLOWING;
  10402. if (xmlStrEqual(name, BAD_CAST "following-sibling"))
  10403. ret = AXIS_FOLLOWING_SIBLING;
  10404. break;
  10405. case 'n':
  10406. if (xmlStrEqual(name, BAD_CAST "namespace"))
  10407. ret = AXIS_NAMESPACE;
  10408. break;
  10409. case 'p':
  10410. if (xmlStrEqual(name, BAD_CAST "parent"))
  10411. ret = AXIS_PARENT;
  10412. if (xmlStrEqual(name, BAD_CAST "preceding"))
  10413. ret = AXIS_PRECEDING;
  10414. if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
  10415. ret = AXIS_PRECEDING_SIBLING;
  10416. break;
  10417. case 's':
  10418. if (xmlStrEqual(name, BAD_CAST "self"))
  10419. ret = AXIS_SELF;
  10420. break;
  10421. }
  10422. return(ret);
  10423. }
  10424. /**
  10425. * xmlXPathCompStep:
  10426. * @ctxt: the XPath Parser context
  10427. *
  10428. * [4] Step ::= AxisSpecifier NodeTest Predicate*
  10429. * | AbbreviatedStep
  10430. *
  10431. * [12] AbbreviatedStep ::= '.' | '..'
  10432. *
  10433. * [5] AxisSpecifier ::= AxisName '::'
  10434. * | AbbreviatedAxisSpecifier
  10435. *
  10436. * [13] AbbreviatedAxisSpecifier ::= '@'?
  10437. *
  10438. * Modified for XPtr range support as:
  10439. *
  10440. * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
  10441. * | AbbreviatedStep
  10442. * | 'range-to' '(' Expr ')' Predicate*
  10443. *
  10444. * Compile one step in a Location Path
  10445. * A location step of . is short for self::node(). This is
  10446. * particularly useful in conjunction with //. For example, the
  10447. * location path .//para is short for
  10448. * self::node()/descendant-or-self::node()/child::para
  10449. * and so will select all para descendant elements of the context
  10450. * node.
  10451. * Similarly, a location step of .. is short for parent::node().
  10452. * For example, ../title is short for parent::node()/child::title
  10453. * and so will select the title children of the parent of the context
  10454. * node.
  10455. */
  10456. static void
  10457. xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
  10458. #ifdef LIBXML_XPTR_ENABLED
  10459. int rangeto = 0;
  10460. int op2 = -1;
  10461. #endif
  10462. SKIP_BLANKS;
  10463. if ((CUR == '.') && (NXT(1) == '.')) {
  10464. SKIP(2);
  10465. SKIP_BLANKS;
  10466. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
  10467. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  10468. } else if (CUR == '.') {
  10469. NEXT;
  10470. SKIP_BLANKS;
  10471. } else {
  10472. xmlChar *name = NULL;
  10473. xmlChar *prefix = NULL;
  10474. xmlXPathTestVal test = (xmlXPathTestVal) 0;
  10475. xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
  10476. xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
  10477. int op1;
  10478. /*
  10479. * The modification needed for XPointer change to the production
  10480. */
  10481. #ifdef LIBXML_XPTR_ENABLED
  10482. if (ctxt->xptr) {
  10483. name = xmlXPathParseNCName(ctxt);
  10484. if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
  10485. op2 = ctxt->comp->last;
  10486. xmlFree(name);
  10487. SKIP_BLANKS;
  10488. if (CUR != '(') {
  10489. XP_ERROR(XPATH_EXPR_ERROR);
  10490. }
  10491. NEXT;
  10492. SKIP_BLANKS;
  10493. xmlXPathCompileExpr(ctxt, 1);
  10494. /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
  10495. CHECK_ERROR;
  10496. SKIP_BLANKS;
  10497. if (CUR != ')') {
  10498. XP_ERROR(XPATH_EXPR_ERROR);
  10499. }
  10500. NEXT;
  10501. rangeto = 1;
  10502. goto eval_predicates;
  10503. }
  10504. }
  10505. #endif
  10506. if (CUR == '*') {
  10507. axis = AXIS_CHILD;
  10508. } else {
  10509. if (name == NULL)
  10510. name = xmlXPathParseNCName(ctxt);
  10511. if (name != NULL) {
  10512. axis = xmlXPathIsAxisName(name);
  10513. if (axis != 0) {
  10514. SKIP_BLANKS;
  10515. if ((CUR == ':') && (NXT(1) == ':')) {
  10516. SKIP(2);
  10517. xmlFree(name);
  10518. name = NULL;
  10519. } else {
  10520. /* an element name can conflict with an axis one :-\ */
  10521. axis = AXIS_CHILD;
  10522. }
  10523. } else {
  10524. axis = AXIS_CHILD;
  10525. }
  10526. } else if (CUR == '@') {
  10527. NEXT;
  10528. axis = AXIS_ATTRIBUTE;
  10529. } else {
  10530. axis = AXIS_CHILD;
  10531. }
  10532. }
  10533. if (ctxt->error != XPATH_EXPRESSION_OK) {
  10534. xmlFree(name);
  10535. return;
  10536. }
  10537. name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
  10538. if (test == 0)
  10539. return;
  10540. if ((prefix != NULL) && (ctxt->context != NULL) &&
  10541. (ctxt->context->flags & XML_XPATH_CHECKNS)) {
  10542. if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
  10543. xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
  10544. }
  10545. }
  10546. #ifdef DEBUG_STEP
  10547. xmlGenericError(xmlGenericErrorContext,
  10548. "Basis : computing new set\n");
  10549. #endif
  10550. #ifdef DEBUG_STEP
  10551. xmlGenericError(xmlGenericErrorContext, "Basis : ");
  10552. if (ctxt->value == NULL)
  10553. xmlGenericError(xmlGenericErrorContext, "no value\n");
  10554. else if (ctxt->value->nodesetval == NULL)
  10555. xmlGenericError(xmlGenericErrorContext, "Empty\n");
  10556. else
  10557. xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
  10558. #endif
  10559. #ifdef LIBXML_XPTR_ENABLED
  10560. eval_predicates:
  10561. #endif
  10562. op1 = ctxt->comp->last;
  10563. ctxt->comp->last = -1;
  10564. SKIP_BLANKS;
  10565. while (CUR == '[') {
  10566. xmlXPathCompPredicate(ctxt, 0);
  10567. }
  10568. #ifdef LIBXML_XPTR_ENABLED
  10569. if (rangeto) {
  10570. PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
  10571. } else
  10572. #endif
  10573. if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
  10574. test, type, (void *)prefix, (void *)name) == -1) {
  10575. xmlFree(prefix);
  10576. xmlFree(name);
  10577. }
  10578. }
  10579. #ifdef DEBUG_STEP
  10580. xmlGenericError(xmlGenericErrorContext, "Step : ");
  10581. if (ctxt->value == NULL)
  10582. xmlGenericError(xmlGenericErrorContext, "no value\n");
  10583. else if (ctxt->value->nodesetval == NULL)
  10584. xmlGenericError(xmlGenericErrorContext, "Empty\n");
  10585. else
  10586. xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
  10587. ctxt->value->nodesetval);
  10588. #endif
  10589. }
  10590. /**
  10591. * xmlXPathCompRelativeLocationPath:
  10592. * @ctxt: the XPath Parser context
  10593. *
  10594. * [3] RelativeLocationPath ::= Step
  10595. * | RelativeLocationPath '/' Step
  10596. * | AbbreviatedRelativeLocationPath
  10597. * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
  10598. *
  10599. * Compile a relative location path.
  10600. */
  10601. static void
  10602. xmlXPathCompRelativeLocationPath
  10603. (xmlXPathParserContextPtr ctxt) {
  10604. SKIP_BLANKS;
  10605. if ((CUR == '/') && (NXT(1) == '/')) {
  10606. SKIP(2);
  10607. SKIP_BLANKS;
  10608. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
  10609. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  10610. } else if (CUR == '/') {
  10611. NEXT;
  10612. SKIP_BLANKS;
  10613. }
  10614. xmlXPathCompStep(ctxt);
  10615. CHECK_ERROR;
  10616. SKIP_BLANKS;
  10617. while (CUR == '/') {
  10618. if ((CUR == '/') && (NXT(1) == '/')) {
  10619. SKIP(2);
  10620. SKIP_BLANKS;
  10621. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
  10622. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  10623. xmlXPathCompStep(ctxt);
  10624. } else if (CUR == '/') {
  10625. NEXT;
  10626. SKIP_BLANKS;
  10627. xmlXPathCompStep(ctxt);
  10628. }
  10629. SKIP_BLANKS;
  10630. }
  10631. }
  10632. /**
  10633. * xmlXPathCompLocationPath:
  10634. * @ctxt: the XPath Parser context
  10635. *
  10636. * [1] LocationPath ::= RelativeLocationPath
  10637. * | AbsoluteLocationPath
  10638. * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
  10639. * | AbbreviatedAbsoluteLocationPath
  10640. * [10] AbbreviatedAbsoluteLocationPath ::=
  10641. * '//' RelativeLocationPath
  10642. *
  10643. * Compile a location path
  10644. *
  10645. * // is short for /descendant-or-self::node()/. For example,
  10646. * //para is short for /descendant-or-self::node()/child::para and
  10647. * so will select any para element in the document (even a para element
  10648. * that is a document element will be selected by //para since the
  10649. * document element node is a child of the root node); div//para is
  10650. * short for div/descendant-or-self::node()/child::para and so will
  10651. * select all para descendants of div children.
  10652. */
  10653. static void
  10654. xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
  10655. SKIP_BLANKS;
  10656. if (CUR != '/') {
  10657. xmlXPathCompRelativeLocationPath(ctxt);
  10658. } else {
  10659. while (CUR == '/') {
  10660. if ((CUR == '/') && (NXT(1) == '/')) {
  10661. SKIP(2);
  10662. SKIP_BLANKS;
  10663. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
  10664. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  10665. xmlXPathCompRelativeLocationPath(ctxt);
  10666. } else if (CUR == '/') {
  10667. NEXT;
  10668. SKIP_BLANKS;
  10669. if ((CUR != 0 ) &&
  10670. ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
  10671. (CUR == '@') || (CUR == '*')))
  10672. xmlXPathCompRelativeLocationPath(ctxt);
  10673. }
  10674. CHECK_ERROR;
  10675. }
  10676. }
  10677. }
  10678. /************************************************************************
  10679. * *
  10680. * XPath precompiled expression evaluation *
  10681. * *
  10682. ************************************************************************/
  10683. static int
  10684. xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
  10685. #ifdef DEBUG_STEP
  10686. static void
  10687. xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
  10688. int nbNodes)
  10689. {
  10690. xmlGenericError(xmlGenericErrorContext, "new step : ");
  10691. switch (op->value) {
  10692. case AXIS_ANCESTOR:
  10693. xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
  10694. break;
  10695. case AXIS_ANCESTOR_OR_SELF:
  10696. xmlGenericError(xmlGenericErrorContext,
  10697. "axis 'ancestors-or-self' ");
  10698. break;
  10699. case AXIS_ATTRIBUTE:
  10700. xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
  10701. break;
  10702. case AXIS_CHILD:
  10703. xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
  10704. break;
  10705. case AXIS_DESCENDANT:
  10706. xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
  10707. break;
  10708. case AXIS_DESCENDANT_OR_SELF:
  10709. xmlGenericError(xmlGenericErrorContext,
  10710. "axis 'descendant-or-self' ");
  10711. break;
  10712. case AXIS_FOLLOWING:
  10713. xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
  10714. break;
  10715. case AXIS_FOLLOWING_SIBLING:
  10716. xmlGenericError(xmlGenericErrorContext,
  10717. "axis 'following-siblings' ");
  10718. break;
  10719. case AXIS_NAMESPACE:
  10720. xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
  10721. break;
  10722. case AXIS_PARENT:
  10723. xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
  10724. break;
  10725. case AXIS_PRECEDING:
  10726. xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
  10727. break;
  10728. case AXIS_PRECEDING_SIBLING:
  10729. xmlGenericError(xmlGenericErrorContext,
  10730. "axis 'preceding-sibling' ");
  10731. break;
  10732. case AXIS_SELF:
  10733. xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
  10734. break;
  10735. }
  10736. xmlGenericError(xmlGenericErrorContext,
  10737. " context contains %d nodes\n", nbNodes);
  10738. switch (op->value2) {
  10739. case NODE_TEST_NONE:
  10740. xmlGenericError(xmlGenericErrorContext,
  10741. " searching for none !!!\n");
  10742. break;
  10743. case NODE_TEST_TYPE:
  10744. xmlGenericError(xmlGenericErrorContext,
  10745. " searching for type %d\n", op->value3);
  10746. break;
  10747. case NODE_TEST_PI:
  10748. xmlGenericError(xmlGenericErrorContext,
  10749. " searching for PI !!!\n");
  10750. break;
  10751. case NODE_TEST_ALL:
  10752. xmlGenericError(xmlGenericErrorContext,
  10753. " searching for *\n");
  10754. break;
  10755. case NODE_TEST_NS:
  10756. xmlGenericError(xmlGenericErrorContext,
  10757. " searching for namespace %s\n",
  10758. op->value5);
  10759. break;
  10760. case NODE_TEST_NAME:
  10761. xmlGenericError(xmlGenericErrorContext,
  10762. " searching for name %s\n", op->value5);
  10763. if (op->value4)
  10764. xmlGenericError(xmlGenericErrorContext,
  10765. " with namespace %s\n", op->value4);
  10766. break;
  10767. }
  10768. xmlGenericError(xmlGenericErrorContext, "Testing : ");
  10769. }
  10770. #endif /* DEBUG_STEP */
  10771. /**
  10772. * xmlXPathNodeSetFilter:
  10773. * @ctxt: the XPath Parser context
  10774. * @set: the node set to filter
  10775. * @filterOpIndex: the index of the predicate/filter op
  10776. * @minPos: minimum position in the filtered set (1-based)
  10777. * @maxPos: maximum position in the filtered set (1-based)
  10778. * @hasNsNodes: true if the node set may contain namespace nodes
  10779. *
  10780. * Filter a node set, keeping only nodes for which the predicate expression
  10781. * matches. Afterwards, keep only nodes between minPos and maxPos in the
  10782. * filtered result.
  10783. */
  10784. static void
  10785. xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
  10786. xmlNodeSetPtr set,
  10787. int filterOpIndex,
  10788. int minPos, int maxPos,
  10789. int hasNsNodes)
  10790. {
  10791. xmlXPathContextPtr xpctxt;
  10792. xmlNodePtr oldnode;
  10793. xmlDocPtr olddoc;
  10794. xmlXPathStepOpPtr filterOp;
  10795. int oldcs, oldpp;
  10796. int i, j, pos;
  10797. if ((set == NULL) || (set->nodeNr == 0))
  10798. return;
  10799. /*
  10800. * Check if the node set contains a sufficient number of nodes for
  10801. * the requested range.
  10802. */
  10803. if (set->nodeNr < minPos) {
  10804. xmlXPathNodeSetClear(set, hasNsNodes);
  10805. return;
  10806. }
  10807. xpctxt = ctxt->context;
  10808. oldnode = xpctxt->node;
  10809. olddoc = xpctxt->doc;
  10810. oldcs = xpctxt->contextSize;
  10811. oldpp = xpctxt->proximityPosition;
  10812. filterOp = &ctxt->comp->steps[filterOpIndex];
  10813. xpctxt->contextSize = set->nodeNr;
  10814. for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
  10815. xmlNodePtr node = set->nodeTab[i];
  10816. int res;
  10817. xpctxt->node = node;
  10818. xpctxt->proximityPosition = i + 1;
  10819. /*
  10820. * Also set the xpath document in case things like
  10821. * key() are evaluated in the predicate.
  10822. *
  10823. * TODO: Get real doc for namespace nodes.
  10824. */
  10825. if ((node->type != XML_NAMESPACE_DECL) &&
  10826. (node->doc != NULL))
  10827. xpctxt->doc = node->doc;
  10828. res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
  10829. if (ctxt->error != XPATH_EXPRESSION_OK)
  10830. break;
  10831. if (res < 0) {
  10832. /* Shouldn't happen */
  10833. xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
  10834. break;
  10835. }
  10836. if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
  10837. if (i != j) {
  10838. set->nodeTab[j] = node;
  10839. set->nodeTab[i] = NULL;
  10840. }
  10841. j += 1;
  10842. } else {
  10843. /* Remove the entry from the initial node set. */
  10844. set->nodeTab[i] = NULL;
  10845. if (node->type == XML_NAMESPACE_DECL)
  10846. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  10847. }
  10848. if (res != 0) {
  10849. if (pos == maxPos) {
  10850. i += 1;
  10851. break;
  10852. }
  10853. pos += 1;
  10854. }
  10855. }
  10856. /* Free remaining nodes. */
  10857. if (hasNsNodes) {
  10858. for (; i < set->nodeNr; i++) {
  10859. xmlNodePtr node = set->nodeTab[i];
  10860. if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
  10861. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  10862. }
  10863. }
  10864. set->nodeNr = j;
  10865. /* If too many elements were removed, shrink table to preserve memory. */
  10866. if ((set->nodeMax > XML_NODESET_DEFAULT) &&
  10867. (set->nodeNr < set->nodeMax / 2)) {
  10868. xmlNodePtr *tmp;
  10869. int nodeMax = set->nodeNr;
  10870. if (nodeMax < XML_NODESET_DEFAULT)
  10871. nodeMax = XML_NODESET_DEFAULT;
  10872. tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
  10873. nodeMax * sizeof(xmlNodePtr));
  10874. if (tmp == NULL) {
  10875. xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
  10876. } else {
  10877. set->nodeTab = tmp;
  10878. set->nodeMax = nodeMax;
  10879. }
  10880. }
  10881. xpctxt->node = oldnode;
  10882. xpctxt->doc = olddoc;
  10883. xpctxt->contextSize = oldcs;
  10884. xpctxt->proximityPosition = oldpp;
  10885. }
  10886. #ifdef LIBXML_XPTR_ENABLED
  10887. /**
  10888. * xmlXPathLocationSetFilter:
  10889. * @ctxt: the XPath Parser context
  10890. * @locset: the location set to filter
  10891. * @filterOpIndex: the index of the predicate/filter op
  10892. * @minPos: minimum position in the filtered set (1-based)
  10893. * @maxPos: maximum position in the filtered set (1-based)
  10894. *
  10895. * Filter a location set, keeping only nodes for which the predicate
  10896. * expression matches. Afterwards, keep only nodes between minPos and maxPos
  10897. * in the filtered result.
  10898. */
  10899. static void
  10900. xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
  10901. xmlLocationSetPtr locset,
  10902. int filterOpIndex,
  10903. int minPos, int maxPos)
  10904. {
  10905. xmlXPathContextPtr xpctxt;
  10906. xmlNodePtr oldnode;
  10907. xmlDocPtr olddoc;
  10908. xmlXPathStepOpPtr filterOp;
  10909. int oldcs, oldpp;
  10910. int i, j, pos;
  10911. if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
  10912. return;
  10913. xpctxt = ctxt->context;
  10914. oldnode = xpctxt->node;
  10915. olddoc = xpctxt->doc;
  10916. oldcs = xpctxt->contextSize;
  10917. oldpp = xpctxt->proximityPosition;
  10918. filterOp = &ctxt->comp->steps[filterOpIndex];
  10919. xpctxt->contextSize = locset->locNr;
  10920. for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
  10921. xmlNodePtr contextNode = locset->locTab[i]->user;
  10922. int res;
  10923. xpctxt->node = contextNode;
  10924. xpctxt->proximityPosition = i + 1;
  10925. /*
  10926. * Also set the xpath document in case things like
  10927. * key() are evaluated in the predicate.
  10928. *
  10929. * TODO: Get real doc for namespace nodes.
  10930. */
  10931. if ((contextNode->type != XML_NAMESPACE_DECL) &&
  10932. (contextNode->doc != NULL))
  10933. xpctxt->doc = contextNode->doc;
  10934. res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
  10935. if (ctxt->error != XPATH_EXPRESSION_OK)
  10936. break;
  10937. if (res < 0) {
  10938. /* Shouldn't happen */
  10939. xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
  10940. break;
  10941. }
  10942. if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
  10943. if (i != j) {
  10944. locset->locTab[j] = locset->locTab[i];
  10945. locset->locTab[i] = NULL;
  10946. }
  10947. j += 1;
  10948. } else {
  10949. /* Remove the entry from the initial location set. */
  10950. xmlXPathFreeObject(locset->locTab[i]);
  10951. locset->locTab[i] = NULL;
  10952. }
  10953. if (res != 0) {
  10954. if (pos == maxPos) {
  10955. i += 1;
  10956. break;
  10957. }
  10958. pos += 1;
  10959. }
  10960. }
  10961. /* Free remaining nodes. */
  10962. for (; i < locset->locNr; i++)
  10963. xmlXPathFreeObject(locset->locTab[i]);
  10964. locset->locNr = j;
  10965. /* If too many elements were removed, shrink table to preserve memory. */
  10966. if ((locset->locMax > XML_NODESET_DEFAULT) &&
  10967. (locset->locNr < locset->locMax / 2)) {
  10968. xmlXPathObjectPtr *tmp;
  10969. int locMax = locset->locNr;
  10970. if (locMax < XML_NODESET_DEFAULT)
  10971. locMax = XML_NODESET_DEFAULT;
  10972. tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
  10973. locMax * sizeof(xmlXPathObjectPtr));
  10974. if (tmp == NULL) {
  10975. xmlXPathPErrMemory(ctxt, "shrinking locset\n");
  10976. } else {
  10977. locset->locTab = tmp;
  10978. locset->locMax = locMax;
  10979. }
  10980. }
  10981. xpctxt->node = oldnode;
  10982. xpctxt->doc = olddoc;
  10983. xpctxt->contextSize = oldcs;
  10984. xpctxt->proximityPosition = oldpp;
  10985. }
  10986. #endif /* LIBXML_XPTR_ENABLED */
  10987. /**
  10988. * xmlXPathCompOpEvalPredicate:
  10989. * @ctxt: the XPath Parser context
  10990. * @op: the predicate op
  10991. * @set: the node set to filter
  10992. * @minPos: minimum position in the filtered set (1-based)
  10993. * @maxPos: maximum position in the filtered set (1-based)
  10994. * @hasNsNodes: true if the node set may contain namespace nodes
  10995. *
  10996. * Filter a node set, keeping only nodes for which the sequence of predicate
  10997. * expressions matches. Afterwards, keep only nodes between minPos and maxPos
  10998. * in the filtered result.
  10999. */
  11000. static void
  11001. xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
  11002. xmlXPathStepOpPtr op,
  11003. xmlNodeSetPtr set,
  11004. int minPos, int maxPos,
  11005. int hasNsNodes)
  11006. {
  11007. if (op->ch1 != -1) {
  11008. xmlXPathCompExprPtr comp = ctxt->comp;
  11009. /*
  11010. * Process inner predicates first.
  11011. */
  11012. if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
  11013. xmlGenericError(xmlGenericErrorContext,
  11014. "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
  11015. XP_ERROR(XPATH_INVALID_OPERAND);
  11016. }
  11017. if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
  11018. XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
  11019. ctxt->context->depth += 1;
  11020. xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
  11021. 1, set->nodeNr, hasNsNodes);
  11022. ctxt->context->depth -= 1;
  11023. CHECK_ERROR;
  11024. }
  11025. if (op->ch2 != -1)
  11026. xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
  11027. }
  11028. static int
  11029. xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
  11030. xmlXPathStepOpPtr op,
  11031. int *maxPos)
  11032. {
  11033. xmlXPathStepOpPtr exprOp;
  11034. /*
  11035. * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
  11036. */
  11037. /*
  11038. * If not -1, then ch1 will point to:
  11039. * 1) For predicates (XPATH_OP_PREDICATE):
  11040. * - an inner predicate operator
  11041. * 2) For filters (XPATH_OP_FILTER):
  11042. * - an inner filter operator OR
  11043. * - an expression selecting the node set.
  11044. * E.g. "key('a', 'b')" or "(//foo | //bar)".
  11045. */
  11046. if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
  11047. return(0);
  11048. if (op->ch2 != -1) {
  11049. exprOp = &ctxt->comp->steps[op->ch2];
  11050. } else
  11051. return(0);
  11052. if ((exprOp != NULL) &&
  11053. (exprOp->op == XPATH_OP_VALUE) &&
  11054. (exprOp->value4 != NULL) &&
  11055. (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
  11056. {
  11057. double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
  11058. /*
  11059. * We have a "[n]" predicate here.
  11060. * TODO: Unfortunately this simplistic test here is not
  11061. * able to detect a position() predicate in compound
  11062. * expressions like "[@attr = 'a" and position() = 1],
  11063. * and even not the usage of position() in
  11064. * "[position() = 1]"; thus - obviously - a position-range,
  11065. * like it "[position() < 5]", is also not detected.
  11066. * Maybe we could rewrite the AST to ease the optimization.
  11067. */
  11068. if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
  11069. *maxPos = (int) floatval;
  11070. if (floatval == (double) *maxPos)
  11071. return(1);
  11072. }
  11073. }
  11074. return(0);
  11075. }
  11076. static int
  11077. xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
  11078. xmlXPathStepOpPtr op,
  11079. xmlNodePtr * first, xmlNodePtr * last,
  11080. int toBool)
  11081. {
  11082. #define XP_TEST_HIT \
  11083. if (hasAxisRange != 0) { \
  11084. if (++pos == maxPos) { \
  11085. if (addNode(seq, cur) < 0) \
  11086. ctxt->error = XPATH_MEMORY_ERROR; \
  11087. goto axis_range_end; } \
  11088. } else { \
  11089. if (addNode(seq, cur) < 0) \
  11090. ctxt->error = XPATH_MEMORY_ERROR; \
  11091. if (breakOnFirstHit) goto first_hit; }
  11092. #define XP_TEST_HIT_NS \
  11093. if (hasAxisRange != 0) { \
  11094. if (++pos == maxPos) { \
  11095. hasNsNodes = 1; \
  11096. if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
  11097. ctxt->error = XPATH_MEMORY_ERROR; \
  11098. goto axis_range_end; } \
  11099. } else { \
  11100. hasNsNodes = 1; \
  11101. if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
  11102. ctxt->error = XPATH_MEMORY_ERROR; \
  11103. if (breakOnFirstHit) goto first_hit; }
  11104. xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
  11105. xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
  11106. xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
  11107. const xmlChar *prefix = op->value4;
  11108. const xmlChar *name = op->value5;
  11109. const xmlChar *URI = NULL;
  11110. #ifdef DEBUG_STEP
  11111. int nbMatches = 0, prevMatches = 0;
  11112. #endif
  11113. int total = 0, hasNsNodes = 0;
  11114. /* The popped object holding the context nodes */
  11115. xmlXPathObjectPtr obj;
  11116. /* The set of context nodes for the node tests */
  11117. xmlNodeSetPtr contextSeq;
  11118. int contextIdx;
  11119. xmlNodePtr contextNode;
  11120. /* The final resulting node set wrt to all context nodes */
  11121. xmlNodeSetPtr outSeq;
  11122. /*
  11123. * The temporary resulting node set wrt 1 context node.
  11124. * Used to feed predicate evaluation.
  11125. */
  11126. xmlNodeSetPtr seq;
  11127. xmlNodePtr cur;
  11128. /* First predicate operator */
  11129. xmlXPathStepOpPtr predOp;
  11130. int maxPos; /* The requested position() (when a "[n]" predicate) */
  11131. int hasPredicateRange, hasAxisRange, pos;
  11132. int breakOnFirstHit;
  11133. xmlXPathTraversalFunction next = NULL;
  11134. int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
  11135. xmlXPathNodeSetMergeFunction mergeAndClear;
  11136. xmlNodePtr oldContextNode;
  11137. xmlXPathContextPtr xpctxt = ctxt->context;
  11138. CHECK_TYPE0(XPATH_NODESET);
  11139. obj = valuePop(ctxt);
  11140. /*
  11141. * Setup namespaces.
  11142. */
  11143. if (prefix != NULL) {
  11144. URI = xmlXPathNsLookup(xpctxt, prefix);
  11145. if (URI == NULL) {
  11146. xmlXPathReleaseObject(xpctxt, obj);
  11147. XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
  11148. }
  11149. }
  11150. /*
  11151. * Setup axis.
  11152. *
  11153. * MAYBE FUTURE TODO: merging optimizations:
  11154. * - If the nodes to be traversed wrt to the initial nodes and
  11155. * the current axis cannot overlap, then we could avoid searching
  11156. * for duplicates during the merge.
  11157. * But the question is how/when to evaluate if they cannot overlap.
  11158. * Example: if we know that for two initial nodes, the one is
  11159. * not in the ancestor-or-self axis of the other, then we could safely
  11160. * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
  11161. * the descendant-or-self axis.
  11162. */
  11163. mergeAndClear = xmlXPathNodeSetMergeAndClear;
  11164. switch (axis) {
  11165. case AXIS_ANCESTOR:
  11166. first = NULL;
  11167. next = xmlXPathNextAncestor;
  11168. break;
  11169. case AXIS_ANCESTOR_OR_SELF:
  11170. first = NULL;
  11171. next = xmlXPathNextAncestorOrSelf;
  11172. break;
  11173. case AXIS_ATTRIBUTE:
  11174. first = NULL;
  11175. last = NULL;
  11176. next = xmlXPathNextAttribute;
  11177. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  11178. break;
  11179. case AXIS_CHILD:
  11180. last = NULL;
  11181. if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
  11182. (type == NODE_TYPE_NODE))
  11183. {
  11184. /*
  11185. * Optimization if an element node type is 'element'.
  11186. */
  11187. next = xmlXPathNextChildElement;
  11188. } else
  11189. next = xmlXPathNextChild;
  11190. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  11191. break;
  11192. case AXIS_DESCENDANT:
  11193. last = NULL;
  11194. next = xmlXPathNextDescendant;
  11195. break;
  11196. case AXIS_DESCENDANT_OR_SELF:
  11197. last = NULL;
  11198. next = xmlXPathNextDescendantOrSelf;
  11199. break;
  11200. case AXIS_FOLLOWING:
  11201. last = NULL;
  11202. next = xmlXPathNextFollowing;
  11203. break;
  11204. case AXIS_FOLLOWING_SIBLING:
  11205. last = NULL;
  11206. next = xmlXPathNextFollowingSibling;
  11207. break;
  11208. case AXIS_NAMESPACE:
  11209. first = NULL;
  11210. last = NULL;
  11211. next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
  11212. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  11213. break;
  11214. case AXIS_PARENT:
  11215. first = NULL;
  11216. next = xmlXPathNextParent;
  11217. break;
  11218. case AXIS_PRECEDING:
  11219. first = NULL;
  11220. next = xmlXPathNextPrecedingInternal;
  11221. break;
  11222. case AXIS_PRECEDING_SIBLING:
  11223. first = NULL;
  11224. next = xmlXPathNextPrecedingSibling;
  11225. break;
  11226. case AXIS_SELF:
  11227. first = NULL;
  11228. last = NULL;
  11229. next = xmlXPathNextSelf;
  11230. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  11231. break;
  11232. }
  11233. #ifdef DEBUG_STEP
  11234. xmlXPathDebugDumpStepAxis(op,
  11235. (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
  11236. #endif
  11237. if (next == NULL) {
  11238. xmlXPathReleaseObject(xpctxt, obj);
  11239. return(0);
  11240. }
  11241. contextSeq = obj->nodesetval;
  11242. if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
  11243. xmlXPathReleaseObject(xpctxt, obj);
  11244. valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
  11245. return(0);
  11246. }
  11247. /*
  11248. * Predicate optimization ---------------------------------------------
  11249. * If this step has a last predicate, which contains a position(),
  11250. * then we'll optimize (although not exactly "position()", but only
  11251. * the short-hand form, i.e., "[n]".
  11252. *
  11253. * Example - expression "/foo[parent::bar][1]":
  11254. *
  11255. * COLLECT 'child' 'name' 'node' foo -- op (we are here)
  11256. * ROOT -- op->ch1
  11257. * PREDICATE -- op->ch2 (predOp)
  11258. * PREDICATE -- predOp->ch1 = [parent::bar]
  11259. * SORT
  11260. * COLLECT 'parent' 'name' 'node' bar
  11261. * NODE
  11262. * ELEM Object is a number : 1 -- predOp->ch2 = [1]
  11263. *
  11264. */
  11265. maxPos = 0;
  11266. predOp = NULL;
  11267. hasPredicateRange = 0;
  11268. hasAxisRange = 0;
  11269. if (op->ch2 != -1) {
  11270. /*
  11271. * There's at least one predicate. 16 == XPATH_OP_PREDICATE
  11272. */
  11273. predOp = &ctxt->comp->steps[op->ch2];
  11274. if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
  11275. if (predOp->ch1 != -1) {
  11276. /*
  11277. * Use the next inner predicate operator.
  11278. */
  11279. predOp = &ctxt->comp->steps[predOp->ch1];
  11280. hasPredicateRange = 1;
  11281. } else {
  11282. /*
  11283. * There's no other predicate than the [n] predicate.
  11284. */
  11285. predOp = NULL;
  11286. hasAxisRange = 1;
  11287. }
  11288. }
  11289. }
  11290. breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
  11291. /*
  11292. * Axis traversal -----------------------------------------------------
  11293. */
  11294. /*
  11295. * 2.3 Node Tests
  11296. * - For the attribute axis, the principal node type is attribute.
  11297. * - For the namespace axis, the principal node type is namespace.
  11298. * - For other axes, the principal node type is element.
  11299. *
  11300. * A node test * is true for any node of the
  11301. * principal node type. For example, child::* will
  11302. * select all element children of the context node
  11303. */
  11304. oldContextNode = xpctxt->node;
  11305. addNode = xmlXPathNodeSetAddUnique;
  11306. outSeq = NULL;
  11307. seq = NULL;
  11308. contextNode = NULL;
  11309. contextIdx = 0;
  11310. while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
  11311. (ctxt->error == XPATH_EXPRESSION_OK)) {
  11312. xpctxt->node = contextSeq->nodeTab[contextIdx++];
  11313. if (seq == NULL) {
  11314. seq = xmlXPathNodeSetCreate(NULL);
  11315. if (seq == NULL) {
  11316. /* TODO: Propagate memory error. */
  11317. total = 0;
  11318. goto error;
  11319. }
  11320. }
  11321. /*
  11322. * Traverse the axis and test the nodes.
  11323. */
  11324. pos = 0;
  11325. cur = NULL;
  11326. hasNsNodes = 0;
  11327. do {
  11328. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  11329. goto error;
  11330. cur = next(ctxt, cur);
  11331. if (cur == NULL)
  11332. break;
  11333. /*
  11334. * QUESTION TODO: What does the "first" and "last" stuff do?
  11335. */
  11336. if ((first != NULL) && (*first != NULL)) {
  11337. if (*first == cur)
  11338. break;
  11339. if (((total % 256) == 0) &&
  11340. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  11341. (xmlXPathCmpNodesExt(*first, cur) >= 0))
  11342. #else
  11343. (xmlXPathCmpNodes(*first, cur) >= 0))
  11344. #endif
  11345. {
  11346. break;
  11347. }
  11348. }
  11349. if ((last != NULL) && (*last != NULL)) {
  11350. if (*last == cur)
  11351. break;
  11352. if (((total % 256) == 0) &&
  11353. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  11354. (xmlXPathCmpNodesExt(cur, *last) >= 0))
  11355. #else
  11356. (xmlXPathCmpNodes(cur, *last) >= 0))
  11357. #endif
  11358. {
  11359. break;
  11360. }
  11361. }
  11362. total++;
  11363. #ifdef DEBUG_STEP
  11364. xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
  11365. #endif
  11366. switch (test) {
  11367. case NODE_TEST_NONE:
  11368. total = 0;
  11369. STRANGE
  11370. goto error;
  11371. case NODE_TEST_TYPE:
  11372. if (type == NODE_TYPE_NODE) {
  11373. switch (cur->type) {
  11374. case XML_DOCUMENT_NODE:
  11375. case XML_HTML_DOCUMENT_NODE:
  11376. #ifdef LIBXML_DOCB_ENABLED
  11377. case XML_DOCB_DOCUMENT_NODE:
  11378. #endif
  11379. case XML_ELEMENT_NODE:
  11380. case XML_ATTRIBUTE_NODE:
  11381. case XML_PI_NODE:
  11382. case XML_COMMENT_NODE:
  11383. case XML_CDATA_SECTION_NODE:
  11384. case XML_TEXT_NODE:
  11385. XP_TEST_HIT
  11386. break;
  11387. case XML_NAMESPACE_DECL: {
  11388. if (axis == AXIS_NAMESPACE) {
  11389. XP_TEST_HIT_NS
  11390. } else {
  11391. hasNsNodes = 1;
  11392. XP_TEST_HIT
  11393. }
  11394. break;
  11395. }
  11396. default:
  11397. break;
  11398. }
  11399. } else if (cur->type == (xmlElementType) type) {
  11400. if (cur->type == XML_NAMESPACE_DECL)
  11401. XP_TEST_HIT_NS
  11402. else
  11403. XP_TEST_HIT
  11404. } else if ((type == NODE_TYPE_TEXT) &&
  11405. (cur->type == XML_CDATA_SECTION_NODE))
  11406. {
  11407. XP_TEST_HIT
  11408. }
  11409. break;
  11410. case NODE_TEST_PI:
  11411. if ((cur->type == XML_PI_NODE) &&
  11412. ((name == NULL) || xmlStrEqual(name, cur->name)))
  11413. {
  11414. XP_TEST_HIT
  11415. }
  11416. break;
  11417. case NODE_TEST_ALL:
  11418. if (axis == AXIS_ATTRIBUTE) {
  11419. if (cur->type == XML_ATTRIBUTE_NODE)
  11420. {
  11421. if (prefix == NULL)
  11422. {
  11423. XP_TEST_HIT
  11424. } else if ((cur->ns != NULL) &&
  11425. (xmlStrEqual(URI, cur->ns->href)))
  11426. {
  11427. XP_TEST_HIT
  11428. }
  11429. }
  11430. } else if (axis == AXIS_NAMESPACE) {
  11431. if (cur->type == XML_NAMESPACE_DECL)
  11432. {
  11433. XP_TEST_HIT_NS
  11434. }
  11435. } else {
  11436. if (cur->type == XML_ELEMENT_NODE) {
  11437. if (prefix == NULL)
  11438. {
  11439. XP_TEST_HIT
  11440. } else if ((cur->ns != NULL) &&
  11441. (xmlStrEqual(URI, cur->ns->href)))
  11442. {
  11443. XP_TEST_HIT
  11444. }
  11445. }
  11446. }
  11447. break;
  11448. case NODE_TEST_NS:{
  11449. TODO;
  11450. break;
  11451. }
  11452. case NODE_TEST_NAME:
  11453. if (axis == AXIS_ATTRIBUTE) {
  11454. if (cur->type != XML_ATTRIBUTE_NODE)
  11455. break;
  11456. } else if (axis == AXIS_NAMESPACE) {
  11457. if (cur->type != XML_NAMESPACE_DECL)
  11458. break;
  11459. } else {
  11460. if (cur->type != XML_ELEMENT_NODE)
  11461. break;
  11462. }
  11463. switch (cur->type) {
  11464. case XML_ELEMENT_NODE:
  11465. if (xmlStrEqual(name, cur->name)) {
  11466. if (prefix == NULL) {
  11467. if (cur->ns == NULL)
  11468. {
  11469. XP_TEST_HIT
  11470. }
  11471. } else {
  11472. if ((cur->ns != NULL) &&
  11473. (xmlStrEqual(URI, cur->ns->href)))
  11474. {
  11475. XP_TEST_HIT
  11476. }
  11477. }
  11478. }
  11479. break;
  11480. case XML_ATTRIBUTE_NODE:{
  11481. xmlAttrPtr attr = (xmlAttrPtr) cur;
  11482. if (xmlStrEqual(name, attr->name)) {
  11483. if (prefix == NULL) {
  11484. if ((attr->ns == NULL) ||
  11485. (attr->ns->prefix == NULL))
  11486. {
  11487. XP_TEST_HIT
  11488. }
  11489. } else {
  11490. if ((attr->ns != NULL) &&
  11491. (xmlStrEqual(URI,
  11492. attr->ns->href)))
  11493. {
  11494. XP_TEST_HIT
  11495. }
  11496. }
  11497. }
  11498. break;
  11499. }
  11500. case XML_NAMESPACE_DECL:
  11501. if (cur->type == XML_NAMESPACE_DECL) {
  11502. xmlNsPtr ns = (xmlNsPtr) cur;
  11503. if ((ns->prefix != NULL) && (name != NULL)
  11504. && (xmlStrEqual(ns->prefix, name)))
  11505. {
  11506. XP_TEST_HIT_NS
  11507. }
  11508. }
  11509. break;
  11510. default:
  11511. break;
  11512. }
  11513. break;
  11514. } /* switch(test) */
  11515. } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
  11516. goto apply_predicates;
  11517. axis_range_end: /* ----------------------------------------------------- */
  11518. /*
  11519. * We have a "/foo[n]", and position() = n was reached.
  11520. * Note that we can have as well "/foo/::parent::foo[1]", so
  11521. * a duplicate-aware merge is still needed.
  11522. * Merge with the result.
  11523. */
  11524. if (outSeq == NULL) {
  11525. outSeq = seq;
  11526. seq = NULL;
  11527. } else
  11528. /* TODO: Check memory error. */
  11529. outSeq = mergeAndClear(outSeq, seq);
  11530. /*
  11531. * Break if only a true/false result was requested.
  11532. */
  11533. if (toBool)
  11534. break;
  11535. continue;
  11536. first_hit: /* ---------------------------------------------------------- */
  11537. /*
  11538. * Break if only a true/false result was requested and
  11539. * no predicates existed and a node test succeeded.
  11540. */
  11541. if (outSeq == NULL) {
  11542. outSeq = seq;
  11543. seq = NULL;
  11544. } else
  11545. /* TODO: Check memory error. */
  11546. outSeq = mergeAndClear(outSeq, seq);
  11547. break;
  11548. #ifdef DEBUG_STEP
  11549. if (seq != NULL)
  11550. nbMatches += seq->nodeNr;
  11551. #endif
  11552. apply_predicates: /* --------------------------------------------------- */
  11553. if (ctxt->error != XPATH_EXPRESSION_OK)
  11554. goto error;
  11555. /*
  11556. * Apply predicates.
  11557. */
  11558. if ((predOp != NULL) && (seq->nodeNr > 0)) {
  11559. /*
  11560. * E.g. when we have a "/foo[some expression][n]".
  11561. */
  11562. /*
  11563. * QUESTION TODO: The old predicate evaluation took into
  11564. * account location-sets.
  11565. * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
  11566. * Do we expect such a set here?
  11567. * All what I learned now from the evaluation semantics
  11568. * does not indicate that a location-set will be processed
  11569. * here, so this looks OK.
  11570. */
  11571. /*
  11572. * Iterate over all predicates, starting with the outermost
  11573. * predicate.
  11574. * TODO: Problem: we cannot execute the inner predicates first
  11575. * since we cannot go back *up* the operator tree!
  11576. * Options we have:
  11577. * 1) Use of recursive functions (like is it currently done
  11578. * via xmlXPathCompOpEval())
  11579. * 2) Add a predicate evaluation information stack to the
  11580. * context struct
  11581. * 3) Change the way the operators are linked; we need a
  11582. * "parent" field on xmlXPathStepOp
  11583. *
  11584. * For the moment, I'll try to solve this with a recursive
  11585. * function: xmlXPathCompOpEvalPredicate().
  11586. */
  11587. if (hasPredicateRange != 0)
  11588. xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
  11589. hasNsNodes);
  11590. else
  11591. xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
  11592. hasNsNodes);
  11593. if (ctxt->error != XPATH_EXPRESSION_OK) {
  11594. total = 0;
  11595. goto error;
  11596. }
  11597. }
  11598. if (seq->nodeNr > 0) {
  11599. /*
  11600. * Add to result set.
  11601. */
  11602. if (outSeq == NULL) {
  11603. outSeq = seq;
  11604. seq = NULL;
  11605. } else {
  11606. /* TODO: Check memory error. */
  11607. outSeq = mergeAndClear(outSeq, seq);
  11608. }
  11609. if (toBool)
  11610. break;
  11611. }
  11612. }
  11613. error:
  11614. if ((obj->boolval) && (obj->user != NULL)) {
  11615. /*
  11616. * QUESTION TODO: What does this do and why?
  11617. * TODO: Do we have to do this also for the "error"
  11618. * cleanup further down?
  11619. */
  11620. ctxt->value->boolval = 1;
  11621. ctxt->value->user = obj->user;
  11622. obj->user = NULL;
  11623. obj->boolval = 0;
  11624. }
  11625. xmlXPathReleaseObject(xpctxt, obj);
  11626. /*
  11627. * Ensure we return at least an empty set.
  11628. */
  11629. if (outSeq == NULL) {
  11630. if ((seq != NULL) && (seq->nodeNr == 0))
  11631. outSeq = seq;
  11632. else
  11633. /* TODO: Check memory error. */
  11634. outSeq = xmlXPathNodeSetCreate(NULL);
  11635. }
  11636. if ((seq != NULL) && (seq != outSeq)) {
  11637. xmlXPathFreeNodeSet(seq);
  11638. }
  11639. /*
  11640. * Hand over the result. Better to push the set also in
  11641. * case of errors.
  11642. */
  11643. valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
  11644. /*
  11645. * Reset the context node.
  11646. */
  11647. xpctxt->node = oldContextNode;
  11648. /*
  11649. * When traversing the namespace axis in "toBool" mode, it's
  11650. * possible that tmpNsList wasn't freed.
  11651. */
  11652. if (xpctxt->tmpNsList != NULL) {
  11653. xmlFree(xpctxt->tmpNsList);
  11654. xpctxt->tmpNsList = NULL;
  11655. }
  11656. #ifdef DEBUG_STEP
  11657. xmlGenericError(xmlGenericErrorContext,
  11658. "\nExamined %d nodes, found %d nodes at that step\n",
  11659. total, nbMatches);
  11660. #endif
  11661. return(total);
  11662. }
  11663. static int
  11664. xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
  11665. xmlXPathStepOpPtr op, xmlNodePtr * first);
  11666. /**
  11667. * xmlXPathCompOpEvalFirst:
  11668. * @ctxt: the XPath parser context with the compiled expression
  11669. * @op: an XPath compiled operation
  11670. * @first: the first elem found so far
  11671. *
  11672. * Evaluate the Precompiled XPath operation searching only the first
  11673. * element in document order
  11674. *
  11675. * Returns the number of examined objects.
  11676. */
  11677. static int
  11678. xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
  11679. xmlXPathStepOpPtr op, xmlNodePtr * first)
  11680. {
  11681. int total = 0, cur;
  11682. xmlXPathCompExprPtr comp;
  11683. xmlXPathObjectPtr arg1, arg2;
  11684. CHECK_ERROR0;
  11685. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  11686. return(0);
  11687. if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
  11688. XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
  11689. ctxt->context->depth += 1;
  11690. comp = ctxt->comp;
  11691. switch (op->op) {
  11692. case XPATH_OP_END:
  11693. break;
  11694. case XPATH_OP_UNION:
  11695. total =
  11696. xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
  11697. first);
  11698. CHECK_ERROR0;
  11699. if ((ctxt->value != NULL)
  11700. && (ctxt->value->type == XPATH_NODESET)
  11701. && (ctxt->value->nodesetval != NULL)
  11702. && (ctxt->value->nodesetval->nodeNr >= 1)) {
  11703. /*
  11704. * limit tree traversing to first node in the result
  11705. */
  11706. /*
  11707. * OPTIMIZE TODO: This implicitly sorts
  11708. * the result, even if not needed. E.g. if the argument
  11709. * of the count() function, no sorting is needed.
  11710. * OPTIMIZE TODO: How do we know if the node-list wasn't
  11711. * already sorted?
  11712. */
  11713. if (ctxt->value->nodesetval->nodeNr > 1)
  11714. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  11715. *first = ctxt->value->nodesetval->nodeTab[0];
  11716. }
  11717. cur =
  11718. xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
  11719. first);
  11720. CHECK_ERROR0;
  11721. arg2 = valuePop(ctxt);
  11722. arg1 = valuePop(ctxt);
  11723. if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
  11724. (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
  11725. xmlXPathReleaseObject(ctxt->context, arg1);
  11726. xmlXPathReleaseObject(ctxt->context, arg2);
  11727. XP_ERROR0(XPATH_INVALID_TYPE);
  11728. }
  11729. if ((ctxt->context->opLimit != 0) &&
  11730. (((arg1->nodesetval != NULL) &&
  11731. (xmlXPathCheckOpLimit(ctxt,
  11732. arg1->nodesetval->nodeNr) < 0)) ||
  11733. ((arg2->nodesetval != NULL) &&
  11734. (xmlXPathCheckOpLimit(ctxt,
  11735. arg2->nodesetval->nodeNr) < 0)))) {
  11736. xmlXPathReleaseObject(ctxt->context, arg1);
  11737. xmlXPathReleaseObject(ctxt->context, arg2);
  11738. break;
  11739. }
  11740. /* TODO: Check memory error. */
  11741. arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
  11742. arg2->nodesetval);
  11743. valuePush(ctxt, arg1);
  11744. xmlXPathReleaseObject(ctxt->context, arg2);
  11745. /* optimizer */
  11746. if (total > cur)
  11747. xmlXPathCompSwap(op);
  11748. total += cur;
  11749. break;
  11750. case XPATH_OP_ROOT:
  11751. xmlXPathRoot(ctxt);
  11752. break;
  11753. case XPATH_OP_NODE:
  11754. if (op->ch1 != -1)
  11755. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11756. CHECK_ERROR0;
  11757. if (op->ch2 != -1)
  11758. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11759. CHECK_ERROR0;
  11760. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  11761. ctxt->context->node));
  11762. break;
  11763. case XPATH_OP_COLLECT:{
  11764. if (op->ch1 == -1)
  11765. break;
  11766. total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11767. CHECK_ERROR0;
  11768. total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
  11769. break;
  11770. }
  11771. case XPATH_OP_VALUE:
  11772. valuePush(ctxt,
  11773. xmlXPathCacheObjectCopy(ctxt->context,
  11774. (xmlXPathObjectPtr) op->value4));
  11775. break;
  11776. case XPATH_OP_SORT:
  11777. if (op->ch1 != -1)
  11778. total +=
  11779. xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
  11780. first);
  11781. CHECK_ERROR0;
  11782. if ((ctxt->value != NULL)
  11783. && (ctxt->value->type == XPATH_NODESET)
  11784. && (ctxt->value->nodesetval != NULL)
  11785. && (ctxt->value->nodesetval->nodeNr > 1))
  11786. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  11787. break;
  11788. #ifdef XP_OPTIMIZED_FILTER_FIRST
  11789. case XPATH_OP_FILTER:
  11790. total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
  11791. break;
  11792. #endif
  11793. default:
  11794. total += xmlXPathCompOpEval(ctxt, op);
  11795. break;
  11796. }
  11797. ctxt->context->depth -= 1;
  11798. return(total);
  11799. }
  11800. /**
  11801. * xmlXPathCompOpEvalLast:
  11802. * @ctxt: the XPath parser context with the compiled expression
  11803. * @op: an XPath compiled operation
  11804. * @last: the last elem found so far
  11805. *
  11806. * Evaluate the Precompiled XPath operation searching only the last
  11807. * element in document order
  11808. *
  11809. * Returns the number of nodes traversed
  11810. */
  11811. static int
  11812. xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
  11813. xmlNodePtr * last)
  11814. {
  11815. int total = 0, cur;
  11816. xmlXPathCompExprPtr comp;
  11817. xmlXPathObjectPtr arg1, arg2;
  11818. CHECK_ERROR0;
  11819. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  11820. return(0);
  11821. if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
  11822. XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
  11823. ctxt->context->depth += 1;
  11824. comp = ctxt->comp;
  11825. switch (op->op) {
  11826. case XPATH_OP_END:
  11827. break;
  11828. case XPATH_OP_UNION:
  11829. total =
  11830. xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
  11831. CHECK_ERROR0;
  11832. if ((ctxt->value != NULL)
  11833. && (ctxt->value->type == XPATH_NODESET)
  11834. && (ctxt->value->nodesetval != NULL)
  11835. && (ctxt->value->nodesetval->nodeNr >= 1)) {
  11836. /*
  11837. * limit tree traversing to first node in the result
  11838. */
  11839. if (ctxt->value->nodesetval->nodeNr > 1)
  11840. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  11841. *last =
  11842. ctxt->value->nodesetval->nodeTab[ctxt->value->
  11843. nodesetval->nodeNr -
  11844. 1];
  11845. }
  11846. cur =
  11847. xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
  11848. CHECK_ERROR0;
  11849. if ((ctxt->value != NULL)
  11850. && (ctxt->value->type == XPATH_NODESET)
  11851. && (ctxt->value->nodesetval != NULL)
  11852. && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
  11853. }
  11854. arg2 = valuePop(ctxt);
  11855. arg1 = valuePop(ctxt);
  11856. if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
  11857. (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
  11858. xmlXPathReleaseObject(ctxt->context, arg1);
  11859. xmlXPathReleaseObject(ctxt->context, arg2);
  11860. XP_ERROR0(XPATH_INVALID_TYPE);
  11861. }
  11862. if ((ctxt->context->opLimit != 0) &&
  11863. (((arg1->nodesetval != NULL) &&
  11864. (xmlXPathCheckOpLimit(ctxt,
  11865. arg1->nodesetval->nodeNr) < 0)) ||
  11866. ((arg2->nodesetval != NULL) &&
  11867. (xmlXPathCheckOpLimit(ctxt,
  11868. arg2->nodesetval->nodeNr) < 0)))) {
  11869. xmlXPathReleaseObject(ctxt->context, arg1);
  11870. xmlXPathReleaseObject(ctxt->context, arg2);
  11871. break;
  11872. }
  11873. /* TODO: Check memory error. */
  11874. arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
  11875. arg2->nodesetval);
  11876. valuePush(ctxt, arg1);
  11877. xmlXPathReleaseObject(ctxt->context, arg2);
  11878. /* optimizer */
  11879. if (total > cur)
  11880. xmlXPathCompSwap(op);
  11881. total += cur;
  11882. break;
  11883. case XPATH_OP_ROOT:
  11884. xmlXPathRoot(ctxt);
  11885. break;
  11886. case XPATH_OP_NODE:
  11887. if (op->ch1 != -1)
  11888. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11889. CHECK_ERROR0;
  11890. if (op->ch2 != -1)
  11891. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11892. CHECK_ERROR0;
  11893. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  11894. ctxt->context->node));
  11895. break;
  11896. case XPATH_OP_COLLECT:{
  11897. if (op->ch1 == -1)
  11898. break;
  11899. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11900. CHECK_ERROR0;
  11901. total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
  11902. break;
  11903. }
  11904. case XPATH_OP_VALUE:
  11905. valuePush(ctxt,
  11906. xmlXPathCacheObjectCopy(ctxt->context,
  11907. (xmlXPathObjectPtr) op->value4));
  11908. break;
  11909. case XPATH_OP_SORT:
  11910. if (op->ch1 != -1)
  11911. total +=
  11912. xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
  11913. last);
  11914. CHECK_ERROR0;
  11915. if ((ctxt->value != NULL)
  11916. && (ctxt->value->type == XPATH_NODESET)
  11917. && (ctxt->value->nodesetval != NULL)
  11918. && (ctxt->value->nodesetval->nodeNr > 1))
  11919. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  11920. break;
  11921. default:
  11922. total += xmlXPathCompOpEval(ctxt, op);
  11923. break;
  11924. }
  11925. ctxt->context->depth -= 1;
  11926. return (total);
  11927. }
  11928. #ifdef XP_OPTIMIZED_FILTER_FIRST
  11929. static int
  11930. xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
  11931. xmlXPathStepOpPtr op, xmlNodePtr * first)
  11932. {
  11933. int total = 0;
  11934. xmlXPathCompExprPtr comp;
  11935. xmlNodeSetPtr set;
  11936. CHECK_ERROR0;
  11937. comp = ctxt->comp;
  11938. /*
  11939. * Optimization for ()[last()] selection i.e. the last elem
  11940. */
  11941. if ((op->ch1 != -1) && (op->ch2 != -1) &&
  11942. (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
  11943. (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
  11944. int f = comp->steps[op->ch2].ch1;
  11945. if ((f != -1) &&
  11946. (comp->steps[f].op == XPATH_OP_FUNCTION) &&
  11947. (comp->steps[f].value5 == NULL) &&
  11948. (comp->steps[f].value == 0) &&
  11949. (comp->steps[f].value4 != NULL) &&
  11950. (xmlStrEqual
  11951. (comp->steps[f].value4, BAD_CAST "last"))) {
  11952. xmlNodePtr last = NULL;
  11953. total +=
  11954. xmlXPathCompOpEvalLast(ctxt,
  11955. &comp->steps[op->ch1],
  11956. &last);
  11957. CHECK_ERROR0;
  11958. /*
  11959. * The nodeset should be in document order,
  11960. * Keep only the last value
  11961. */
  11962. if ((ctxt->value != NULL) &&
  11963. (ctxt->value->type == XPATH_NODESET) &&
  11964. (ctxt->value->nodesetval != NULL) &&
  11965. (ctxt->value->nodesetval->nodeTab != NULL) &&
  11966. (ctxt->value->nodesetval->nodeNr > 1)) {
  11967. xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
  11968. *first = *(ctxt->value->nodesetval->nodeTab);
  11969. }
  11970. return (total);
  11971. }
  11972. }
  11973. if (op->ch1 != -1)
  11974. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11975. CHECK_ERROR0;
  11976. if (op->ch2 == -1)
  11977. return (total);
  11978. if (ctxt->value == NULL)
  11979. return (total);
  11980. #ifdef LIBXML_XPTR_ENABLED
  11981. /*
  11982. * Hum are we filtering the result of an XPointer expression
  11983. */
  11984. if (ctxt->value->type == XPATH_LOCATIONSET) {
  11985. xmlLocationSetPtr locset = ctxt->value->user;
  11986. if (locset != NULL) {
  11987. xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
  11988. if (locset->locNr > 0)
  11989. *first = (xmlNodePtr) locset->locTab[0]->user;
  11990. }
  11991. return (total);
  11992. }
  11993. #endif /* LIBXML_XPTR_ENABLED */
  11994. CHECK_TYPE0(XPATH_NODESET);
  11995. set = ctxt->value->nodesetval;
  11996. if (set != NULL) {
  11997. xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
  11998. if (set->nodeNr > 0)
  11999. *first = set->nodeTab[0];
  12000. }
  12001. return (total);
  12002. }
  12003. #endif /* XP_OPTIMIZED_FILTER_FIRST */
  12004. /**
  12005. * xmlXPathCompOpEval:
  12006. * @ctxt: the XPath parser context with the compiled expression
  12007. * @op: an XPath compiled operation
  12008. *
  12009. * Evaluate the Precompiled XPath operation
  12010. * Returns the number of nodes traversed
  12011. */
  12012. static int
  12013. xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
  12014. {
  12015. int total = 0;
  12016. int equal, ret;
  12017. xmlXPathCompExprPtr comp;
  12018. xmlXPathObjectPtr arg1, arg2;
  12019. CHECK_ERROR0;
  12020. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  12021. return(0);
  12022. if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
  12023. XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
  12024. ctxt->context->depth += 1;
  12025. comp = ctxt->comp;
  12026. switch (op->op) {
  12027. case XPATH_OP_END:
  12028. break;
  12029. case XPATH_OP_AND:
  12030. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12031. CHECK_ERROR0;
  12032. xmlXPathBooleanFunction(ctxt, 1);
  12033. if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
  12034. break;
  12035. arg2 = valuePop(ctxt);
  12036. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12037. if (ctxt->error) {
  12038. xmlXPathFreeObject(arg2);
  12039. break;
  12040. }
  12041. xmlXPathBooleanFunction(ctxt, 1);
  12042. if (ctxt->value != NULL)
  12043. ctxt->value->boolval &= arg2->boolval;
  12044. xmlXPathReleaseObject(ctxt->context, arg2);
  12045. break;
  12046. case XPATH_OP_OR:
  12047. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12048. CHECK_ERROR0;
  12049. xmlXPathBooleanFunction(ctxt, 1);
  12050. if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
  12051. break;
  12052. arg2 = valuePop(ctxt);
  12053. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12054. if (ctxt->error) {
  12055. xmlXPathFreeObject(arg2);
  12056. break;
  12057. }
  12058. xmlXPathBooleanFunction(ctxt, 1);
  12059. if (ctxt->value != NULL)
  12060. ctxt->value->boolval |= arg2->boolval;
  12061. xmlXPathReleaseObject(ctxt->context, arg2);
  12062. break;
  12063. case XPATH_OP_EQUAL:
  12064. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12065. CHECK_ERROR0;
  12066. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12067. CHECK_ERROR0;
  12068. if (op->value)
  12069. equal = xmlXPathEqualValues(ctxt);
  12070. else
  12071. equal = xmlXPathNotEqualValues(ctxt);
  12072. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
  12073. break;
  12074. case XPATH_OP_CMP:
  12075. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12076. CHECK_ERROR0;
  12077. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12078. CHECK_ERROR0;
  12079. ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
  12080. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
  12081. break;
  12082. case XPATH_OP_PLUS:
  12083. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12084. CHECK_ERROR0;
  12085. if (op->ch2 != -1) {
  12086. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12087. }
  12088. CHECK_ERROR0;
  12089. if (op->value == 0)
  12090. xmlXPathSubValues(ctxt);
  12091. else if (op->value == 1)
  12092. xmlXPathAddValues(ctxt);
  12093. else if (op->value == 2)
  12094. xmlXPathValueFlipSign(ctxt);
  12095. else if (op->value == 3) {
  12096. CAST_TO_NUMBER;
  12097. CHECK_TYPE0(XPATH_NUMBER);
  12098. }
  12099. break;
  12100. case XPATH_OP_MULT:
  12101. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12102. CHECK_ERROR0;
  12103. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12104. CHECK_ERROR0;
  12105. if (op->value == 0)
  12106. xmlXPathMultValues(ctxt);
  12107. else if (op->value == 1)
  12108. xmlXPathDivValues(ctxt);
  12109. else if (op->value == 2)
  12110. xmlXPathModValues(ctxt);
  12111. break;
  12112. case XPATH_OP_UNION:
  12113. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12114. CHECK_ERROR0;
  12115. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12116. CHECK_ERROR0;
  12117. arg2 = valuePop(ctxt);
  12118. arg1 = valuePop(ctxt);
  12119. if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
  12120. (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
  12121. xmlXPathReleaseObject(ctxt->context, arg1);
  12122. xmlXPathReleaseObject(ctxt->context, arg2);
  12123. XP_ERROR0(XPATH_INVALID_TYPE);
  12124. }
  12125. if ((ctxt->context->opLimit != 0) &&
  12126. (((arg1->nodesetval != NULL) &&
  12127. (xmlXPathCheckOpLimit(ctxt,
  12128. arg1->nodesetval->nodeNr) < 0)) ||
  12129. ((arg2->nodesetval != NULL) &&
  12130. (xmlXPathCheckOpLimit(ctxt,
  12131. arg2->nodesetval->nodeNr) < 0)))) {
  12132. xmlXPathReleaseObject(ctxt->context, arg1);
  12133. xmlXPathReleaseObject(ctxt->context, arg2);
  12134. break;
  12135. }
  12136. if ((arg1->nodesetval == NULL) ||
  12137. ((arg2->nodesetval != NULL) &&
  12138. (arg2->nodesetval->nodeNr != 0)))
  12139. {
  12140. /* TODO: Check memory error. */
  12141. arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
  12142. arg2->nodesetval);
  12143. }
  12144. valuePush(ctxt, arg1);
  12145. xmlXPathReleaseObject(ctxt->context, arg2);
  12146. break;
  12147. case XPATH_OP_ROOT:
  12148. xmlXPathRoot(ctxt);
  12149. break;
  12150. case XPATH_OP_NODE:
  12151. if (op->ch1 != -1)
  12152. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12153. CHECK_ERROR0;
  12154. if (op->ch2 != -1)
  12155. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12156. CHECK_ERROR0;
  12157. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  12158. ctxt->context->node));
  12159. break;
  12160. case XPATH_OP_COLLECT:{
  12161. if (op->ch1 == -1)
  12162. break;
  12163. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12164. CHECK_ERROR0;
  12165. total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
  12166. break;
  12167. }
  12168. case XPATH_OP_VALUE:
  12169. valuePush(ctxt,
  12170. xmlXPathCacheObjectCopy(ctxt->context,
  12171. (xmlXPathObjectPtr) op->value4));
  12172. break;
  12173. case XPATH_OP_VARIABLE:{
  12174. xmlXPathObjectPtr val;
  12175. if (op->ch1 != -1)
  12176. total +=
  12177. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12178. if (op->value5 == NULL) {
  12179. val = xmlXPathVariableLookup(ctxt->context, op->value4);
  12180. if (val == NULL)
  12181. XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
  12182. valuePush(ctxt, val);
  12183. } else {
  12184. const xmlChar *URI;
  12185. URI = xmlXPathNsLookup(ctxt->context, op->value5);
  12186. if (URI == NULL) {
  12187. xmlGenericError(xmlGenericErrorContext,
  12188. "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
  12189. (char *) op->value4, (char *)op->value5);
  12190. ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
  12191. break;
  12192. }
  12193. val = xmlXPathVariableLookupNS(ctxt->context,
  12194. op->value4, URI);
  12195. if (val == NULL)
  12196. XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
  12197. valuePush(ctxt, val);
  12198. }
  12199. break;
  12200. }
  12201. case XPATH_OP_FUNCTION:{
  12202. xmlXPathFunction func;
  12203. const xmlChar *oldFunc, *oldFuncURI;
  12204. int i;
  12205. int frame;
  12206. frame = xmlXPathSetFrame(ctxt);
  12207. if (op->ch1 != -1) {
  12208. total +=
  12209. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12210. if (ctxt->error != XPATH_EXPRESSION_OK) {
  12211. xmlXPathPopFrame(ctxt, frame);
  12212. break;
  12213. }
  12214. }
  12215. if (ctxt->valueNr < ctxt->valueFrame + op->value) {
  12216. xmlGenericError(xmlGenericErrorContext,
  12217. "xmlXPathCompOpEval: parameter error\n");
  12218. ctxt->error = XPATH_INVALID_OPERAND;
  12219. xmlXPathPopFrame(ctxt, frame);
  12220. break;
  12221. }
  12222. for (i = 0; i < op->value; i++) {
  12223. if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
  12224. xmlGenericError(xmlGenericErrorContext,
  12225. "xmlXPathCompOpEval: parameter error\n");
  12226. ctxt->error = XPATH_INVALID_OPERAND;
  12227. xmlXPathPopFrame(ctxt, frame);
  12228. break;
  12229. }
  12230. }
  12231. if (op->cache != NULL)
  12232. func = op->cache;
  12233. else {
  12234. const xmlChar *URI = NULL;
  12235. if (op->value5 == NULL)
  12236. func =
  12237. xmlXPathFunctionLookup(ctxt->context,
  12238. op->value4);
  12239. else {
  12240. URI = xmlXPathNsLookup(ctxt->context, op->value5);
  12241. if (URI == NULL) {
  12242. xmlGenericError(xmlGenericErrorContext,
  12243. "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
  12244. (char *)op->value4, (char *)op->value5);
  12245. xmlXPathPopFrame(ctxt, frame);
  12246. ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
  12247. break;
  12248. }
  12249. func = xmlXPathFunctionLookupNS(ctxt->context,
  12250. op->value4, URI);
  12251. }
  12252. if (func == NULL) {
  12253. xmlGenericError(xmlGenericErrorContext,
  12254. "xmlXPathCompOpEval: function %s not found\n",
  12255. (char *)op->value4);
  12256. XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
  12257. }
  12258. op->cache = func;
  12259. op->cacheURI = (void *) URI;
  12260. }
  12261. oldFunc = ctxt->context->function;
  12262. oldFuncURI = ctxt->context->functionURI;
  12263. ctxt->context->function = op->value4;
  12264. ctxt->context->functionURI = op->cacheURI;
  12265. func(ctxt, op->value);
  12266. ctxt->context->function = oldFunc;
  12267. ctxt->context->functionURI = oldFuncURI;
  12268. if ((ctxt->error == XPATH_EXPRESSION_OK) &&
  12269. (ctxt->valueNr != ctxt->valueFrame + 1))
  12270. XP_ERROR0(XPATH_STACK_ERROR);
  12271. xmlXPathPopFrame(ctxt, frame);
  12272. break;
  12273. }
  12274. case XPATH_OP_ARG:
  12275. if (op->ch1 != -1) {
  12276. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12277. CHECK_ERROR0;
  12278. }
  12279. if (op->ch2 != -1) {
  12280. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12281. CHECK_ERROR0;
  12282. }
  12283. break;
  12284. case XPATH_OP_PREDICATE:
  12285. case XPATH_OP_FILTER:{
  12286. xmlNodeSetPtr set;
  12287. /*
  12288. * Optimization for ()[1] selection i.e. the first elem
  12289. */
  12290. if ((op->ch1 != -1) && (op->ch2 != -1) &&
  12291. #ifdef XP_OPTIMIZED_FILTER_FIRST
  12292. /*
  12293. * FILTER TODO: Can we assume that the inner processing
  12294. * will result in an ordered list if we have an
  12295. * XPATH_OP_FILTER?
  12296. * What about an additional field or flag on
  12297. * xmlXPathObject like @sorted ? This way we wouldn't need
  12298. * to assume anything, so it would be more robust and
  12299. * easier to optimize.
  12300. */
  12301. ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
  12302. (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
  12303. #else
  12304. (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
  12305. #endif
  12306. (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
  12307. xmlXPathObjectPtr val;
  12308. val = comp->steps[op->ch2].value4;
  12309. if ((val != NULL) && (val->type == XPATH_NUMBER) &&
  12310. (val->floatval == 1.0)) {
  12311. xmlNodePtr first = NULL;
  12312. total +=
  12313. xmlXPathCompOpEvalFirst(ctxt,
  12314. &comp->steps[op->ch1],
  12315. &first);
  12316. CHECK_ERROR0;
  12317. /*
  12318. * The nodeset should be in document order,
  12319. * Keep only the first value
  12320. */
  12321. if ((ctxt->value != NULL) &&
  12322. (ctxt->value->type == XPATH_NODESET) &&
  12323. (ctxt->value->nodesetval != NULL) &&
  12324. (ctxt->value->nodesetval->nodeNr > 1))
  12325. xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
  12326. 1, 1);
  12327. break;
  12328. }
  12329. }
  12330. /*
  12331. * Optimization for ()[last()] selection i.e. the last elem
  12332. */
  12333. if ((op->ch1 != -1) && (op->ch2 != -1) &&
  12334. (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
  12335. (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
  12336. int f = comp->steps[op->ch2].ch1;
  12337. if ((f != -1) &&
  12338. (comp->steps[f].op == XPATH_OP_FUNCTION) &&
  12339. (comp->steps[f].value5 == NULL) &&
  12340. (comp->steps[f].value == 0) &&
  12341. (comp->steps[f].value4 != NULL) &&
  12342. (xmlStrEqual
  12343. (comp->steps[f].value4, BAD_CAST "last"))) {
  12344. xmlNodePtr last = NULL;
  12345. total +=
  12346. xmlXPathCompOpEvalLast(ctxt,
  12347. &comp->steps[op->ch1],
  12348. &last);
  12349. CHECK_ERROR0;
  12350. /*
  12351. * The nodeset should be in document order,
  12352. * Keep only the last value
  12353. */
  12354. if ((ctxt->value != NULL) &&
  12355. (ctxt->value->type == XPATH_NODESET) &&
  12356. (ctxt->value->nodesetval != NULL) &&
  12357. (ctxt->value->nodesetval->nodeTab != NULL) &&
  12358. (ctxt->value->nodesetval->nodeNr > 1))
  12359. xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
  12360. break;
  12361. }
  12362. }
  12363. /*
  12364. * Process inner predicates first.
  12365. * Example "index[parent::book][1]":
  12366. * ...
  12367. * PREDICATE <-- we are here "[1]"
  12368. * PREDICATE <-- process "[parent::book]" first
  12369. * SORT
  12370. * COLLECT 'parent' 'name' 'node' book
  12371. * NODE
  12372. * ELEM Object is a number : 1
  12373. */
  12374. if (op->ch1 != -1)
  12375. total +=
  12376. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12377. CHECK_ERROR0;
  12378. if (op->ch2 == -1)
  12379. break;
  12380. if (ctxt->value == NULL)
  12381. break;
  12382. #ifdef LIBXML_XPTR_ENABLED
  12383. /*
  12384. * Hum are we filtering the result of an XPointer expression
  12385. */
  12386. if (ctxt->value->type == XPATH_LOCATIONSET) {
  12387. xmlLocationSetPtr locset = ctxt->value->user;
  12388. xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
  12389. 1, locset->locNr);
  12390. break;
  12391. }
  12392. #endif /* LIBXML_XPTR_ENABLED */
  12393. CHECK_TYPE0(XPATH_NODESET);
  12394. set = ctxt->value->nodesetval;
  12395. if (set != NULL)
  12396. xmlXPathNodeSetFilter(ctxt, set, op->ch2,
  12397. 1, set->nodeNr, 1);
  12398. break;
  12399. }
  12400. case XPATH_OP_SORT:
  12401. if (op->ch1 != -1)
  12402. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12403. CHECK_ERROR0;
  12404. if ((ctxt->value != NULL) &&
  12405. (ctxt->value->type == XPATH_NODESET) &&
  12406. (ctxt->value->nodesetval != NULL) &&
  12407. (ctxt->value->nodesetval->nodeNr > 1))
  12408. {
  12409. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  12410. }
  12411. break;
  12412. #ifdef LIBXML_XPTR_ENABLED
  12413. case XPATH_OP_RANGETO:{
  12414. xmlXPathObjectPtr range;
  12415. xmlXPathObjectPtr res, obj;
  12416. xmlXPathObjectPtr tmp;
  12417. xmlLocationSetPtr newlocset = NULL;
  12418. xmlLocationSetPtr oldlocset;
  12419. xmlNodeSetPtr oldset;
  12420. xmlNodePtr oldnode = ctxt->context->node;
  12421. int oldcs = ctxt->context->contextSize;
  12422. int oldpp = ctxt->context->proximityPosition;
  12423. int i, j;
  12424. if (op->ch1 != -1) {
  12425. total +=
  12426. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12427. CHECK_ERROR0;
  12428. }
  12429. if (ctxt->value == NULL) {
  12430. XP_ERROR0(XPATH_INVALID_OPERAND);
  12431. }
  12432. if (op->ch2 == -1)
  12433. break;
  12434. if (ctxt->value->type == XPATH_LOCATIONSET) {
  12435. /*
  12436. * Extract the old locset, and then evaluate the result of the
  12437. * expression for all the element in the locset. use it to grow
  12438. * up a new locset.
  12439. */
  12440. CHECK_TYPE0(XPATH_LOCATIONSET);
  12441. if ((ctxt->value->user == NULL) ||
  12442. (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
  12443. break;
  12444. obj = valuePop(ctxt);
  12445. oldlocset = obj->user;
  12446. newlocset = xmlXPtrLocationSetCreate(NULL);
  12447. for (i = 0; i < oldlocset->locNr; i++) {
  12448. /*
  12449. * Run the evaluation with a node list made of a
  12450. * single item in the nodelocset.
  12451. */
  12452. ctxt->context->node = oldlocset->locTab[i]->user;
  12453. ctxt->context->contextSize = oldlocset->locNr;
  12454. ctxt->context->proximityPosition = i + 1;
  12455. tmp = xmlXPathCacheNewNodeSet(ctxt->context,
  12456. ctxt->context->node);
  12457. valuePush(ctxt, tmp);
  12458. if (op->ch2 != -1)
  12459. total +=
  12460. xmlXPathCompOpEval(ctxt,
  12461. &comp->steps[op->ch2]);
  12462. if (ctxt->error != XPATH_EXPRESSION_OK) {
  12463. xmlXPtrFreeLocationSet(newlocset);
  12464. goto rangeto_error;
  12465. }
  12466. res = valuePop(ctxt);
  12467. if (res->type == XPATH_LOCATIONSET) {
  12468. xmlLocationSetPtr rloc =
  12469. (xmlLocationSetPtr)res->user;
  12470. for (j=0; j<rloc->locNr; j++) {
  12471. range = xmlXPtrNewRange(
  12472. oldlocset->locTab[i]->user,
  12473. oldlocset->locTab[i]->index,
  12474. rloc->locTab[j]->user2,
  12475. rloc->locTab[j]->index2);
  12476. if (range != NULL) {
  12477. xmlXPtrLocationSetAdd(newlocset, range);
  12478. }
  12479. }
  12480. } else {
  12481. range = xmlXPtrNewRangeNodeObject(
  12482. (xmlNodePtr)oldlocset->locTab[i]->user, res);
  12483. if (range != NULL) {
  12484. xmlXPtrLocationSetAdd(newlocset,range);
  12485. }
  12486. }
  12487. /*
  12488. * Cleanup
  12489. */
  12490. if (res != NULL) {
  12491. xmlXPathReleaseObject(ctxt->context, res);
  12492. }
  12493. if (ctxt->value == tmp) {
  12494. res = valuePop(ctxt);
  12495. xmlXPathReleaseObject(ctxt->context, res);
  12496. }
  12497. }
  12498. } else { /* Not a location set */
  12499. CHECK_TYPE0(XPATH_NODESET);
  12500. obj = valuePop(ctxt);
  12501. oldset = obj->nodesetval;
  12502. newlocset = xmlXPtrLocationSetCreate(NULL);
  12503. if (oldset != NULL) {
  12504. for (i = 0; i < oldset->nodeNr; i++) {
  12505. /*
  12506. * Run the evaluation with a node list made of a single item
  12507. * in the nodeset.
  12508. */
  12509. ctxt->context->node = oldset->nodeTab[i];
  12510. /*
  12511. * OPTIMIZE TODO: Avoid recreation for every iteration.
  12512. */
  12513. tmp = xmlXPathCacheNewNodeSet(ctxt->context,
  12514. ctxt->context->node);
  12515. valuePush(ctxt, tmp);
  12516. if (op->ch2 != -1)
  12517. total +=
  12518. xmlXPathCompOpEval(ctxt,
  12519. &comp->steps[op->ch2]);
  12520. if (ctxt->error != XPATH_EXPRESSION_OK) {
  12521. xmlXPtrFreeLocationSet(newlocset);
  12522. goto rangeto_error;
  12523. }
  12524. res = valuePop(ctxt);
  12525. range =
  12526. xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
  12527. res);
  12528. if (range != NULL) {
  12529. xmlXPtrLocationSetAdd(newlocset, range);
  12530. }
  12531. /*
  12532. * Cleanup
  12533. */
  12534. if (res != NULL) {
  12535. xmlXPathReleaseObject(ctxt->context, res);
  12536. }
  12537. if (ctxt->value == tmp) {
  12538. res = valuePop(ctxt);
  12539. xmlXPathReleaseObject(ctxt->context, res);
  12540. }
  12541. }
  12542. }
  12543. }
  12544. /*
  12545. * The result is used as the new evaluation set.
  12546. */
  12547. valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
  12548. rangeto_error:
  12549. xmlXPathReleaseObject(ctxt->context, obj);
  12550. ctxt->context->node = oldnode;
  12551. ctxt->context->contextSize = oldcs;
  12552. ctxt->context->proximityPosition = oldpp;
  12553. break;
  12554. }
  12555. #endif /* LIBXML_XPTR_ENABLED */
  12556. default:
  12557. xmlGenericError(xmlGenericErrorContext,
  12558. "XPath: unknown precompiled operation %d\n", op->op);
  12559. ctxt->error = XPATH_INVALID_OPERAND;
  12560. break;
  12561. }
  12562. ctxt->context->depth -= 1;
  12563. return (total);
  12564. }
  12565. /**
  12566. * xmlXPathCompOpEvalToBoolean:
  12567. * @ctxt: the XPath parser context
  12568. *
  12569. * Evaluates if the expression evaluates to true.
  12570. *
  12571. * Returns 1 if true, 0 if false and -1 on API or internal errors.
  12572. */
  12573. static int
  12574. xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
  12575. xmlXPathStepOpPtr op,
  12576. int isPredicate)
  12577. {
  12578. xmlXPathObjectPtr resObj = NULL;
  12579. start:
  12580. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  12581. return(0);
  12582. /* comp = ctxt->comp; */
  12583. switch (op->op) {
  12584. case XPATH_OP_END:
  12585. return (0);
  12586. case XPATH_OP_VALUE:
  12587. resObj = (xmlXPathObjectPtr) op->value4;
  12588. if (isPredicate)
  12589. return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
  12590. return(xmlXPathCastToBoolean(resObj));
  12591. case XPATH_OP_SORT:
  12592. /*
  12593. * We don't need sorting for boolean results. Skip this one.
  12594. */
  12595. if (op->ch1 != -1) {
  12596. op = &ctxt->comp->steps[op->ch1];
  12597. goto start;
  12598. }
  12599. return(0);
  12600. case XPATH_OP_COLLECT:
  12601. if (op->ch1 == -1)
  12602. return(0);
  12603. xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
  12604. if (ctxt->error != XPATH_EXPRESSION_OK)
  12605. return(-1);
  12606. xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
  12607. if (ctxt->error != XPATH_EXPRESSION_OK)
  12608. return(-1);
  12609. resObj = valuePop(ctxt);
  12610. if (resObj == NULL)
  12611. return(-1);
  12612. break;
  12613. default:
  12614. /*
  12615. * Fallback to call xmlXPathCompOpEval().
  12616. */
  12617. xmlXPathCompOpEval(ctxt, op);
  12618. if (ctxt->error != XPATH_EXPRESSION_OK)
  12619. return(-1);
  12620. resObj = valuePop(ctxt);
  12621. if (resObj == NULL)
  12622. return(-1);
  12623. break;
  12624. }
  12625. if (resObj) {
  12626. int res;
  12627. if (resObj->type == XPATH_BOOLEAN) {
  12628. res = resObj->boolval;
  12629. } else if (isPredicate) {
  12630. /*
  12631. * For predicates a result of type "number" is handled
  12632. * differently:
  12633. * SPEC XPath 1.0:
  12634. * "If the result is a number, the result will be converted
  12635. * to true if the number is equal to the context position
  12636. * and will be converted to false otherwise;"
  12637. */
  12638. res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
  12639. } else {
  12640. res = xmlXPathCastToBoolean(resObj);
  12641. }
  12642. xmlXPathReleaseObject(ctxt->context, resObj);
  12643. return(res);
  12644. }
  12645. return(0);
  12646. }
  12647. #ifdef XPATH_STREAMING
  12648. /**
  12649. * xmlXPathRunStreamEval:
  12650. * @ctxt: the XPath parser context with the compiled expression
  12651. *
  12652. * Evaluate the Precompiled Streamable XPath expression in the given context.
  12653. */
  12654. static int
  12655. xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
  12656. xmlXPathObjectPtr *resultSeq, int toBool)
  12657. {
  12658. int max_depth, min_depth;
  12659. int from_root;
  12660. int ret, depth;
  12661. int eval_all_nodes;
  12662. xmlNodePtr cur = NULL, limit = NULL;
  12663. xmlStreamCtxtPtr patstream = NULL;
  12664. int nb_nodes = 0;
  12665. if ((ctxt == NULL) || (comp == NULL))
  12666. return(-1);
  12667. max_depth = xmlPatternMaxDepth(comp);
  12668. if (max_depth == -1)
  12669. return(-1);
  12670. if (max_depth == -2)
  12671. max_depth = 10000;
  12672. min_depth = xmlPatternMinDepth(comp);
  12673. if (min_depth == -1)
  12674. return(-1);
  12675. from_root = xmlPatternFromRoot(comp);
  12676. if (from_root < 0)
  12677. return(-1);
  12678. #if 0
  12679. printf("stream eval: depth %d from root %d\n", max_depth, from_root);
  12680. #endif
  12681. if (! toBool) {
  12682. if (resultSeq == NULL)
  12683. return(-1);
  12684. *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
  12685. if (*resultSeq == NULL)
  12686. return(-1);
  12687. }
  12688. /*
  12689. * handle the special cases of "/" amd "." being matched
  12690. */
  12691. if (min_depth == 0) {
  12692. if (from_root) {
  12693. /* Select "/" */
  12694. if (toBool)
  12695. return(1);
  12696. /* TODO: Check memory error. */
  12697. xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
  12698. (xmlNodePtr) ctxt->doc);
  12699. } else {
  12700. /* Select "self::node()" */
  12701. if (toBool)
  12702. return(1);
  12703. /* TODO: Check memory error. */
  12704. xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
  12705. }
  12706. }
  12707. if (max_depth == 0) {
  12708. return(0);
  12709. }
  12710. if (from_root) {
  12711. cur = (xmlNodePtr)ctxt->doc;
  12712. } else if (ctxt->node != NULL) {
  12713. switch (ctxt->node->type) {
  12714. case XML_ELEMENT_NODE:
  12715. case XML_DOCUMENT_NODE:
  12716. case XML_DOCUMENT_FRAG_NODE:
  12717. case XML_HTML_DOCUMENT_NODE:
  12718. #ifdef LIBXML_DOCB_ENABLED
  12719. case XML_DOCB_DOCUMENT_NODE:
  12720. #endif
  12721. cur = ctxt->node;
  12722. break;
  12723. case XML_ATTRIBUTE_NODE:
  12724. case XML_TEXT_NODE:
  12725. case XML_CDATA_SECTION_NODE:
  12726. case XML_ENTITY_REF_NODE:
  12727. case XML_ENTITY_NODE:
  12728. case XML_PI_NODE:
  12729. case XML_COMMENT_NODE:
  12730. case XML_NOTATION_NODE:
  12731. case XML_DTD_NODE:
  12732. case XML_DOCUMENT_TYPE_NODE:
  12733. case XML_ELEMENT_DECL:
  12734. case XML_ATTRIBUTE_DECL:
  12735. case XML_ENTITY_DECL:
  12736. case XML_NAMESPACE_DECL:
  12737. case XML_XINCLUDE_START:
  12738. case XML_XINCLUDE_END:
  12739. break;
  12740. }
  12741. limit = cur;
  12742. }
  12743. if (cur == NULL) {
  12744. return(0);
  12745. }
  12746. patstream = xmlPatternGetStreamCtxt(comp);
  12747. if (patstream == NULL) {
  12748. /*
  12749. * QUESTION TODO: Is this an error?
  12750. */
  12751. return(0);
  12752. }
  12753. eval_all_nodes = xmlStreamWantsAnyNode(patstream);
  12754. if (from_root) {
  12755. ret = xmlStreamPush(patstream, NULL, NULL);
  12756. if (ret < 0) {
  12757. } else if (ret == 1) {
  12758. if (toBool)
  12759. goto return_1;
  12760. /* TODO: Check memory error. */
  12761. xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
  12762. }
  12763. }
  12764. depth = 0;
  12765. goto scan_children;
  12766. next_node:
  12767. do {
  12768. if (ctxt->opLimit != 0) {
  12769. if (ctxt->opCount >= ctxt->opLimit) {
  12770. xmlGenericError(xmlGenericErrorContext,
  12771. "XPath operation limit exceeded\n");
  12772. xmlFreeStreamCtxt(patstream);
  12773. return(-1);
  12774. }
  12775. ctxt->opCount++;
  12776. }
  12777. nb_nodes++;
  12778. switch (cur->type) {
  12779. case XML_ELEMENT_NODE:
  12780. case XML_TEXT_NODE:
  12781. case XML_CDATA_SECTION_NODE:
  12782. case XML_COMMENT_NODE:
  12783. case XML_PI_NODE:
  12784. if (cur->type == XML_ELEMENT_NODE) {
  12785. ret = xmlStreamPush(patstream, cur->name,
  12786. (cur->ns ? cur->ns->href : NULL));
  12787. } else if (eval_all_nodes)
  12788. ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
  12789. else
  12790. break;
  12791. if (ret < 0) {
  12792. /* NOP. */
  12793. } else if (ret == 1) {
  12794. if (toBool)
  12795. goto return_1;
  12796. if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
  12797. < 0) {
  12798. ctxt->lastError.domain = XML_FROM_XPATH;
  12799. ctxt->lastError.code = XML_ERR_NO_MEMORY;
  12800. }
  12801. }
  12802. if ((cur->children == NULL) || (depth >= max_depth)) {
  12803. ret = xmlStreamPop(patstream);
  12804. while (cur->next != NULL) {
  12805. cur = cur->next;
  12806. if ((cur->type != XML_ENTITY_DECL) &&
  12807. (cur->type != XML_DTD_NODE))
  12808. goto next_node;
  12809. }
  12810. }
  12811. default:
  12812. break;
  12813. }
  12814. scan_children:
  12815. if (cur->type == XML_NAMESPACE_DECL) break;
  12816. if ((cur->children != NULL) && (depth < max_depth)) {
  12817. /*
  12818. * Do not descend on entities declarations
  12819. */
  12820. if (cur->children->type != XML_ENTITY_DECL) {
  12821. cur = cur->children;
  12822. depth++;
  12823. /*
  12824. * Skip DTDs
  12825. */
  12826. if (cur->type != XML_DTD_NODE)
  12827. continue;
  12828. }
  12829. }
  12830. if (cur == limit)
  12831. break;
  12832. while (cur->next != NULL) {
  12833. cur = cur->next;
  12834. if ((cur->type != XML_ENTITY_DECL) &&
  12835. (cur->type != XML_DTD_NODE))
  12836. goto next_node;
  12837. }
  12838. do {
  12839. cur = cur->parent;
  12840. depth--;
  12841. if ((cur == NULL) || (cur == limit) ||
  12842. (cur->type == XML_DOCUMENT_NODE))
  12843. goto done;
  12844. if (cur->type == XML_ELEMENT_NODE) {
  12845. ret = xmlStreamPop(patstream);
  12846. } else if ((eval_all_nodes) &&
  12847. ((cur->type == XML_TEXT_NODE) ||
  12848. (cur->type == XML_CDATA_SECTION_NODE) ||
  12849. (cur->type == XML_COMMENT_NODE) ||
  12850. (cur->type == XML_PI_NODE)))
  12851. {
  12852. ret = xmlStreamPop(patstream);
  12853. }
  12854. if (cur->next != NULL) {
  12855. cur = cur->next;
  12856. break;
  12857. }
  12858. } while (cur != NULL);
  12859. } while ((cur != NULL) && (depth >= 0));
  12860. done:
  12861. #if 0
  12862. printf("stream eval: checked %d nodes selected %d\n",
  12863. nb_nodes, retObj->nodesetval->nodeNr);
  12864. #endif
  12865. if (patstream)
  12866. xmlFreeStreamCtxt(patstream);
  12867. return(0);
  12868. return_1:
  12869. if (patstream)
  12870. xmlFreeStreamCtxt(patstream);
  12871. return(1);
  12872. }
  12873. #endif /* XPATH_STREAMING */
  12874. /**
  12875. * xmlXPathRunEval:
  12876. * @ctxt: the XPath parser context with the compiled expression
  12877. * @toBool: evaluate to a boolean result
  12878. *
  12879. * Evaluate the Precompiled XPath expression in the given context.
  12880. */
  12881. static int
  12882. xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
  12883. {
  12884. xmlXPathCompExprPtr comp;
  12885. if ((ctxt == NULL) || (ctxt->comp == NULL))
  12886. return(-1);
  12887. ctxt->context->depth = 0;
  12888. if (ctxt->valueTab == NULL) {
  12889. /* Allocate the value stack */
  12890. ctxt->valueTab = (xmlXPathObjectPtr *)
  12891. xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
  12892. if (ctxt->valueTab == NULL) {
  12893. xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
  12894. xmlFree(ctxt);
  12895. }
  12896. ctxt->valueNr = 0;
  12897. ctxt->valueMax = 10;
  12898. ctxt->value = NULL;
  12899. ctxt->valueFrame = 0;
  12900. }
  12901. #ifdef XPATH_STREAMING
  12902. if (ctxt->comp->stream) {
  12903. int res;
  12904. if (toBool) {
  12905. /*
  12906. * Evaluation to boolean result.
  12907. */
  12908. res = xmlXPathRunStreamEval(ctxt->context,
  12909. ctxt->comp->stream, NULL, 1);
  12910. if (res != -1)
  12911. return(res);
  12912. } else {
  12913. xmlXPathObjectPtr resObj = NULL;
  12914. /*
  12915. * Evaluation to a sequence.
  12916. */
  12917. res = xmlXPathRunStreamEval(ctxt->context,
  12918. ctxt->comp->stream, &resObj, 0);
  12919. if ((res != -1) && (resObj != NULL)) {
  12920. valuePush(ctxt, resObj);
  12921. return(0);
  12922. }
  12923. if (resObj != NULL)
  12924. xmlXPathReleaseObject(ctxt->context, resObj);
  12925. }
  12926. /*
  12927. * QUESTION TODO: This falls back to normal XPath evaluation
  12928. * if res == -1. Is this intended?
  12929. */
  12930. }
  12931. #endif
  12932. comp = ctxt->comp;
  12933. if (comp->last < 0) {
  12934. xmlGenericError(xmlGenericErrorContext,
  12935. "xmlXPathRunEval: last is less than zero\n");
  12936. return(-1);
  12937. }
  12938. if (toBool)
  12939. return(xmlXPathCompOpEvalToBoolean(ctxt,
  12940. &comp->steps[comp->last], 0));
  12941. else
  12942. xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
  12943. return(0);
  12944. }
  12945. /************************************************************************
  12946. * *
  12947. * Public interfaces *
  12948. * *
  12949. ************************************************************************/
  12950. /**
  12951. * xmlXPathEvalPredicate:
  12952. * @ctxt: the XPath context
  12953. * @res: the Predicate Expression evaluation result
  12954. *
  12955. * Evaluate a predicate result for the current node.
  12956. * A PredicateExpr is evaluated by evaluating the Expr and converting
  12957. * the result to a boolean. If the result is a number, the result will
  12958. * be converted to true if the number is equal to the position of the
  12959. * context node in the context node list (as returned by the position
  12960. * function) and will be converted to false otherwise; if the result
  12961. * is not a number, then the result will be converted as if by a call
  12962. * to the boolean function.
  12963. *
  12964. * Returns 1 if predicate is true, 0 otherwise
  12965. */
  12966. int
  12967. xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
  12968. if ((ctxt == NULL) || (res == NULL)) return(0);
  12969. switch (res->type) {
  12970. case XPATH_BOOLEAN:
  12971. return(res->boolval);
  12972. case XPATH_NUMBER:
  12973. return(res->floatval == ctxt->proximityPosition);
  12974. case XPATH_NODESET:
  12975. case XPATH_XSLT_TREE:
  12976. if (res->nodesetval == NULL)
  12977. return(0);
  12978. return(res->nodesetval->nodeNr != 0);
  12979. case XPATH_STRING:
  12980. return((res->stringval != NULL) &&
  12981. (xmlStrlen(res->stringval) != 0));
  12982. default:
  12983. STRANGE
  12984. }
  12985. return(0);
  12986. }
  12987. /**
  12988. * xmlXPathEvaluatePredicateResult:
  12989. * @ctxt: the XPath Parser context
  12990. * @res: the Predicate Expression evaluation result
  12991. *
  12992. * Evaluate a predicate result for the current node.
  12993. * A PredicateExpr is evaluated by evaluating the Expr and converting
  12994. * the result to a boolean. If the result is a number, the result will
  12995. * be converted to true if the number is equal to the position of the
  12996. * context node in the context node list (as returned by the position
  12997. * function) and will be converted to false otherwise; if the result
  12998. * is not a number, then the result will be converted as if by a call
  12999. * to the boolean function.
  13000. *
  13001. * Returns 1 if predicate is true, 0 otherwise
  13002. */
  13003. int
  13004. xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
  13005. xmlXPathObjectPtr res) {
  13006. if ((ctxt == NULL) || (res == NULL)) return(0);
  13007. switch (res->type) {
  13008. case XPATH_BOOLEAN:
  13009. return(res->boolval);
  13010. case XPATH_NUMBER:
  13011. #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
  13012. return((res->floatval == ctxt->context->proximityPosition) &&
  13013. (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
  13014. #else
  13015. return(res->floatval == ctxt->context->proximityPosition);
  13016. #endif
  13017. case XPATH_NODESET:
  13018. case XPATH_XSLT_TREE:
  13019. if (res->nodesetval == NULL)
  13020. return(0);
  13021. return(res->nodesetval->nodeNr != 0);
  13022. case XPATH_STRING:
  13023. return((res->stringval != NULL) && (res->stringval[0] != 0));
  13024. #ifdef LIBXML_XPTR_ENABLED
  13025. case XPATH_LOCATIONSET:{
  13026. xmlLocationSetPtr ptr = res->user;
  13027. if (ptr == NULL)
  13028. return(0);
  13029. return (ptr->locNr != 0);
  13030. }
  13031. #endif
  13032. default:
  13033. STRANGE
  13034. }
  13035. return(0);
  13036. }
  13037. #ifdef XPATH_STREAMING
  13038. /**
  13039. * xmlXPathTryStreamCompile:
  13040. * @ctxt: an XPath context
  13041. * @str: the XPath expression
  13042. *
  13043. * Try to compile the XPath expression as a streamable subset.
  13044. *
  13045. * Returns the compiled expression or NULL if failed to compile.
  13046. */
  13047. static xmlXPathCompExprPtr
  13048. xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
  13049. /*
  13050. * Optimization: use streaming patterns when the XPath expression can
  13051. * be compiled to a stream lookup
  13052. */
  13053. xmlPatternPtr stream;
  13054. xmlXPathCompExprPtr comp;
  13055. xmlDictPtr dict = NULL;
  13056. const xmlChar **namespaces = NULL;
  13057. xmlNsPtr ns;
  13058. int i, j;
  13059. if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
  13060. (!xmlStrchr(str, '@'))) {
  13061. const xmlChar *tmp;
  13062. /*
  13063. * We don't try to handle expressions using the verbose axis
  13064. * specifiers ("::"), just the simplified form at this point.
  13065. * Additionally, if there is no list of namespaces available and
  13066. * there's a ":" in the expression, indicating a prefixed QName,
  13067. * then we won't try to compile either. xmlPatterncompile() needs
  13068. * to have a list of namespaces at compilation time in order to
  13069. * compile prefixed name tests.
  13070. */
  13071. tmp = xmlStrchr(str, ':');
  13072. if ((tmp != NULL) &&
  13073. ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
  13074. return(NULL);
  13075. if (ctxt != NULL) {
  13076. dict = ctxt->dict;
  13077. if (ctxt->nsNr > 0) {
  13078. namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
  13079. if (namespaces == NULL) {
  13080. xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
  13081. return(NULL);
  13082. }
  13083. for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
  13084. ns = ctxt->namespaces[j];
  13085. namespaces[i++] = ns->href;
  13086. namespaces[i++] = ns->prefix;
  13087. }
  13088. namespaces[i++] = NULL;
  13089. namespaces[i] = NULL;
  13090. }
  13091. }
  13092. stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
  13093. if (namespaces != NULL) {
  13094. xmlFree((xmlChar **)namespaces);
  13095. }
  13096. if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
  13097. comp = xmlXPathNewCompExpr();
  13098. if (comp == NULL) {
  13099. xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
  13100. return(NULL);
  13101. }
  13102. comp->stream = stream;
  13103. comp->dict = dict;
  13104. if (comp->dict)
  13105. xmlDictReference(comp->dict);
  13106. return(comp);
  13107. }
  13108. xmlFreePattern(stream);
  13109. }
  13110. return(NULL);
  13111. }
  13112. #endif /* XPATH_STREAMING */
  13113. static void
  13114. xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
  13115. xmlXPathStepOpPtr op)
  13116. {
  13117. xmlXPathCompExprPtr comp = pctxt->comp;
  13118. xmlXPathContextPtr ctxt;
  13119. /*
  13120. * Try to rewrite "descendant-or-self::node()/foo" to an optimized
  13121. * internal representation.
  13122. */
  13123. if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
  13124. (op->ch1 != -1) &&
  13125. (op->ch2 == -1 /* no predicate */))
  13126. {
  13127. xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
  13128. if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
  13129. ((xmlXPathAxisVal) prevop->value ==
  13130. AXIS_DESCENDANT_OR_SELF) &&
  13131. (prevop->ch2 == -1) &&
  13132. ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
  13133. ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
  13134. {
  13135. /*
  13136. * This is a "descendant-or-self::node()" without predicates.
  13137. * Try to eliminate it.
  13138. */
  13139. switch ((xmlXPathAxisVal) op->value) {
  13140. case AXIS_CHILD:
  13141. case AXIS_DESCENDANT:
  13142. /*
  13143. * Convert "descendant-or-self::node()/child::" or
  13144. * "descendant-or-self::node()/descendant::" to
  13145. * "descendant::"
  13146. */
  13147. op->ch1 = prevop->ch1;
  13148. op->value = AXIS_DESCENDANT;
  13149. break;
  13150. case AXIS_SELF:
  13151. case AXIS_DESCENDANT_OR_SELF:
  13152. /*
  13153. * Convert "descendant-or-self::node()/self::" or
  13154. * "descendant-or-self::node()/descendant-or-self::" to
  13155. * to "descendant-or-self::"
  13156. */
  13157. op->ch1 = prevop->ch1;
  13158. op->value = AXIS_DESCENDANT_OR_SELF;
  13159. break;
  13160. default:
  13161. break;
  13162. }
  13163. }
  13164. }
  13165. /* OP_VALUE has invalid ch1. */
  13166. if (op->op == XPATH_OP_VALUE)
  13167. return;
  13168. /* Recurse */
  13169. ctxt = pctxt->context;
  13170. if (ctxt != NULL) {
  13171. if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
  13172. return;
  13173. ctxt->depth += 1;
  13174. }
  13175. if (op->ch1 != -1)
  13176. xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
  13177. if (op->ch2 != -1)
  13178. xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
  13179. if (ctxt != NULL)
  13180. ctxt->depth -= 1;
  13181. }
  13182. /**
  13183. * xmlXPathCtxtCompile:
  13184. * @ctxt: an XPath context
  13185. * @str: the XPath expression
  13186. *
  13187. * Compile an XPath expression
  13188. *
  13189. * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
  13190. * the caller has to free the object.
  13191. */
  13192. xmlXPathCompExprPtr
  13193. xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
  13194. xmlXPathParserContextPtr pctxt;
  13195. xmlXPathCompExprPtr comp;
  13196. #ifdef XPATH_STREAMING
  13197. comp = xmlXPathTryStreamCompile(ctxt, str);
  13198. if (comp != NULL)
  13199. return(comp);
  13200. #endif
  13201. xmlInitParser();
  13202. pctxt = xmlXPathNewParserContext(str, ctxt);
  13203. if (pctxt == NULL)
  13204. return NULL;
  13205. if (ctxt != NULL)
  13206. ctxt->depth = 0;
  13207. xmlXPathCompileExpr(pctxt, 1);
  13208. if( pctxt->error != XPATH_EXPRESSION_OK )
  13209. {
  13210. xmlXPathFreeParserContext(pctxt);
  13211. return(NULL);
  13212. }
  13213. if (*pctxt->cur != 0) {
  13214. /*
  13215. * aleksey: in some cases this line prints *second* error message
  13216. * (see bug #78858) and probably this should be fixed.
  13217. * However, we are not sure that all error messages are printed
  13218. * out in other places. It's not critical so we leave it as-is for now
  13219. */
  13220. xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
  13221. comp = NULL;
  13222. } else {
  13223. comp = pctxt->comp;
  13224. if ((comp->nbStep > 1) && (comp->last >= 0)) {
  13225. if (ctxt != NULL)
  13226. ctxt->depth = 0;
  13227. xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
  13228. }
  13229. pctxt->comp = NULL;
  13230. }
  13231. xmlXPathFreeParserContext(pctxt);
  13232. if (comp != NULL) {
  13233. comp->expr = xmlStrdup(str);
  13234. #ifdef DEBUG_EVAL_COUNTS
  13235. comp->string = xmlStrdup(str);
  13236. comp->nb = 0;
  13237. #endif
  13238. }
  13239. return(comp);
  13240. }
  13241. /**
  13242. * xmlXPathCompile:
  13243. * @str: the XPath expression
  13244. *
  13245. * Compile an XPath expression
  13246. *
  13247. * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
  13248. * the caller has to free the object.
  13249. */
  13250. xmlXPathCompExprPtr
  13251. xmlXPathCompile(const xmlChar *str) {
  13252. return(xmlXPathCtxtCompile(NULL, str));
  13253. }
  13254. /**
  13255. * xmlXPathCompiledEvalInternal:
  13256. * @comp: the compiled XPath expression
  13257. * @ctxt: the XPath context
  13258. * @resObj: the resulting XPath object or NULL
  13259. * @toBool: 1 if only a boolean result is requested
  13260. *
  13261. * Evaluate the Precompiled XPath expression in the given context.
  13262. * The caller has to free @resObj.
  13263. *
  13264. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  13265. * the caller has to free the object.
  13266. */
  13267. static int
  13268. xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
  13269. xmlXPathContextPtr ctxt,
  13270. xmlXPathObjectPtr *resObjPtr,
  13271. int toBool)
  13272. {
  13273. xmlXPathParserContextPtr pctxt;
  13274. xmlXPathObjectPtr resObj;
  13275. #ifndef LIBXML_THREAD_ENABLED
  13276. static int reentance = 0;
  13277. #endif
  13278. int res;
  13279. CHECK_CTXT_NEG(ctxt)
  13280. if (comp == NULL)
  13281. return(-1);
  13282. xmlInitParser();
  13283. #ifndef LIBXML_THREAD_ENABLED
  13284. reentance++;
  13285. if (reentance > 1)
  13286. xmlXPathDisableOptimizer = 1;
  13287. #endif
  13288. #ifdef DEBUG_EVAL_COUNTS
  13289. comp->nb++;
  13290. if ((comp->string != NULL) && (comp->nb > 100)) {
  13291. fprintf(stderr, "100 x %s\n", comp->string);
  13292. comp->nb = 0;
  13293. }
  13294. #endif
  13295. pctxt = xmlXPathCompParserContext(comp, ctxt);
  13296. res = xmlXPathRunEval(pctxt, toBool);
  13297. if (pctxt->error != XPATH_EXPRESSION_OK) {
  13298. resObj = NULL;
  13299. } else {
  13300. resObj = valuePop(pctxt);
  13301. if (resObj == NULL) {
  13302. if (!toBool)
  13303. xmlGenericError(xmlGenericErrorContext,
  13304. "xmlXPathCompiledEval: No result on the stack.\n");
  13305. } else if (pctxt->valueNr > 0) {
  13306. xmlGenericError(xmlGenericErrorContext,
  13307. "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
  13308. pctxt->valueNr);
  13309. }
  13310. }
  13311. if (resObjPtr)
  13312. *resObjPtr = resObj;
  13313. else
  13314. xmlXPathReleaseObject(ctxt, resObj);
  13315. pctxt->comp = NULL;
  13316. xmlXPathFreeParserContext(pctxt);
  13317. #ifndef LIBXML_THREAD_ENABLED
  13318. reentance--;
  13319. #endif
  13320. return(res);
  13321. }
  13322. /**
  13323. * xmlXPathCompiledEval:
  13324. * @comp: the compiled XPath expression
  13325. * @ctx: the XPath context
  13326. *
  13327. * Evaluate the Precompiled XPath expression in the given context.
  13328. *
  13329. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  13330. * the caller has to free the object.
  13331. */
  13332. xmlXPathObjectPtr
  13333. xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
  13334. {
  13335. xmlXPathObjectPtr res = NULL;
  13336. xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
  13337. return(res);
  13338. }
  13339. /**
  13340. * xmlXPathCompiledEvalToBoolean:
  13341. * @comp: the compiled XPath expression
  13342. * @ctxt: the XPath context
  13343. *
  13344. * Applies the XPath boolean() function on the result of the given
  13345. * compiled expression.
  13346. *
  13347. * Returns 1 if the expression evaluated to true, 0 if to false and
  13348. * -1 in API and internal errors.
  13349. */
  13350. int
  13351. xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
  13352. xmlXPathContextPtr ctxt)
  13353. {
  13354. return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
  13355. }
  13356. /**
  13357. * xmlXPathEvalExpr:
  13358. * @ctxt: the XPath Parser context
  13359. *
  13360. * Parse and evaluate an XPath expression in the given context,
  13361. * then push the result on the context stack
  13362. */
  13363. void
  13364. xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
  13365. #ifdef XPATH_STREAMING
  13366. xmlXPathCompExprPtr comp;
  13367. #endif
  13368. if (ctxt == NULL) return;
  13369. #ifdef XPATH_STREAMING
  13370. comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
  13371. if (comp != NULL) {
  13372. if (ctxt->comp != NULL)
  13373. xmlXPathFreeCompExpr(ctxt->comp);
  13374. ctxt->comp = comp;
  13375. } else
  13376. #endif
  13377. {
  13378. if (ctxt->context != NULL)
  13379. ctxt->context->depth = 0;
  13380. xmlXPathCompileExpr(ctxt, 1);
  13381. CHECK_ERROR;
  13382. /* Check for trailing characters. */
  13383. if (*ctxt->cur != 0)
  13384. XP_ERROR(XPATH_EXPR_ERROR);
  13385. if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
  13386. if (ctxt->context != NULL)
  13387. ctxt->context->depth = 0;
  13388. xmlXPathOptimizeExpression(ctxt,
  13389. &ctxt->comp->steps[ctxt->comp->last]);
  13390. }
  13391. }
  13392. xmlXPathRunEval(ctxt, 0);
  13393. }
  13394. /**
  13395. * xmlXPathEval:
  13396. * @str: the XPath expression
  13397. * @ctx: the XPath context
  13398. *
  13399. * Evaluate the XPath Location Path in the given context.
  13400. *
  13401. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  13402. * the caller has to free the object.
  13403. */
  13404. xmlXPathObjectPtr
  13405. xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
  13406. xmlXPathParserContextPtr ctxt;
  13407. xmlXPathObjectPtr res;
  13408. CHECK_CTXT(ctx)
  13409. xmlInitParser();
  13410. ctxt = xmlXPathNewParserContext(str, ctx);
  13411. if (ctxt == NULL)
  13412. return NULL;
  13413. xmlXPathEvalExpr(ctxt);
  13414. if (ctxt->error != XPATH_EXPRESSION_OK) {
  13415. res = NULL;
  13416. } else {
  13417. res = valuePop(ctxt);
  13418. if (res == NULL) {
  13419. xmlGenericError(xmlGenericErrorContext,
  13420. "xmlXPathCompiledEval: No result on the stack.\n");
  13421. } else if (ctxt->valueNr > 0) {
  13422. xmlGenericError(xmlGenericErrorContext,
  13423. "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
  13424. ctxt->valueNr);
  13425. }
  13426. }
  13427. xmlXPathFreeParserContext(ctxt);
  13428. return(res);
  13429. }
  13430. /**
  13431. * xmlXPathSetContextNode:
  13432. * @node: the node to to use as the context node
  13433. * @ctx: the XPath context
  13434. *
  13435. * Sets 'node' as the context node. The node must be in the same
  13436. * document as that associated with the context.
  13437. *
  13438. * Returns -1 in case of error or 0 if successful
  13439. */
  13440. int
  13441. xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
  13442. if ((node == NULL) || (ctx == NULL))
  13443. return(-1);
  13444. if (node->doc == ctx->doc) {
  13445. ctx->node = node;
  13446. return(0);
  13447. }
  13448. return(-1);
  13449. }
  13450. /**
  13451. * xmlXPathNodeEval:
  13452. * @node: the node to to use as the context node
  13453. * @str: the XPath expression
  13454. * @ctx: the XPath context
  13455. *
  13456. * Evaluate the XPath Location Path in the given context. The node 'node'
  13457. * is set as the context node. The context node is not restored.
  13458. *
  13459. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  13460. * the caller has to free the object.
  13461. */
  13462. xmlXPathObjectPtr
  13463. xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
  13464. if (str == NULL)
  13465. return(NULL);
  13466. if (xmlXPathSetContextNode(node, ctx) < 0)
  13467. return(NULL);
  13468. return(xmlXPathEval(str, ctx));
  13469. }
  13470. /**
  13471. * xmlXPathEvalExpression:
  13472. * @str: the XPath expression
  13473. * @ctxt: the XPath context
  13474. *
  13475. * Alias for xmlXPathEval().
  13476. *
  13477. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  13478. * the caller has to free the object.
  13479. */
  13480. xmlXPathObjectPtr
  13481. xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
  13482. return(xmlXPathEval(str, ctxt));
  13483. }
  13484. /************************************************************************
  13485. * *
  13486. * Extra functions not pertaining to the XPath spec *
  13487. * *
  13488. ************************************************************************/
  13489. /**
  13490. * xmlXPathEscapeUriFunction:
  13491. * @ctxt: the XPath Parser context
  13492. * @nargs: the number of arguments
  13493. *
  13494. * Implement the escape-uri() XPath function
  13495. * string escape-uri(string $str, bool $escape-reserved)
  13496. *
  13497. * This function applies the URI escaping rules defined in section 2 of [RFC
  13498. * 2396] to the string supplied as $uri-part, which typically represents all
  13499. * or part of a URI. The effect of the function is to replace any special
  13500. * character in the string by an escape sequence of the form %xx%yy...,
  13501. * where xxyy... is the hexadecimal representation of the octets used to
  13502. * represent the character in UTF-8.
  13503. *
  13504. * The set of characters that are escaped depends on the setting of the
  13505. * boolean argument $escape-reserved.
  13506. *
  13507. * If $escape-reserved is true, all characters are escaped other than lower
  13508. * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
  13509. * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
  13510. * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
  13511. * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
  13512. * A-F).
  13513. *
  13514. * If $escape-reserved is false, the behavior differs in that characters
  13515. * referred to in [RFC 2396] as reserved characters are not escaped. These
  13516. * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
  13517. *
  13518. * [RFC 2396] does not define whether escaped URIs should use lower case or
  13519. * upper case for hexadecimal digits. To ensure that escaped URIs can be
  13520. * compared using string comparison functions, this function must always use
  13521. * the upper-case letters A-F.
  13522. *
  13523. * Generally, $escape-reserved should be set to true when escaping a string
  13524. * that is to form a single part of a URI, and to false when escaping an
  13525. * entire URI or URI reference.
  13526. *
  13527. * In the case of non-ascii characters, the string is encoded according to
  13528. * utf-8 and then converted according to RFC 2396.
  13529. *
  13530. * Examples
  13531. * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
  13532. * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
  13533. * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
  13534. * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
  13535. *
  13536. */
  13537. static void
  13538. xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  13539. xmlXPathObjectPtr str;
  13540. int escape_reserved;
  13541. xmlBufPtr target;
  13542. xmlChar *cptr;
  13543. xmlChar escape[4];
  13544. CHECK_ARITY(2);
  13545. escape_reserved = xmlXPathPopBoolean(ctxt);
  13546. CAST_TO_STRING;
  13547. str = valuePop(ctxt);
  13548. target = xmlBufCreate();
  13549. escape[0] = '%';
  13550. escape[3] = 0;
  13551. if (target) {
  13552. for (cptr = str->stringval; *cptr; cptr++) {
  13553. if ((*cptr >= 'A' && *cptr <= 'Z') ||
  13554. (*cptr >= 'a' && *cptr <= 'z') ||
  13555. (*cptr >= '0' && *cptr <= '9') ||
  13556. *cptr == '-' || *cptr == '_' || *cptr == '.' ||
  13557. *cptr == '!' || *cptr == '~' || *cptr == '*' ||
  13558. *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
  13559. (*cptr == '%' &&
  13560. ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
  13561. (cptr[1] >= 'a' && cptr[1] <= 'f') ||
  13562. (cptr[1] >= '0' && cptr[1] <= '9')) &&
  13563. ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
  13564. (cptr[2] >= 'a' && cptr[2] <= 'f') ||
  13565. (cptr[2] >= '0' && cptr[2] <= '9'))) ||
  13566. (!escape_reserved &&
  13567. (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
  13568. *cptr == ':' || *cptr == '@' || *cptr == '&' ||
  13569. *cptr == '=' || *cptr == '+' || *cptr == '$' ||
  13570. *cptr == ','))) {
  13571. xmlBufAdd(target, cptr, 1);
  13572. } else {
  13573. if ((*cptr >> 4) < 10)
  13574. escape[1] = '0' + (*cptr >> 4);
  13575. else
  13576. escape[1] = 'A' - 10 + (*cptr >> 4);
  13577. if ((*cptr & 0xF) < 10)
  13578. escape[2] = '0' + (*cptr & 0xF);
  13579. else
  13580. escape[2] = 'A' - 10 + (*cptr & 0xF);
  13581. xmlBufAdd(target, &escape[0], 3);
  13582. }
  13583. }
  13584. }
  13585. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  13586. xmlBufContent(target)));
  13587. xmlBufFree(target);
  13588. xmlXPathReleaseObject(ctxt->context, str);
  13589. }
  13590. /**
  13591. * xmlXPathRegisterAllFunctions:
  13592. * @ctxt: the XPath context
  13593. *
  13594. * Registers all default XPath functions in this context
  13595. */
  13596. void
  13597. xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
  13598. {
  13599. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
  13600. xmlXPathBooleanFunction);
  13601. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
  13602. xmlXPathCeilingFunction);
  13603. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
  13604. xmlXPathCountFunction);
  13605. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
  13606. xmlXPathConcatFunction);
  13607. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
  13608. xmlXPathContainsFunction);
  13609. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
  13610. xmlXPathIdFunction);
  13611. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
  13612. xmlXPathFalseFunction);
  13613. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
  13614. xmlXPathFloorFunction);
  13615. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
  13616. xmlXPathLastFunction);
  13617. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
  13618. xmlXPathLangFunction);
  13619. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
  13620. xmlXPathLocalNameFunction);
  13621. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
  13622. xmlXPathNotFunction);
  13623. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
  13624. xmlXPathNameFunction);
  13625. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
  13626. xmlXPathNamespaceURIFunction);
  13627. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
  13628. xmlXPathNormalizeFunction);
  13629. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
  13630. xmlXPathNumberFunction);
  13631. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
  13632. xmlXPathPositionFunction);
  13633. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
  13634. xmlXPathRoundFunction);
  13635. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
  13636. xmlXPathStringFunction);
  13637. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
  13638. xmlXPathStringLengthFunction);
  13639. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
  13640. xmlXPathStartsWithFunction);
  13641. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
  13642. xmlXPathSubstringFunction);
  13643. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
  13644. xmlXPathSubstringBeforeFunction);
  13645. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
  13646. xmlXPathSubstringAfterFunction);
  13647. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
  13648. xmlXPathSumFunction);
  13649. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
  13650. xmlXPathTrueFunction);
  13651. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
  13652. xmlXPathTranslateFunction);
  13653. xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
  13654. (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
  13655. xmlXPathEscapeUriFunction);
  13656. }
  13657. #endif /* LIBXML_XPATH_ENABLED */
  13658. #define bottom_xpath
  13659. #include "elfgcchack.h"