xpath.c 400 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732
  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 -= 1;
  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. CHECK_ERROR NULL;
  10308. *test = NODE_TEST_PI;
  10309. SKIP_BLANKS;
  10310. }
  10311. }
  10312. if (CUR != ')') {
  10313. if (name != NULL)
  10314. xmlFree(name);
  10315. XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
  10316. }
  10317. NEXT;
  10318. return(name);
  10319. }
  10320. *test = NODE_TEST_NAME;
  10321. if ((!blanks) && (CUR == ':')) {
  10322. NEXT;
  10323. /*
  10324. * Since currently the parser context don't have a
  10325. * namespace list associated:
  10326. * The namespace name for this prefix can be computed
  10327. * only at evaluation time. The compilation is done
  10328. * outside of any context.
  10329. */
  10330. #if 0
  10331. *prefix = xmlXPathNsLookup(ctxt->context, name);
  10332. if (name != NULL)
  10333. xmlFree(name);
  10334. if (*prefix == NULL) {
  10335. XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
  10336. }
  10337. #else
  10338. *prefix = name;
  10339. #endif
  10340. if (CUR == '*') {
  10341. /*
  10342. * All elements
  10343. */
  10344. NEXT;
  10345. *test = NODE_TEST_ALL;
  10346. return(NULL);
  10347. }
  10348. name = xmlXPathParseNCName(ctxt);
  10349. if (name == NULL) {
  10350. XP_ERRORNULL(XPATH_EXPR_ERROR);
  10351. }
  10352. }
  10353. return(name);
  10354. }
  10355. /**
  10356. * xmlXPathIsAxisName:
  10357. * @name: a preparsed name token
  10358. *
  10359. * [6] AxisName ::= 'ancestor'
  10360. * | 'ancestor-or-self'
  10361. * | 'attribute'
  10362. * | 'child'
  10363. * | 'descendant'
  10364. * | 'descendant-or-self'
  10365. * | 'following'
  10366. * | 'following-sibling'
  10367. * | 'namespace'
  10368. * | 'parent'
  10369. * | 'preceding'
  10370. * | 'preceding-sibling'
  10371. * | 'self'
  10372. *
  10373. * Returns the axis or 0
  10374. */
  10375. static xmlXPathAxisVal
  10376. xmlXPathIsAxisName(const xmlChar *name) {
  10377. xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
  10378. switch (name[0]) {
  10379. case 'a':
  10380. if (xmlStrEqual(name, BAD_CAST "ancestor"))
  10381. ret = AXIS_ANCESTOR;
  10382. if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
  10383. ret = AXIS_ANCESTOR_OR_SELF;
  10384. if (xmlStrEqual(name, BAD_CAST "attribute"))
  10385. ret = AXIS_ATTRIBUTE;
  10386. break;
  10387. case 'c':
  10388. if (xmlStrEqual(name, BAD_CAST "child"))
  10389. ret = AXIS_CHILD;
  10390. break;
  10391. case 'd':
  10392. if (xmlStrEqual(name, BAD_CAST "descendant"))
  10393. ret = AXIS_DESCENDANT;
  10394. if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
  10395. ret = AXIS_DESCENDANT_OR_SELF;
  10396. break;
  10397. case 'f':
  10398. if (xmlStrEqual(name, BAD_CAST "following"))
  10399. ret = AXIS_FOLLOWING;
  10400. if (xmlStrEqual(name, BAD_CAST "following-sibling"))
  10401. ret = AXIS_FOLLOWING_SIBLING;
  10402. break;
  10403. case 'n':
  10404. if (xmlStrEqual(name, BAD_CAST "namespace"))
  10405. ret = AXIS_NAMESPACE;
  10406. break;
  10407. case 'p':
  10408. if (xmlStrEqual(name, BAD_CAST "parent"))
  10409. ret = AXIS_PARENT;
  10410. if (xmlStrEqual(name, BAD_CAST "preceding"))
  10411. ret = AXIS_PRECEDING;
  10412. if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
  10413. ret = AXIS_PRECEDING_SIBLING;
  10414. break;
  10415. case 's':
  10416. if (xmlStrEqual(name, BAD_CAST "self"))
  10417. ret = AXIS_SELF;
  10418. break;
  10419. }
  10420. return(ret);
  10421. }
  10422. /**
  10423. * xmlXPathCompStep:
  10424. * @ctxt: the XPath Parser context
  10425. *
  10426. * [4] Step ::= AxisSpecifier NodeTest Predicate*
  10427. * | AbbreviatedStep
  10428. *
  10429. * [12] AbbreviatedStep ::= '.' | '..'
  10430. *
  10431. * [5] AxisSpecifier ::= AxisName '::'
  10432. * | AbbreviatedAxisSpecifier
  10433. *
  10434. * [13] AbbreviatedAxisSpecifier ::= '@'?
  10435. *
  10436. * Modified for XPtr range support as:
  10437. *
  10438. * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
  10439. * | AbbreviatedStep
  10440. * | 'range-to' '(' Expr ')' Predicate*
  10441. *
  10442. * Compile one step in a Location Path
  10443. * A location step of . is short for self::node(). This is
  10444. * particularly useful in conjunction with //. For example, the
  10445. * location path .//para is short for
  10446. * self::node()/descendant-or-self::node()/child::para
  10447. * and so will select all para descendant elements of the context
  10448. * node.
  10449. * Similarly, a location step of .. is short for parent::node().
  10450. * For example, ../title is short for parent::node()/child::title
  10451. * and so will select the title children of the parent of the context
  10452. * node.
  10453. */
  10454. static void
  10455. xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
  10456. #ifdef LIBXML_XPTR_ENABLED
  10457. int rangeto = 0;
  10458. int op2 = -1;
  10459. #endif
  10460. SKIP_BLANKS;
  10461. if ((CUR == '.') && (NXT(1) == '.')) {
  10462. SKIP(2);
  10463. SKIP_BLANKS;
  10464. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
  10465. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  10466. } else if (CUR == '.') {
  10467. NEXT;
  10468. SKIP_BLANKS;
  10469. } else {
  10470. xmlChar *name = NULL;
  10471. xmlChar *prefix = NULL;
  10472. xmlXPathTestVal test = (xmlXPathTestVal) 0;
  10473. xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
  10474. xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
  10475. int op1;
  10476. /*
  10477. * The modification needed for XPointer change to the production
  10478. */
  10479. #ifdef LIBXML_XPTR_ENABLED
  10480. if (ctxt->xptr) {
  10481. name = xmlXPathParseNCName(ctxt);
  10482. if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
  10483. op2 = ctxt->comp->last;
  10484. xmlFree(name);
  10485. SKIP_BLANKS;
  10486. if (CUR != '(') {
  10487. XP_ERROR(XPATH_EXPR_ERROR);
  10488. }
  10489. NEXT;
  10490. SKIP_BLANKS;
  10491. xmlXPathCompileExpr(ctxt, 1);
  10492. /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
  10493. CHECK_ERROR;
  10494. SKIP_BLANKS;
  10495. if (CUR != ')') {
  10496. XP_ERROR(XPATH_EXPR_ERROR);
  10497. }
  10498. NEXT;
  10499. rangeto = 1;
  10500. goto eval_predicates;
  10501. }
  10502. }
  10503. #endif
  10504. if (CUR == '*') {
  10505. axis = AXIS_CHILD;
  10506. } else {
  10507. if (name == NULL)
  10508. name = xmlXPathParseNCName(ctxt);
  10509. if (name != NULL) {
  10510. axis = xmlXPathIsAxisName(name);
  10511. if (axis != 0) {
  10512. SKIP_BLANKS;
  10513. if ((CUR == ':') && (NXT(1) == ':')) {
  10514. SKIP(2);
  10515. xmlFree(name);
  10516. name = NULL;
  10517. } else {
  10518. /* an element name can conflict with an axis one :-\ */
  10519. axis = AXIS_CHILD;
  10520. }
  10521. } else {
  10522. axis = AXIS_CHILD;
  10523. }
  10524. } else if (CUR == '@') {
  10525. NEXT;
  10526. axis = AXIS_ATTRIBUTE;
  10527. } else {
  10528. axis = AXIS_CHILD;
  10529. }
  10530. }
  10531. if (ctxt->error != XPATH_EXPRESSION_OK) {
  10532. xmlFree(name);
  10533. return;
  10534. }
  10535. name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
  10536. if (test == 0)
  10537. return;
  10538. if ((prefix != NULL) && (ctxt->context != NULL) &&
  10539. (ctxt->context->flags & XML_XPATH_CHECKNS)) {
  10540. if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
  10541. xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
  10542. }
  10543. }
  10544. #ifdef DEBUG_STEP
  10545. xmlGenericError(xmlGenericErrorContext,
  10546. "Basis : computing new set\n");
  10547. #endif
  10548. #ifdef DEBUG_STEP
  10549. xmlGenericError(xmlGenericErrorContext, "Basis : ");
  10550. if (ctxt->value == NULL)
  10551. xmlGenericError(xmlGenericErrorContext, "no value\n");
  10552. else if (ctxt->value->nodesetval == NULL)
  10553. xmlGenericError(xmlGenericErrorContext, "Empty\n");
  10554. else
  10555. xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
  10556. #endif
  10557. #ifdef LIBXML_XPTR_ENABLED
  10558. eval_predicates:
  10559. #endif
  10560. op1 = ctxt->comp->last;
  10561. ctxt->comp->last = -1;
  10562. SKIP_BLANKS;
  10563. while (CUR == '[') {
  10564. xmlXPathCompPredicate(ctxt, 0);
  10565. }
  10566. #ifdef LIBXML_XPTR_ENABLED
  10567. if (rangeto) {
  10568. PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
  10569. } else
  10570. #endif
  10571. if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
  10572. test, type, (void *)prefix, (void *)name) == -1) {
  10573. xmlFree(prefix);
  10574. xmlFree(name);
  10575. }
  10576. }
  10577. #ifdef DEBUG_STEP
  10578. xmlGenericError(xmlGenericErrorContext, "Step : ");
  10579. if (ctxt->value == NULL)
  10580. xmlGenericError(xmlGenericErrorContext, "no value\n");
  10581. else if (ctxt->value->nodesetval == NULL)
  10582. xmlGenericError(xmlGenericErrorContext, "Empty\n");
  10583. else
  10584. xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
  10585. ctxt->value->nodesetval);
  10586. #endif
  10587. }
  10588. /**
  10589. * xmlXPathCompRelativeLocationPath:
  10590. * @ctxt: the XPath Parser context
  10591. *
  10592. * [3] RelativeLocationPath ::= Step
  10593. * | RelativeLocationPath '/' Step
  10594. * | AbbreviatedRelativeLocationPath
  10595. * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
  10596. *
  10597. * Compile a relative location path.
  10598. */
  10599. static void
  10600. xmlXPathCompRelativeLocationPath
  10601. (xmlXPathParserContextPtr ctxt) {
  10602. SKIP_BLANKS;
  10603. if ((CUR == '/') && (NXT(1) == '/')) {
  10604. SKIP(2);
  10605. SKIP_BLANKS;
  10606. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
  10607. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  10608. } else if (CUR == '/') {
  10609. NEXT;
  10610. SKIP_BLANKS;
  10611. }
  10612. xmlXPathCompStep(ctxt);
  10613. CHECK_ERROR;
  10614. SKIP_BLANKS;
  10615. while (CUR == '/') {
  10616. if ((CUR == '/') && (NXT(1) == '/')) {
  10617. SKIP(2);
  10618. SKIP_BLANKS;
  10619. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
  10620. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  10621. xmlXPathCompStep(ctxt);
  10622. } else if (CUR == '/') {
  10623. NEXT;
  10624. SKIP_BLANKS;
  10625. xmlXPathCompStep(ctxt);
  10626. }
  10627. SKIP_BLANKS;
  10628. }
  10629. }
  10630. /**
  10631. * xmlXPathCompLocationPath:
  10632. * @ctxt: the XPath Parser context
  10633. *
  10634. * [1] LocationPath ::= RelativeLocationPath
  10635. * | AbsoluteLocationPath
  10636. * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
  10637. * | AbbreviatedAbsoluteLocationPath
  10638. * [10] AbbreviatedAbsoluteLocationPath ::=
  10639. * '//' RelativeLocationPath
  10640. *
  10641. * Compile a location path
  10642. *
  10643. * // is short for /descendant-or-self::node()/. For example,
  10644. * //para is short for /descendant-or-self::node()/child::para and
  10645. * so will select any para element in the document (even a para element
  10646. * that is a document element will be selected by //para since the
  10647. * document element node is a child of the root node); div//para is
  10648. * short for div/descendant-or-self::node()/child::para and so will
  10649. * select all para descendants of div children.
  10650. */
  10651. static void
  10652. xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
  10653. SKIP_BLANKS;
  10654. if (CUR != '/') {
  10655. xmlXPathCompRelativeLocationPath(ctxt);
  10656. } else {
  10657. while (CUR == '/') {
  10658. if ((CUR == '/') && (NXT(1) == '/')) {
  10659. SKIP(2);
  10660. SKIP_BLANKS;
  10661. PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
  10662. NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
  10663. xmlXPathCompRelativeLocationPath(ctxt);
  10664. } else if (CUR == '/') {
  10665. NEXT;
  10666. SKIP_BLANKS;
  10667. if ((CUR != 0 ) &&
  10668. ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
  10669. (CUR == '@') || (CUR == '*')))
  10670. xmlXPathCompRelativeLocationPath(ctxt);
  10671. }
  10672. CHECK_ERROR;
  10673. }
  10674. }
  10675. }
  10676. /************************************************************************
  10677. * *
  10678. * XPath precompiled expression evaluation *
  10679. * *
  10680. ************************************************************************/
  10681. static int
  10682. xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
  10683. #ifdef DEBUG_STEP
  10684. static void
  10685. xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
  10686. int nbNodes)
  10687. {
  10688. xmlGenericError(xmlGenericErrorContext, "new step : ");
  10689. switch (op->value) {
  10690. case AXIS_ANCESTOR:
  10691. xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
  10692. break;
  10693. case AXIS_ANCESTOR_OR_SELF:
  10694. xmlGenericError(xmlGenericErrorContext,
  10695. "axis 'ancestors-or-self' ");
  10696. break;
  10697. case AXIS_ATTRIBUTE:
  10698. xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
  10699. break;
  10700. case AXIS_CHILD:
  10701. xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
  10702. break;
  10703. case AXIS_DESCENDANT:
  10704. xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
  10705. break;
  10706. case AXIS_DESCENDANT_OR_SELF:
  10707. xmlGenericError(xmlGenericErrorContext,
  10708. "axis 'descendant-or-self' ");
  10709. break;
  10710. case AXIS_FOLLOWING:
  10711. xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
  10712. break;
  10713. case AXIS_FOLLOWING_SIBLING:
  10714. xmlGenericError(xmlGenericErrorContext,
  10715. "axis 'following-siblings' ");
  10716. break;
  10717. case AXIS_NAMESPACE:
  10718. xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
  10719. break;
  10720. case AXIS_PARENT:
  10721. xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
  10722. break;
  10723. case AXIS_PRECEDING:
  10724. xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
  10725. break;
  10726. case AXIS_PRECEDING_SIBLING:
  10727. xmlGenericError(xmlGenericErrorContext,
  10728. "axis 'preceding-sibling' ");
  10729. break;
  10730. case AXIS_SELF:
  10731. xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
  10732. break;
  10733. }
  10734. xmlGenericError(xmlGenericErrorContext,
  10735. " context contains %d nodes\n", nbNodes);
  10736. switch (op->value2) {
  10737. case NODE_TEST_NONE:
  10738. xmlGenericError(xmlGenericErrorContext,
  10739. " searching for none !!!\n");
  10740. break;
  10741. case NODE_TEST_TYPE:
  10742. xmlGenericError(xmlGenericErrorContext,
  10743. " searching for type %d\n", op->value3);
  10744. break;
  10745. case NODE_TEST_PI:
  10746. xmlGenericError(xmlGenericErrorContext,
  10747. " searching for PI !!!\n");
  10748. break;
  10749. case NODE_TEST_ALL:
  10750. xmlGenericError(xmlGenericErrorContext,
  10751. " searching for *\n");
  10752. break;
  10753. case NODE_TEST_NS:
  10754. xmlGenericError(xmlGenericErrorContext,
  10755. " searching for namespace %s\n",
  10756. op->value5);
  10757. break;
  10758. case NODE_TEST_NAME:
  10759. xmlGenericError(xmlGenericErrorContext,
  10760. " searching for name %s\n", op->value5);
  10761. if (op->value4)
  10762. xmlGenericError(xmlGenericErrorContext,
  10763. " with namespace %s\n", op->value4);
  10764. break;
  10765. }
  10766. xmlGenericError(xmlGenericErrorContext, "Testing : ");
  10767. }
  10768. #endif /* DEBUG_STEP */
  10769. /**
  10770. * xmlXPathNodeSetFilter:
  10771. * @ctxt: the XPath Parser context
  10772. * @set: the node set to filter
  10773. * @filterOpIndex: the index of the predicate/filter op
  10774. * @minPos: minimum position in the filtered set (1-based)
  10775. * @maxPos: maximum position in the filtered set (1-based)
  10776. * @hasNsNodes: true if the node set may contain namespace nodes
  10777. *
  10778. * Filter a node set, keeping only nodes for which the predicate expression
  10779. * matches. Afterwards, keep only nodes between minPos and maxPos in the
  10780. * filtered result.
  10781. */
  10782. static void
  10783. xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
  10784. xmlNodeSetPtr set,
  10785. int filterOpIndex,
  10786. int minPos, int maxPos,
  10787. int hasNsNodes)
  10788. {
  10789. xmlXPathContextPtr xpctxt;
  10790. xmlNodePtr oldnode;
  10791. xmlDocPtr olddoc;
  10792. xmlXPathStepOpPtr filterOp;
  10793. int oldcs, oldpp;
  10794. int i, j, pos;
  10795. if ((set == NULL) || (set->nodeNr == 0))
  10796. return;
  10797. /*
  10798. * Check if the node set contains a sufficient number of nodes for
  10799. * the requested range.
  10800. */
  10801. if (set->nodeNr < minPos) {
  10802. xmlXPathNodeSetClear(set, hasNsNodes);
  10803. return;
  10804. }
  10805. xpctxt = ctxt->context;
  10806. oldnode = xpctxt->node;
  10807. olddoc = xpctxt->doc;
  10808. oldcs = xpctxt->contextSize;
  10809. oldpp = xpctxt->proximityPosition;
  10810. filterOp = &ctxt->comp->steps[filterOpIndex];
  10811. xpctxt->contextSize = set->nodeNr;
  10812. for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
  10813. xmlNodePtr node = set->nodeTab[i];
  10814. int res;
  10815. xpctxt->node = node;
  10816. xpctxt->proximityPosition = i + 1;
  10817. /*
  10818. * Also set the xpath document in case things like
  10819. * key() are evaluated in the predicate.
  10820. *
  10821. * TODO: Get real doc for namespace nodes.
  10822. */
  10823. if ((node->type != XML_NAMESPACE_DECL) &&
  10824. (node->doc != NULL))
  10825. xpctxt->doc = node->doc;
  10826. res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
  10827. if (ctxt->error != XPATH_EXPRESSION_OK)
  10828. break;
  10829. if (res < 0) {
  10830. /* Shouldn't happen */
  10831. xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
  10832. break;
  10833. }
  10834. if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
  10835. if (i != j) {
  10836. set->nodeTab[j] = node;
  10837. set->nodeTab[i] = NULL;
  10838. }
  10839. j += 1;
  10840. } else {
  10841. /* Remove the entry from the initial node set. */
  10842. set->nodeTab[i] = NULL;
  10843. if (node->type == XML_NAMESPACE_DECL)
  10844. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  10845. }
  10846. if (res != 0) {
  10847. if (pos == maxPos) {
  10848. i += 1;
  10849. break;
  10850. }
  10851. pos += 1;
  10852. }
  10853. }
  10854. /* Free remaining nodes. */
  10855. if (hasNsNodes) {
  10856. for (; i < set->nodeNr; i++) {
  10857. xmlNodePtr node = set->nodeTab[i];
  10858. if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
  10859. xmlXPathNodeSetFreeNs((xmlNsPtr) node);
  10860. }
  10861. }
  10862. set->nodeNr = j;
  10863. /* If too many elements were removed, shrink table to preserve memory. */
  10864. if ((set->nodeMax > XML_NODESET_DEFAULT) &&
  10865. (set->nodeNr < set->nodeMax / 2)) {
  10866. xmlNodePtr *tmp;
  10867. int nodeMax = set->nodeNr;
  10868. if (nodeMax < XML_NODESET_DEFAULT)
  10869. nodeMax = XML_NODESET_DEFAULT;
  10870. tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
  10871. nodeMax * sizeof(xmlNodePtr));
  10872. if (tmp == NULL) {
  10873. xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
  10874. } else {
  10875. set->nodeTab = tmp;
  10876. set->nodeMax = nodeMax;
  10877. }
  10878. }
  10879. xpctxt->node = oldnode;
  10880. xpctxt->doc = olddoc;
  10881. xpctxt->contextSize = oldcs;
  10882. xpctxt->proximityPosition = oldpp;
  10883. }
  10884. #ifdef LIBXML_XPTR_ENABLED
  10885. /**
  10886. * xmlXPathLocationSetFilter:
  10887. * @ctxt: the XPath Parser context
  10888. * @locset: the location set to filter
  10889. * @filterOpIndex: the index of the predicate/filter op
  10890. * @minPos: minimum position in the filtered set (1-based)
  10891. * @maxPos: maximum position in the filtered set (1-based)
  10892. *
  10893. * Filter a location set, keeping only nodes for which the predicate
  10894. * expression matches. Afterwards, keep only nodes between minPos and maxPos
  10895. * in the filtered result.
  10896. */
  10897. static void
  10898. xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
  10899. xmlLocationSetPtr locset,
  10900. int filterOpIndex,
  10901. int minPos, int maxPos)
  10902. {
  10903. xmlXPathContextPtr xpctxt;
  10904. xmlNodePtr oldnode;
  10905. xmlDocPtr olddoc;
  10906. xmlXPathStepOpPtr filterOp;
  10907. int oldcs, oldpp;
  10908. int i, j, pos;
  10909. if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
  10910. return;
  10911. xpctxt = ctxt->context;
  10912. oldnode = xpctxt->node;
  10913. olddoc = xpctxt->doc;
  10914. oldcs = xpctxt->contextSize;
  10915. oldpp = xpctxt->proximityPosition;
  10916. filterOp = &ctxt->comp->steps[filterOpIndex];
  10917. xpctxt->contextSize = locset->locNr;
  10918. for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
  10919. xmlNodePtr contextNode = locset->locTab[i]->user;
  10920. int res;
  10921. xpctxt->node = contextNode;
  10922. xpctxt->proximityPosition = i + 1;
  10923. /*
  10924. * Also set the xpath document in case things like
  10925. * key() are evaluated in the predicate.
  10926. *
  10927. * TODO: Get real doc for namespace nodes.
  10928. */
  10929. if ((contextNode->type != XML_NAMESPACE_DECL) &&
  10930. (contextNode->doc != NULL))
  10931. xpctxt->doc = contextNode->doc;
  10932. res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
  10933. if (ctxt->error != XPATH_EXPRESSION_OK)
  10934. break;
  10935. if (res < 0) {
  10936. /* Shouldn't happen */
  10937. xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
  10938. break;
  10939. }
  10940. if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
  10941. if (i != j) {
  10942. locset->locTab[j] = locset->locTab[i];
  10943. locset->locTab[i] = NULL;
  10944. }
  10945. j += 1;
  10946. } else {
  10947. /* Remove the entry from the initial location set. */
  10948. xmlXPathFreeObject(locset->locTab[i]);
  10949. locset->locTab[i] = NULL;
  10950. }
  10951. if (res != 0) {
  10952. if (pos == maxPos) {
  10953. i += 1;
  10954. break;
  10955. }
  10956. pos += 1;
  10957. }
  10958. }
  10959. /* Free remaining nodes. */
  10960. for (; i < locset->locNr; i++)
  10961. xmlXPathFreeObject(locset->locTab[i]);
  10962. locset->locNr = j;
  10963. /* If too many elements were removed, shrink table to preserve memory. */
  10964. if ((locset->locMax > XML_NODESET_DEFAULT) &&
  10965. (locset->locNr < locset->locMax / 2)) {
  10966. xmlXPathObjectPtr *tmp;
  10967. int locMax = locset->locNr;
  10968. if (locMax < XML_NODESET_DEFAULT)
  10969. locMax = XML_NODESET_DEFAULT;
  10970. tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
  10971. locMax * sizeof(xmlXPathObjectPtr));
  10972. if (tmp == NULL) {
  10973. xmlXPathPErrMemory(ctxt, "shrinking locset\n");
  10974. } else {
  10975. locset->locTab = tmp;
  10976. locset->locMax = locMax;
  10977. }
  10978. }
  10979. xpctxt->node = oldnode;
  10980. xpctxt->doc = olddoc;
  10981. xpctxt->contextSize = oldcs;
  10982. xpctxt->proximityPosition = oldpp;
  10983. }
  10984. #endif /* LIBXML_XPTR_ENABLED */
  10985. /**
  10986. * xmlXPathCompOpEvalPredicate:
  10987. * @ctxt: the XPath Parser context
  10988. * @op: the predicate op
  10989. * @set: the node set to filter
  10990. * @minPos: minimum position in the filtered set (1-based)
  10991. * @maxPos: maximum position in the filtered set (1-based)
  10992. * @hasNsNodes: true if the node set may contain namespace nodes
  10993. *
  10994. * Filter a node set, keeping only nodes for which the sequence of predicate
  10995. * expressions matches. Afterwards, keep only nodes between minPos and maxPos
  10996. * in the filtered result.
  10997. */
  10998. static void
  10999. xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
  11000. xmlXPathStepOpPtr op,
  11001. xmlNodeSetPtr set,
  11002. int minPos, int maxPos,
  11003. int hasNsNodes)
  11004. {
  11005. if (op->ch1 != -1) {
  11006. xmlXPathCompExprPtr comp = ctxt->comp;
  11007. /*
  11008. * Process inner predicates first.
  11009. */
  11010. if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
  11011. xmlGenericError(xmlGenericErrorContext,
  11012. "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
  11013. XP_ERROR(XPATH_INVALID_OPERAND);
  11014. }
  11015. if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
  11016. XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
  11017. ctxt->context->depth += 1;
  11018. xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
  11019. 1, set->nodeNr, hasNsNodes);
  11020. ctxt->context->depth -= 1;
  11021. CHECK_ERROR;
  11022. }
  11023. if (op->ch2 != -1)
  11024. xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
  11025. }
  11026. static int
  11027. xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
  11028. xmlXPathStepOpPtr op,
  11029. int *maxPos)
  11030. {
  11031. xmlXPathStepOpPtr exprOp;
  11032. /*
  11033. * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
  11034. */
  11035. /*
  11036. * If not -1, then ch1 will point to:
  11037. * 1) For predicates (XPATH_OP_PREDICATE):
  11038. * - an inner predicate operator
  11039. * 2) For filters (XPATH_OP_FILTER):
  11040. * - an inner filter operator OR
  11041. * - an expression selecting the node set.
  11042. * E.g. "key('a', 'b')" or "(//foo | //bar)".
  11043. */
  11044. if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
  11045. return(0);
  11046. if (op->ch2 != -1) {
  11047. exprOp = &ctxt->comp->steps[op->ch2];
  11048. } else
  11049. return(0);
  11050. if ((exprOp != NULL) &&
  11051. (exprOp->op == XPATH_OP_VALUE) &&
  11052. (exprOp->value4 != NULL) &&
  11053. (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
  11054. {
  11055. double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
  11056. /*
  11057. * We have a "[n]" predicate here.
  11058. * TODO: Unfortunately this simplistic test here is not
  11059. * able to detect a position() predicate in compound
  11060. * expressions like "[@attr = 'a" and position() = 1],
  11061. * and even not the usage of position() in
  11062. * "[position() = 1]"; thus - obviously - a position-range,
  11063. * like it "[position() < 5]", is also not detected.
  11064. * Maybe we could rewrite the AST to ease the optimization.
  11065. */
  11066. if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
  11067. *maxPos = (int) floatval;
  11068. if (floatval == (double) *maxPos)
  11069. return(1);
  11070. }
  11071. }
  11072. return(0);
  11073. }
  11074. static int
  11075. xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
  11076. xmlXPathStepOpPtr op,
  11077. xmlNodePtr * first, xmlNodePtr * last,
  11078. int toBool)
  11079. {
  11080. #define XP_TEST_HIT \
  11081. if (hasAxisRange != 0) { \
  11082. if (++pos == maxPos) { \
  11083. if (addNode(seq, cur) < 0) \
  11084. ctxt->error = XPATH_MEMORY_ERROR; \
  11085. goto axis_range_end; } \
  11086. } else { \
  11087. if (addNode(seq, cur) < 0) \
  11088. ctxt->error = XPATH_MEMORY_ERROR; \
  11089. if (breakOnFirstHit) goto first_hit; }
  11090. #define XP_TEST_HIT_NS \
  11091. if (hasAxisRange != 0) { \
  11092. if (++pos == maxPos) { \
  11093. hasNsNodes = 1; \
  11094. if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
  11095. ctxt->error = XPATH_MEMORY_ERROR; \
  11096. goto axis_range_end; } \
  11097. } else { \
  11098. hasNsNodes = 1; \
  11099. if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
  11100. ctxt->error = XPATH_MEMORY_ERROR; \
  11101. if (breakOnFirstHit) goto first_hit; }
  11102. xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
  11103. xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
  11104. xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
  11105. const xmlChar *prefix = op->value4;
  11106. const xmlChar *name = op->value5;
  11107. const xmlChar *URI = NULL;
  11108. #ifdef DEBUG_STEP
  11109. int nbMatches = 0, prevMatches = 0;
  11110. #endif
  11111. int total = 0, hasNsNodes = 0;
  11112. /* The popped object holding the context nodes */
  11113. xmlXPathObjectPtr obj;
  11114. /* The set of context nodes for the node tests */
  11115. xmlNodeSetPtr contextSeq;
  11116. int contextIdx;
  11117. xmlNodePtr contextNode;
  11118. /* The final resulting node set wrt to all context nodes */
  11119. xmlNodeSetPtr outSeq;
  11120. /*
  11121. * The temporary resulting node set wrt 1 context node.
  11122. * Used to feed predicate evaluation.
  11123. */
  11124. xmlNodeSetPtr seq;
  11125. xmlNodePtr cur;
  11126. /* First predicate operator */
  11127. xmlXPathStepOpPtr predOp;
  11128. int maxPos; /* The requested position() (when a "[n]" predicate) */
  11129. int hasPredicateRange, hasAxisRange, pos;
  11130. int breakOnFirstHit;
  11131. xmlXPathTraversalFunction next = NULL;
  11132. int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
  11133. xmlXPathNodeSetMergeFunction mergeAndClear;
  11134. xmlNodePtr oldContextNode;
  11135. xmlXPathContextPtr xpctxt = ctxt->context;
  11136. CHECK_TYPE0(XPATH_NODESET);
  11137. obj = valuePop(ctxt);
  11138. /*
  11139. * Setup namespaces.
  11140. */
  11141. if (prefix != NULL) {
  11142. URI = xmlXPathNsLookup(xpctxt, prefix);
  11143. if (URI == NULL) {
  11144. xmlXPathReleaseObject(xpctxt, obj);
  11145. XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
  11146. }
  11147. }
  11148. /*
  11149. * Setup axis.
  11150. *
  11151. * MAYBE FUTURE TODO: merging optimizations:
  11152. * - If the nodes to be traversed wrt to the initial nodes and
  11153. * the current axis cannot overlap, then we could avoid searching
  11154. * for duplicates during the merge.
  11155. * But the question is how/when to evaluate if they cannot overlap.
  11156. * Example: if we know that for two initial nodes, the one is
  11157. * not in the ancestor-or-self axis of the other, then we could safely
  11158. * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
  11159. * the descendant-or-self axis.
  11160. */
  11161. mergeAndClear = xmlXPathNodeSetMergeAndClear;
  11162. switch (axis) {
  11163. case AXIS_ANCESTOR:
  11164. first = NULL;
  11165. next = xmlXPathNextAncestor;
  11166. break;
  11167. case AXIS_ANCESTOR_OR_SELF:
  11168. first = NULL;
  11169. next = xmlXPathNextAncestorOrSelf;
  11170. break;
  11171. case AXIS_ATTRIBUTE:
  11172. first = NULL;
  11173. last = NULL;
  11174. next = xmlXPathNextAttribute;
  11175. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  11176. break;
  11177. case AXIS_CHILD:
  11178. last = NULL;
  11179. if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
  11180. (type == NODE_TYPE_NODE))
  11181. {
  11182. /*
  11183. * Optimization if an element node type is 'element'.
  11184. */
  11185. next = xmlXPathNextChildElement;
  11186. } else
  11187. next = xmlXPathNextChild;
  11188. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  11189. break;
  11190. case AXIS_DESCENDANT:
  11191. last = NULL;
  11192. next = xmlXPathNextDescendant;
  11193. break;
  11194. case AXIS_DESCENDANT_OR_SELF:
  11195. last = NULL;
  11196. next = xmlXPathNextDescendantOrSelf;
  11197. break;
  11198. case AXIS_FOLLOWING:
  11199. last = NULL;
  11200. next = xmlXPathNextFollowing;
  11201. break;
  11202. case AXIS_FOLLOWING_SIBLING:
  11203. last = NULL;
  11204. next = xmlXPathNextFollowingSibling;
  11205. break;
  11206. case AXIS_NAMESPACE:
  11207. first = NULL;
  11208. last = NULL;
  11209. next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
  11210. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  11211. break;
  11212. case AXIS_PARENT:
  11213. first = NULL;
  11214. next = xmlXPathNextParent;
  11215. break;
  11216. case AXIS_PRECEDING:
  11217. first = NULL;
  11218. next = xmlXPathNextPrecedingInternal;
  11219. break;
  11220. case AXIS_PRECEDING_SIBLING:
  11221. first = NULL;
  11222. next = xmlXPathNextPrecedingSibling;
  11223. break;
  11224. case AXIS_SELF:
  11225. first = NULL;
  11226. last = NULL;
  11227. next = xmlXPathNextSelf;
  11228. mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
  11229. break;
  11230. }
  11231. #ifdef DEBUG_STEP
  11232. xmlXPathDebugDumpStepAxis(op,
  11233. (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
  11234. #endif
  11235. if (next == NULL) {
  11236. xmlXPathReleaseObject(xpctxt, obj);
  11237. return(0);
  11238. }
  11239. contextSeq = obj->nodesetval;
  11240. if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
  11241. xmlXPathReleaseObject(xpctxt, obj);
  11242. valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
  11243. return(0);
  11244. }
  11245. /*
  11246. * Predicate optimization ---------------------------------------------
  11247. * If this step has a last predicate, which contains a position(),
  11248. * then we'll optimize (although not exactly "position()", but only
  11249. * the short-hand form, i.e., "[n]".
  11250. *
  11251. * Example - expression "/foo[parent::bar][1]":
  11252. *
  11253. * COLLECT 'child' 'name' 'node' foo -- op (we are here)
  11254. * ROOT -- op->ch1
  11255. * PREDICATE -- op->ch2 (predOp)
  11256. * PREDICATE -- predOp->ch1 = [parent::bar]
  11257. * SORT
  11258. * COLLECT 'parent' 'name' 'node' bar
  11259. * NODE
  11260. * ELEM Object is a number : 1 -- predOp->ch2 = [1]
  11261. *
  11262. */
  11263. maxPos = 0;
  11264. predOp = NULL;
  11265. hasPredicateRange = 0;
  11266. hasAxisRange = 0;
  11267. if (op->ch2 != -1) {
  11268. /*
  11269. * There's at least one predicate. 16 == XPATH_OP_PREDICATE
  11270. */
  11271. predOp = &ctxt->comp->steps[op->ch2];
  11272. if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
  11273. if (predOp->ch1 != -1) {
  11274. /*
  11275. * Use the next inner predicate operator.
  11276. */
  11277. predOp = &ctxt->comp->steps[predOp->ch1];
  11278. hasPredicateRange = 1;
  11279. } else {
  11280. /*
  11281. * There's no other predicate than the [n] predicate.
  11282. */
  11283. predOp = NULL;
  11284. hasAxisRange = 1;
  11285. }
  11286. }
  11287. }
  11288. breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
  11289. /*
  11290. * Axis traversal -----------------------------------------------------
  11291. */
  11292. /*
  11293. * 2.3 Node Tests
  11294. * - For the attribute axis, the principal node type is attribute.
  11295. * - For the namespace axis, the principal node type is namespace.
  11296. * - For other axes, the principal node type is element.
  11297. *
  11298. * A node test * is true for any node of the
  11299. * principal node type. For example, child::* will
  11300. * select all element children of the context node
  11301. */
  11302. oldContextNode = xpctxt->node;
  11303. addNode = xmlXPathNodeSetAddUnique;
  11304. outSeq = NULL;
  11305. seq = NULL;
  11306. contextNode = NULL;
  11307. contextIdx = 0;
  11308. while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
  11309. (ctxt->error == XPATH_EXPRESSION_OK)) {
  11310. xpctxt->node = contextSeq->nodeTab[contextIdx++];
  11311. if (seq == NULL) {
  11312. seq = xmlXPathNodeSetCreate(NULL);
  11313. if (seq == NULL) {
  11314. /* TODO: Propagate memory error. */
  11315. total = 0;
  11316. goto error;
  11317. }
  11318. }
  11319. /*
  11320. * Traverse the axis and test the nodes.
  11321. */
  11322. pos = 0;
  11323. cur = NULL;
  11324. hasNsNodes = 0;
  11325. do {
  11326. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  11327. goto error;
  11328. cur = next(ctxt, cur);
  11329. if (cur == NULL)
  11330. break;
  11331. /*
  11332. * QUESTION TODO: What does the "first" and "last" stuff do?
  11333. */
  11334. if ((first != NULL) && (*first != NULL)) {
  11335. if (*first == cur)
  11336. break;
  11337. if (((total % 256) == 0) &&
  11338. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  11339. (xmlXPathCmpNodesExt(*first, cur) >= 0))
  11340. #else
  11341. (xmlXPathCmpNodes(*first, cur) >= 0))
  11342. #endif
  11343. {
  11344. break;
  11345. }
  11346. }
  11347. if ((last != NULL) && (*last != NULL)) {
  11348. if (*last == cur)
  11349. break;
  11350. if (((total % 256) == 0) &&
  11351. #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
  11352. (xmlXPathCmpNodesExt(cur, *last) >= 0))
  11353. #else
  11354. (xmlXPathCmpNodes(cur, *last) >= 0))
  11355. #endif
  11356. {
  11357. break;
  11358. }
  11359. }
  11360. total++;
  11361. #ifdef DEBUG_STEP
  11362. xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
  11363. #endif
  11364. switch (test) {
  11365. case NODE_TEST_NONE:
  11366. total = 0;
  11367. STRANGE
  11368. goto error;
  11369. case NODE_TEST_TYPE:
  11370. if (type == NODE_TYPE_NODE) {
  11371. switch (cur->type) {
  11372. case XML_DOCUMENT_NODE:
  11373. case XML_HTML_DOCUMENT_NODE:
  11374. #ifdef LIBXML_DOCB_ENABLED
  11375. case XML_DOCB_DOCUMENT_NODE:
  11376. #endif
  11377. case XML_ELEMENT_NODE:
  11378. case XML_ATTRIBUTE_NODE:
  11379. case XML_PI_NODE:
  11380. case XML_COMMENT_NODE:
  11381. case XML_CDATA_SECTION_NODE:
  11382. case XML_TEXT_NODE:
  11383. XP_TEST_HIT
  11384. break;
  11385. case XML_NAMESPACE_DECL: {
  11386. if (axis == AXIS_NAMESPACE) {
  11387. XP_TEST_HIT_NS
  11388. } else {
  11389. hasNsNodes = 1;
  11390. XP_TEST_HIT
  11391. }
  11392. break;
  11393. }
  11394. default:
  11395. break;
  11396. }
  11397. } else if (cur->type == (xmlElementType) type) {
  11398. if (cur->type == XML_NAMESPACE_DECL)
  11399. XP_TEST_HIT_NS
  11400. else
  11401. XP_TEST_HIT
  11402. } else if ((type == NODE_TYPE_TEXT) &&
  11403. (cur->type == XML_CDATA_SECTION_NODE))
  11404. {
  11405. XP_TEST_HIT
  11406. }
  11407. break;
  11408. case NODE_TEST_PI:
  11409. if ((cur->type == XML_PI_NODE) &&
  11410. ((name == NULL) || xmlStrEqual(name, cur->name)))
  11411. {
  11412. XP_TEST_HIT
  11413. }
  11414. break;
  11415. case NODE_TEST_ALL:
  11416. if (axis == AXIS_ATTRIBUTE) {
  11417. if (cur->type == XML_ATTRIBUTE_NODE)
  11418. {
  11419. if (prefix == NULL)
  11420. {
  11421. XP_TEST_HIT
  11422. } else if ((cur->ns != NULL) &&
  11423. (xmlStrEqual(URI, cur->ns->href)))
  11424. {
  11425. XP_TEST_HIT
  11426. }
  11427. }
  11428. } else if (axis == AXIS_NAMESPACE) {
  11429. if (cur->type == XML_NAMESPACE_DECL)
  11430. {
  11431. XP_TEST_HIT_NS
  11432. }
  11433. } else {
  11434. if (cur->type == XML_ELEMENT_NODE) {
  11435. if (prefix == NULL)
  11436. {
  11437. XP_TEST_HIT
  11438. } else if ((cur->ns != NULL) &&
  11439. (xmlStrEqual(URI, cur->ns->href)))
  11440. {
  11441. XP_TEST_HIT
  11442. }
  11443. }
  11444. }
  11445. break;
  11446. case NODE_TEST_NS:{
  11447. TODO;
  11448. break;
  11449. }
  11450. case NODE_TEST_NAME:
  11451. if (axis == AXIS_ATTRIBUTE) {
  11452. if (cur->type != XML_ATTRIBUTE_NODE)
  11453. break;
  11454. } else if (axis == AXIS_NAMESPACE) {
  11455. if (cur->type != XML_NAMESPACE_DECL)
  11456. break;
  11457. } else {
  11458. if (cur->type != XML_ELEMENT_NODE)
  11459. break;
  11460. }
  11461. switch (cur->type) {
  11462. case XML_ELEMENT_NODE:
  11463. if (xmlStrEqual(name, cur->name)) {
  11464. if (prefix == NULL) {
  11465. if (cur->ns == NULL)
  11466. {
  11467. XP_TEST_HIT
  11468. }
  11469. } else {
  11470. if ((cur->ns != NULL) &&
  11471. (xmlStrEqual(URI, cur->ns->href)))
  11472. {
  11473. XP_TEST_HIT
  11474. }
  11475. }
  11476. }
  11477. break;
  11478. case XML_ATTRIBUTE_NODE:{
  11479. xmlAttrPtr attr = (xmlAttrPtr) cur;
  11480. if (xmlStrEqual(name, attr->name)) {
  11481. if (prefix == NULL) {
  11482. if ((attr->ns == NULL) ||
  11483. (attr->ns->prefix == NULL))
  11484. {
  11485. XP_TEST_HIT
  11486. }
  11487. } else {
  11488. if ((attr->ns != NULL) &&
  11489. (xmlStrEqual(URI,
  11490. attr->ns->href)))
  11491. {
  11492. XP_TEST_HIT
  11493. }
  11494. }
  11495. }
  11496. break;
  11497. }
  11498. case XML_NAMESPACE_DECL:
  11499. if (cur->type == XML_NAMESPACE_DECL) {
  11500. xmlNsPtr ns = (xmlNsPtr) cur;
  11501. if ((ns->prefix != NULL) && (name != NULL)
  11502. && (xmlStrEqual(ns->prefix, name)))
  11503. {
  11504. XP_TEST_HIT_NS
  11505. }
  11506. }
  11507. break;
  11508. default:
  11509. break;
  11510. }
  11511. break;
  11512. } /* switch(test) */
  11513. } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
  11514. goto apply_predicates;
  11515. axis_range_end: /* ----------------------------------------------------- */
  11516. /*
  11517. * We have a "/foo[n]", and position() = n was reached.
  11518. * Note that we can have as well "/foo/::parent::foo[1]", so
  11519. * a duplicate-aware merge is still needed.
  11520. * Merge with the result.
  11521. */
  11522. if (outSeq == NULL) {
  11523. outSeq = seq;
  11524. seq = NULL;
  11525. } else
  11526. /* TODO: Check memory error. */
  11527. outSeq = mergeAndClear(outSeq, seq);
  11528. /*
  11529. * Break if only a true/false result was requested.
  11530. */
  11531. if (toBool)
  11532. break;
  11533. continue;
  11534. first_hit: /* ---------------------------------------------------------- */
  11535. /*
  11536. * Break if only a true/false result was requested and
  11537. * no predicates existed and a node test succeeded.
  11538. */
  11539. if (outSeq == NULL) {
  11540. outSeq = seq;
  11541. seq = NULL;
  11542. } else
  11543. /* TODO: Check memory error. */
  11544. outSeq = mergeAndClear(outSeq, seq);
  11545. break;
  11546. #ifdef DEBUG_STEP
  11547. if (seq != NULL)
  11548. nbMatches += seq->nodeNr;
  11549. #endif
  11550. apply_predicates: /* --------------------------------------------------- */
  11551. if (ctxt->error != XPATH_EXPRESSION_OK)
  11552. goto error;
  11553. /*
  11554. * Apply predicates.
  11555. */
  11556. if ((predOp != NULL) && (seq->nodeNr > 0)) {
  11557. /*
  11558. * E.g. when we have a "/foo[some expression][n]".
  11559. */
  11560. /*
  11561. * QUESTION TODO: The old predicate evaluation took into
  11562. * account location-sets.
  11563. * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
  11564. * Do we expect such a set here?
  11565. * All what I learned now from the evaluation semantics
  11566. * does not indicate that a location-set will be processed
  11567. * here, so this looks OK.
  11568. */
  11569. /*
  11570. * Iterate over all predicates, starting with the outermost
  11571. * predicate.
  11572. * TODO: Problem: we cannot execute the inner predicates first
  11573. * since we cannot go back *up* the operator tree!
  11574. * Options we have:
  11575. * 1) Use of recursive functions (like is it currently done
  11576. * via xmlXPathCompOpEval())
  11577. * 2) Add a predicate evaluation information stack to the
  11578. * context struct
  11579. * 3) Change the way the operators are linked; we need a
  11580. * "parent" field on xmlXPathStepOp
  11581. *
  11582. * For the moment, I'll try to solve this with a recursive
  11583. * function: xmlXPathCompOpEvalPredicate().
  11584. */
  11585. if (hasPredicateRange != 0)
  11586. xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
  11587. hasNsNodes);
  11588. else
  11589. xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
  11590. hasNsNodes);
  11591. if (ctxt->error != XPATH_EXPRESSION_OK) {
  11592. total = 0;
  11593. goto error;
  11594. }
  11595. }
  11596. if (seq->nodeNr > 0) {
  11597. /*
  11598. * Add to result set.
  11599. */
  11600. if (outSeq == NULL) {
  11601. outSeq = seq;
  11602. seq = NULL;
  11603. } else {
  11604. /* TODO: Check memory error. */
  11605. outSeq = mergeAndClear(outSeq, seq);
  11606. }
  11607. if (toBool)
  11608. break;
  11609. }
  11610. }
  11611. error:
  11612. if ((obj->boolval) && (obj->user != NULL)) {
  11613. /*
  11614. * QUESTION TODO: What does this do and why?
  11615. * TODO: Do we have to do this also for the "error"
  11616. * cleanup further down?
  11617. */
  11618. ctxt->value->boolval = 1;
  11619. ctxt->value->user = obj->user;
  11620. obj->user = NULL;
  11621. obj->boolval = 0;
  11622. }
  11623. xmlXPathReleaseObject(xpctxt, obj);
  11624. /*
  11625. * Ensure we return at least an empty set.
  11626. */
  11627. if (outSeq == NULL) {
  11628. if ((seq != NULL) && (seq->nodeNr == 0))
  11629. outSeq = seq;
  11630. else
  11631. /* TODO: Check memory error. */
  11632. outSeq = xmlXPathNodeSetCreate(NULL);
  11633. }
  11634. if ((seq != NULL) && (seq != outSeq)) {
  11635. xmlXPathFreeNodeSet(seq);
  11636. }
  11637. /*
  11638. * Hand over the result. Better to push the set also in
  11639. * case of errors.
  11640. */
  11641. valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
  11642. /*
  11643. * Reset the context node.
  11644. */
  11645. xpctxt->node = oldContextNode;
  11646. /*
  11647. * When traversing the namespace axis in "toBool" mode, it's
  11648. * possible that tmpNsList wasn't freed.
  11649. */
  11650. if (xpctxt->tmpNsList != NULL) {
  11651. xmlFree(xpctxt->tmpNsList);
  11652. xpctxt->tmpNsList = NULL;
  11653. }
  11654. #ifdef DEBUG_STEP
  11655. xmlGenericError(xmlGenericErrorContext,
  11656. "\nExamined %d nodes, found %d nodes at that step\n",
  11657. total, nbMatches);
  11658. #endif
  11659. return(total);
  11660. }
  11661. static int
  11662. xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
  11663. xmlXPathStepOpPtr op, xmlNodePtr * first);
  11664. /**
  11665. * xmlXPathCompOpEvalFirst:
  11666. * @ctxt: the XPath parser context with the compiled expression
  11667. * @op: an XPath compiled operation
  11668. * @first: the first elem found so far
  11669. *
  11670. * Evaluate the Precompiled XPath operation searching only the first
  11671. * element in document order
  11672. *
  11673. * Returns the number of examined objects.
  11674. */
  11675. static int
  11676. xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
  11677. xmlXPathStepOpPtr op, xmlNodePtr * first)
  11678. {
  11679. int total = 0, cur;
  11680. xmlXPathCompExprPtr comp;
  11681. xmlXPathObjectPtr arg1, arg2;
  11682. CHECK_ERROR0;
  11683. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  11684. return(0);
  11685. if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
  11686. XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
  11687. ctxt->context->depth += 1;
  11688. comp = ctxt->comp;
  11689. switch (op->op) {
  11690. case XPATH_OP_END:
  11691. break;
  11692. case XPATH_OP_UNION:
  11693. total =
  11694. xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
  11695. first);
  11696. CHECK_ERROR0;
  11697. if ((ctxt->value != NULL)
  11698. && (ctxt->value->type == XPATH_NODESET)
  11699. && (ctxt->value->nodesetval != NULL)
  11700. && (ctxt->value->nodesetval->nodeNr >= 1)) {
  11701. /*
  11702. * limit tree traversing to first node in the result
  11703. */
  11704. /*
  11705. * OPTIMIZE TODO: This implicitly sorts
  11706. * the result, even if not needed. E.g. if the argument
  11707. * of the count() function, no sorting is needed.
  11708. * OPTIMIZE TODO: How do we know if the node-list wasn't
  11709. * already sorted?
  11710. */
  11711. if (ctxt->value->nodesetval->nodeNr > 1)
  11712. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  11713. *first = ctxt->value->nodesetval->nodeTab[0];
  11714. }
  11715. cur =
  11716. xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
  11717. first);
  11718. CHECK_ERROR0;
  11719. arg2 = valuePop(ctxt);
  11720. arg1 = valuePop(ctxt);
  11721. if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
  11722. (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
  11723. xmlXPathReleaseObject(ctxt->context, arg1);
  11724. xmlXPathReleaseObject(ctxt->context, arg2);
  11725. XP_ERROR0(XPATH_INVALID_TYPE);
  11726. }
  11727. if ((ctxt->context->opLimit != 0) &&
  11728. (((arg1->nodesetval != NULL) &&
  11729. (xmlXPathCheckOpLimit(ctxt,
  11730. arg1->nodesetval->nodeNr) < 0)) ||
  11731. ((arg2->nodesetval != NULL) &&
  11732. (xmlXPathCheckOpLimit(ctxt,
  11733. arg2->nodesetval->nodeNr) < 0)))) {
  11734. xmlXPathReleaseObject(ctxt->context, arg1);
  11735. xmlXPathReleaseObject(ctxt->context, arg2);
  11736. break;
  11737. }
  11738. /* TODO: Check memory error. */
  11739. arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
  11740. arg2->nodesetval);
  11741. valuePush(ctxt, arg1);
  11742. xmlXPathReleaseObject(ctxt->context, arg2);
  11743. /* optimizer */
  11744. if (total > cur)
  11745. xmlXPathCompSwap(op);
  11746. total += cur;
  11747. break;
  11748. case XPATH_OP_ROOT:
  11749. xmlXPathRoot(ctxt);
  11750. break;
  11751. case XPATH_OP_NODE:
  11752. if (op->ch1 != -1)
  11753. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11754. CHECK_ERROR0;
  11755. if (op->ch2 != -1)
  11756. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11757. CHECK_ERROR0;
  11758. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  11759. ctxt->context->node));
  11760. break;
  11761. case XPATH_OP_COLLECT:{
  11762. if (op->ch1 == -1)
  11763. break;
  11764. total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11765. CHECK_ERROR0;
  11766. total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
  11767. break;
  11768. }
  11769. case XPATH_OP_VALUE:
  11770. valuePush(ctxt,
  11771. xmlXPathCacheObjectCopy(ctxt->context,
  11772. (xmlXPathObjectPtr) op->value4));
  11773. break;
  11774. case XPATH_OP_SORT:
  11775. if (op->ch1 != -1)
  11776. total +=
  11777. xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
  11778. first);
  11779. CHECK_ERROR0;
  11780. if ((ctxt->value != NULL)
  11781. && (ctxt->value->type == XPATH_NODESET)
  11782. && (ctxt->value->nodesetval != NULL)
  11783. && (ctxt->value->nodesetval->nodeNr > 1))
  11784. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  11785. break;
  11786. #ifdef XP_OPTIMIZED_FILTER_FIRST
  11787. case XPATH_OP_FILTER:
  11788. total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
  11789. break;
  11790. #endif
  11791. default:
  11792. total += xmlXPathCompOpEval(ctxt, op);
  11793. break;
  11794. }
  11795. ctxt->context->depth -= 1;
  11796. return(total);
  11797. }
  11798. /**
  11799. * xmlXPathCompOpEvalLast:
  11800. * @ctxt: the XPath parser context with the compiled expression
  11801. * @op: an XPath compiled operation
  11802. * @last: the last elem found so far
  11803. *
  11804. * Evaluate the Precompiled XPath operation searching only the last
  11805. * element in document order
  11806. *
  11807. * Returns the number of nodes traversed
  11808. */
  11809. static int
  11810. xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
  11811. xmlNodePtr * last)
  11812. {
  11813. int total = 0, cur;
  11814. xmlXPathCompExprPtr comp;
  11815. xmlXPathObjectPtr arg1, arg2;
  11816. CHECK_ERROR0;
  11817. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  11818. return(0);
  11819. if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
  11820. XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
  11821. ctxt->context->depth += 1;
  11822. comp = ctxt->comp;
  11823. switch (op->op) {
  11824. case XPATH_OP_END:
  11825. break;
  11826. case XPATH_OP_UNION:
  11827. total =
  11828. xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
  11829. CHECK_ERROR0;
  11830. if ((ctxt->value != NULL)
  11831. && (ctxt->value->type == XPATH_NODESET)
  11832. && (ctxt->value->nodesetval != NULL)
  11833. && (ctxt->value->nodesetval->nodeNr >= 1)) {
  11834. /*
  11835. * limit tree traversing to first node in the result
  11836. */
  11837. if (ctxt->value->nodesetval->nodeNr > 1)
  11838. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  11839. *last =
  11840. ctxt->value->nodesetval->nodeTab[ctxt->value->
  11841. nodesetval->nodeNr -
  11842. 1];
  11843. }
  11844. cur =
  11845. xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
  11846. CHECK_ERROR0;
  11847. if ((ctxt->value != NULL)
  11848. && (ctxt->value->type == XPATH_NODESET)
  11849. && (ctxt->value->nodesetval != NULL)
  11850. && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
  11851. }
  11852. arg2 = valuePop(ctxt);
  11853. arg1 = valuePop(ctxt);
  11854. if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
  11855. (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
  11856. xmlXPathReleaseObject(ctxt->context, arg1);
  11857. xmlXPathReleaseObject(ctxt->context, arg2);
  11858. XP_ERROR0(XPATH_INVALID_TYPE);
  11859. }
  11860. if ((ctxt->context->opLimit != 0) &&
  11861. (((arg1->nodesetval != NULL) &&
  11862. (xmlXPathCheckOpLimit(ctxt,
  11863. arg1->nodesetval->nodeNr) < 0)) ||
  11864. ((arg2->nodesetval != NULL) &&
  11865. (xmlXPathCheckOpLimit(ctxt,
  11866. arg2->nodesetval->nodeNr) < 0)))) {
  11867. xmlXPathReleaseObject(ctxt->context, arg1);
  11868. xmlXPathReleaseObject(ctxt->context, arg2);
  11869. break;
  11870. }
  11871. /* TODO: Check memory error. */
  11872. arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
  11873. arg2->nodesetval);
  11874. valuePush(ctxt, arg1);
  11875. xmlXPathReleaseObject(ctxt->context, arg2);
  11876. /* optimizer */
  11877. if (total > cur)
  11878. xmlXPathCompSwap(op);
  11879. total += cur;
  11880. break;
  11881. case XPATH_OP_ROOT:
  11882. xmlXPathRoot(ctxt);
  11883. break;
  11884. case XPATH_OP_NODE:
  11885. if (op->ch1 != -1)
  11886. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11887. CHECK_ERROR0;
  11888. if (op->ch2 != -1)
  11889. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  11890. CHECK_ERROR0;
  11891. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  11892. ctxt->context->node));
  11893. break;
  11894. case XPATH_OP_COLLECT:{
  11895. if (op->ch1 == -1)
  11896. break;
  11897. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11898. CHECK_ERROR0;
  11899. total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
  11900. break;
  11901. }
  11902. case XPATH_OP_VALUE:
  11903. valuePush(ctxt,
  11904. xmlXPathCacheObjectCopy(ctxt->context,
  11905. (xmlXPathObjectPtr) op->value4));
  11906. break;
  11907. case XPATH_OP_SORT:
  11908. if (op->ch1 != -1)
  11909. total +=
  11910. xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
  11911. last);
  11912. CHECK_ERROR0;
  11913. if ((ctxt->value != NULL)
  11914. && (ctxt->value->type == XPATH_NODESET)
  11915. && (ctxt->value->nodesetval != NULL)
  11916. && (ctxt->value->nodesetval->nodeNr > 1))
  11917. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  11918. break;
  11919. default:
  11920. total += xmlXPathCompOpEval(ctxt, op);
  11921. break;
  11922. }
  11923. ctxt->context->depth -= 1;
  11924. return (total);
  11925. }
  11926. #ifdef XP_OPTIMIZED_FILTER_FIRST
  11927. static int
  11928. xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
  11929. xmlXPathStepOpPtr op, xmlNodePtr * first)
  11930. {
  11931. int total = 0;
  11932. xmlXPathCompExprPtr comp;
  11933. xmlNodeSetPtr set;
  11934. CHECK_ERROR0;
  11935. comp = ctxt->comp;
  11936. /*
  11937. * Optimization for ()[last()] selection i.e. the last elem
  11938. */
  11939. if ((op->ch1 != -1) && (op->ch2 != -1) &&
  11940. (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
  11941. (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
  11942. int f = comp->steps[op->ch2].ch1;
  11943. if ((f != -1) &&
  11944. (comp->steps[f].op == XPATH_OP_FUNCTION) &&
  11945. (comp->steps[f].value5 == NULL) &&
  11946. (comp->steps[f].value == 0) &&
  11947. (comp->steps[f].value4 != NULL) &&
  11948. (xmlStrEqual
  11949. (comp->steps[f].value4, BAD_CAST "last"))) {
  11950. xmlNodePtr last = NULL;
  11951. total +=
  11952. xmlXPathCompOpEvalLast(ctxt,
  11953. &comp->steps[op->ch1],
  11954. &last);
  11955. CHECK_ERROR0;
  11956. /*
  11957. * The nodeset should be in document order,
  11958. * Keep only the last value
  11959. */
  11960. if ((ctxt->value != NULL) &&
  11961. (ctxt->value->type == XPATH_NODESET) &&
  11962. (ctxt->value->nodesetval != NULL) &&
  11963. (ctxt->value->nodesetval->nodeTab != NULL) &&
  11964. (ctxt->value->nodesetval->nodeNr > 1)) {
  11965. xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
  11966. *first = *(ctxt->value->nodesetval->nodeTab);
  11967. }
  11968. return (total);
  11969. }
  11970. }
  11971. if (op->ch1 != -1)
  11972. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  11973. CHECK_ERROR0;
  11974. if (op->ch2 == -1)
  11975. return (total);
  11976. if (ctxt->value == NULL)
  11977. return (total);
  11978. #ifdef LIBXML_XPTR_ENABLED
  11979. /*
  11980. * Hum are we filtering the result of an XPointer expression
  11981. */
  11982. if (ctxt->value->type == XPATH_LOCATIONSET) {
  11983. xmlLocationSetPtr locset = ctxt->value->user;
  11984. if (locset != NULL) {
  11985. xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
  11986. if (locset->locNr > 0)
  11987. *first = (xmlNodePtr) locset->locTab[0]->user;
  11988. }
  11989. return (total);
  11990. }
  11991. #endif /* LIBXML_XPTR_ENABLED */
  11992. CHECK_TYPE0(XPATH_NODESET);
  11993. set = ctxt->value->nodesetval;
  11994. if (set != NULL) {
  11995. xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
  11996. if (set->nodeNr > 0)
  11997. *first = set->nodeTab[0];
  11998. }
  11999. return (total);
  12000. }
  12001. #endif /* XP_OPTIMIZED_FILTER_FIRST */
  12002. /**
  12003. * xmlXPathCompOpEval:
  12004. * @ctxt: the XPath parser context with the compiled expression
  12005. * @op: an XPath compiled operation
  12006. *
  12007. * Evaluate the Precompiled XPath operation
  12008. * Returns the number of nodes traversed
  12009. */
  12010. static int
  12011. xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
  12012. {
  12013. int total = 0;
  12014. int equal, ret;
  12015. xmlXPathCompExprPtr comp;
  12016. xmlXPathObjectPtr arg1, arg2;
  12017. CHECK_ERROR0;
  12018. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  12019. return(0);
  12020. if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
  12021. XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
  12022. ctxt->context->depth += 1;
  12023. comp = ctxt->comp;
  12024. switch (op->op) {
  12025. case XPATH_OP_END:
  12026. break;
  12027. case XPATH_OP_AND:
  12028. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12029. CHECK_ERROR0;
  12030. xmlXPathBooleanFunction(ctxt, 1);
  12031. if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
  12032. break;
  12033. arg2 = valuePop(ctxt);
  12034. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12035. if (ctxt->error) {
  12036. xmlXPathFreeObject(arg2);
  12037. break;
  12038. }
  12039. xmlXPathBooleanFunction(ctxt, 1);
  12040. if (ctxt->value != NULL)
  12041. ctxt->value->boolval &= arg2->boolval;
  12042. xmlXPathReleaseObject(ctxt->context, arg2);
  12043. break;
  12044. case XPATH_OP_OR:
  12045. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12046. CHECK_ERROR0;
  12047. xmlXPathBooleanFunction(ctxt, 1);
  12048. if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
  12049. break;
  12050. arg2 = valuePop(ctxt);
  12051. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12052. if (ctxt->error) {
  12053. xmlXPathFreeObject(arg2);
  12054. break;
  12055. }
  12056. xmlXPathBooleanFunction(ctxt, 1);
  12057. if (ctxt->value != NULL)
  12058. ctxt->value->boolval |= arg2->boolval;
  12059. xmlXPathReleaseObject(ctxt->context, arg2);
  12060. break;
  12061. case XPATH_OP_EQUAL:
  12062. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12063. CHECK_ERROR0;
  12064. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12065. CHECK_ERROR0;
  12066. if (op->value)
  12067. equal = xmlXPathEqualValues(ctxt);
  12068. else
  12069. equal = xmlXPathNotEqualValues(ctxt);
  12070. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
  12071. break;
  12072. case XPATH_OP_CMP:
  12073. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12074. CHECK_ERROR0;
  12075. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12076. CHECK_ERROR0;
  12077. ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
  12078. valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
  12079. break;
  12080. case XPATH_OP_PLUS:
  12081. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12082. CHECK_ERROR0;
  12083. if (op->ch2 != -1) {
  12084. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12085. }
  12086. CHECK_ERROR0;
  12087. if (op->value == 0)
  12088. xmlXPathSubValues(ctxt);
  12089. else if (op->value == 1)
  12090. xmlXPathAddValues(ctxt);
  12091. else if (op->value == 2)
  12092. xmlXPathValueFlipSign(ctxt);
  12093. else if (op->value == 3) {
  12094. CAST_TO_NUMBER;
  12095. CHECK_TYPE0(XPATH_NUMBER);
  12096. }
  12097. break;
  12098. case XPATH_OP_MULT:
  12099. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12100. CHECK_ERROR0;
  12101. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12102. CHECK_ERROR0;
  12103. if (op->value == 0)
  12104. xmlXPathMultValues(ctxt);
  12105. else if (op->value == 1)
  12106. xmlXPathDivValues(ctxt);
  12107. else if (op->value == 2)
  12108. xmlXPathModValues(ctxt);
  12109. break;
  12110. case XPATH_OP_UNION:
  12111. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12112. CHECK_ERROR0;
  12113. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12114. CHECK_ERROR0;
  12115. arg2 = valuePop(ctxt);
  12116. arg1 = valuePop(ctxt);
  12117. if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
  12118. (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
  12119. xmlXPathReleaseObject(ctxt->context, arg1);
  12120. xmlXPathReleaseObject(ctxt->context, arg2);
  12121. XP_ERROR0(XPATH_INVALID_TYPE);
  12122. }
  12123. if ((ctxt->context->opLimit != 0) &&
  12124. (((arg1->nodesetval != NULL) &&
  12125. (xmlXPathCheckOpLimit(ctxt,
  12126. arg1->nodesetval->nodeNr) < 0)) ||
  12127. ((arg2->nodesetval != NULL) &&
  12128. (xmlXPathCheckOpLimit(ctxt,
  12129. arg2->nodesetval->nodeNr) < 0)))) {
  12130. xmlXPathReleaseObject(ctxt->context, arg1);
  12131. xmlXPathReleaseObject(ctxt->context, arg2);
  12132. break;
  12133. }
  12134. if ((arg1->nodesetval == NULL) ||
  12135. ((arg2->nodesetval != NULL) &&
  12136. (arg2->nodesetval->nodeNr != 0)))
  12137. {
  12138. /* TODO: Check memory error. */
  12139. arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
  12140. arg2->nodesetval);
  12141. }
  12142. valuePush(ctxt, arg1);
  12143. xmlXPathReleaseObject(ctxt->context, arg2);
  12144. break;
  12145. case XPATH_OP_ROOT:
  12146. xmlXPathRoot(ctxt);
  12147. break;
  12148. case XPATH_OP_NODE:
  12149. if (op->ch1 != -1)
  12150. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12151. CHECK_ERROR0;
  12152. if (op->ch2 != -1)
  12153. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12154. CHECK_ERROR0;
  12155. valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
  12156. ctxt->context->node));
  12157. break;
  12158. case XPATH_OP_COLLECT:{
  12159. if (op->ch1 == -1)
  12160. break;
  12161. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12162. CHECK_ERROR0;
  12163. total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
  12164. break;
  12165. }
  12166. case XPATH_OP_VALUE:
  12167. valuePush(ctxt,
  12168. xmlXPathCacheObjectCopy(ctxt->context,
  12169. (xmlXPathObjectPtr) op->value4));
  12170. break;
  12171. case XPATH_OP_VARIABLE:{
  12172. xmlXPathObjectPtr val;
  12173. if (op->ch1 != -1)
  12174. total +=
  12175. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12176. if (op->value5 == NULL) {
  12177. val = xmlXPathVariableLookup(ctxt->context, op->value4);
  12178. if (val == NULL)
  12179. XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
  12180. valuePush(ctxt, val);
  12181. } else {
  12182. const xmlChar *URI;
  12183. URI = xmlXPathNsLookup(ctxt->context, op->value5);
  12184. if (URI == NULL) {
  12185. xmlGenericError(xmlGenericErrorContext,
  12186. "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
  12187. (char *) op->value4, (char *)op->value5);
  12188. ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
  12189. break;
  12190. }
  12191. val = xmlXPathVariableLookupNS(ctxt->context,
  12192. op->value4, URI);
  12193. if (val == NULL)
  12194. XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
  12195. valuePush(ctxt, val);
  12196. }
  12197. break;
  12198. }
  12199. case XPATH_OP_FUNCTION:{
  12200. xmlXPathFunction func;
  12201. const xmlChar *oldFunc, *oldFuncURI;
  12202. int i;
  12203. int frame;
  12204. frame = xmlXPathSetFrame(ctxt);
  12205. if (op->ch1 != -1) {
  12206. total +=
  12207. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12208. if (ctxt->error != XPATH_EXPRESSION_OK) {
  12209. xmlXPathPopFrame(ctxt, frame);
  12210. break;
  12211. }
  12212. }
  12213. if (ctxt->valueNr < ctxt->valueFrame + op->value) {
  12214. xmlGenericError(xmlGenericErrorContext,
  12215. "xmlXPathCompOpEval: parameter error\n");
  12216. ctxt->error = XPATH_INVALID_OPERAND;
  12217. xmlXPathPopFrame(ctxt, frame);
  12218. break;
  12219. }
  12220. for (i = 0; i < op->value; i++) {
  12221. if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
  12222. xmlGenericError(xmlGenericErrorContext,
  12223. "xmlXPathCompOpEval: parameter error\n");
  12224. ctxt->error = XPATH_INVALID_OPERAND;
  12225. xmlXPathPopFrame(ctxt, frame);
  12226. break;
  12227. }
  12228. }
  12229. if (op->cache != NULL)
  12230. func = op->cache;
  12231. else {
  12232. const xmlChar *URI = NULL;
  12233. if (op->value5 == NULL)
  12234. func =
  12235. xmlXPathFunctionLookup(ctxt->context,
  12236. op->value4);
  12237. else {
  12238. URI = xmlXPathNsLookup(ctxt->context, op->value5);
  12239. if (URI == NULL) {
  12240. xmlGenericError(xmlGenericErrorContext,
  12241. "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
  12242. (char *)op->value4, (char *)op->value5);
  12243. xmlXPathPopFrame(ctxt, frame);
  12244. ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
  12245. break;
  12246. }
  12247. func = xmlXPathFunctionLookupNS(ctxt->context,
  12248. op->value4, URI);
  12249. }
  12250. if (func == NULL) {
  12251. xmlGenericError(xmlGenericErrorContext,
  12252. "xmlXPathCompOpEval: function %s not found\n",
  12253. (char *)op->value4);
  12254. XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
  12255. }
  12256. op->cache = func;
  12257. op->cacheURI = (void *) URI;
  12258. }
  12259. oldFunc = ctxt->context->function;
  12260. oldFuncURI = ctxt->context->functionURI;
  12261. ctxt->context->function = op->value4;
  12262. ctxt->context->functionURI = op->cacheURI;
  12263. func(ctxt, op->value);
  12264. ctxt->context->function = oldFunc;
  12265. ctxt->context->functionURI = oldFuncURI;
  12266. if ((ctxt->error == XPATH_EXPRESSION_OK) &&
  12267. (ctxt->valueNr != ctxt->valueFrame + 1))
  12268. XP_ERROR0(XPATH_STACK_ERROR);
  12269. xmlXPathPopFrame(ctxt, frame);
  12270. break;
  12271. }
  12272. case XPATH_OP_ARG:
  12273. if (op->ch1 != -1) {
  12274. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12275. CHECK_ERROR0;
  12276. }
  12277. if (op->ch2 != -1) {
  12278. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
  12279. CHECK_ERROR0;
  12280. }
  12281. break;
  12282. case XPATH_OP_PREDICATE:
  12283. case XPATH_OP_FILTER:{
  12284. xmlNodeSetPtr set;
  12285. /*
  12286. * Optimization for ()[1] selection i.e. the first elem
  12287. */
  12288. if ((op->ch1 != -1) && (op->ch2 != -1) &&
  12289. #ifdef XP_OPTIMIZED_FILTER_FIRST
  12290. /*
  12291. * FILTER TODO: Can we assume that the inner processing
  12292. * will result in an ordered list if we have an
  12293. * XPATH_OP_FILTER?
  12294. * What about an additional field or flag on
  12295. * xmlXPathObject like @sorted ? This way we wouldn't need
  12296. * to assume anything, so it would be more robust and
  12297. * easier to optimize.
  12298. */
  12299. ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
  12300. (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
  12301. #else
  12302. (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
  12303. #endif
  12304. (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
  12305. xmlXPathObjectPtr val;
  12306. val = comp->steps[op->ch2].value4;
  12307. if ((val != NULL) && (val->type == XPATH_NUMBER) &&
  12308. (val->floatval == 1.0)) {
  12309. xmlNodePtr first = NULL;
  12310. total +=
  12311. xmlXPathCompOpEvalFirst(ctxt,
  12312. &comp->steps[op->ch1],
  12313. &first);
  12314. CHECK_ERROR0;
  12315. /*
  12316. * The nodeset should be in document order,
  12317. * Keep only the first value
  12318. */
  12319. if ((ctxt->value != NULL) &&
  12320. (ctxt->value->type == XPATH_NODESET) &&
  12321. (ctxt->value->nodesetval != NULL) &&
  12322. (ctxt->value->nodesetval->nodeNr > 1))
  12323. xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
  12324. 1, 1);
  12325. break;
  12326. }
  12327. }
  12328. /*
  12329. * Optimization for ()[last()] selection i.e. the last elem
  12330. */
  12331. if ((op->ch1 != -1) && (op->ch2 != -1) &&
  12332. (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
  12333. (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
  12334. int f = comp->steps[op->ch2].ch1;
  12335. if ((f != -1) &&
  12336. (comp->steps[f].op == XPATH_OP_FUNCTION) &&
  12337. (comp->steps[f].value5 == NULL) &&
  12338. (comp->steps[f].value == 0) &&
  12339. (comp->steps[f].value4 != NULL) &&
  12340. (xmlStrEqual
  12341. (comp->steps[f].value4, BAD_CAST "last"))) {
  12342. xmlNodePtr last = NULL;
  12343. total +=
  12344. xmlXPathCompOpEvalLast(ctxt,
  12345. &comp->steps[op->ch1],
  12346. &last);
  12347. CHECK_ERROR0;
  12348. /*
  12349. * The nodeset should be in document order,
  12350. * Keep only the last value
  12351. */
  12352. if ((ctxt->value != NULL) &&
  12353. (ctxt->value->type == XPATH_NODESET) &&
  12354. (ctxt->value->nodesetval != NULL) &&
  12355. (ctxt->value->nodesetval->nodeTab != NULL) &&
  12356. (ctxt->value->nodesetval->nodeNr > 1))
  12357. xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
  12358. break;
  12359. }
  12360. }
  12361. /*
  12362. * Process inner predicates first.
  12363. * Example "index[parent::book][1]":
  12364. * ...
  12365. * PREDICATE <-- we are here "[1]"
  12366. * PREDICATE <-- process "[parent::book]" first
  12367. * SORT
  12368. * COLLECT 'parent' 'name' 'node' book
  12369. * NODE
  12370. * ELEM Object is a number : 1
  12371. */
  12372. if (op->ch1 != -1)
  12373. total +=
  12374. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12375. CHECK_ERROR0;
  12376. if (op->ch2 == -1)
  12377. break;
  12378. if (ctxt->value == NULL)
  12379. break;
  12380. #ifdef LIBXML_XPTR_ENABLED
  12381. /*
  12382. * Hum are we filtering the result of an XPointer expression
  12383. */
  12384. if (ctxt->value->type == XPATH_LOCATIONSET) {
  12385. xmlLocationSetPtr locset = ctxt->value->user;
  12386. xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
  12387. 1, locset->locNr);
  12388. break;
  12389. }
  12390. #endif /* LIBXML_XPTR_ENABLED */
  12391. CHECK_TYPE0(XPATH_NODESET);
  12392. set = ctxt->value->nodesetval;
  12393. if (set != NULL)
  12394. xmlXPathNodeSetFilter(ctxt, set, op->ch2,
  12395. 1, set->nodeNr, 1);
  12396. break;
  12397. }
  12398. case XPATH_OP_SORT:
  12399. if (op->ch1 != -1)
  12400. total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12401. CHECK_ERROR0;
  12402. if ((ctxt->value != NULL) &&
  12403. (ctxt->value->type == XPATH_NODESET) &&
  12404. (ctxt->value->nodesetval != NULL) &&
  12405. (ctxt->value->nodesetval->nodeNr > 1))
  12406. {
  12407. xmlXPathNodeSetSort(ctxt->value->nodesetval);
  12408. }
  12409. break;
  12410. #ifdef LIBXML_XPTR_ENABLED
  12411. case XPATH_OP_RANGETO:{
  12412. xmlXPathObjectPtr range;
  12413. xmlXPathObjectPtr res, obj;
  12414. xmlXPathObjectPtr tmp;
  12415. xmlLocationSetPtr newlocset = NULL;
  12416. xmlLocationSetPtr oldlocset;
  12417. xmlNodeSetPtr oldset;
  12418. xmlNodePtr oldnode = ctxt->context->node;
  12419. int oldcs = ctxt->context->contextSize;
  12420. int oldpp = ctxt->context->proximityPosition;
  12421. int i, j;
  12422. if (op->ch1 != -1) {
  12423. total +=
  12424. xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
  12425. CHECK_ERROR0;
  12426. }
  12427. if (ctxt->value == NULL) {
  12428. XP_ERROR0(XPATH_INVALID_OPERAND);
  12429. }
  12430. if (op->ch2 == -1)
  12431. break;
  12432. if (ctxt->value->type == XPATH_LOCATIONSET) {
  12433. /*
  12434. * Extract the old locset, and then evaluate the result of the
  12435. * expression for all the element in the locset. use it to grow
  12436. * up a new locset.
  12437. */
  12438. CHECK_TYPE0(XPATH_LOCATIONSET);
  12439. if ((ctxt->value->user == NULL) ||
  12440. (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
  12441. break;
  12442. obj = valuePop(ctxt);
  12443. oldlocset = obj->user;
  12444. newlocset = xmlXPtrLocationSetCreate(NULL);
  12445. for (i = 0; i < oldlocset->locNr; i++) {
  12446. /*
  12447. * Run the evaluation with a node list made of a
  12448. * single item in the nodelocset.
  12449. */
  12450. ctxt->context->node = oldlocset->locTab[i]->user;
  12451. ctxt->context->contextSize = oldlocset->locNr;
  12452. ctxt->context->proximityPosition = i + 1;
  12453. tmp = xmlXPathCacheNewNodeSet(ctxt->context,
  12454. ctxt->context->node);
  12455. valuePush(ctxt, tmp);
  12456. if (op->ch2 != -1)
  12457. total +=
  12458. xmlXPathCompOpEval(ctxt,
  12459. &comp->steps[op->ch2]);
  12460. if (ctxt->error != XPATH_EXPRESSION_OK) {
  12461. xmlXPtrFreeLocationSet(newlocset);
  12462. goto rangeto_error;
  12463. }
  12464. res = valuePop(ctxt);
  12465. if (res->type == XPATH_LOCATIONSET) {
  12466. xmlLocationSetPtr rloc =
  12467. (xmlLocationSetPtr)res->user;
  12468. for (j=0; j<rloc->locNr; j++) {
  12469. range = xmlXPtrNewRange(
  12470. oldlocset->locTab[i]->user,
  12471. oldlocset->locTab[i]->index,
  12472. rloc->locTab[j]->user2,
  12473. rloc->locTab[j]->index2);
  12474. if (range != NULL) {
  12475. xmlXPtrLocationSetAdd(newlocset, range);
  12476. }
  12477. }
  12478. } else {
  12479. range = xmlXPtrNewRangeNodeObject(
  12480. (xmlNodePtr)oldlocset->locTab[i]->user, res);
  12481. if (range != NULL) {
  12482. xmlXPtrLocationSetAdd(newlocset,range);
  12483. }
  12484. }
  12485. /*
  12486. * Cleanup
  12487. */
  12488. if (res != NULL) {
  12489. xmlXPathReleaseObject(ctxt->context, res);
  12490. }
  12491. if (ctxt->value == tmp) {
  12492. res = valuePop(ctxt);
  12493. xmlXPathReleaseObject(ctxt->context, res);
  12494. }
  12495. }
  12496. } else { /* Not a location set */
  12497. CHECK_TYPE0(XPATH_NODESET);
  12498. obj = valuePop(ctxt);
  12499. oldset = obj->nodesetval;
  12500. newlocset = xmlXPtrLocationSetCreate(NULL);
  12501. if (oldset != NULL) {
  12502. for (i = 0; i < oldset->nodeNr; i++) {
  12503. /*
  12504. * Run the evaluation with a node list made of a single item
  12505. * in the nodeset.
  12506. */
  12507. ctxt->context->node = oldset->nodeTab[i];
  12508. /*
  12509. * OPTIMIZE TODO: Avoid recreation for every iteration.
  12510. */
  12511. tmp = xmlXPathCacheNewNodeSet(ctxt->context,
  12512. ctxt->context->node);
  12513. valuePush(ctxt, tmp);
  12514. if (op->ch2 != -1)
  12515. total +=
  12516. xmlXPathCompOpEval(ctxt,
  12517. &comp->steps[op->ch2]);
  12518. if (ctxt->error != XPATH_EXPRESSION_OK) {
  12519. xmlXPtrFreeLocationSet(newlocset);
  12520. goto rangeto_error;
  12521. }
  12522. res = valuePop(ctxt);
  12523. range =
  12524. xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
  12525. res);
  12526. if (range != NULL) {
  12527. xmlXPtrLocationSetAdd(newlocset, range);
  12528. }
  12529. /*
  12530. * Cleanup
  12531. */
  12532. if (res != NULL) {
  12533. xmlXPathReleaseObject(ctxt->context, res);
  12534. }
  12535. if (ctxt->value == tmp) {
  12536. res = valuePop(ctxt);
  12537. xmlXPathReleaseObject(ctxt->context, res);
  12538. }
  12539. }
  12540. }
  12541. }
  12542. /*
  12543. * The result is used as the new evaluation set.
  12544. */
  12545. valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
  12546. rangeto_error:
  12547. xmlXPathReleaseObject(ctxt->context, obj);
  12548. ctxt->context->node = oldnode;
  12549. ctxt->context->contextSize = oldcs;
  12550. ctxt->context->proximityPosition = oldpp;
  12551. break;
  12552. }
  12553. #endif /* LIBXML_XPTR_ENABLED */
  12554. default:
  12555. xmlGenericError(xmlGenericErrorContext,
  12556. "XPath: unknown precompiled operation %d\n", op->op);
  12557. ctxt->error = XPATH_INVALID_OPERAND;
  12558. break;
  12559. }
  12560. ctxt->context->depth -= 1;
  12561. return (total);
  12562. }
  12563. /**
  12564. * xmlXPathCompOpEvalToBoolean:
  12565. * @ctxt: the XPath parser context
  12566. *
  12567. * Evaluates if the expression evaluates to true.
  12568. *
  12569. * Returns 1 if true, 0 if false and -1 on API or internal errors.
  12570. */
  12571. static int
  12572. xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
  12573. xmlXPathStepOpPtr op,
  12574. int isPredicate)
  12575. {
  12576. xmlXPathObjectPtr resObj = NULL;
  12577. start:
  12578. if (OP_LIMIT_EXCEEDED(ctxt, 1))
  12579. return(0);
  12580. /* comp = ctxt->comp; */
  12581. switch (op->op) {
  12582. case XPATH_OP_END:
  12583. return (0);
  12584. case XPATH_OP_VALUE:
  12585. resObj = (xmlXPathObjectPtr) op->value4;
  12586. if (isPredicate)
  12587. return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
  12588. return(xmlXPathCastToBoolean(resObj));
  12589. case XPATH_OP_SORT:
  12590. /*
  12591. * We don't need sorting for boolean results. Skip this one.
  12592. */
  12593. if (op->ch1 != -1) {
  12594. op = &ctxt->comp->steps[op->ch1];
  12595. goto start;
  12596. }
  12597. return(0);
  12598. case XPATH_OP_COLLECT:
  12599. if (op->ch1 == -1)
  12600. return(0);
  12601. xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
  12602. if (ctxt->error != XPATH_EXPRESSION_OK)
  12603. return(-1);
  12604. xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
  12605. if (ctxt->error != XPATH_EXPRESSION_OK)
  12606. return(-1);
  12607. resObj = valuePop(ctxt);
  12608. if (resObj == NULL)
  12609. return(-1);
  12610. break;
  12611. default:
  12612. /*
  12613. * Fallback to call xmlXPathCompOpEval().
  12614. */
  12615. xmlXPathCompOpEval(ctxt, op);
  12616. if (ctxt->error != XPATH_EXPRESSION_OK)
  12617. return(-1);
  12618. resObj = valuePop(ctxt);
  12619. if (resObj == NULL)
  12620. return(-1);
  12621. break;
  12622. }
  12623. if (resObj) {
  12624. int res;
  12625. if (resObj->type == XPATH_BOOLEAN) {
  12626. res = resObj->boolval;
  12627. } else if (isPredicate) {
  12628. /*
  12629. * For predicates a result of type "number" is handled
  12630. * differently:
  12631. * SPEC XPath 1.0:
  12632. * "If the result is a number, the result will be converted
  12633. * to true if the number is equal to the context position
  12634. * and will be converted to false otherwise;"
  12635. */
  12636. res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
  12637. } else {
  12638. res = xmlXPathCastToBoolean(resObj);
  12639. }
  12640. xmlXPathReleaseObject(ctxt->context, resObj);
  12641. return(res);
  12642. }
  12643. return(0);
  12644. }
  12645. #ifdef XPATH_STREAMING
  12646. /**
  12647. * xmlXPathRunStreamEval:
  12648. * @ctxt: the XPath parser context with the compiled expression
  12649. *
  12650. * Evaluate the Precompiled Streamable XPath expression in the given context.
  12651. */
  12652. static int
  12653. xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
  12654. xmlXPathObjectPtr *resultSeq, int toBool)
  12655. {
  12656. int max_depth, min_depth;
  12657. int from_root;
  12658. int ret, depth;
  12659. int eval_all_nodes;
  12660. xmlNodePtr cur = NULL, limit = NULL;
  12661. xmlStreamCtxtPtr patstream = NULL;
  12662. int nb_nodes = 0;
  12663. if ((ctxt == NULL) || (comp == NULL))
  12664. return(-1);
  12665. max_depth = xmlPatternMaxDepth(comp);
  12666. if (max_depth == -1)
  12667. return(-1);
  12668. if (max_depth == -2)
  12669. max_depth = 10000;
  12670. min_depth = xmlPatternMinDepth(comp);
  12671. if (min_depth == -1)
  12672. return(-1);
  12673. from_root = xmlPatternFromRoot(comp);
  12674. if (from_root < 0)
  12675. return(-1);
  12676. #if 0
  12677. printf("stream eval: depth %d from root %d\n", max_depth, from_root);
  12678. #endif
  12679. if (! toBool) {
  12680. if (resultSeq == NULL)
  12681. return(-1);
  12682. *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
  12683. if (*resultSeq == NULL)
  12684. return(-1);
  12685. }
  12686. /*
  12687. * handle the special cases of "/" amd "." being matched
  12688. */
  12689. if (min_depth == 0) {
  12690. if (from_root) {
  12691. /* Select "/" */
  12692. if (toBool)
  12693. return(1);
  12694. /* TODO: Check memory error. */
  12695. xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
  12696. (xmlNodePtr) ctxt->doc);
  12697. } else {
  12698. /* Select "self::node()" */
  12699. if (toBool)
  12700. return(1);
  12701. /* TODO: Check memory error. */
  12702. xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
  12703. }
  12704. }
  12705. if (max_depth == 0) {
  12706. return(0);
  12707. }
  12708. if (from_root) {
  12709. cur = (xmlNodePtr)ctxt->doc;
  12710. } else if (ctxt->node != NULL) {
  12711. switch (ctxt->node->type) {
  12712. case XML_ELEMENT_NODE:
  12713. case XML_DOCUMENT_NODE:
  12714. case XML_DOCUMENT_FRAG_NODE:
  12715. case XML_HTML_DOCUMENT_NODE:
  12716. #ifdef LIBXML_DOCB_ENABLED
  12717. case XML_DOCB_DOCUMENT_NODE:
  12718. #endif
  12719. cur = ctxt->node;
  12720. break;
  12721. case XML_ATTRIBUTE_NODE:
  12722. case XML_TEXT_NODE:
  12723. case XML_CDATA_SECTION_NODE:
  12724. case XML_ENTITY_REF_NODE:
  12725. case XML_ENTITY_NODE:
  12726. case XML_PI_NODE:
  12727. case XML_COMMENT_NODE:
  12728. case XML_NOTATION_NODE:
  12729. case XML_DTD_NODE:
  12730. case XML_DOCUMENT_TYPE_NODE:
  12731. case XML_ELEMENT_DECL:
  12732. case XML_ATTRIBUTE_DECL:
  12733. case XML_ENTITY_DECL:
  12734. case XML_NAMESPACE_DECL:
  12735. case XML_XINCLUDE_START:
  12736. case XML_XINCLUDE_END:
  12737. break;
  12738. }
  12739. limit = cur;
  12740. }
  12741. if (cur == NULL) {
  12742. return(0);
  12743. }
  12744. patstream = xmlPatternGetStreamCtxt(comp);
  12745. if (patstream == NULL) {
  12746. /*
  12747. * QUESTION TODO: Is this an error?
  12748. */
  12749. return(0);
  12750. }
  12751. eval_all_nodes = xmlStreamWantsAnyNode(patstream);
  12752. if (from_root) {
  12753. ret = xmlStreamPush(patstream, NULL, NULL);
  12754. if (ret < 0) {
  12755. } else if (ret == 1) {
  12756. if (toBool)
  12757. goto return_1;
  12758. /* TODO: Check memory error. */
  12759. xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
  12760. }
  12761. }
  12762. depth = 0;
  12763. goto scan_children;
  12764. next_node:
  12765. do {
  12766. if (ctxt->opLimit != 0) {
  12767. if (ctxt->opCount >= ctxt->opLimit) {
  12768. xmlGenericError(xmlGenericErrorContext,
  12769. "XPath operation limit exceeded\n");
  12770. xmlFreeStreamCtxt(patstream);
  12771. return(-1);
  12772. }
  12773. ctxt->opCount++;
  12774. }
  12775. nb_nodes++;
  12776. switch (cur->type) {
  12777. case XML_ELEMENT_NODE:
  12778. case XML_TEXT_NODE:
  12779. case XML_CDATA_SECTION_NODE:
  12780. case XML_COMMENT_NODE:
  12781. case XML_PI_NODE:
  12782. if (cur->type == XML_ELEMENT_NODE) {
  12783. ret = xmlStreamPush(patstream, cur->name,
  12784. (cur->ns ? cur->ns->href : NULL));
  12785. } else if (eval_all_nodes)
  12786. ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
  12787. else
  12788. break;
  12789. if (ret < 0) {
  12790. /* NOP. */
  12791. } else if (ret == 1) {
  12792. if (toBool)
  12793. goto return_1;
  12794. if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
  12795. < 0) {
  12796. ctxt->lastError.domain = XML_FROM_XPATH;
  12797. ctxt->lastError.code = XML_ERR_NO_MEMORY;
  12798. }
  12799. }
  12800. if ((cur->children == NULL) || (depth >= max_depth)) {
  12801. ret = xmlStreamPop(patstream);
  12802. while (cur->next != NULL) {
  12803. cur = cur->next;
  12804. if ((cur->type != XML_ENTITY_DECL) &&
  12805. (cur->type != XML_DTD_NODE))
  12806. goto next_node;
  12807. }
  12808. }
  12809. default:
  12810. break;
  12811. }
  12812. scan_children:
  12813. if (cur->type == XML_NAMESPACE_DECL) break;
  12814. if ((cur->children != NULL) && (depth < max_depth)) {
  12815. /*
  12816. * Do not descend on entities declarations
  12817. */
  12818. if (cur->children->type != XML_ENTITY_DECL) {
  12819. cur = cur->children;
  12820. depth++;
  12821. /*
  12822. * Skip DTDs
  12823. */
  12824. if (cur->type != XML_DTD_NODE)
  12825. continue;
  12826. }
  12827. }
  12828. if (cur == limit)
  12829. break;
  12830. while (cur->next != NULL) {
  12831. cur = cur->next;
  12832. if ((cur->type != XML_ENTITY_DECL) &&
  12833. (cur->type != XML_DTD_NODE))
  12834. goto next_node;
  12835. }
  12836. do {
  12837. cur = cur->parent;
  12838. depth--;
  12839. if ((cur == NULL) || (cur == limit) ||
  12840. (cur->type == XML_DOCUMENT_NODE))
  12841. goto done;
  12842. if (cur->type == XML_ELEMENT_NODE) {
  12843. ret = xmlStreamPop(patstream);
  12844. } else if ((eval_all_nodes) &&
  12845. ((cur->type == XML_TEXT_NODE) ||
  12846. (cur->type == XML_CDATA_SECTION_NODE) ||
  12847. (cur->type == XML_COMMENT_NODE) ||
  12848. (cur->type == XML_PI_NODE)))
  12849. {
  12850. ret = xmlStreamPop(patstream);
  12851. }
  12852. if (cur->next != NULL) {
  12853. cur = cur->next;
  12854. break;
  12855. }
  12856. } while (cur != NULL);
  12857. } while ((cur != NULL) && (depth >= 0));
  12858. done:
  12859. #if 0
  12860. printf("stream eval: checked %d nodes selected %d\n",
  12861. nb_nodes, retObj->nodesetval->nodeNr);
  12862. #endif
  12863. if (patstream)
  12864. xmlFreeStreamCtxt(patstream);
  12865. return(0);
  12866. return_1:
  12867. if (patstream)
  12868. xmlFreeStreamCtxt(patstream);
  12869. return(1);
  12870. }
  12871. #endif /* XPATH_STREAMING */
  12872. /**
  12873. * xmlXPathRunEval:
  12874. * @ctxt: the XPath parser context with the compiled expression
  12875. * @toBool: evaluate to a boolean result
  12876. *
  12877. * Evaluate the Precompiled XPath expression in the given context.
  12878. */
  12879. static int
  12880. xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
  12881. {
  12882. xmlXPathCompExprPtr comp;
  12883. if ((ctxt == NULL) || (ctxt->comp == NULL))
  12884. return(-1);
  12885. ctxt->context->depth = 0;
  12886. if (ctxt->valueTab == NULL) {
  12887. /* Allocate the value stack */
  12888. ctxt->valueTab = (xmlXPathObjectPtr *)
  12889. xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
  12890. if (ctxt->valueTab == NULL) {
  12891. xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
  12892. xmlFree(ctxt);
  12893. }
  12894. ctxt->valueNr = 0;
  12895. ctxt->valueMax = 10;
  12896. ctxt->value = NULL;
  12897. ctxt->valueFrame = 0;
  12898. }
  12899. #ifdef XPATH_STREAMING
  12900. if (ctxt->comp->stream) {
  12901. int res;
  12902. if (toBool) {
  12903. /*
  12904. * Evaluation to boolean result.
  12905. */
  12906. res = xmlXPathRunStreamEval(ctxt->context,
  12907. ctxt->comp->stream, NULL, 1);
  12908. if (res != -1)
  12909. return(res);
  12910. } else {
  12911. xmlXPathObjectPtr resObj = NULL;
  12912. /*
  12913. * Evaluation to a sequence.
  12914. */
  12915. res = xmlXPathRunStreamEval(ctxt->context,
  12916. ctxt->comp->stream, &resObj, 0);
  12917. if ((res != -1) && (resObj != NULL)) {
  12918. valuePush(ctxt, resObj);
  12919. return(0);
  12920. }
  12921. if (resObj != NULL)
  12922. xmlXPathReleaseObject(ctxt->context, resObj);
  12923. }
  12924. /*
  12925. * QUESTION TODO: This falls back to normal XPath evaluation
  12926. * if res == -1. Is this intended?
  12927. */
  12928. }
  12929. #endif
  12930. comp = ctxt->comp;
  12931. if (comp->last < 0) {
  12932. xmlGenericError(xmlGenericErrorContext,
  12933. "xmlXPathRunEval: last is less than zero\n");
  12934. return(-1);
  12935. }
  12936. if (toBool)
  12937. return(xmlXPathCompOpEvalToBoolean(ctxt,
  12938. &comp->steps[comp->last], 0));
  12939. else
  12940. xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
  12941. return(0);
  12942. }
  12943. /************************************************************************
  12944. * *
  12945. * Public interfaces *
  12946. * *
  12947. ************************************************************************/
  12948. /**
  12949. * xmlXPathEvalPredicate:
  12950. * @ctxt: the XPath context
  12951. * @res: the Predicate Expression evaluation result
  12952. *
  12953. * Evaluate a predicate result for the current node.
  12954. * A PredicateExpr is evaluated by evaluating the Expr and converting
  12955. * the result to a boolean. If the result is a number, the result will
  12956. * be converted to true if the number is equal to the position of the
  12957. * context node in the context node list (as returned by the position
  12958. * function) and will be converted to false otherwise; if the result
  12959. * is not a number, then the result will be converted as if by a call
  12960. * to the boolean function.
  12961. *
  12962. * Returns 1 if predicate is true, 0 otherwise
  12963. */
  12964. int
  12965. xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
  12966. if ((ctxt == NULL) || (res == NULL)) return(0);
  12967. switch (res->type) {
  12968. case XPATH_BOOLEAN:
  12969. return(res->boolval);
  12970. case XPATH_NUMBER:
  12971. return(res->floatval == ctxt->proximityPosition);
  12972. case XPATH_NODESET:
  12973. case XPATH_XSLT_TREE:
  12974. if (res->nodesetval == NULL)
  12975. return(0);
  12976. return(res->nodesetval->nodeNr != 0);
  12977. case XPATH_STRING:
  12978. return((res->stringval != NULL) &&
  12979. (xmlStrlen(res->stringval) != 0));
  12980. default:
  12981. STRANGE
  12982. }
  12983. return(0);
  12984. }
  12985. /**
  12986. * xmlXPathEvaluatePredicateResult:
  12987. * @ctxt: the XPath Parser context
  12988. * @res: the Predicate Expression evaluation result
  12989. *
  12990. * Evaluate a predicate result for the current node.
  12991. * A PredicateExpr is evaluated by evaluating the Expr and converting
  12992. * the result to a boolean. If the result is a number, the result will
  12993. * be converted to true if the number is equal to the position of the
  12994. * context node in the context node list (as returned by the position
  12995. * function) and will be converted to false otherwise; if the result
  12996. * is not a number, then the result will be converted as if by a call
  12997. * to the boolean function.
  12998. *
  12999. * Returns 1 if predicate is true, 0 otherwise
  13000. */
  13001. int
  13002. xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
  13003. xmlXPathObjectPtr res) {
  13004. if ((ctxt == NULL) || (res == NULL)) return(0);
  13005. switch (res->type) {
  13006. case XPATH_BOOLEAN:
  13007. return(res->boolval);
  13008. case XPATH_NUMBER:
  13009. #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
  13010. return((res->floatval == ctxt->context->proximityPosition) &&
  13011. (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
  13012. #else
  13013. return(res->floatval == ctxt->context->proximityPosition);
  13014. #endif
  13015. case XPATH_NODESET:
  13016. case XPATH_XSLT_TREE:
  13017. if (res->nodesetval == NULL)
  13018. return(0);
  13019. return(res->nodesetval->nodeNr != 0);
  13020. case XPATH_STRING:
  13021. return((res->stringval != NULL) && (res->stringval[0] != 0));
  13022. #ifdef LIBXML_XPTR_ENABLED
  13023. case XPATH_LOCATIONSET:{
  13024. xmlLocationSetPtr ptr = res->user;
  13025. if (ptr == NULL)
  13026. return(0);
  13027. return (ptr->locNr != 0);
  13028. }
  13029. #endif
  13030. default:
  13031. STRANGE
  13032. }
  13033. return(0);
  13034. }
  13035. #ifdef XPATH_STREAMING
  13036. /**
  13037. * xmlXPathTryStreamCompile:
  13038. * @ctxt: an XPath context
  13039. * @str: the XPath expression
  13040. *
  13041. * Try to compile the XPath expression as a streamable subset.
  13042. *
  13043. * Returns the compiled expression or NULL if failed to compile.
  13044. */
  13045. static xmlXPathCompExprPtr
  13046. xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
  13047. /*
  13048. * Optimization: use streaming patterns when the XPath expression can
  13049. * be compiled to a stream lookup
  13050. */
  13051. xmlPatternPtr stream;
  13052. xmlXPathCompExprPtr comp;
  13053. xmlDictPtr dict = NULL;
  13054. const xmlChar **namespaces = NULL;
  13055. xmlNsPtr ns;
  13056. int i, j;
  13057. if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
  13058. (!xmlStrchr(str, '@'))) {
  13059. const xmlChar *tmp;
  13060. /*
  13061. * We don't try to handle expressions using the verbose axis
  13062. * specifiers ("::"), just the simplified form at this point.
  13063. * Additionally, if there is no list of namespaces available and
  13064. * there's a ":" in the expression, indicating a prefixed QName,
  13065. * then we won't try to compile either. xmlPatterncompile() needs
  13066. * to have a list of namespaces at compilation time in order to
  13067. * compile prefixed name tests.
  13068. */
  13069. tmp = xmlStrchr(str, ':');
  13070. if ((tmp != NULL) &&
  13071. ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
  13072. return(NULL);
  13073. if (ctxt != NULL) {
  13074. dict = ctxt->dict;
  13075. if (ctxt->nsNr > 0) {
  13076. namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
  13077. if (namespaces == NULL) {
  13078. xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
  13079. return(NULL);
  13080. }
  13081. for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
  13082. ns = ctxt->namespaces[j];
  13083. namespaces[i++] = ns->href;
  13084. namespaces[i++] = ns->prefix;
  13085. }
  13086. namespaces[i++] = NULL;
  13087. namespaces[i] = NULL;
  13088. }
  13089. }
  13090. stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
  13091. if (namespaces != NULL) {
  13092. xmlFree((xmlChar **)namespaces);
  13093. }
  13094. if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
  13095. comp = xmlXPathNewCompExpr();
  13096. if (comp == NULL) {
  13097. xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
  13098. return(NULL);
  13099. }
  13100. comp->stream = stream;
  13101. comp->dict = dict;
  13102. if (comp->dict)
  13103. xmlDictReference(comp->dict);
  13104. return(comp);
  13105. }
  13106. xmlFreePattern(stream);
  13107. }
  13108. return(NULL);
  13109. }
  13110. #endif /* XPATH_STREAMING */
  13111. static void
  13112. xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
  13113. xmlXPathStepOpPtr op)
  13114. {
  13115. xmlXPathCompExprPtr comp = pctxt->comp;
  13116. xmlXPathContextPtr ctxt;
  13117. /*
  13118. * Try to rewrite "descendant-or-self::node()/foo" to an optimized
  13119. * internal representation.
  13120. */
  13121. if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
  13122. (op->ch1 != -1) &&
  13123. (op->ch2 == -1 /* no predicate */))
  13124. {
  13125. xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
  13126. if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
  13127. ((xmlXPathAxisVal) prevop->value ==
  13128. AXIS_DESCENDANT_OR_SELF) &&
  13129. (prevop->ch2 == -1) &&
  13130. ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
  13131. ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
  13132. {
  13133. /*
  13134. * This is a "descendant-or-self::node()" without predicates.
  13135. * Try to eliminate it.
  13136. */
  13137. switch ((xmlXPathAxisVal) op->value) {
  13138. case AXIS_CHILD:
  13139. case AXIS_DESCENDANT:
  13140. /*
  13141. * Convert "descendant-or-self::node()/child::" or
  13142. * "descendant-or-self::node()/descendant::" to
  13143. * "descendant::"
  13144. */
  13145. op->ch1 = prevop->ch1;
  13146. op->value = AXIS_DESCENDANT;
  13147. break;
  13148. case AXIS_SELF:
  13149. case AXIS_DESCENDANT_OR_SELF:
  13150. /*
  13151. * Convert "descendant-or-self::node()/self::" or
  13152. * "descendant-or-self::node()/descendant-or-self::" to
  13153. * to "descendant-or-self::"
  13154. */
  13155. op->ch1 = prevop->ch1;
  13156. op->value = AXIS_DESCENDANT_OR_SELF;
  13157. break;
  13158. default:
  13159. break;
  13160. }
  13161. }
  13162. }
  13163. /* OP_VALUE has invalid ch1. */
  13164. if (op->op == XPATH_OP_VALUE)
  13165. return;
  13166. /* Recurse */
  13167. ctxt = pctxt->context;
  13168. if (ctxt != NULL) {
  13169. if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
  13170. return;
  13171. ctxt->depth += 1;
  13172. }
  13173. if (op->ch1 != -1)
  13174. xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
  13175. if (op->ch2 != -1)
  13176. xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
  13177. if (ctxt != NULL)
  13178. ctxt->depth -= 1;
  13179. }
  13180. /**
  13181. * xmlXPathCtxtCompile:
  13182. * @ctxt: an XPath context
  13183. * @str: the XPath expression
  13184. *
  13185. * Compile an XPath expression
  13186. *
  13187. * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
  13188. * the caller has to free the object.
  13189. */
  13190. xmlXPathCompExprPtr
  13191. xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
  13192. xmlXPathParserContextPtr pctxt;
  13193. xmlXPathCompExprPtr comp;
  13194. #ifdef XPATH_STREAMING
  13195. comp = xmlXPathTryStreamCompile(ctxt, str);
  13196. if (comp != NULL)
  13197. return(comp);
  13198. #endif
  13199. xmlInitParser();
  13200. pctxt = xmlXPathNewParserContext(str, ctxt);
  13201. if (pctxt == NULL)
  13202. return NULL;
  13203. if (ctxt != NULL)
  13204. ctxt->depth = 0;
  13205. xmlXPathCompileExpr(pctxt, 1);
  13206. if( pctxt->error != XPATH_EXPRESSION_OK )
  13207. {
  13208. xmlXPathFreeParserContext(pctxt);
  13209. return(NULL);
  13210. }
  13211. if (*pctxt->cur != 0) {
  13212. /*
  13213. * aleksey: in some cases this line prints *second* error message
  13214. * (see bug #78858) and probably this should be fixed.
  13215. * However, we are not sure that all error messages are printed
  13216. * out in other places. It's not critical so we leave it as-is for now
  13217. */
  13218. xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
  13219. comp = NULL;
  13220. } else {
  13221. comp = pctxt->comp;
  13222. if ((comp->nbStep > 1) && (comp->last >= 0)) {
  13223. if (ctxt != NULL)
  13224. ctxt->depth = 0;
  13225. xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
  13226. }
  13227. pctxt->comp = NULL;
  13228. }
  13229. xmlXPathFreeParserContext(pctxt);
  13230. if (comp != NULL) {
  13231. comp->expr = xmlStrdup(str);
  13232. #ifdef DEBUG_EVAL_COUNTS
  13233. comp->string = xmlStrdup(str);
  13234. comp->nb = 0;
  13235. #endif
  13236. }
  13237. return(comp);
  13238. }
  13239. /**
  13240. * xmlXPathCompile:
  13241. * @str: the XPath expression
  13242. *
  13243. * Compile an XPath expression
  13244. *
  13245. * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
  13246. * the caller has to free the object.
  13247. */
  13248. xmlXPathCompExprPtr
  13249. xmlXPathCompile(const xmlChar *str) {
  13250. return(xmlXPathCtxtCompile(NULL, str));
  13251. }
  13252. /**
  13253. * xmlXPathCompiledEvalInternal:
  13254. * @comp: the compiled XPath expression
  13255. * @ctxt: the XPath context
  13256. * @resObj: the resulting XPath object or NULL
  13257. * @toBool: 1 if only a boolean result is requested
  13258. *
  13259. * Evaluate the Precompiled XPath expression in the given context.
  13260. * The caller has to free @resObj.
  13261. *
  13262. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  13263. * the caller has to free the object.
  13264. */
  13265. static int
  13266. xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
  13267. xmlXPathContextPtr ctxt,
  13268. xmlXPathObjectPtr *resObjPtr,
  13269. int toBool)
  13270. {
  13271. xmlXPathParserContextPtr pctxt;
  13272. xmlXPathObjectPtr resObj;
  13273. #ifndef LIBXML_THREAD_ENABLED
  13274. static int reentance = 0;
  13275. #endif
  13276. int res;
  13277. CHECK_CTXT_NEG(ctxt)
  13278. if (comp == NULL)
  13279. return(-1);
  13280. xmlInitParser();
  13281. #ifndef LIBXML_THREAD_ENABLED
  13282. reentance++;
  13283. if (reentance > 1)
  13284. xmlXPathDisableOptimizer = 1;
  13285. #endif
  13286. #ifdef DEBUG_EVAL_COUNTS
  13287. comp->nb++;
  13288. if ((comp->string != NULL) && (comp->nb > 100)) {
  13289. fprintf(stderr, "100 x %s\n", comp->string);
  13290. comp->nb = 0;
  13291. }
  13292. #endif
  13293. pctxt = xmlXPathCompParserContext(comp, ctxt);
  13294. res = xmlXPathRunEval(pctxt, toBool);
  13295. if (pctxt->error != XPATH_EXPRESSION_OK) {
  13296. resObj = NULL;
  13297. } else {
  13298. resObj = valuePop(pctxt);
  13299. if (resObj == NULL) {
  13300. if (!toBool)
  13301. xmlGenericError(xmlGenericErrorContext,
  13302. "xmlXPathCompiledEval: No result on the stack.\n");
  13303. } else if (pctxt->valueNr > 0) {
  13304. xmlGenericError(xmlGenericErrorContext,
  13305. "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
  13306. pctxt->valueNr);
  13307. }
  13308. }
  13309. if (resObjPtr)
  13310. *resObjPtr = resObj;
  13311. else
  13312. xmlXPathReleaseObject(ctxt, resObj);
  13313. pctxt->comp = NULL;
  13314. xmlXPathFreeParserContext(pctxt);
  13315. #ifndef LIBXML_THREAD_ENABLED
  13316. reentance--;
  13317. #endif
  13318. return(res);
  13319. }
  13320. /**
  13321. * xmlXPathCompiledEval:
  13322. * @comp: the compiled XPath expression
  13323. * @ctx: the XPath context
  13324. *
  13325. * Evaluate the Precompiled XPath expression in the given context.
  13326. *
  13327. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  13328. * the caller has to free the object.
  13329. */
  13330. xmlXPathObjectPtr
  13331. xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
  13332. {
  13333. xmlXPathObjectPtr res = NULL;
  13334. xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
  13335. return(res);
  13336. }
  13337. /**
  13338. * xmlXPathCompiledEvalToBoolean:
  13339. * @comp: the compiled XPath expression
  13340. * @ctxt: the XPath context
  13341. *
  13342. * Applies the XPath boolean() function on the result of the given
  13343. * compiled expression.
  13344. *
  13345. * Returns 1 if the expression evaluated to true, 0 if to false and
  13346. * -1 in API and internal errors.
  13347. */
  13348. int
  13349. xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
  13350. xmlXPathContextPtr ctxt)
  13351. {
  13352. return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
  13353. }
  13354. /**
  13355. * xmlXPathEvalExpr:
  13356. * @ctxt: the XPath Parser context
  13357. *
  13358. * Parse and evaluate an XPath expression in the given context,
  13359. * then push the result on the context stack
  13360. */
  13361. void
  13362. xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
  13363. #ifdef XPATH_STREAMING
  13364. xmlXPathCompExprPtr comp;
  13365. #endif
  13366. if (ctxt == NULL) return;
  13367. #ifdef XPATH_STREAMING
  13368. comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
  13369. if (comp != NULL) {
  13370. if (ctxt->comp != NULL)
  13371. xmlXPathFreeCompExpr(ctxt->comp);
  13372. ctxt->comp = comp;
  13373. } else
  13374. #endif
  13375. {
  13376. if (ctxt->context != NULL)
  13377. ctxt->context->depth = 0;
  13378. xmlXPathCompileExpr(ctxt, 1);
  13379. CHECK_ERROR;
  13380. /* Check for trailing characters. */
  13381. if (*ctxt->cur != 0)
  13382. XP_ERROR(XPATH_EXPR_ERROR);
  13383. if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
  13384. if (ctxt->context != NULL)
  13385. ctxt->context->depth = 0;
  13386. xmlXPathOptimizeExpression(ctxt,
  13387. &ctxt->comp->steps[ctxt->comp->last]);
  13388. }
  13389. }
  13390. xmlXPathRunEval(ctxt, 0);
  13391. }
  13392. /**
  13393. * xmlXPathEval:
  13394. * @str: the XPath expression
  13395. * @ctx: the XPath context
  13396. *
  13397. * Evaluate the XPath Location Path in the given context.
  13398. *
  13399. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  13400. * the caller has to free the object.
  13401. */
  13402. xmlXPathObjectPtr
  13403. xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
  13404. xmlXPathParserContextPtr ctxt;
  13405. xmlXPathObjectPtr res;
  13406. CHECK_CTXT(ctx)
  13407. xmlInitParser();
  13408. ctxt = xmlXPathNewParserContext(str, ctx);
  13409. if (ctxt == NULL)
  13410. return NULL;
  13411. xmlXPathEvalExpr(ctxt);
  13412. if (ctxt->error != XPATH_EXPRESSION_OK) {
  13413. res = NULL;
  13414. } else {
  13415. res = valuePop(ctxt);
  13416. if (res == NULL) {
  13417. xmlGenericError(xmlGenericErrorContext,
  13418. "xmlXPathCompiledEval: No result on the stack.\n");
  13419. } else if (ctxt->valueNr > 0) {
  13420. xmlGenericError(xmlGenericErrorContext,
  13421. "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
  13422. ctxt->valueNr);
  13423. }
  13424. }
  13425. xmlXPathFreeParserContext(ctxt);
  13426. return(res);
  13427. }
  13428. /**
  13429. * xmlXPathSetContextNode:
  13430. * @node: the node to to use as the context node
  13431. * @ctx: the XPath context
  13432. *
  13433. * Sets 'node' as the context node. The node must be in the same
  13434. * document as that associated with the context.
  13435. *
  13436. * Returns -1 in case of error or 0 if successful
  13437. */
  13438. int
  13439. xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
  13440. if ((node == NULL) || (ctx == NULL))
  13441. return(-1);
  13442. if (node->doc == ctx->doc) {
  13443. ctx->node = node;
  13444. return(0);
  13445. }
  13446. return(-1);
  13447. }
  13448. /**
  13449. * xmlXPathNodeEval:
  13450. * @node: the node to to use as the context node
  13451. * @str: the XPath expression
  13452. * @ctx: the XPath context
  13453. *
  13454. * Evaluate the XPath Location Path in the given context. The node 'node'
  13455. * is set as the context node. The context node is not restored.
  13456. *
  13457. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  13458. * the caller has to free the object.
  13459. */
  13460. xmlXPathObjectPtr
  13461. xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
  13462. if (str == NULL)
  13463. return(NULL);
  13464. if (xmlXPathSetContextNode(node, ctx) < 0)
  13465. return(NULL);
  13466. return(xmlXPathEval(str, ctx));
  13467. }
  13468. /**
  13469. * xmlXPathEvalExpression:
  13470. * @str: the XPath expression
  13471. * @ctxt: the XPath context
  13472. *
  13473. * Alias for xmlXPathEval().
  13474. *
  13475. * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
  13476. * the caller has to free the object.
  13477. */
  13478. xmlXPathObjectPtr
  13479. xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
  13480. return(xmlXPathEval(str, ctxt));
  13481. }
  13482. /************************************************************************
  13483. * *
  13484. * Extra functions not pertaining to the XPath spec *
  13485. * *
  13486. ************************************************************************/
  13487. /**
  13488. * xmlXPathEscapeUriFunction:
  13489. * @ctxt: the XPath Parser context
  13490. * @nargs: the number of arguments
  13491. *
  13492. * Implement the escape-uri() XPath function
  13493. * string escape-uri(string $str, bool $escape-reserved)
  13494. *
  13495. * This function applies the URI escaping rules defined in section 2 of [RFC
  13496. * 2396] to the string supplied as $uri-part, which typically represents all
  13497. * or part of a URI. The effect of the function is to replace any special
  13498. * character in the string by an escape sequence of the form %xx%yy...,
  13499. * where xxyy... is the hexadecimal representation of the octets used to
  13500. * represent the character in UTF-8.
  13501. *
  13502. * The set of characters that are escaped depends on the setting of the
  13503. * boolean argument $escape-reserved.
  13504. *
  13505. * If $escape-reserved is true, all characters are escaped other than lower
  13506. * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
  13507. * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
  13508. * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
  13509. * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
  13510. * A-F).
  13511. *
  13512. * If $escape-reserved is false, the behavior differs in that characters
  13513. * referred to in [RFC 2396] as reserved characters are not escaped. These
  13514. * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
  13515. *
  13516. * [RFC 2396] does not define whether escaped URIs should use lower case or
  13517. * upper case for hexadecimal digits. To ensure that escaped URIs can be
  13518. * compared using string comparison functions, this function must always use
  13519. * the upper-case letters A-F.
  13520. *
  13521. * Generally, $escape-reserved should be set to true when escaping a string
  13522. * that is to form a single part of a URI, and to false when escaping an
  13523. * entire URI or URI reference.
  13524. *
  13525. * In the case of non-ascii characters, the string is encoded according to
  13526. * utf-8 and then converted according to RFC 2396.
  13527. *
  13528. * Examples
  13529. * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
  13530. * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
  13531. * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
  13532. * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
  13533. *
  13534. */
  13535. static void
  13536. xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  13537. xmlXPathObjectPtr str;
  13538. int escape_reserved;
  13539. xmlBufPtr target;
  13540. xmlChar *cptr;
  13541. xmlChar escape[4];
  13542. CHECK_ARITY(2);
  13543. escape_reserved = xmlXPathPopBoolean(ctxt);
  13544. CAST_TO_STRING;
  13545. str = valuePop(ctxt);
  13546. target = xmlBufCreate();
  13547. escape[0] = '%';
  13548. escape[3] = 0;
  13549. if (target) {
  13550. for (cptr = str->stringval; *cptr; cptr++) {
  13551. if ((*cptr >= 'A' && *cptr <= 'Z') ||
  13552. (*cptr >= 'a' && *cptr <= 'z') ||
  13553. (*cptr >= '0' && *cptr <= '9') ||
  13554. *cptr == '-' || *cptr == '_' || *cptr == '.' ||
  13555. *cptr == '!' || *cptr == '~' || *cptr == '*' ||
  13556. *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
  13557. (*cptr == '%' &&
  13558. ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
  13559. (cptr[1] >= 'a' && cptr[1] <= 'f') ||
  13560. (cptr[1] >= '0' && cptr[1] <= '9')) &&
  13561. ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
  13562. (cptr[2] >= 'a' && cptr[2] <= 'f') ||
  13563. (cptr[2] >= '0' && cptr[2] <= '9'))) ||
  13564. (!escape_reserved &&
  13565. (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
  13566. *cptr == ':' || *cptr == '@' || *cptr == '&' ||
  13567. *cptr == '=' || *cptr == '+' || *cptr == '$' ||
  13568. *cptr == ','))) {
  13569. xmlBufAdd(target, cptr, 1);
  13570. } else {
  13571. if ((*cptr >> 4) < 10)
  13572. escape[1] = '0' + (*cptr >> 4);
  13573. else
  13574. escape[1] = 'A' - 10 + (*cptr >> 4);
  13575. if ((*cptr & 0xF) < 10)
  13576. escape[2] = '0' + (*cptr & 0xF);
  13577. else
  13578. escape[2] = 'A' - 10 + (*cptr & 0xF);
  13579. xmlBufAdd(target, &escape[0], 3);
  13580. }
  13581. }
  13582. }
  13583. valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
  13584. xmlBufContent(target)));
  13585. xmlBufFree(target);
  13586. xmlXPathReleaseObject(ctxt->context, str);
  13587. }
  13588. /**
  13589. * xmlXPathRegisterAllFunctions:
  13590. * @ctxt: the XPath context
  13591. *
  13592. * Registers all default XPath functions in this context
  13593. */
  13594. void
  13595. xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
  13596. {
  13597. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
  13598. xmlXPathBooleanFunction);
  13599. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
  13600. xmlXPathCeilingFunction);
  13601. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
  13602. xmlXPathCountFunction);
  13603. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
  13604. xmlXPathConcatFunction);
  13605. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
  13606. xmlXPathContainsFunction);
  13607. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
  13608. xmlXPathIdFunction);
  13609. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
  13610. xmlXPathFalseFunction);
  13611. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
  13612. xmlXPathFloorFunction);
  13613. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
  13614. xmlXPathLastFunction);
  13615. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
  13616. xmlXPathLangFunction);
  13617. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
  13618. xmlXPathLocalNameFunction);
  13619. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
  13620. xmlXPathNotFunction);
  13621. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
  13622. xmlXPathNameFunction);
  13623. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
  13624. xmlXPathNamespaceURIFunction);
  13625. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
  13626. xmlXPathNormalizeFunction);
  13627. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
  13628. xmlXPathNumberFunction);
  13629. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
  13630. xmlXPathPositionFunction);
  13631. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
  13632. xmlXPathRoundFunction);
  13633. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
  13634. xmlXPathStringFunction);
  13635. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
  13636. xmlXPathStringLengthFunction);
  13637. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
  13638. xmlXPathStartsWithFunction);
  13639. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
  13640. xmlXPathSubstringFunction);
  13641. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
  13642. xmlXPathSubstringBeforeFunction);
  13643. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
  13644. xmlXPathSubstringAfterFunction);
  13645. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
  13646. xmlXPathSumFunction);
  13647. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
  13648. xmlXPathTrueFunction);
  13649. xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
  13650. xmlXPathTranslateFunction);
  13651. xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
  13652. (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
  13653. xmlXPathEscapeUriFunction);
  13654. }
  13655. #endif /* LIBXML_XPATH_ENABLED */
  13656. #define bottom_xpath
  13657. #include "elfgcchack.h"