dclib-numeric.c 246 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020
  1. /***************************************************************************
  2. * *
  3. * _____ ____ *
  4. * | __ \ / __ \ _ _ _____ *
  5. * | | \ \ / / \_\ | | | | _ \ *
  6. * | | \ \| | | | | | |_| | *
  7. * | | | || | | | | | ___/ *
  8. * | | / /| | __ | | | | _ \ *
  9. * | |__/ / \ \__/ / | |___| | |_| | *
  10. * |_____/ \____/ |_____|_|_____/ *
  11. * *
  12. * Wiimms source code library *
  13. * *
  14. ***************************************************************************
  15. * *
  16. * Copyright (c) 2012-2022 by Dirk Clemens <wiimm@wiimm.de> *
  17. * *
  18. ***************************************************************************
  19. * *
  20. * This library is free software; you can redistribute it and/or modify *
  21. * it under the terms of the GNU General Public License as published by *
  22. * the Free Software Foundation; either version 2 of the License, or *
  23. * (at your option) any later version. *
  24. * *
  25. * This library is distributed in the hope that it will be useful, *
  26. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  27. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  28. * GNU General Public License for more details. *
  29. * *
  30. * See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt *
  31. * *
  32. ***************************************************************************/
  33. #define _GNU_SOURCE 1
  34. #include <string.h>
  35. #include <unistd.h>
  36. #include <stddef.h>
  37. #include <time.h>
  38. #include <stdio.h>
  39. #include <errno.h>
  40. #include <sys/time.h>
  41. #include <sys/resource.h>
  42. #include <fcntl.h>
  43. #include "dclib-basics.h"
  44. #include "dclib-debug.h"
  45. #include "dclib-utf8.h"
  46. //
  47. ///////////////////////////////////////////////////////////////////////////////
  48. /////////////// bits ///////////////
  49. ///////////////////////////////////////////////////////////////////////////////
  50. uint Count1Bits ( cvp addr, uint size )
  51. {
  52. DASSERT( CHAR_BIT == 8 );
  53. uint count = 0;
  54. const uchar *ptr = addr;
  55. while ( size-- > 0 )
  56. count += TableBitCount[*ptr++];
  57. return count;
  58. }
  59. ///////////////////////////////////////////////////////////////////////////////
  60. ///////////////////////////////////////////////////////////////////////////////
  61. int FindLowest0BitLE ( cvp addr, uint size )
  62. {
  63. DASSERT( CHAR_BIT == 8 );
  64. const uchar *ptr = addr;
  65. uint idx;
  66. for ( idx = 0; idx < size; idx++ )
  67. {
  68. const int val = TableLowest0Bit[*ptr++];
  69. if ( val >= 0 )
  70. return 8*idx + val;
  71. }
  72. return -1;
  73. }
  74. ///////////////////////////////////////////////////////////////////////////////
  75. int FindLowest1BitLE ( cvp addr, uint size )
  76. {
  77. DASSERT( CHAR_BIT == 8 );
  78. const uchar *ptr = addr;
  79. uint idx;
  80. for ( idx = 0; idx < size; idx++ )
  81. {
  82. const int val = TableLowest1Bit[*ptr++];
  83. if ( val >= 0 )
  84. return 8*idx + val;
  85. }
  86. return -1;
  87. }
  88. ///////////////////////////////////////////////////////////////////////////////
  89. int FindHighest0BitLE ( cvp addr, uint size )
  90. {
  91. DASSERT( CHAR_BIT == 8 );
  92. const uchar *ptr = addr + size;
  93. while ( size-- > 0 )
  94. {
  95. const int val = TableHighest0Bit[*--ptr];
  96. if ( val >= 0 )
  97. return 8*size + val;
  98. }
  99. return -1;
  100. }
  101. ///////////////////////////////////////////////////////////////////////////////
  102. int FindHighest1BitLE ( cvp addr, uint size )
  103. {
  104. DASSERT( CHAR_BIT == 8 );
  105. const uchar *ptr = addr + size;
  106. while ( size-- > 0 )
  107. {
  108. const int val = TableHighest1Bit[*--ptr];
  109. if ( val >= 0 )
  110. return 8*size + val;
  111. }
  112. return -1;
  113. }
  114. ///////////////////////////////////////////////////////////////////////////////
  115. ///////////////////////////////////////////////////////////////////////////////
  116. u32 GetAlign32 ( u32 data )
  117. {
  118. const int index = FindLowest1Bit(&data,sizeof(data));
  119. return index < 0 ? 0 : 1 << index;
  120. }
  121. ///////////////////////////////////////////////////////////////////////////////
  122. u64 GetAlign64 ( u64 data )
  123. {
  124. const int index = FindLowest1Bit(&data,sizeof(data));
  125. return index < 0 ? 0 : 1llu << index;
  126. }
  127. ///////////////////////////////////////////////////////////////////////////////
  128. ///////////////////////////////////////////////////////////////////////////////
  129. int FindLowest0BitBE ( cvp addr, uint size )
  130. {
  131. DASSERT( CHAR_BIT == 8 );
  132. const uchar *ptr = addr + size;
  133. uint idx;
  134. for ( idx = 0; idx < size; idx++ )
  135. {
  136. const int val = TableLowest0Bit[*--ptr];
  137. if ( val >= 0 )
  138. return 8*idx + val;
  139. }
  140. return -1;
  141. }
  142. ///////////////////////////////////////////////////////////////////////////////
  143. int FindLowest1BitBE ( cvp addr, uint size )
  144. {
  145. DASSERT( CHAR_BIT == 8 );
  146. const uchar *ptr = addr + size;
  147. uint idx;
  148. for ( idx = 0; idx < size; idx++ )
  149. {
  150. const int val = TableLowest1Bit[*--ptr];
  151. if ( val >= 0 )
  152. return 8*idx + val;
  153. }
  154. return -1;
  155. }
  156. ///////////////////////////////////////////////////////////////////////////////
  157. int FindHighest0BitBE ( cvp addr, uint size )
  158. {
  159. DASSERT( CHAR_BIT == 8 );
  160. const uchar *ptr = addr;
  161. while ( size-- > 0 )
  162. {
  163. const int val = TableHighest0Bit[*ptr++];
  164. if ( val >= 0 )
  165. return 8*size + val;
  166. }
  167. return -1;
  168. }
  169. ///////////////////////////////////////////////////////////////////////////////
  170. int FindHighest1BitBE ( cvp addr, uint size )
  171. {
  172. DASSERT( CHAR_BIT == 8 );
  173. const uchar *ptr = addr;
  174. while ( size-- > 0 )
  175. {
  176. const int val = TableHighest1Bit[*ptr++];
  177. if ( val >= 0 )
  178. return 8*size + val;
  179. }
  180. return -1;
  181. }
  182. //
  183. ///////////////////////////////////////////////////////////////////////////////
  184. /////////////// bit manipulation ///////////////
  185. ///////////////////////////////////////////////////////////////////////////////
  186. bool TestSetBit ( void *addr, uint bit_num )
  187. {
  188. const u8 mask = 1 << ( bit_num & 7 );
  189. u8 *ptr = ((u8*)addr) + ( bit_num >> 3 );
  190. const bool result = ( *ptr & mask ) != 0;
  191. *ptr |= mask;
  192. return result;
  193. }
  194. ///////////////////////////////////////////////////////////////////////////////
  195. bool TestClearBit ( void *addr, uint bit_num )
  196. {
  197. const u8 mask = 1 << ( bit_num & 7 );
  198. u8 *ptr = ((u8*)addr) + ( bit_num >> 3 );
  199. const bool result = ( *ptr & mask ) != 0;
  200. *ptr &= ~mask;
  201. return result;
  202. }
  203. ///////////////////////////////////////////////////////////////////////////////
  204. bool TestInvertBit ( void *addr, uint bit_num )
  205. {
  206. const u8 mask = 1 << ( bit_num & 7 );
  207. u8 *ptr = ((u8*)addr) + ( bit_num >> 3 );
  208. const bool result = ( *ptr & mask ) != 0;
  209. *ptr ^= mask;
  210. return result;
  211. }
  212. ///////////////////////////////////////////////////////////////////////////////
  213. ///////////////////////////////////////////////////////////////////////////////
  214. void SetBits ( void *addr, uint beg_bitnum, uint end_bitnum )
  215. {
  216. static uchar tab1[] = { 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80 };
  217. static uchar tab2[] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
  218. if ( beg_bitnum < end_bitnum )
  219. {
  220. const uint lo8 = beg_bitnum >> 3;
  221. const uint hi8 = --end_bitnum >> 3;
  222. if ( lo8 < hi8 )
  223. {
  224. uchar * dest = (uchar*)addr + lo8;
  225. *dest++ |= tab1[ beg_bitnum & 7 ];
  226. uchar * end = (uchar*)addr + hi8;
  227. *end |= tab2[ end_bitnum & 7 ];
  228. while ( dest < end )
  229. *dest++ = 0xff;
  230. }
  231. else
  232. {
  233. uchar * dest = (uchar*)addr + lo8;
  234. *dest |= tab1[ beg_bitnum & 7 ] & tab2[ end_bitnum & 7 ];
  235. }
  236. }
  237. }
  238. ///////////////////////////////////////////////////////////////////////////////
  239. void ClearBits ( void *addr, uint beg_bitnum, uint end_bitnum )
  240. {
  241. static uchar tab1[] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f };
  242. static uchar tab2[] = { 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00 };
  243. if ( beg_bitnum < end_bitnum )
  244. {
  245. const uint lo8 = beg_bitnum >> 3;
  246. const uint hi8 = --end_bitnum >> 3;
  247. if ( lo8 < hi8 )
  248. {
  249. uchar * dest = (uchar*)addr + lo8;
  250. *dest++ &= tab1[ beg_bitnum & 7 ];
  251. uchar * end = (uchar*)addr + hi8;
  252. *end &= tab2[ end_bitnum & 7 ];
  253. while ( dest < end )
  254. *dest++ = 0;
  255. }
  256. else
  257. {
  258. uchar * dest = (uchar*)addr + lo8;
  259. *dest &= tab1[ beg_bitnum & 7 ] | tab2[ end_bitnum & 7 ];
  260. }
  261. }
  262. }
  263. ///////////////////////////////////////////////////////////////////////////////
  264. ///////////////////////////////////////////////////////////////////////////////
  265. void InvertBits ( void *addr, uint beg_bitnum, uint end_bitnum )
  266. {
  267. static uchar tab1[] = { 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80 };
  268. static uchar tab2[] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
  269. if ( beg_bitnum < end_bitnum )
  270. {
  271. const uint lo8 = beg_bitnum >> 3;
  272. const uint hi8 = --end_bitnum >> 3;
  273. if ( lo8 < hi8 )
  274. {
  275. uchar * dest = (uchar*)addr + lo8;
  276. *dest++ ^= tab1[ beg_bitnum & 7 ];
  277. uchar * end = (uchar*)addr + hi8;
  278. *end ^= tab2[ end_bitnum & 7 ];
  279. while ( dest < end )
  280. *dest++ ^= 0xff;
  281. }
  282. else
  283. {
  284. uchar * dest = (uchar*)addr + lo8;
  285. *dest ^= tab1[ beg_bitnum & 7 ] & tab2[ end_bitnum & 7 ];
  286. }
  287. }
  288. }
  289. ///////////////////////////////////////////////////////////////////////////////
  290. ///////////////////////////////////////////////////////////////////////////////
  291. #undef GET_NEXT
  292. #define GET_NEXT ch = *src++; \
  293. if ( ++min_idx > max_idx ) goto term; \
  294. if ( min_idx == max_idx ) ch &= max_mask
  295. int PrintBitfieldEx
  296. (
  297. // returns the number of printed characters, or -1 if buffer is to small
  298. char *buf, // buffer
  299. uint buf_size, // size of 'buf'
  300. cvp bit_field, // address of bit field
  301. uint min_idx, // minimal index (inclusive) to check
  302. uint max_idx, // maximal index (inclusive) to check
  303. bool use_ranges, // true: create ranges 'a:b'
  304. int mult, // each printed index is first multiplyed by 'mult'
  305. int add // ... and then added to 'add'.
  306. )
  307. {
  308. DASSERT(buf);
  309. DASSERT(buf_size);
  310. DASSERT(bit_field);
  311. char *dest = buf;
  312. char *end = buf + buf_size;
  313. char *sep = "";
  314. const u8 *src = (u8*)bit_field + (min_idx >> 3);
  315. u8 ch = *src++; // always preload the current byte
  316. if ( min_idx & 7 )
  317. ch &= ~((1<<(min_idx&7))-1);
  318. min_idx >>= 3;
  319. const u8 max_mask = (2<<(max_idx&7))-1;
  320. max_idx >>= 3;
  321. noPRINT("SETUP[%zx] %02x, %u..%u, max_mask=%02x\n",
  322. src-(u8*)bit_field-1, ch, min_idx, max_idx, max_mask );
  323. while ( min_idx <= max_idx )
  324. {
  325. //--- first skip bytes with value 0
  326. if (!ch)
  327. do { GET_NEXT; } while (!ch);
  328. //-- now find the first set bit
  329. DASSERT(ch);
  330. noPRINT("CHECK[%zx] %02x, %u..%u\n", src-(u8*)bit_field-1, ch, min_idx, max_idx);
  331. u8 mask = 1;
  332. uint bit_idx = 0;
  333. while ( !(ch & mask) )
  334. mask <<= 1, bit_idx++;
  335. uint first = 8*min_idx + bit_idx;
  336. noPRINT("FOUND-BEG[%zx.%u=%u] %02x, %u..%u\n",
  337. src-(u8*)bit_field-1, bit_idx, first, ch, min_idx, max_idx );
  338. //-- now find the first bit not set
  339. while ( ch & mask )
  340. mask <<= 1, bit_idx++;
  341. if ( bit_idx == 8 )
  342. {
  343. do { GET_NEXT; } while (ch == 0xff);
  344. mask = 1;
  345. bit_idx = 0;
  346. while ( ch & mask )
  347. mask <<= 1, bit_idx++;
  348. }
  349. uint last = 8*min_idx + bit_idx - 1;
  350. noPRINT("FOUND-END[%zx.%u=%u] %02x, %u..%u\n",
  351. src-(u8*)bit_field-1, bit_idx, last, ch, min_idx, max_idx );
  352. if ( first == last )
  353. dest = snprintfE(dest,end,"%s%d",sep,first*mult+add);
  354. else if ( use_ranges )
  355. dest = snprintfE(dest,end,"%s%d:%d",
  356. sep,
  357. first * mult + add,
  358. last * mult + add );
  359. else
  360. while ( first <= last )
  361. {
  362. dest = snprintfE(dest,end,"%s%d",sep,first++*mult+add);
  363. sep = ",";
  364. }
  365. if ( dest >= end-1 )
  366. {
  367. *dest = 0;
  368. return -1;
  369. }
  370. sep = ",";
  371. ch &= ~((1<<bit_idx)-1);
  372. }
  373. term:
  374. *dest = 0;
  375. return dest - buf;
  376. }
  377. //
  378. ///////////////////////////////////////////////////////////////////////////////
  379. /////////////// low level endian conversions ///////////////
  380. ///////////////////////////////////////////////////////////////////////////////
  381. void write_be16 ( void * be_data_ptr, u16 data )
  382. {
  383. DASSERT(be_data_ptr);
  384. u8 * dest = be_data_ptr;
  385. *dest++ = data >> 8;
  386. *dest = data;
  387. }
  388. void write_be24 ( void * be_data_ptr, u32 data )
  389. {
  390. DASSERT(be_data_ptr);
  391. u8 * dest = be_data_ptr + 2;
  392. *dest-- = data; data >>= 8;
  393. *dest-- = data;
  394. *dest = data >> 8;
  395. }
  396. void write_be32 ( void * be_data_ptr, u32 data )
  397. {
  398. DASSERT(be_data_ptr);
  399. u8 * dest = be_data_ptr + 3;
  400. *dest-- = data; data >>= 8;
  401. *dest-- = data; data >>= 8;
  402. *dest-- = data;
  403. *dest = data >> 8;
  404. }
  405. void write_be40 ( void * be_data_ptr, u64 data )
  406. {
  407. DASSERT(be_data_ptr);
  408. *(u8*)be_data_ptr = data>>32;
  409. write_be32( (u8*)be_data_ptr+1, data );
  410. }
  411. void write_be48 ( void * be_data_ptr, u64 data )
  412. {
  413. DASSERT(be_data_ptr);
  414. write_be16( be_data_ptr, data>>32 );
  415. write_be32( (u8*)be_data_ptr+2, data );
  416. }
  417. void write_be56 ( void * be_data_ptr, u64 data )
  418. {
  419. DASSERT(be_data_ptr);
  420. write_be24( be_data_ptr, data>>32 );
  421. write_be32( (u8*)be_data_ptr+3, data );
  422. }
  423. void write_be64 ( void * be_data_ptr, u64 data )
  424. {
  425. DASSERT(be_data_ptr);
  426. write_be32( be_data_ptr, data >> 32 );
  427. write_be32( (u8*)be_data_ptr+4, data );
  428. }
  429. void write_bef4 ( void * be_data_ptr, float data )
  430. {
  431. // assume: local system supports IEEE 754
  432. write_be32(be_data_ptr,*(u32*)&data);
  433. }
  434. void write_bef8 ( void * be_data_ptr, double data )
  435. {
  436. // assume: local system supports IEEE 754
  437. write_be64(be_data_ptr,*(u64*)&data);
  438. }
  439. ///////////////////////////////////////////////////////////////////////////////
  440. void write_le16 ( void * le_data_ptr, u16 data )
  441. {
  442. DASSERT(le_data_ptr);
  443. u8 * dest = le_data_ptr;
  444. *dest++ = data;
  445. *dest = data >> 8;
  446. }
  447. void write_le24 ( void * le_data_ptr, u32 data )
  448. {
  449. DASSERT(le_data_ptr);
  450. u8 * dest = le_data_ptr;
  451. *dest++ = data; data >>= 8;
  452. *dest++ = data;
  453. *dest = data >> 8;
  454. }
  455. void write_le32 ( void * le_data_ptr, u32 data )
  456. {
  457. DASSERT(le_data_ptr);
  458. u8 * dest = le_data_ptr;
  459. *dest++ = data; data >>= 8;
  460. *dest++ = data; data >>= 8;
  461. *dest++ = data;
  462. *dest = data >> 8;
  463. }
  464. void write_le40 ( void * le_data_ptr, u64 data )
  465. {
  466. DASSERT(le_data_ptr);
  467. *(u8*)le_data_ptr = (u8)data;
  468. write_le32( (u8*)le_data_ptr+1, data >> 8 );
  469. }
  470. void write_le48 ( void * le_data_ptr, u64 data )
  471. {
  472. DASSERT(le_data_ptr);
  473. write_le16( le_data_ptr, data );
  474. write_le32( (u8*)le_data_ptr+2, data >> 16 );
  475. }
  476. void write_le56 ( void * le_data_ptr, u64 data )
  477. {
  478. DASSERT(le_data_ptr);
  479. write_le32( le_data_ptr, data );
  480. write_le24( (u8*)le_data_ptr+4, data >> 32 );
  481. }
  482. void write_le64 ( void * le_data_ptr, u64 data )
  483. {
  484. DASSERT(le_data_ptr);
  485. write_le32( le_data_ptr, data );
  486. write_le32( (u8*)le_data_ptr+4, data >> 32 );
  487. }
  488. void write_lef4 ( void * le_data_ptr, float data )
  489. {
  490. // assume: local system supports IEEE 754
  491. write_le32(le_data_ptr,*(u32*)&data);
  492. }
  493. void write_lef8 ( void * le_data_ptr, double data )
  494. {
  495. // assume: local system supports IEEE 754
  496. write_le64(le_data_ptr,*(u64*)&data);
  497. }
  498. ///////////////////////////////////////////////////////////////////////////////
  499. // convert lists
  500. void be16n ( u16 * dest, const u16 * src, int n )
  501. {
  502. DASSERT( dest );
  503. DASSERT( n >= 0 );
  504. DASSERT( src || !n );
  505. while ( n-- > 0 )
  506. *dest++ = be16(src++);
  507. }
  508. void be32n ( u32 * dest, const u32 * src, int n )
  509. {
  510. DASSERT( dest );
  511. DASSERT( n >= 0 );
  512. DASSERT( src || !n );
  513. while ( n-- > 0 )
  514. *dest++ = be32(src++);
  515. }
  516. void bef4n ( float32 * dest, const float32 * src, int n )
  517. {
  518. DASSERT( dest );
  519. DASSERT( n >= 0 );
  520. DASSERT( src || !n );
  521. while ( n-- > 0 )
  522. *dest++ = bef4(src++);
  523. }
  524. void write_be16n ( u16 * dest, const u16 * src, int n )
  525. {
  526. DASSERT( dest );
  527. DASSERT( n >= 0 );
  528. DASSERT( src || !n );
  529. while ( n-- > 0 )
  530. write_be16(dest++,*src++);
  531. }
  532. void write_be32n ( u32 * dest, const u32 * src, int n )
  533. {
  534. DASSERT( dest );
  535. DASSERT( n >= 0 );
  536. DASSERT( src || !n );
  537. while ( n-- > 0 )
  538. write_be32(dest++,*src++);
  539. }
  540. void write_bef4n ( float32 * dest, const float32 * src, int n )
  541. {
  542. DASSERT( dest );
  543. DASSERT( n >= 0 );
  544. DASSERT( src || !n );
  545. while ( n-- > 0 )
  546. write_bef4(dest++,*src++);
  547. }
  548. ///////////////////////////////////////////////////////////////////////////////
  549. // convert lists
  550. void le16n ( u16 * dest, const u16 * src, int n )
  551. {
  552. DASSERT( dest );
  553. DASSERT( n >= 0 );
  554. DASSERT( src || !n );
  555. while ( n-- > 0 )
  556. *dest++ = le16(src++);
  557. }
  558. void le32n ( u32 * dest, const u32 * src, int n )
  559. {
  560. DASSERT( dest );
  561. DASSERT( n >= 0 );
  562. DASSERT( src || !n );
  563. while ( n-- > 0 )
  564. *dest++ = le32(src++);
  565. }
  566. void lef4n ( float32 * dest, const float32 * src, int n )
  567. {
  568. DASSERT( dest );
  569. DASSERT( n >= 0 );
  570. DASSERT( src || !n );
  571. while ( n-- > 0 )
  572. *dest++ = lef4(src++);
  573. }
  574. void write_le16n ( u16 * dest, const u16 * src, int n )
  575. {
  576. DASSERT( dest );
  577. DASSERT( n >= 0 );
  578. DASSERT( src || !n );
  579. while ( n-- > 0 )
  580. write_le16(dest++,*src++);
  581. }
  582. void write_le32n ( u32 * dest, const u32 * src, int n )
  583. {
  584. DASSERT( dest );
  585. DASSERT( n >= 0 );
  586. DASSERT( src || !n );
  587. while ( n-- > 0 )
  588. write_le32(dest++,*src++);
  589. }
  590. void write_lef4n ( float32 * dest, const float32 * src, int n )
  591. {
  592. DASSERT( dest );
  593. DASSERT( n >= 0 );
  594. DASSERT( src || !n );
  595. while ( n-- > 0 )
  596. write_lef4(dest++,*src++);
  597. }
  598. ///////////////////////////////////////////////////////////////////////////////
  599. static inline u16 ident16 ( u16 data ) { return data; }
  600. static inline u32 ident32 ( u32 data ) { return data; }
  601. static inline u64 ident64 ( u64 data ) { return data; }
  602. static inline u16 reverse16 ( u16 data ) { return swap16(&data); }
  603. static inline u32 reverse32 ( u32 data ) { return swap32(&data); }
  604. static inline u64 reverse64 ( u64 data ) { return swap64(&data); }
  605. const endian_func_t be_func =
  606. {
  607. {0xfe,0xff}, true, false, DC_BIG_ENDIAN,
  608. be16, be24, be32, be40, be48, be56, be64, bef4, bef8,
  609. write_be16, write_be24, write_be32,
  610. write_be40, write_be48, write_be56, write_be64,
  611. write_bef4, write_bef8,
  612. #if IS_BIG_ENDIAN
  613. ident16, ident32, ident64,
  614. ident16, ident32, ident64,
  615. #else
  616. reverse16, reverse32, reverse64,
  617. reverse16, reverse32, reverse64,
  618. #endif
  619. };
  620. const endian_func_t le_func =
  621. {
  622. {0xff,0xfe}, false, true, DC_LITTLE_ENDIAN,
  623. le16, le24, le32, le40, le48, le56, le64, lef4, lef8,
  624. write_le16, write_le24, write_le32,
  625. write_le40, write_le48, write_le56, write_le64,
  626. write_lef4, write_lef8,
  627. #if IS_LITTLE_ENDIAN
  628. ident16, ident32, ident64,
  629. ident16, ident32, ident64,
  630. #else
  631. reverse16, reverse32, reverse64,
  632. reverse16, reverse32, reverse64,
  633. #endif
  634. };
  635. const endian_func_t * GetEndianFunc ( const void * byte_order_mark )
  636. {
  637. DASSERT(byte_order_mark);
  638. const u8 * bom = byte_order_mark;
  639. return bom[0] == 0xfe && bom[1] == 0xff
  640. ? &be_func
  641. : bom[0] == 0xff && bom[1] == 0xfe
  642. ? &le_func
  643. : 0;
  644. }
  645. ///////////////////////////////////////////////////////////////////////////////
  646. uint GetTextBOMLen ( const void * data, uint data_size )
  647. {
  648. static const u8 be_bom[] = { 0xef, 0xbb, 0xbf };
  649. static const u8 le_bom[] = { 0xef, 0xbf, 0xbe };
  650. if ( data_size >= 3 && ( !memcmp(data,be_bom,3) || !memcmp(data,le_bom,3) ))
  651. return 3;
  652. if ( data_size >= 2 && ( *(u16*)data == 0xfeff || *(u16*)data == 0xfffe ))
  653. return 2;
  654. return 0;
  655. }
  656. //
  657. ///////////////////////////////////////////////////////////////////////////////
  658. /////////////// check index ///////////////
  659. ///////////////////////////////////////////////////////////////////////////////
  660. int CheckIndex1 ( int max, int index )
  661. {
  662. DASSERT( max >= 0 );
  663. if ( index >= 0 )
  664. return index <= max ? index : max;
  665. index += max;
  666. return index >= 0 ? index : 0;
  667. }
  668. ///////////////////////////////////////////////////////////////////////////////
  669. int CheckIndex1End ( int max, int index )
  670. {
  671. DASSERT( max >= 0 );
  672. if ( index > 0 )
  673. return index <= max ? index : max;
  674. index += max;
  675. return index >= 0 ? index : 0;
  676. }
  677. ///////////////////////////////////////////////////////////////////////////////
  678. int CheckIndex2 ( int max, int * p_begin, int * p_end )
  679. {
  680. DASSERT( max >= 0 );
  681. DASSERT(p_begin);
  682. DASSERT(p_end);
  683. int begin = *p_begin;
  684. if ( begin < 0 )
  685. {
  686. begin += max;
  687. if ( begin < 0 )
  688. begin = 0;
  689. }
  690. else if ( begin > max )
  691. begin = max;
  692. int end = *p_end;
  693. if ( end < 0 )
  694. {
  695. end += max;
  696. // don't check for 'end<0' here, because 'end<begin' is checked later
  697. }
  698. else if ( end > max )
  699. end = max;
  700. if ( end < begin )
  701. end = begin;
  702. *p_begin = begin;
  703. *p_end = end;
  704. return end - begin;
  705. }
  706. ///////////////////////////////////////////////////////////////////////////////
  707. int CheckIndex2End ( int max, int * p_begin, int * p_end )
  708. {
  709. DASSERT( max >= 0 );
  710. DASSERT(p_begin);
  711. DASSERT(p_end);
  712. int begin = *p_begin;
  713. if ( begin <= 0 )
  714. {
  715. begin += max;
  716. if ( begin < 0 )
  717. begin = 0;
  718. }
  719. else if ( begin > max )
  720. begin = max;
  721. int end = *p_end;
  722. if ( end <= 0 )
  723. {
  724. end += max;
  725. // don't check for 'end<0' here, because 'end<begin' is checked later
  726. }
  727. else if ( end > max )
  728. end = max;
  729. if ( end < begin )
  730. end = begin;
  731. *p_begin = begin;
  732. *p_end = end;
  733. return end - begin;
  734. }
  735. ///////////////////////////////////////////////////////////////////////////////
  736. int CheckIndexC ( int max, int * p_begin, int count )
  737. {
  738. DASSERT( max >= 0 );
  739. DASSERT(p_begin);
  740. int begin = *p_begin, end = begin + count;
  741. if ( begin < 0 )
  742. {
  743. begin += max;
  744. end = begin + count;
  745. if ( begin < 0 )
  746. begin = 0;
  747. }
  748. else if ( begin > max )
  749. begin = max;
  750. if ( end < 0 )
  751. end = 0;
  752. else if ( end > max )
  753. end = max;
  754. if ( end < begin )
  755. {
  756. *p_begin = end;
  757. return begin-end;
  758. }
  759. *p_begin = begin;
  760. return end - begin;
  761. }
  762. ///////////////////////////////////////////////////////////////////////////////
  763. int CheckIndexCEnd ( int max, int * p_begin, int count )
  764. {
  765. DASSERT( max >= 0 );
  766. DASSERT(p_begin);
  767. int begin = *p_begin, end = begin + count;
  768. if ( begin <= 0 )
  769. {
  770. begin += max;
  771. end = begin + count;
  772. if ( begin < 0 )
  773. begin = 0;
  774. }
  775. else if ( begin > max )
  776. begin = max;
  777. if ( end < 0 )
  778. end = 0;
  779. else if ( end > max )
  780. end = max;
  781. if ( end < begin )
  782. {
  783. *p_begin = end;
  784. return begin-end;
  785. }
  786. *p_begin = begin;
  787. return end - begin;
  788. }
  789. //
  790. ///////////////////////////////////////////////////////////////////////////////
  791. /////////////// lt/eq/gt ///////////////
  792. ///////////////////////////////////////////////////////////////////////////////
  793. char * ScanCompareOp ( compare_operator_t *dest_op, ccp arg )
  794. {
  795. compare_operator_t op = COP_FALSE;
  796. ccp ptr = arg;
  797. if (ptr)
  798. {
  799. while ( *ptr > 0 && *ptr <= ' ' )
  800. ptr++;
  801. if ( (uchar)ptr[0] == 0xe2 && (uchar)ptr[1] == 0x89 )
  802. {
  803. switch ((uchar)ptr[2])
  804. {
  805. case 0xa0: op = COP_NE; ptr += 3; break; // UTF8 ≠
  806. case 0xa4: op = COP_LE; ptr += 3; break; // UTF8 ≤
  807. case 0xa5: op = COP_GE; ptr += 3; break; // UTF8 ≥
  808. }
  809. }
  810. else if ( *ptr == '!' )
  811. {
  812. if ( *++ptr == '=' )
  813. {
  814. op = COP_NE;
  815. ptr++;
  816. }
  817. }
  818. else
  819. switch (*ptr)
  820. {
  821. case '=':
  822. op = COP_EQ;
  823. if ( *++ptr == '=' )
  824. ptr++;
  825. break;
  826. case '<':
  827. op = COP_LT;
  828. switch (*++ptr)
  829. {
  830. case '=':
  831. op = COP_LE;
  832. ptr++;
  833. break;
  834. case '>':
  835. op = COP_NE;
  836. ptr++;
  837. break;
  838. }
  839. break;
  840. case '>':
  841. op = COP_GT;
  842. if ( *++ptr == '=' )
  843. {
  844. op = COP_GE;
  845. ptr++;
  846. }
  847. break;
  848. }
  849. }
  850. if (dest_op)
  851. *dest_op = op;
  852. return op == COP_FALSE ? (char*)arg : (char*)ptr;
  853. }
  854. ///////////////////////////////////////////////////////////////////////////////
  855. ccp GetCompareOpName ( compare_operator_t op )
  856. {
  857. switch (op)
  858. {
  859. case COP_EQ: return "==";
  860. case COP_LT: return "<";
  861. case COP_GT: return ">";
  862. case COP_NE: return "!=";
  863. case COP_LE: return "<=";
  864. case COP_GE: return ">=";
  865. case COP_TRUE: return "*";
  866. default: return "%";
  867. }
  868. }
  869. ///////////////////////////////////////////////////////////////////////////////
  870. bool CompareByOpStat ( int stat, compare_operator_t op )
  871. {
  872. switch (op)
  873. {
  874. case COP_EQ: return stat == 0;
  875. case COP_LT: return stat < 0;
  876. case COP_GT: return stat > 0;
  877. case COP_NE: return stat != 0;
  878. case COP_LE: return stat <= 0;
  879. case COP_GE: return stat >= 0;
  880. case COP_TRUE: return true;
  881. default: return false;
  882. }
  883. }
  884. ///////////////////////////////////////////////////////////////////////////////
  885. bool CompareByOpINT ( int a, compare_operator_t op, int b )
  886. {
  887. switch (op)
  888. {
  889. case COP_EQ: return a == b;
  890. case COP_LT: return a < b;
  891. case COP_GT: return a > b;
  892. case COP_NE: return a != b;
  893. case COP_LE: return a <= b;
  894. case COP_GE: return a >= b;
  895. case COP_TRUE: return true;
  896. default: return false;
  897. }
  898. }
  899. ///////////////////////////////////////////////////////////////////////////////
  900. bool CompareByOpUINT ( uint a, compare_operator_t op, uint b )
  901. {
  902. switch (op)
  903. {
  904. case COP_EQ: return a == b;
  905. case COP_LT: return a < b;
  906. case COP_GT: return a > b;
  907. case COP_NE: return a != b;
  908. case COP_LE: return a <= b;
  909. case COP_GE: return a >= b;
  910. case COP_TRUE: return true;
  911. default: return false;
  912. }
  913. }
  914. ///////////////////////////////////////////////////////////////////////////////
  915. bool CompareByOpI64 ( s64 a, compare_operator_t op, s64 b )
  916. {
  917. switch (op)
  918. {
  919. case COP_EQ: return a == b;
  920. case COP_LT: return a < b;
  921. case COP_GT: return a > b;
  922. case COP_NE: return a != b;
  923. case COP_LE: return a <= b;
  924. case COP_GE: return a >= b;
  925. case COP_TRUE: return true;
  926. default: return false;
  927. }
  928. }
  929. ///////////////////////////////////////////////////////////////////////////////
  930. bool CompareByOpU64 ( u64 a, compare_operator_t op, u64 b )
  931. {
  932. switch (op)
  933. {
  934. case COP_EQ: return a == b;
  935. case COP_LT: return a < b;
  936. case COP_GT: return a > b;
  937. case COP_NE: return a != b;
  938. case COP_LE: return a <= b;
  939. case COP_GE: return a >= b;
  940. case COP_TRUE: return true;
  941. default: return false;
  942. }
  943. }
  944. ///////////////////////////////////////////////////////////////////////////////
  945. bool CompareByOpFLT ( float a, compare_operator_t op, float b )
  946. {
  947. switch (op)
  948. {
  949. case COP_EQ: return a == b;
  950. case COP_LT: return a < b;
  951. case COP_GT: return a > b;
  952. case COP_NE: return a != b;
  953. case COP_LE: return a <= b;
  954. case COP_GE: return a >= b;
  955. case COP_TRUE: return true;
  956. default: return false;
  957. }
  958. }
  959. ///////////////////////////////////////////////////////////////////////////////
  960. bool CompareByOpDBL ( double a, compare_operator_t op, double b )
  961. {
  962. switch (op)
  963. {
  964. case COP_EQ: return a == b;
  965. case COP_LT: return a < b;
  966. case COP_GT: return a > b;
  967. case COP_NE: return a != b;
  968. case COP_LE: return a <= b;
  969. case COP_GE: return a >= b;
  970. case COP_TRUE: return true;
  971. default: return false;
  972. }
  973. }
  974. //
  975. ///////////////////////////////////////////////////////////////////////////////
  976. /////////////// encoding/decoding ///////////////
  977. ///////////////////////////////////////////////////////////////////////////////
  978. ccp GetEncodingName ( EncodeMode_t em )
  979. {
  980. static const char tab[][7] =
  981. {
  982. "OFF",
  983. "ANSI",
  984. "UTF8",
  985. "BASE64",
  986. "URL64",
  987. "STAR64",
  988. "XML64",
  989. "JSON",
  990. };
  991. return (uint)em < sizeof(tab)/sizeof(*tab) ? tab[em] : PrintCircBuf("%d",em);
  992. }
  993. ///////////////////////////////////////////////////////////////////////////////
  994. uint GetEscapeLen
  995. (
  996. // returns the extra size needed for escapes.
  997. // Add 'src_len' to get the escaped string size.
  998. // Add 'additionally 4 to get a good buffer size.
  999. ccp source, // NULL or string to print
  1000. int src_len, // length of string. if -1, str is null terminated
  1001. CharMode_t char_mode, // modes, bit field (CHMD_*)
  1002. char quote // NULL or quotation char, that must be quoted
  1003. )
  1004. {
  1005. const CharMode_t utf8 = char_mode & CHMD_UTF8;
  1006. const int esc_size = char_mode & CHMD_ESC ? 1 : 3;
  1007. const int pipe_size = char_mode & CHMD_PIPE ? 1 : 0;
  1008. if ( !source || !*source )
  1009. return 0;
  1010. ccp str = source;
  1011. ccp end = src_len < 0 ? 0 : str + src_len;
  1012. uint size = 0;
  1013. while ( !end || str < end )
  1014. {
  1015. const u8 ch = (u8)*str++;
  1016. switch (ch)
  1017. {
  1018. case 0:
  1019. if (!end)
  1020. return size;
  1021. size += 3;
  1022. break;
  1023. case '\\':
  1024. case '\a':
  1025. case '\b':
  1026. case '\f':
  1027. case '\n':
  1028. case '\r':
  1029. case '\t':
  1030. case '\v':
  1031. size++;
  1032. break;
  1033. case '\033':
  1034. size += esc_size;
  1035. break;
  1036. case '|':
  1037. size += pipe_size;
  1038. break;
  1039. default:
  1040. if ( ch == quote )
  1041. size++;
  1042. else if ( ch < ' ' || !utf8 && (ch&0x7f) < ' ' || (ch&0x7f) == 0x7f )
  1043. size += 3;
  1044. }
  1045. }
  1046. return size;
  1047. }
  1048. ///////////////////////////////////////////////////////////////////////////////
  1049. char * PrintEscapedString
  1050. (
  1051. // returns 'buf'
  1052. char *buf, // valid destination buffer
  1053. uint buf_size, // size of 'buf', >= 10
  1054. ccp source, // NULL or string to print
  1055. int len, // length of string. if -1, str is null terminated
  1056. CharMode_t char_mode, // modes, bit field (CHMD_*)
  1057. char quote, // NULL or quotation char, that must be quoted
  1058. uint *dest_len // not NULL: Store length of result here
  1059. )
  1060. {
  1061. ///////////////////////////////////////////////////////
  1062. ///// Update GetEscapeLen() on modifications!! /////
  1063. ///////////////////////////////////////////////////////
  1064. DASSERT(buf);
  1065. DASSERT(buf_size>=10);
  1066. const CharMode_t utf8 = char_mode & CHMD_UTF8;
  1067. const CharMode_t allow_e = char_mode & CHMD_ESC;
  1068. const CharMode_t esc_pipe = char_mode & CHMD_PIPE;
  1069. char *dest = buf;
  1070. char *dest_end = dest + buf_size - 4;
  1071. if (!source)
  1072. source = "";
  1073. ccp str = source;
  1074. ccp end = len < 0 ? 0 : str + len;
  1075. while ( dest < dest_end && ( !end || str < end ) )
  1076. {
  1077. const u8 ch = (u8)*str++;
  1078. switch (ch)
  1079. {
  1080. case 0:
  1081. if (!end)
  1082. {
  1083. str--;
  1084. goto eos;
  1085. }
  1086. *dest++ = '\\';
  1087. *dest++ = 'x';
  1088. *dest++ = '0';
  1089. *dest++ = '0';
  1090. break;
  1091. case '\\': *dest++ = '\\'; *dest++ = '\\'; break;
  1092. case '\a': *dest++ = '\\'; *dest++ = 'a'; break;
  1093. case '\b': *dest++ = '\\'; *dest++ = 'b'; break;
  1094. case '\f': *dest++ = '\\'; *dest++ = 'f'; break;
  1095. case '\n': *dest++ = '\\'; *dest++ = 'n'; break;
  1096. case '\r': *dest++ = '\\'; *dest++ = 'r'; break;
  1097. case '\t': *dest++ = '\\'; *dest++ = 't'; break;
  1098. case '\v': *dest++ = '\\'; *dest++ = 'v'; break;
  1099. case '\033':
  1100. *dest++ = '\\';
  1101. if (allow_e)
  1102. *dest++ = 'e';
  1103. else
  1104. {
  1105. *dest++ = 'x';
  1106. *dest++ = '1';
  1107. *dest++ = 'B';
  1108. }
  1109. break;
  1110. case '|':
  1111. if (esc_pipe)
  1112. {
  1113. *dest++ = '\\';
  1114. *dest++ = '!';
  1115. }
  1116. else
  1117. *dest++ = '|';
  1118. break;
  1119. default:
  1120. if ( ch == quote )
  1121. {
  1122. *dest++ = '\\';
  1123. *dest++ = quote;
  1124. }
  1125. else if ( ch < ' ' || !utf8 && (ch&0x7f) < ' ' || (ch&0x7f) == 0x7f )
  1126. {
  1127. *dest++ = '\\';
  1128. *dest++ = 'x';
  1129. *dest++ = HiDigits[ch>>4];
  1130. *dest++ = HiDigits[ch&15];
  1131. }
  1132. else
  1133. *dest++ = ch;
  1134. }
  1135. }
  1136. eos:
  1137. *dest = 0;
  1138. if (dest_len)
  1139. *dest_len = dest - buf;
  1140. return buf;
  1141. }
  1142. ///////////////////////////////////////////////////////////////////////////////
  1143. uint ScanEscapedString
  1144. (
  1145. // returns the number of valid bytes in 'buf' (NULL term added but not counted)
  1146. char *buf, // valid destination buffer, maybe source
  1147. uint buf_size, // size of 'buf'
  1148. ccp source, // string to scan
  1149. int len, // length of string. if -1, str is null terminated
  1150. bool utf8, // true: source and output is UTF-8
  1151. int quote, // -1:auto, 0:none, >0: quotation char
  1152. uint *scanned_len // not NULL: Store number of scanned 'source' bytes here
  1153. )
  1154. {
  1155. DASSERT(buf);
  1156. DASSERT(buf_size>3);
  1157. DASSERT(source);
  1158. char *dest = buf;
  1159. char *dest_end = dest + buf_size - ( utf8 ? 4 : 1 );
  1160. ccp src = source;
  1161. ccp src_end = src + ( len < 0 ? strlen(src) : len );
  1162. bool have_quote = quote > 0;
  1163. if ( quote == -1 && src < src_end && ( *src == '"' || *src == '\'' ))
  1164. {
  1165. quote = *src++;
  1166. have_quote = true;
  1167. }
  1168. else if ( have_quote && *src == quote )
  1169. src++;
  1170. while ( dest < dest_end && src < src_end )
  1171. {
  1172. uint code;
  1173. if ( *src == '\\' )
  1174. src = ScanEscape(&code,src+1,src_end);
  1175. else
  1176. {
  1177. if (utf8)
  1178. code = ScanUTF8AnsiCharE(&src,src_end);
  1179. else
  1180. code = *src++;
  1181. if ( code == quote && have_quote )
  1182. break;
  1183. }
  1184. if (utf8)
  1185. dest = PrintUTF8Char(dest,code);
  1186. else
  1187. *dest++ = code;
  1188. }
  1189. if (scanned_len)
  1190. *scanned_len = src - source;
  1191. *dest = 0;
  1192. return dest - buf;
  1193. }
  1194. ///////////////////////////////////////////////////////////////////////////////
  1195. ///////////////////////////////////////////////////////////////////////////////
  1196. u32 CalcCRC32 ( u32 crc, cvp buf, uint size )
  1197. {
  1198. #if HAVE_PRINT0
  1199. static bool done = false;
  1200. if ( !done && TRACE_FILE )
  1201. {
  1202. done = true;
  1203. fprintf(TRACE_FILE,"\nstatic const u32 TableCRC32[0x100] =\n{\n");
  1204. uint i;
  1205. for ( i = 0; i < 0x100; i += 8 )
  1206. fprintf(TRACE_FILE," %#010x,%#010x,%#010x,%#010x, %#010x,%#010x,%#010x,%#010x,\n",
  1207. TableCRC32[i+0],
  1208. TableCRC32[i+1],
  1209. TableCRC32[i+2],
  1210. TableCRC32[i+3],
  1211. TableCRC32[i+4],
  1212. TableCRC32[i+5],
  1213. TableCRC32[i+6],
  1214. TableCRC32[i+7] );
  1215. fprintf(TRACE_FILE,"};\n");
  1216. }
  1217. #endif
  1218. crc = ~crc;
  1219. const u8 *p = buf;
  1220. while ( size-- )
  1221. crc = TableCRC32[ (crc ^ *p++) & 0xff ] ^ crc >> 8;
  1222. return ~crc;
  1223. }
  1224. ///////////////////////////////////////////////////////////////////////////////
  1225. ///////////////////////////////////////////////////////////////////////////////
  1226. u64 DecodeU64
  1227. (
  1228. ccp source, // string to decode
  1229. int len, // length of string. if -1, str is null terminated
  1230. uint base, // number of possible digits (2..36):
  1231. uint *scanned_len // not NULL: Store number of scanned 'str' bytes here
  1232. )
  1233. {
  1234. DASSERT(source);
  1235. DASSERT( base <= 36 );
  1236. u64 num = 0;
  1237. ccp src = source;
  1238. ccp end = len < 0 ? 0 : src + len;
  1239. while ( !end || src < end )
  1240. {
  1241. u8 digit = TableNumbers[(u8)*src];
  1242. if ( digit >= base )
  1243. break;
  1244. num = num * base + digit;
  1245. src++;
  1246. }
  1247. if (scanned_len)
  1248. *scanned_len = src - source;
  1249. return num;
  1250. }
  1251. ///////////////////////////////////////////////////////////////////////////////
  1252. ccp EncodeU64
  1253. (
  1254. char * buf, // result buffer (size depends on base)
  1255. // If NULL, a local circulary static buffer is used
  1256. size_t buf_size, // size of 'buf', ignored if buf==NULL
  1257. u64 num, // number to encaode
  1258. uint base // number of possible digits (2..64):
  1259. )
  1260. {
  1261. DASSERT( base >= 2 );
  1262. DASSERT( base <= 64 );
  1263. if ( base < 2 )
  1264. base = 2;
  1265. else if ( base > 64 )
  1266. base = 64;
  1267. char digits[65], *dest = digits + sizeof(digits);
  1268. *--dest = 0;
  1269. while ( num )
  1270. {
  1271. *--dest = LoDigits[ num % base ];
  1272. num /= base;
  1273. }
  1274. if (!buf)
  1275. buf = GetCircBuf ( buf_size = digits + sizeof(digits)-1 - dest );
  1276. StringCopyS(buf,buf_size,dest);
  1277. return buf;
  1278. }
  1279. ///////////////////////////////////////////////////////////////////////////////
  1280. ///////////////////////////////////////////////////////////////////////////////
  1281. // Default tables for DecodeBase64() and EncodeBase64(), if no table is defined.
  1282. ccp TableDecode64default = TableDecode64;
  1283. ccp TableEncode64default = TableEncode64;
  1284. ///////////////////////////////////////////////////////////////////////////////
  1285. uint DecodeBase64
  1286. (
  1287. // returns the number of valid bytes in 'buf'
  1288. char *buf, // valid destination buffer
  1289. uint buf_size, // size of 'buf', >= 3
  1290. ccp source, // NULL or string to decode
  1291. int len, // length of string. if -1, str is null terminated
  1292. const char decode64[256], // decoding table; if NULL: use TableDecode64default
  1293. bool allow_white_spaces, // true: skip white spaces
  1294. uint *scanned_len // not NULL: Store number of scanned 'str' bytes here
  1295. )
  1296. {
  1297. DASSERT(buf);
  1298. DASSERT(buf_size>=3);
  1299. u8 *dest = (u8*)buf;
  1300. u8 *dest_end = dest + ( scanned_len ? buf_size / 3 * 3 : buf_size );
  1301. if (!source)
  1302. source = "";
  1303. ccp src = source;
  1304. ccp end = src + ( len < 0 ? strlen(src) : len );
  1305. int ch1, ch2;
  1306. if (!decode64)
  1307. decode64 = TableDecode64default;
  1308. while ( dest < dest_end && src < end )
  1309. {
  1310. ch1 = decode64[(u8)*src++];
  1311. if (allow_white_spaces)
  1312. while ( ch1 == DECODE_SPACE && src < end )
  1313. ch1 = decode64[(u8)*src++];
  1314. if ( ch1 < 0 )
  1315. {
  1316. src--;
  1317. break;
  1318. }
  1319. if ( src == end )
  1320. break;
  1321. ch2 = decode64[(u8)*src++];
  1322. if (allow_white_spaces)
  1323. while ( ch2 == DECODE_SPACE && src < end )
  1324. ch2 = decode64[(u8)*src++];
  1325. if ( ch2 < 0 )
  1326. {
  1327. src--;
  1328. break;
  1329. }
  1330. *dest++ = ch1 << 2 | ch2 >> 4;
  1331. if ( src == end || dest == dest_end )
  1332. break;
  1333. ch1 = decode64[(u8)*src++];
  1334. if (allow_white_spaces)
  1335. while ( ch1 == DECODE_SPACE && src < end )
  1336. ch1 = decode64[(u8)*src++];
  1337. if ( ch1 < 0 )
  1338. {
  1339. src--;
  1340. break;
  1341. }
  1342. *dest++ = ch2 << 4 | ch1 >> 2;
  1343. if ( src == end || dest == dest_end )
  1344. break;
  1345. ch2 = decode64[(u8)*src++];
  1346. if (allow_white_spaces)
  1347. while ( ch2 == DECODE_SPACE && src < end )
  1348. ch2 = decode64[(u8)*src++];
  1349. if ( ch2 < 0 )
  1350. {
  1351. src--;
  1352. break;
  1353. }
  1354. *dest++ = ch1 << 6 | ch2;
  1355. }
  1356. if (scanned_len)
  1357. {
  1358. while ( src < end && decode64[(u8)*src] == DECODE_FILLER )
  1359. src++;
  1360. *scanned_len = src - source;
  1361. }
  1362. return dest - (u8*)buf;
  1363. }
  1364. ///////////////////////////////////////////////////////////////////////////////
  1365. mem_t DecodeBase64Circ
  1366. (
  1367. // Returns a buffer alloced by GetCircBuf()
  1368. // with valid pointer and null terminated.
  1369. // If result is too large (>CIRC_BUF_MAX_ALLOC) then (0,0) is returned.
  1370. ccp source, // NULL or string to decode
  1371. int len, // length of string. if -1, str is null terminated
  1372. const char decode64[256] // decoding table; if NULL: use TableDecode64default
  1373. )
  1374. {
  1375. char buf[CIRC_BUF_MAX_ALLOC+10];
  1376. mem_t mem;
  1377. mem.len = DecodeBase64(buf,sizeof(buf),source,len,decode64,false,0);
  1378. if ( mem.len < CIRC_BUF_MAX_ALLOC )
  1379. mem.ptr = CopyCircBuf0(buf,mem.len);
  1380. else
  1381. {
  1382. mem.ptr = 0;
  1383. mem.len = 0;
  1384. }
  1385. return mem;
  1386. }
  1387. ///////////////////////////////////////////////////////////////////////////////
  1388. ///////////////////////////////////////////////////////////////////////////////
  1389. uint EncodeBase64
  1390. (
  1391. // returns the number of scanned bytes of 'source'
  1392. char *buf, // valid destination buffer
  1393. uint buf_size, // size of 'buf' >= 4
  1394. const void *source, // NULL or data to encode
  1395. int source_len, // length of 'source'; if <0: use strlen(source)
  1396. const char encode64[64+1], // encoding table; if NULL: use TableEncode64default
  1397. bool use_filler, // use filler for aligned output
  1398. ccp next_line, // not NULL: use this string as new line sep
  1399. uint bytes_per_line // >0: use 'next_line' every # input bytes
  1400. // will be rounded down to multiple of 3
  1401. )
  1402. {
  1403. DASSERT(buf);
  1404. DASSERT(buf_size>3);
  1405. DASSERT(source||!source_len);
  1406. noPRINT("EncodeBase64(sz=%u,len=%d,fil=%d)\n",buf_size,source_len,use_filler);
  1407. if (!next_line)
  1408. bytes_per_line = ~0;
  1409. else if (!bytes_per_line)
  1410. bytes_per_line = 19;
  1411. else
  1412. bytes_per_line /= 3;
  1413. char *dest = buf;
  1414. char *dest_end = buf + buf_size - 4;
  1415. if (!source)
  1416. source = "";
  1417. const u8 *src = source;
  1418. const u8 *src_end = src + ( source_len < 0 ? strlen(source) : source_len );
  1419. if (!encode64)
  1420. encode64 = TableEncode64default;
  1421. uint n_tupel = 0;
  1422. while ( src < src_end && dest < dest_end )
  1423. {
  1424. if ( ++n_tupel > bytes_per_line && next_line )
  1425. {
  1426. char *next = StringCopyE(dest,(char*)buf+buf_size,next_line);
  1427. if ( next >= dest_end )
  1428. break;
  1429. dest = next;
  1430. n_tupel = 1;
  1431. }
  1432. //----- start: no pending bits
  1433. u8 ch1 = *src++;
  1434. *dest++ = encode64 [ ch1 >> 2 ];
  1435. ch1 &= 0x03;
  1436. DASSERT( (ch1 & ~0x03) == 0 );
  1437. if ( src == src_end )
  1438. {
  1439. *dest++ = encode64[ch1<<4];
  1440. if (use_filler)
  1441. {
  1442. *dest++ = encode64[64];
  1443. *dest++ = encode64[64];
  1444. }
  1445. break;
  1446. }
  1447. //----- 2 pending bits in 'ch1'
  1448. u8 ch2 = *src++;
  1449. *dest++ = encode64 [ ch1 << 4 | ch2 >> 4 ];
  1450. ch2 &= 0x0f;
  1451. DASSERT( (ch2 & ~0x0f) == 0 );
  1452. if ( src == src_end )
  1453. {
  1454. *dest++ = encode64[ch2<<2];
  1455. if (use_filler)
  1456. *dest++ = encode64[64];
  1457. break;
  1458. }
  1459. //----- 4 pending bits in 'ch2'
  1460. ch1 = *src++;
  1461. *dest++ = encode64 [ ch2 << 2 | ch1 >> 6 ];
  1462. //----- 6 pending bits in 'ch1'
  1463. *dest++ = encode64[ch1&0x3f];
  1464. }
  1465. *dest = 0;
  1466. return src - (const u8*)source;
  1467. }
  1468. ///////////////////////////////////////////////////////////////////////////////
  1469. mem_t EncodeBase64Circ
  1470. (
  1471. // Returns a buffer alloced by GetCircBuf()
  1472. // with valid pointer and null terminated.
  1473. // If result is too large (>CIRC_BUF_MAX_ALLOC) then (0,0) is returned.
  1474. const void *source, // NULL or data to encode
  1475. int source_len, // length of 'source'; if <0: use strlen(source)
  1476. const char encode64[64+1] // encoding table; if NULL: use TableEncode64default
  1477. )
  1478. {
  1479. char buf[CIRC_BUF_MAX_ALLOC+10];
  1480. EncodeBase64(buf,sizeof(buf),source,source_len,encode64,false,0,0);
  1481. mem_t mem;
  1482. mem.len = strlen(buf);
  1483. if ( mem.len < CIRC_BUF_MAX_ALLOC )
  1484. mem.ptr = CopyCircBuf(buf,mem.len+1);
  1485. else
  1486. {
  1487. mem.ptr = 0;
  1488. mem.len = 0;
  1489. }
  1490. return mem;
  1491. }
  1492. ///////////////////////////////////////////////////////////////////////////////
  1493. uint EncodeBase64ml // ml: multi line
  1494. (
  1495. // returns the number of scanned bytes of 'source'
  1496. char *buf, // valid destination buffer
  1497. uint buf_size, // size of 'buf' >= 4
  1498. const void *source, // NULL or data to encode
  1499. int source_len, // length of 'source'; if <0: use strlen(source)
  1500. const char encode64[64+1], // encoding table; if NULL: use TableEncode64default
  1501. bool use_filler, // use filler for aligned output
  1502. int indent, // indention of output
  1503. ccp prefix, // NULL or prefix before encoded data
  1504. ccp eol, // line terminator, if NULL then use NL
  1505. int bytes_per_line // create a new line every # input bytes
  1506. // will be rounded down to multiple of 3
  1507. )
  1508. {
  1509. indent = NormalizeIndent(indent);
  1510. if (!eol)
  1511. eol = "\n";
  1512. char linesep[200];
  1513. int pre_pos;
  1514. snprintf(linesep,sizeof(linesep),"%s%n%*s%s",
  1515. eol,
  1516. &pre_pos,
  1517. indent, "",
  1518. prefix ? prefix : ""
  1519. );
  1520. char *end = buf + buf_size;
  1521. char *dest = StringCopyE(buf,end,linesep+pre_pos);
  1522. const uint scanned = EncodeBase64( dest, end-dest, source, source_len,
  1523. encode64, use_filler, linesep, bytes_per_line );
  1524. dest = buf + strlen(buf);
  1525. StringCopyE(dest,end,eol);
  1526. return scanned;
  1527. }
  1528. ///////////////////////////////////////////////////////////////////////////////
  1529. ///////////////////////////////////////////////////////////////////////////////
  1530. uint EncodeJSON
  1531. (
  1532. // returns the number of valid bytes in 'buf'. Result is NULL-terminated.
  1533. char *buf, // valid destination buffer
  1534. uint buf_size, // size of 'buf', >2 and 2 bytes longer than needed
  1535. const void *source, // NULL or data to encode
  1536. int source_len // length of 'source'; if <0: use strlen(source)
  1537. )
  1538. {
  1539. DASSERT(buf);
  1540. DASSERT(buf_size>2);
  1541. char *dest = buf;
  1542. char *dest_end = dest + buf_size - 2;
  1543. if (!source)
  1544. source = "";
  1545. ccp str = source;
  1546. ccp end = str + ( source_len < 0 ? strlen(str) : source_len );
  1547. while ( dest < dest_end && str < end )
  1548. {
  1549. const u8 ch = (u8)*str++;
  1550. switch (ch)
  1551. {
  1552. case '"': *dest++ = '\\'; *dest++ = '"'; break;
  1553. case '\\': *dest++ = '\\'; *dest++ = '\\'; break;
  1554. case '\b': *dest++ = '\\'; *dest++ = 'b'; break;
  1555. case '\f': *dest++ = '\\'; *dest++ = 'f'; break;
  1556. case '\n': *dest++ = '\\'; *dest++ = 'n'; break;
  1557. case '\r': *dest++ = '\\'; *dest++ = 'r'; break;
  1558. case '\t': *dest++ = '\\'; *dest++ = 't'; break;
  1559. default:
  1560. if ( ch >= ' ' )
  1561. *dest++ = ch;
  1562. else if ( dest + 5 > dest_end )
  1563. goto eos;
  1564. else
  1565. {
  1566. *dest++ = '\\';
  1567. *dest++ = 'u';
  1568. *dest++ = '0';
  1569. *dest++ = '0';
  1570. *dest++ = HiDigits[ch>>4];
  1571. *dest++ = HiDigits[ch&15];
  1572. }
  1573. break;
  1574. }
  1575. }
  1576. eos:
  1577. *dest = 0;
  1578. return dest - buf;
  1579. }
  1580. //-----------------------------------------------------------------------------
  1581. mem_t EncodeJSONCirc
  1582. (
  1583. // Returns a buffer alloced by GetCircBuf()
  1584. // with valid pointer and null terminated.
  1585. // If result is too large (>CIRC_BUF_MAX_ALLOC) then (0,0) is returned.
  1586. const void *source, // NULL or data to encode
  1587. int source_len // length of 'source'; if <0: use strlen(source)
  1588. )
  1589. {
  1590. char buf[CIRC_BUF_MAX_ALLOC+10];
  1591. mem_t mem;
  1592. mem.len = EncodeJSON(buf,sizeof(buf),source,source_len);
  1593. if ( mem.len < CIRC_BUF_MAX_ALLOC )
  1594. mem.ptr = CopyCircBuf(buf,mem.len+1);
  1595. else
  1596. {
  1597. mem.ptr = 0;
  1598. mem.len = 0;
  1599. }
  1600. return mem;
  1601. }
  1602. //-----------------------------------------------------------------------------
  1603. mem_t QuoteJSONCirc
  1604. (
  1605. // Returns a buffer alloced by GetCircBuf()
  1606. // with valid pointer and null terminated.
  1607. // If result is too large (>CIRC_BUF_MAX_ALLOC) then (0,0) is returned.
  1608. const void *source, // NULL or data to encode
  1609. int source_len, // length of 'source'; if <0: use strlen(source)
  1610. int null_if // return 'null' without quotes ...
  1611. // <=0: never
  1612. // >=1: if source == NULL
  1613. // >=2: if source_len == 0
  1614. )
  1615. {
  1616. if ( source_len < 0 )
  1617. source_len = source ? strlen(source) : 0;
  1618. mem_t mem;
  1619. if ( null_if > 0 && !source || null_if > 1 && !source_len )
  1620. {
  1621. mem.ptr = "null";
  1622. mem.len = 4;
  1623. }
  1624. else
  1625. {
  1626. char buf[CIRC_BUF_MAX_ALLOC+10];
  1627. mem.len = EncodeJSON(buf+1,sizeof(buf)-2,source,source_len) + 2;
  1628. if ( mem.len < CIRC_BUF_MAX_ALLOC - 2 )
  1629. {
  1630. buf[0] = buf[mem.len-1] = '"';
  1631. buf[mem.len] = 0;
  1632. mem.ptr = CopyCircBuf(buf,mem.len+1);
  1633. }
  1634. else
  1635. {
  1636. mem.ptr = 0;
  1637. mem.len = 0;
  1638. }
  1639. }
  1640. return mem;
  1641. }
  1642. //-----------------------------------------------------------------------------
  1643. mem_t DecodeJSONCirc
  1644. (
  1645. // Returns a buffer alloced by GetCircBuf()
  1646. // with valid pointer and null terminated.
  1647. // If result is too large (>CIRC_BUF_MAX_ALLOC) then (0,0) is returned.
  1648. ccp source, // NULL or string to decode
  1649. int source_len, // length of 'source'. If -1, str is NULL terminated
  1650. int quote // -1:auto, 0:none, >0: quotation char
  1651. )
  1652. {
  1653. char buf[CIRC_BUF_MAX_ALLOC+10];
  1654. mem_t mem;
  1655. mem.len = DecodeJSON(buf,sizeof(buf),source,source_len,quote,0);
  1656. if ( mem.len < CIRC_BUF_MAX_ALLOC )
  1657. mem.ptr = CopyCircBuf(buf,mem.len+1);
  1658. else
  1659. {
  1660. mem.ptr = 0;
  1661. mem.len = 0;
  1662. }
  1663. return mem;
  1664. }
  1665. ///////////////////////////////////////////////////////////////////////////////
  1666. ///////////////////////////////////////////////////////////////////////////////
  1667. // [[hex]]
  1668. uint EncodeHex
  1669. (
  1670. // returns the number of valid bytes in 'buf'. Result is NULL-terminated.
  1671. char *buf, // valid destination buffer
  1672. uint buf_size, // size of 'buf', >2 and 2 bytes longer than needed
  1673. const void *source, // NULL or data to encode
  1674. int source_len, // length of 'source'; if <0: use strlen(source)
  1675. ccp digits // digits to use, eg. LoDigits[] (=fallback) or HiDigits[]
  1676. )
  1677. {
  1678. DASSERT(buf);
  1679. DASSERT(buf_size>2);
  1680. if (!digits)
  1681. digits = LoDigits;
  1682. char *dest = buf;
  1683. char *dest_end = dest + buf_size - 1;
  1684. if (!source)
  1685. source = "";
  1686. ccp str = source;
  1687. ccp end = str + ( source_len < 0 ? strlen(str) : source_len );
  1688. while ( dest < dest_end && str < end )
  1689. {
  1690. const u8 ch = (u8)*str++;
  1691. *dest++ = digits[ch>>4];
  1692. *dest++ = digits[ch&15];
  1693. }
  1694. *dest = 0;
  1695. return dest - buf;
  1696. }
  1697. //-----------------------------------------------------------------------------
  1698. // [[hex]]
  1699. mem_t EncodeHexCirc
  1700. (
  1701. // Returns a buffer alloced by GetCircBuf()
  1702. // with valid pointer and null terminated.
  1703. // If result is too large (>CIRC_BUF_MAX_ALLOC) then (0,0) is returned.
  1704. const void *source, // NULL or data to encode
  1705. int source_len, // length of 'source'; if <0: use strlen(source)
  1706. ccp digits // digits to use, eg. LoDigits[] (=fallback) or HiDigits[]
  1707. )
  1708. {
  1709. char buf[CIRC_BUF_MAX_ALLOC+10];
  1710. mem_t mem;
  1711. mem.len = EncodeHex(buf,sizeof(buf),source,source_len,digits);
  1712. if ( mem.len < CIRC_BUF_MAX_ALLOC )
  1713. mem.ptr = CopyCircBuf(buf,mem.len+1);
  1714. else
  1715. {
  1716. mem.ptr = 0;
  1717. mem.len = 0;
  1718. }
  1719. return mem;
  1720. }
  1721. ///////////////////////////////////////////////////////////////////////////////
  1722. // [[hex]]
  1723. uint DecodeHex
  1724. (
  1725. // returns the number of valid bytes in 'buf'
  1726. char *buf, // valid destination buffer
  1727. uint buf_size, // size of 'buf', >= 3
  1728. ccp source, // NULL or string to decode
  1729. int source_len, // length of 'source'. If -1, str is NULL terminated
  1730. int quote, // -1:auto, 0:none, >0: quotation char
  1731. uint *scanned_len // not NULL: Store number of scanned 'str' bytes here
  1732. )
  1733. {
  1734. DASSERT(buf);
  1735. DASSERT(buf_size>3);
  1736. DASSERT(source);
  1737. char *dest = buf;
  1738. char *dest_end = dest + buf_size - 1;
  1739. ccp src = source;
  1740. ccp src_end = src + ( source_len < 0 ? strlen(src) : source_len );
  1741. bool have_quote = quote > 0;
  1742. if ( quote == -1 && src < src_end && ( *src == '"' || *src == '\'' ))
  1743. {
  1744. quote = *src++;
  1745. have_quote = true;
  1746. }
  1747. while ( dest < dest_end && src < src_end )
  1748. {
  1749. u8 hi = TableNumbers[(u8)*src];
  1750. if ( hi >= 16 )
  1751. break;
  1752. hi <<= 4;
  1753. u8 lo = ++src < src_end ? TableNumbers[(u8)*src] : 0;
  1754. if ( lo >= 16 )
  1755. {
  1756. *dest++ = hi;
  1757. break;
  1758. }
  1759. *dest++ = hi | lo;
  1760. src++;
  1761. }
  1762. if (scanned_len)
  1763. {
  1764. if ( have_quote && src < src_end && *src == quote )
  1765. src++;
  1766. *scanned_len = src - source;
  1767. }
  1768. *dest = 0;
  1769. return dest - buf;
  1770. }
  1771. //-----------------------------------------------------------------------------
  1772. // [[hex]]
  1773. mem_t DecodeHexCirc
  1774. (
  1775. // Returns a buffer alloced by GetCircBuf()
  1776. // with valid pointer and null terminated.
  1777. // If result is too large (>CIRC_BUF_MAX_ALLOC) then (0,0) is returned.
  1778. ccp source, // NULL or string to decode
  1779. int source_len, // length of 'source'. If -1, str is NULL terminated
  1780. int quote // -1:auto, 0:none, >0: quotation char
  1781. )
  1782. {
  1783. char buf[CIRC_BUF_MAX_ALLOC+10];
  1784. mem_t mem;
  1785. mem.len = DecodeHex(buf,sizeof(buf),source,source_len,quote,0);
  1786. if ( mem.len < CIRC_BUF_MAX_ALLOC )
  1787. mem.ptr = CopyCircBuf(buf,mem.len+1);
  1788. else
  1789. {
  1790. mem.ptr = 0;
  1791. mem.len = 0;
  1792. }
  1793. return mem;
  1794. }
  1795. ///////////////////////////////////////////////////////////////////////////////
  1796. ///////////////////////////////////////////////////////////////////////////////
  1797. uint DecodeByMode
  1798. (
  1799. // returns the number of valid bytes in 'buf'. Result is NULL-terminated.
  1800. char *buf, // valid destination buffer
  1801. uint buf_size, // size of 'buf', >= 3
  1802. ccp source, // string to decode
  1803. int slen, // length of string. if -1, str is null terminated
  1804. EncodeMode_t emode, // encoding mode
  1805. uint *scanned_len // not NULL: Store number of scanned 'str' bytes here
  1806. )
  1807. {
  1808. DASSERT(buf);
  1809. DASSERT( buf_size >= 1 );
  1810. DASSERT( source || !slen );
  1811. DASSERT( (uint)emode < ENCODE__N );
  1812. uint len = 0;
  1813. if ( buf_size < 4 )
  1814. {
  1815. char temp[4];
  1816. len = DecodeByMode(temp,sizeof(temp),source,slen,emode,scanned_len);
  1817. memcpy(buf,temp,buf_size);
  1818. goto term;
  1819. }
  1820. DASSERT( buf_size >= 3 );
  1821. switch (emode)
  1822. {
  1823. case ENCODE_STRING:
  1824. case ENCODE_PIPE:
  1825. len = ScanEscapedString(buf,buf_size,source,slen,false,-1,scanned_len);
  1826. break;
  1827. case ENCODE_UTF8:
  1828. case ENCODE_PIPE8:
  1829. len = ScanEscapedString(buf,buf_size,source,slen,true,-1,scanned_len);
  1830. break;
  1831. case ENCODE_BASE64:
  1832. len = DecodeBase64(buf,buf_size-1,source,slen,TableDecode64,true,scanned_len);
  1833. break;
  1834. case ENCODE_BASE64URL:
  1835. case ENCODE_BASE64STAR:
  1836. len = DecodeBase64(buf,buf_size-1,source,slen,TableDecode64url,true,scanned_len);
  1837. break;
  1838. case ENCODE_BASE64XML:
  1839. len = DecodeBase64(buf,buf_size-1,source,slen,TableDecode64xml,true,scanned_len);
  1840. break;
  1841. case ENCODE_JSON:
  1842. len = DecodeJSON(buf,buf_size,source,slen,-1,scanned_len);
  1843. break;
  1844. case ENCODE_HEX:
  1845. len = DecodeHex(buf,buf_size,source,slen,-1,scanned_len);
  1846. break;
  1847. default:
  1848. if ( slen < 0 )
  1849. len = StringCopyS(buf,buf_size,source) - buf;
  1850. else
  1851. len = StringCopySM(buf,buf_size,source,slen) - buf;
  1852. if (scanned_len)
  1853. *scanned_len = len;
  1854. break;
  1855. }
  1856. //--- terminate with NULL
  1857. term:;
  1858. if ( len >= buf_size )
  1859. len = buf_size - 1;
  1860. buf[len] = 0;
  1861. return len;
  1862. }
  1863. ///////////////////////////////////////////////////////////////////////////////
  1864. mem_t DecodeByModeMem
  1865. (
  1866. // Returns the decoded 'source'. Result is NULL-terminated.
  1867. // It points either to 'buf' or is alloced (on buf==NULL or too less space)
  1868. // If alloced (mem.ptr!=buf) => call FreeMem(&mem)
  1869. char *buf, // NULL or destination buffer
  1870. uint buf_size, // size of 'buf'
  1871. ccp source, // string to decode
  1872. int slen, // length of string. if -1, str is null terminated
  1873. EncodeMode_t emode, // encoding mode
  1874. uint *scanned_len // not NULL: Store number of scanned 'str' bytes here
  1875. )
  1876. {
  1877. DASSERT( source || !slen );
  1878. DASSERT( (uint)emode < ENCODE__N );
  1879. if ( slen < 0 )
  1880. slen = source ? strlen(source) : 0;
  1881. uint need;
  1882. switch (emode)
  1883. {
  1884. case ENCODE_STRING:
  1885. case ENCODE_UTF8:
  1886. case ENCODE_PIPE:
  1887. case ENCODE_PIPE8:
  1888. need = slen + 5;
  1889. break;
  1890. case ENCODE_BASE64:
  1891. case ENCODE_BASE64URL:
  1892. case ENCODE_BASE64STAR:
  1893. case ENCODE_BASE64XML:
  1894. need = ( 3*slen ) / 4 + 12;
  1895. break;
  1896. case ENCODE_HEX:
  1897. need = (slen+3)/2;
  1898. break;
  1899. //case ENCODE_JSON: // [[json]]
  1900. default:
  1901. need = slen + 3; // at least 3 bytes
  1902. break;
  1903. }
  1904. const bool alloced = !buf || buf_size < need;
  1905. if (alloced)
  1906. {
  1907. buf = MALLOC(need);
  1908. buf_size = need;
  1909. }
  1910. mem_t mem;
  1911. mem.len = DecodeByMode(buf,buf_size,source,slen,emode,scanned_len);
  1912. if ( alloced && mem.len+10 < buf_size )
  1913. buf = REALLOC( buf, mem.len+1 );
  1914. mem.ptr = buf;
  1915. return mem;
  1916. }
  1917. ///////////////////////////////////////////////////////////////////////////////
  1918. uint DecodeByModeMemList
  1919. (
  1920. // returns the number of scanned strings
  1921. mem_list_t *res, // result
  1922. uint res_mode, // 0:append, 1:clear, 2:init
  1923. ccp source, // string to decode
  1924. int slen, // length of string. if -1, str is null terminated
  1925. EncodeMode_t emode, // encoding mode
  1926. uint *scanned_len // not NULL: Store number of scanned 'str' bytes here
  1927. )
  1928. {
  1929. DASSERT(res);
  1930. if ( res_mode > 1 )
  1931. InitializeMemList(res);
  1932. else if ( res_mode > 0 )
  1933. ResetMemList(res);
  1934. if (!source)
  1935. {
  1936. if (scanned_len)
  1937. *scanned_len = 0;
  1938. return 0;
  1939. }
  1940. ccp src = source;
  1941. if ( slen < 0 )
  1942. slen = strlen(src);
  1943. NeedBufMemList(res,slen,0);
  1944. ccp end = src + slen;
  1945. char buf[4000];
  1946. uint count;
  1947. for ( count = 1;; count++ )
  1948. {
  1949. if ( emode != ENCODE_OFF )
  1950. while ( src < end && (uchar)*src <= ' ' )
  1951. src++;
  1952. if ( src >= end )
  1953. {
  1954. AppendMemListN(res,&EmptyMem,1,MEMLM_ALL);
  1955. break;
  1956. }
  1957. if ( *src == ',' )
  1958. AppendMemListN(res,&EmptyMem,1,MEMLM_ALL);
  1959. else if ( *src == '%' )
  1960. {
  1961. AppendMemListN(res,&NullMem,1,MEMLM_ALL);
  1962. src++;
  1963. }
  1964. else if ( emode == ENCODE_OFF )
  1965. {
  1966. mem_t mem;
  1967. mem.ptr = src;
  1968. src = memchr(src,',',end-src);
  1969. if (!src)
  1970. src = end;
  1971. mem.len = src - mem.ptr;
  1972. AppendMemListN(res,&mem,1,MEMLM_ALL);
  1973. }
  1974. else
  1975. {
  1976. uint scanned;
  1977. mem_t mem = DecodeByModeMem(buf,sizeof(buf),src,end-src,emode,&scanned);
  1978. src += scanned;
  1979. AppendMemListN(res,&mem,1,MEMLM_ALL);
  1980. if ( mem.ptr != buf )
  1981. FreeString(mem.ptr);
  1982. }
  1983. while ( src < end && (uchar)*src <= ' ' )
  1984. src++;
  1985. if ( src >= end || *src != ',' )
  1986. break;
  1987. src++;
  1988. }
  1989. //--- terminate
  1990. if (scanned_len)
  1991. *scanned_len = src - source;
  1992. return count;
  1993. }
  1994. ///////////////////////////////////////////////////////////////////////////////
  1995. uint EncodeByMode
  1996. (
  1997. // returns the number of valid bytes in 'buf'. Result is NULL-terminated.
  1998. char *buf, // valid destination buffer
  1999. uint buf_size, // size of 'buf' >= 4
  2000. ccp source, // string to encode
  2001. int slen, // length of string. if -1, str is null terminated
  2002. EncodeMode_t emode // encoding mode
  2003. )
  2004. {
  2005. DASSERT(buf);
  2006. DASSERT( buf_size >= 3 );
  2007. DASSERT( source || !slen );
  2008. DASSERT( (uint)emode < ENCODE__N );
  2009. noPRINT("EncodeByMode(,%u,%d,%d)\n",buf_size,slen,emode);
  2010. uint len = 0;
  2011. switch (emode)
  2012. {
  2013. case ENCODE_STRING:
  2014. PrintEscapedString(buf,buf_size,source,slen,0,0,&len);
  2015. break;
  2016. case ENCODE_UTF8:
  2017. PrintEscapedString(buf,buf_size,source,slen,CHMD__MODERN,0,&len);
  2018. break;
  2019. case ENCODE_PIPE:
  2020. PrintEscapedString(buf,buf_size,source,slen,CHMD_IF_REQUIRED|CHMD_PIPE,0,&len);
  2021. break;
  2022. case ENCODE_PIPE8:
  2023. PrintEscapedString(buf,buf_size,source,slen,CHMD__MODERN|CHMD_IF_REQUIRED|CHMD_PIPE,0,&len);
  2024. break;
  2025. case ENCODE_BASE64:
  2026. len = EncodeBase64(buf,buf_size,source,slen,TableEncode64,true,0,0);
  2027. len = GetEncodeBase64FillLen(len);
  2028. break;
  2029. case ENCODE_BASE64URL:
  2030. len = EncodeBase64(buf,buf_size,source,slen,TableEncode64url,true,0,0);
  2031. len = GetEncodeBase64FillLen(len);
  2032. break;
  2033. case ENCODE_BASE64STAR:
  2034. len = EncodeBase64(buf,buf_size,source,slen,TableEncode64star,true,0,0);
  2035. len = GetEncodeBase64FillLen(len);
  2036. break;
  2037. case ENCODE_BASE64XML:
  2038. len = EncodeBase64(buf,buf_size,source,slen,TableEncode64xml,true,0,0);
  2039. len = GetEncodeBase64FillLen(len);
  2040. break;
  2041. case ENCODE_JSON:
  2042. len = EncodeJSON(buf,buf_size,source,slen);
  2043. break;
  2044. case ENCODE_HEX:
  2045. len = EncodeHex(buf,buf_size,source,slen,0);
  2046. break;
  2047. default:
  2048. if ( slen < 0 )
  2049. len = StringCopyS(buf,buf_size,source) - buf;
  2050. else
  2051. len = StringCopySM(buf,buf_size,source,slen) - buf;
  2052. break;
  2053. }
  2054. //--- terminate with NULL
  2055. if ( len >= buf_size )
  2056. len = buf_size - 1;
  2057. buf[len] = 0;
  2058. return len;
  2059. }
  2060. ///////////////////////////////////////////////////////////////////////////////
  2061. mem_t EncodeByModeMem
  2062. (
  2063. // Returns the encoded 'source'. Result is NULL-terminated.
  2064. // It points either to 'buf' or is alloced (on buf==NULL or too less space)
  2065. // If alloced (mem.ptr!=buf) => call FreeMem(&mem)
  2066. char *buf, // NULL or destination buffer
  2067. uint buf_size, // size of 'buf'
  2068. ccp source, // string to encode
  2069. int slen, // length of string. if -1, str is null terminated
  2070. EncodeMode_t emode // encoding mode
  2071. )
  2072. {
  2073. DASSERT( source || slen <= 0 );
  2074. DASSERT( (uint)emode < ENCODE__N );
  2075. if ( slen < 0 )
  2076. slen = source ? strlen(source) : 0;
  2077. uint need;
  2078. switch (emode)
  2079. {
  2080. case ENCODE_STRING:
  2081. case ENCODE_UTF8:
  2082. case ENCODE_PIPE:
  2083. case ENCODE_PIPE8:
  2084. need = slen * 4 + 5;
  2085. break;
  2086. case ENCODE_BASE64:
  2087. case ENCODE_BASE64URL:
  2088. case ENCODE_BASE64STAR:
  2089. case ENCODE_BASE64XML:
  2090. need = ( 4*slen ) / 3 + 10;
  2091. break;
  2092. case ENCODE_HEX:
  2093. need = 2*slen + 1;
  2094. break;
  2095. case ENCODE_JSON: // [[json]]
  2096. {
  2097. need = slen + 1;
  2098. ccp ptr = source;
  2099. ccp end = ptr + slen;
  2100. while ( ptr < end )
  2101. if ( (uchar)*ptr++ < ' ' )
  2102. need += 5;
  2103. }
  2104. break;
  2105. default:
  2106. need = slen + 1;
  2107. break;
  2108. }
  2109. const bool alloced = !buf || buf_size < need;
  2110. if (alloced)
  2111. {
  2112. buf = MALLOC(need);
  2113. buf_size = need;
  2114. }
  2115. mem_t mem;
  2116. mem.len = EncodeByMode(buf,buf_size,source,slen,emode);
  2117. if ( alloced && mem.len+10 < buf_size )
  2118. buf = REALLOC( buf, mem.len+1 );
  2119. mem.ptr = buf;
  2120. return mem;
  2121. }
  2122. //
  2123. ///////////////////////////////////////////////////////////////////////////////
  2124. /////////////// escape/quote strings, alloc space ///////////////
  2125. ///////////////////////////////////////////////////////////////////////////////
  2126. exmem_t EscapeStringEx
  2127. (
  2128. // Returns an exmem_t struct. If not quoted (CHMD_IF_REQUIRED) it returns 'src'
  2129. // Use FreeExMem(&result) to free possible alloced result.
  2130. cvp src, // NULL or source
  2131. int src_len, // size of 'src'. If -1: Use strlen(src)
  2132. cvp return_if_null, // return this, if 'src==NULL'
  2133. cvp return_if_empty, // return this, if src is empty (have no chars)
  2134. CharMode_t char_mode, // how to escape (CHMD_*)
  2135. char quote, // quoting character: " or ' or $ (for $'...')
  2136. bool try_circ // use circ-buffer, if result is small enough
  2137. )
  2138. {
  2139. if (!src)
  2140. return ExMemByString((char*)return_if_null);
  2141. if ( src_len < 0 )
  2142. src_len = strlen(src);
  2143. if (!src_len)
  2144. return ExMemByString((char*)return_if_empty);
  2145. char quote_char;
  2146. uint quote_mode;
  2147. if ( quote == '$' )
  2148. {
  2149. quote_mode = 3;
  2150. quote_char = '\'';
  2151. }
  2152. else if (quote)
  2153. {
  2154. quote_mode = 2;
  2155. quote_char = quote;
  2156. }
  2157. else
  2158. {
  2159. quote_mode = 0;
  2160. quote_char = '"';
  2161. }
  2162. uint size = GetEscapeLen(src,src_len,char_mode,quote_char);
  2163. if ( !size && char_mode & CHMD_IF_REQUIRED )
  2164. return ExMemByS(src,src_len);
  2165. size += quote_mode + src_len + 4;
  2166. const bool use_circ = try_circ && size <= CIRC_BUF_MAX_ALLOC;
  2167. char *buf = use_circ ? GetCircBuf(size) : MALLOC(size);
  2168. uint len;
  2169. if ( quote_mode == 3 )
  2170. {
  2171. PrintEscapedString(buf+2,size-3,src,src_len,char_mode,quote_char,&len);
  2172. buf[0] = '$';
  2173. buf[1] = buf[len+2] = quote_char;
  2174. buf[len+3] = 0;
  2175. }
  2176. else if ( quote_mode == 2 )
  2177. {
  2178. PrintEscapedString(buf+1,size-2,src,src_len,char_mode,quote_char,&len);
  2179. buf[0] = buf[len+1] = quote_char;
  2180. buf[len+2] = 0;
  2181. }
  2182. else
  2183. PrintEscapedString(buf,size,src,src_len,char_mode,quote_char,&len);
  2184. exmem_t res = { .data={ buf, len+quote_mode },
  2185. .is_circ_buf = use_circ, .is_alloced = !use_circ };
  2186. return res;
  2187. };
  2188. ///////////////////////////////////////////////////////////////////////////////
  2189. char * EscapeString
  2190. (
  2191. // Returns a pointer.
  2192. // Use FreeString(result) to free possible alloced result.
  2193. // circ-buffer is ignored by FreeString().
  2194. cvp src, // NULL or source
  2195. int src_len, // size of 'src'. If -1: Use strlen(src)
  2196. cvp return_if_null, // return this, if 'src==NULL'
  2197. cvp return_if_empty, // return this, if src is empty (have no chars)
  2198. CharMode_t char_mode, // how to escape
  2199. char quote, // quoting character: " or ' or $ (for $'...')
  2200. bool try_circ, // use circ-buffer, if result is small enough
  2201. uint *dest_len // not NULL: Store length of result here
  2202. )
  2203. {
  2204. if (!src)
  2205. return (char*)return_if_null;
  2206. if ( src_len < 0 )
  2207. src_len = strlen(src);
  2208. if (!src_len)
  2209. return (char*)return_if_empty;
  2210. #if 1
  2211. exmem_t res = EscapeStringEx(src,src_len,return_if_null,return_if_empty,char_mode,quote,try_circ);
  2212. if (dest_len)
  2213. *dest_len = res.data.len;
  2214. return res.is_circ_buf || res.is_alloced
  2215. ? (char*)res.data.ptr
  2216. : MEMDUP(res.data.ptr,res.data.len);
  2217. #else // [[2do]] [[obsolete]]
  2218. char quote_char;
  2219. uint quote_mode;
  2220. if ( quote == '$' )
  2221. {
  2222. quote_mode = 3;
  2223. quote_char = '\'';
  2224. }
  2225. else if (quote)
  2226. {
  2227. quote_mode = 2;
  2228. quote_char = quote;
  2229. }
  2230. else
  2231. {
  2232. quote_mode = 0;
  2233. quote_char = '"';
  2234. }
  2235. uint size = GetEscapeLen(src,src_len,char_mode,quote_char);
  2236. if ( !size && char_mode & CHMD_IF_REQUIRED )
  2237. {
  2238. char *buf = try_circ && size <= CIRC_BUF_MAX_ALLOC ? GetCircBuf(src_len+1) : MALLOC(src_len+1);
  2239. memcpy(buf,src,src_len);
  2240. buf[src_len] = 0;
  2241. if (dest_len)
  2242. *dest_len = src_len;
  2243. return buf;
  2244. }
  2245. size += quote_mode + src_len + 4;
  2246. char *buf = try_circ && size <= CIRC_BUF_MAX_ALLOC ? GetCircBuf(size) : MALLOC(size);
  2247. uint len;
  2248. if ( quote_mode == 3 )
  2249. {
  2250. PrintEscapedString(buf+2,size-3,src,src_len,char_mode,quote_char,&len);
  2251. buf[0] = '$';
  2252. buf[1] = buf[len+2] = quote_char;
  2253. buf[len+3] = 0;
  2254. }
  2255. else if ( quote_mode == 2 )
  2256. {
  2257. PrintEscapedString(buf+1,size-2,src,src_len,char_mode,quote_char,&len);
  2258. buf[0] = buf[len+1] = quote_char;
  2259. buf[len+2] = 0;
  2260. }
  2261. else
  2262. PrintEscapedString(buf,size,src,src_len,char_mode,quote_char,&len);
  2263. if (dest_len)
  2264. *dest_len = len + quote_mode;
  2265. return buf;
  2266. #endif
  2267. };
  2268. //
  2269. ///////////////////////////////////////////////////////////////////////////////
  2270. /////////////// struct Escape_t ///////////////
  2271. ///////////////////////////////////////////////////////////////////////////////
  2272. // https://en.wikipedia.org/wiki/ANSI_escape_code
  2273. const char ecape_stat_name[ESCST__N+1][5] =
  2274. {
  2275. "-", // ESCST_NONE
  2276. "CHAR", // ESCST_CHAR
  2277. "FE", // ESCST_FE
  2278. "SS2", // ESCST_SS2
  2279. "SS3", // ESCST_SS3
  2280. "CSI", // ESCST_CSI
  2281. "OSC", // ESCST_OSC
  2282. "", // ESCST__N
  2283. };
  2284. ///////////////////////////////////////////////////////////////////////////////
  2285. EscapeStat_t CheckEscape ( Escape_t *esc, cvp source, cvp end, bool check_esc )
  2286. {
  2287. DASSERT(esc);
  2288. memset(esc,0,sizeof(*esc));
  2289. if (!source)
  2290. return 0;
  2291. ccp src = source;
  2292. if (!end)
  2293. end = src + strlen(src);
  2294. if ( src >= (ccp)end )
  2295. return 0;
  2296. ccp beg = src;
  2297. if (check_esc)
  2298. {
  2299. if ( *src != '\e' )
  2300. {
  2301. esc->status = ESCST_CHAR;
  2302. esc->code = *src++;
  2303. goto term;
  2304. }
  2305. src++;
  2306. if ( src >= (ccp)end )
  2307. return 0;
  2308. }
  2309. esc->code = *src++;
  2310. int term_wd = 0;
  2311. switch (esc->code)
  2312. {
  2313. case 'N': //--- SS2: Single Shift 2 ---
  2314. if ( src < (ccp)end )
  2315. {
  2316. esc->status = ESCST_SS2;
  2317. esc->code = *src++;
  2318. }
  2319. break;
  2320. case 'O': //--- SS3: Single Shift 3 ---
  2321. if ( src < (ccp)end )
  2322. {
  2323. esc->status = ESCST_SS3;
  2324. esc->code = *src++;
  2325. }
  2326. break;
  2327. case '[': //--- CSI ---
  2328. while ( src < (ccp)end && *src >= 0x30 && *src <= 0x3f )
  2329. src++;
  2330. while ( src < (ccp)end && *src >= 0x20 && *src <= 0x2f )
  2331. src++;
  2332. if ( src < (ccp)end && *src >= 0x40 && *src <= 0x7e )
  2333. {
  2334. esc->status = ESCST_CSI;
  2335. esc->code = *src++;
  2336. }
  2337. break;
  2338. case ']': //--- OSC ---
  2339. // terminate by ST (ESC \ == 0x9c) or BEL (7)
  2340. for ( ; src < (ccp)end; src++ )
  2341. {
  2342. if ( *src == 7 || (u8)*src == 0x9c )
  2343. {
  2344. src++;
  2345. term_wd = 1;
  2346. esc->status = ESCST_OSC;
  2347. break;
  2348. }
  2349. if ( src+1 < (ccp)end && src[0] == '\e' && src[1] == '\\' )
  2350. {
  2351. src += 2;
  2352. term_wd = 2;
  2353. esc->status = ESCST_OSC;
  2354. break;
  2355. }
  2356. }
  2357. break;
  2358. default: //--- single char ---
  2359. esc->status = ESCST_CHAR;
  2360. break;
  2361. }
  2362. term:;
  2363. if ( esc->status != ESCST_NONE )
  2364. {
  2365. esc->scanned_len = src - (ccp)source;
  2366. if ( esc->status > ESCST_CHAR )
  2367. {
  2368. esc->esc.ptr = beg;
  2369. esc->esc.len = src - beg - term_wd;
  2370. }
  2371. }
  2372. return esc->status;
  2373. }
  2374. //
  2375. ///////////////////////////////////////////////////////////////////////////////
  2376. /////////////// time ///////////////
  2377. ///////////////////////////////////////////////////////////////////////////////
  2378. ccp micro_second_char = "u";
  2379. s64 timezone_adjust_sec = -1;
  2380. s64 timezone_adjust_usec = -1;
  2381. s64 timezone_adjust_nsec = -1;
  2382. int timezone_adjust_isdst = -1;
  2383. ///////////////////////////////////////////////////////////////////////////////
  2384. void SetupTimezone ( bool force )
  2385. {
  2386. if ( force || timezone_adjust_sec == -1 )
  2387. {
  2388. timezone_adjust_sec = GetTimezoneAdjust(GetTimeSec(false));
  2389. timezone_adjust_usec = USEC_PER_SEC * timezone_adjust_sec;
  2390. timezone_adjust_nsec = NSEC_PER_SEC * timezone_adjust_sec;
  2391. TRACE("TZ: %s,%s, %ld, %d => %lld %lld %lld\n",
  2392. tzname[0], tzname[1], timezone, daylight,
  2393. timezone_adjust_sec, timezone_adjust_usec, timezone_adjust_nsec );
  2394. }
  2395. }
  2396. ///////////////////////////////////////////////////////////////////////////////
  2397. int GetTimezoneAdjust ( time_t tim )
  2398. {
  2399. struct tm gmt, loc;
  2400. gmtime_r(&tim,&gmt);
  2401. localtime_r(&tim,&loc);
  2402. int delta = ( gmt.tm_hour - loc.tm_hour ) * 3600
  2403. + ( gmt.tm_min - loc.tm_min ) * 60
  2404. + ( gmt.tm_sec - loc.tm_sec );
  2405. if ( gmt.tm_yday != loc.tm_yday )
  2406. {
  2407. if ( gmt.tm_year < loc.tm_year
  2408. || gmt.tm_year == loc.tm_year && gmt.tm_yday < loc.tm_yday )
  2409. {
  2410. delta -= 24*3600;
  2411. }
  2412. else
  2413. {
  2414. delta += 24*3600;
  2415. }
  2416. }
  2417. return delta;
  2418. }
  2419. ///////////////////////////////////////////////////////////////////////////////
  2420. static u_sec_t AdjustLocalTime ( u_sec_t sec )
  2421. {
  2422. static uint last_hour = 0;
  2423. const uint hour = sec / 3600;
  2424. if ( last_hour != hour )
  2425. {
  2426. last_hour = hour;
  2427. SetupTimezone(true);
  2428. }
  2429. return sec - timezone_adjust_sec;
  2430. }
  2431. //-----------------------------------------------------------------------------
  2432. struct timeval GetTimeOfDay ( bool localtime )
  2433. {
  2434. struct timeval tval;
  2435. gettimeofday(&tval,NULL);
  2436. if (localtime)
  2437. tval.tv_sec = AdjustLocalTime(tval.tv_sec);
  2438. return tval;
  2439. }
  2440. //-----------------------------------------------------------------------------
  2441. struct timespec GetClockTime ( bool localtime )
  2442. {
  2443. struct timespec ts;
  2444. #if HAVE_CLOCK_GETTIME
  2445. if (!clock_gettime(CLOCK_REALTIME,&ts))
  2446. {
  2447. if (localtime)
  2448. ts.tv_sec = AdjustLocalTime(ts.tv_sec);
  2449. return ts;
  2450. }
  2451. #endif
  2452. // fall back
  2453. struct timeval tval = GetTimeOfDay(localtime);
  2454. ts.tv_sec = tval.tv_sec;
  2455. ts.tv_nsec = tval.tv_usec * NSEC_PER_USEC;
  2456. return ts;
  2457. }
  2458. //-----------------------------------------------------------------------------
  2459. struct timespec GetClockTimer(void)
  2460. {
  2461. struct timespec ts;
  2462. #if HAVE_CLOCK_GETTIME
  2463. if (!clock_gettime(CLOCK_MONOTONIC,&ts))
  2464. return ts;
  2465. #endif
  2466. // fall back
  2467. struct timeval tval = GetTimeOfDay(false);
  2468. ts.tv_sec = tval.tv_sec;
  2469. ts.tv_nsec = tval.tv_usec * NSEC_PER_USEC;
  2470. return ts;
  2471. }
  2472. ///////////////////////////////////////////////////////////////////////////////
  2473. DayTime_t GetDayTime ( bool localtime )
  2474. {
  2475. div_t d;
  2476. DayTime_t dt;
  2477. #if HAVE_CLOCK_GETTIME
  2478. struct timespec tim = GetClockTime(localtime);
  2479. dt.usec = tim.tv_nsec / NSEC_PER_USEC;
  2480. dt.nsec = tim.tv_nsec;
  2481. #else
  2482. struct timeval tim = GetTimeOfDay(localtime);
  2483. dt.usec = tim.tv_usec;
  2484. dt.nsec = tim.tv_usec * NSEC_PER_USEC;
  2485. #endif
  2486. dt.time = tim.tv_sec;
  2487. d = div(tim.tv_sec,86400);
  2488. dt.day = d.quot;
  2489. d = div(d.rem,3600);
  2490. dt.hour = d.quot;
  2491. d = div(d.rem,60);
  2492. dt.min = d.quot;
  2493. dt.sec = d.rem;
  2494. return dt;
  2495. }
  2496. ///////////////////////////////////////////////////////////////////////////////
  2497. u_sec_t GetTimeSec ( bool localtime )
  2498. {
  2499. struct timeval tval = GetTimeOfDay(localtime);
  2500. return tval.tv_sec;
  2501. }
  2502. ///////////////////////////////////////////////////////////////////////////////
  2503. u_msec_t GetTimeMSec ( bool localtime )
  2504. {
  2505. struct timeval tval = GetTimeOfDay(localtime);
  2506. return (u_msec_t)(tval.tv_sec) * MSEC_PER_SEC + tval.tv_usec/USEC_PER_MSEC;
  2507. }
  2508. ///////////////////////////////////////////////////////////////////////////////
  2509. u_usec_t GetTimeUSec ( bool localtime )
  2510. {
  2511. struct timeval tval = GetTimeOfDay(localtime);
  2512. return (u_usec_t)(tval.tv_sec) * USEC_PER_SEC + tval.tv_usec;
  2513. }
  2514. ///////////////////////////////////////////////////////////////////////////////
  2515. u_nsec_t GetTimeNSec ( bool localtime )
  2516. {
  2517. struct timespec ts = GetClockTime(localtime);
  2518. return (u_nsec_t)(ts.tv_sec) * NSEC_PER_SEC + ts.tv_nsec;
  2519. }
  2520. ///////////////////////////////////////////////////////////////////////////////
  2521. ///////////////////////////////////////////////////////////////////////////////
  2522. CurrentTime_t current_time = {0};
  2523. CurrentTime_t GetCurrentTime ( bool localtime )
  2524. {
  2525. struct timeval tval = GetTimeOfDay(localtime);
  2526. CurrentTime_t ct;
  2527. ct.sec = tval.tv_sec;
  2528. ct.usec = tval.tv_sec * USEC_PER_SEC + tval.tv_usec;
  2529. ct.msec = ct.usec / 1000;
  2530. return ct;
  2531. }
  2532. //
  2533. ///////////////////////////////////////////////////////////////////////////////
  2534. /////////////// timer ///////////////
  2535. ///////////////////////////////////////////////////////////////////////////////
  2536. u_sec_t GetTimerSec()
  2537. {
  2538. struct timespec ts = GetClockTimer();
  2539. return ts.tv_sec;
  2540. }
  2541. ///////////////////////////////////////////////////////////////////////////////
  2542. u_msec_t GetTimerMSec()
  2543. {
  2544. struct timespec ts = GetClockTimer();
  2545. return ts.tv_sec * MSEC_PER_SEC + ts.tv_nsec / NSEC_PER_MSEC;
  2546. }
  2547. ///////////////////////////////////////////////////////////////////////////////
  2548. u_usec_t GetTimerUSec()
  2549. {
  2550. struct timespec ts = GetClockTimer();
  2551. return ts.tv_sec * USEC_PER_SEC + ts.tv_nsec / NSEC_PER_USEC;
  2552. }
  2553. ///////////////////////////////////////////////////////////////////////////////
  2554. u_nsec_t GetTimerNSec()
  2555. {
  2556. struct timespec ts = GetClockTimer();
  2557. return ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
  2558. }
  2559. ///////////////////////////////////////////////////////////////////////////////
  2560. ///////////////////////////////////////////////////////////////////////////////
  2561. ccp PrintRefTime
  2562. (
  2563. u_sec_t tim, // seconds since epoch; 0 is replaced by time()
  2564. u_sec_t *ref_tim // NULL or ref_tim; if *ref_tim==0: write current time
  2565. // it is used to select format
  2566. )
  2567. {
  2568. u_sec_t ref;
  2569. if (!ref_tim)
  2570. ref = GetTimeSec(false);
  2571. else
  2572. {
  2573. if (!*ref_tim)
  2574. *ref_tim = GetTimeSec(false);
  2575. ref = *ref_tim;
  2576. }
  2577. ccp format = tim >= ref - 10*SEC_PER_HOUR && tim <= ref + 10*SEC_PER_HOUR
  2578. ? " %k:%M:%S"
  2579. : tim >= ref - 12*SEC_PER_DAY && tim <= ref + 10*SEC_PER_DAY
  2580. ? " %e. %k:%M"
  2581. : "%F";
  2582. return PrintTimeByFormat(format,tim);
  2583. }
  2584. //-----------------------------------------------------------------------------
  2585. ccp PrintRefTimeUTC
  2586. (
  2587. u_sec_t tim, // seconds since epoch; 0 is replaced by time()
  2588. u_sec_t *ref_tim // NULL or ref_tim; if *ref_tim==0: write current time
  2589. // it is used to select format
  2590. )
  2591. {
  2592. u_sec_t ref;
  2593. if (!ref_tim)
  2594. ref = GetTimeSec(false);
  2595. else
  2596. {
  2597. if (!*ref_tim)
  2598. *ref_tim = GetTimeSec(false);
  2599. ref = *ref_tim;
  2600. }
  2601. ccp format = tim >= ref - 10*SEC_PER_HOUR && tim <= ref + 10*SEC_PER_HOUR
  2602. ? " %k:%M:%S"
  2603. : tim >= ref - 12*SEC_PER_DAY && tim <= ref + 10*SEC_PER_DAY
  2604. ? " %e. %k:%M"
  2605. : "%F";
  2606. return PrintTimeByFormatUTC(format,tim);
  2607. }
  2608. ///////////////////////////////////////////////////////////////////////////////
  2609. ccp PrintTimeByFormat
  2610. (
  2611. // returns temporary buffer by GetCircBuf();
  2612. ccp format, // format string for strftime()
  2613. u_sec_t tim // seconds since epoch; 0 is replaced by time()
  2614. )
  2615. {
  2616. char buf[100];
  2617. const time_t reftime = tim ? tim : time(0);
  2618. struct tm *tm = localtime(&reftime);
  2619. const uint len = strftime(buf,sizeof(buf),format,tm);
  2620. return CopyCircBuf(buf,len+1);
  2621. }
  2622. //-----------------------------------------------------------------------------
  2623. ccp PrintTimeByFormatUTC
  2624. (
  2625. // returns temporary buffer by GetCircBuf();
  2626. ccp format, // format string for strftime()
  2627. u_sec_t tim // seconds since epoch; 0 is replaced by time()
  2628. )
  2629. {
  2630. char buf[100];
  2631. const time_t reftime = tim ? tim : time(0);
  2632. struct tm *tm = gmtime(&reftime);
  2633. const uint len = strftime(buf,sizeof(buf),format,tm);
  2634. return CopyCircBuf(buf,len+1);
  2635. }
  2636. ///////////////////////////////////////////////////////////////////////////////
  2637. ccp PrintNSecByFormat
  2638. (
  2639. // returns temporary buffer by GetCircBuf();
  2640. ccp format, // format string for strftime()
  2641. // 1-9 '@' in row replaced by digits of 'nsec'
  2642. time_t tim, // seconds since epoch
  2643. uint nsec // nanosecond of second
  2644. )
  2645. {
  2646. char buf[100];
  2647. struct tm *tm = localtime(&tim);
  2648. const uint len = strftime(buf,sizeof(buf),format,tm);
  2649. char *at = strchr(buf,'@');
  2650. if (at)
  2651. {
  2652. char nbuf[10];
  2653. snprintf(nbuf,sizeof(nbuf),"%09u",nsec);
  2654. ccp src = nbuf;
  2655. while ( *at == '@' && *src )
  2656. *at++ = *src++;
  2657. }
  2658. return CopyCircBuf(buf,len+1);
  2659. }
  2660. //-----------------------------------------------------------------------------
  2661. ccp PrintNSecByFormatUTC
  2662. (
  2663. // returns temporary buffer by GetCircBuf();
  2664. ccp format, // format string for strftime()
  2665. // 1-9 '@' in row replaced by digits of 'nsec'
  2666. time_t tim, // seconds since epoch
  2667. uint nsec // nanosecond of second
  2668. )
  2669. {
  2670. char buf[100];
  2671. struct tm *tm = gmtime(&tim);
  2672. const uint len = strftime(buf,sizeof(buf),format,tm);
  2673. char *at = strchr(buf,'@');
  2674. if (at)
  2675. {
  2676. char nbuf[10];
  2677. snprintf(nbuf,sizeof(nbuf),"%09u",nsec);
  2678. ccp src = nbuf;
  2679. while ( *at == '@' && *src )
  2680. *at++ = *src++;
  2681. }
  2682. return CopyCircBuf(buf,len+1);
  2683. }
  2684. //-----------------------------------------------------------------------------
  2685. ccp PrintNTimeByFormat
  2686. (
  2687. // returns temporary buffer by GetCircBuf();
  2688. ccp format, // format string for strftime()
  2689. // 1-9 '@' in row replaced by digits of 'usec'
  2690. u_nsec_t ntime
  2691. )
  2692. {
  2693. return PrintNSecByFormat(format,ntime/NSEC_PER_SEC,ntime%NSEC_PER_SEC);
  2694. }
  2695. //-----------------------------------------------------------------------------
  2696. ccp PrintNTimeByFormatUTC
  2697. (
  2698. // returns temporary buffer by GetCircBuf();
  2699. ccp format, // format string for strftime()
  2700. // 1-9 '@' in row replaced by digits of 'usec'
  2701. u_nsec_t ntime
  2702. )
  2703. {
  2704. return PrintNSecByFormatUTC(format,ntime/NSEC_PER_SEC,ntime%NSEC_PER_SEC);
  2705. }
  2706. ///////////////////////////////////////////////////////////////////////////////
  2707. ccp PrintUTimeByFormat
  2708. (
  2709. // returns temporary buffer by GetCircBuf();
  2710. ccp format, // format string for strftime()
  2711. // 1-9 '@' in row replaced by digits of 'usec'
  2712. u_usec_t utime
  2713. )
  2714. {
  2715. return PrintNSecByFormat(format,utime/USEC_PER_SEC,utime%USEC_PER_SEC*NSEC_PER_USEC);
  2716. }
  2717. //-----------------------------------------------------------------------------
  2718. ccp PrintUTimeByFormatUTC
  2719. (
  2720. // returns temporary buffer by GetCircBuf();
  2721. ccp format, // format string for strftime()
  2722. // 1-9 '@' in row replaced by digits of 'usec'
  2723. u_usec_t utime
  2724. )
  2725. {
  2726. return PrintNSecByFormatUTC(format,utime/USEC_PER_SEC,utime%USEC_PER_SEC*NSEC_PER_USEC);
  2727. }
  2728. ///////////////////////////////////////////////////////////////////////////////
  2729. ccp PrintMTimeByFormat
  2730. (
  2731. // returns temporary buffer by GetCircBuf();
  2732. ccp format, // format string for strftime()
  2733. // 1-9 '@' in row replaced by digits of 'usec'
  2734. u_msec_t mtime
  2735. )
  2736. {
  2737. return PrintNSecByFormat(format,mtime/MSEC_PER_SEC,mtime%MSEC_PER_SEC*NSEC_PER_MSEC);
  2738. }
  2739. //-----------------------------------------------------------------------------
  2740. ccp PrintMTimeByFormatUTC
  2741. (
  2742. // returns temporary buffer by GetCircBuf();
  2743. ccp format, // format string for strftime()
  2744. // 1-9 '@' in row replaced by digits of 'usec'
  2745. u_msec_t mtime
  2746. )
  2747. {
  2748. return PrintNSecByFormatUTC(format,mtime/MSEC_PER_SEC,mtime%MSEC_PER_SEC*NSEC_PER_MSEC);
  2749. }
  2750. ///////////////////////////////////////////////////////////////////////////////
  2751. ccp PrintTimevalByFormat
  2752. (
  2753. // returns temporary buffer by GetCircBuf();
  2754. ccp format, // format string for strftime()
  2755. const struct timeval *tv // time to print, if NULL use gettimeofday()
  2756. )
  2757. {
  2758. struct timeval temp;
  2759. if (!tv)
  2760. {
  2761. gettimeofday(&temp,0);
  2762. tv = &temp;
  2763. }
  2764. return PrintUSecByFormat(format,tv->tv_sec,tv->tv_usec);
  2765. }
  2766. //-----------------------------------------------------------------------------
  2767. ccp PrintTimevalByFormatUTC
  2768. (
  2769. // returns temporary buffer by GetCircBuf();
  2770. ccp format, // format string for strftime()
  2771. const struct timeval *tv // time to print, if NULL use gettimeofday()
  2772. )
  2773. {
  2774. struct timeval temp;
  2775. if (!tv)
  2776. {
  2777. gettimeofday(&temp,0);
  2778. tv = &temp;
  2779. }
  2780. return PrintUSecByFormatUTC(format,tv->tv_sec,tv->tv_usec);
  2781. }
  2782. ///////////////////////////////////////////////////////////////////////////////
  2783. ccp PrintTimespecByFormat
  2784. (
  2785. // returns temporary buffer by GetCircBuf();
  2786. ccp format, // format string for strftime()
  2787. const struct timespec *ts // time to print, if NULL use GetClockTime(false)
  2788. )
  2789. {
  2790. struct timespec temp;
  2791. if (!ts)
  2792. {
  2793. temp = GetClockTime(true);
  2794. ts = &temp;
  2795. }
  2796. return PrintNSecByFormat(format,ts->tv_sec,ts->tv_nsec);
  2797. }
  2798. //-----------------------------------------------------------------------------
  2799. ccp PrintTimespecByFormatUTC
  2800. (
  2801. // returns temporary buffer by GetCircBuf();
  2802. ccp format, // format string for strftime()
  2803. const struct timespec *ts // time to print, if NULL use GetClockTime(false)
  2804. )
  2805. {
  2806. struct timespec temp;
  2807. if (!ts)
  2808. {
  2809. temp = GetClockTime(false);
  2810. ts = &temp;
  2811. }
  2812. return PrintNSecByFormatUTC(format,ts->tv_sec,ts->tv_nsec);
  2813. }
  2814. ///////////////////////////////////////////////////////////////////////////////
  2815. ///////////////////////////////////////////////////////////////////////////////
  2816. ccp PrintTimeSec
  2817. (
  2818. char * buf, // result buffer (>19 bytes are good)
  2819. // If NULL, a local circulary static buffer is used
  2820. size_t buf_size, // size of 'buf', ignored if buf==NULL
  2821. uint sec // seconds (=time) to print
  2822. )
  2823. {
  2824. if (!buf)
  2825. buf = GetCircBuf( buf_size = 20 );
  2826. time_t time = sec;
  2827. struct tm *tm = localtime(&time);
  2828. strftime(buf,buf_size,"%F %T",tm);
  2829. return buf;
  2830. }
  2831. ///////////////////////////////////////////////////////////////////////////////
  2832. ccp PrintTimeMSec
  2833. (
  2834. char * buf, // result buffer (>23 bytes are good)
  2835. // If NULL, a local circulary static buffer is used
  2836. size_t buf_size, // size of 'buf', ignored if buf==NULL
  2837. u_msec_t msec, // milliseconds to print
  2838. uint fraction // number of digits (0-3) to print as fraction
  2839. )
  2840. {
  2841. if (!buf)
  2842. buf = GetCircBuf( buf_size = 24 );
  2843. time_t time = msec / MSEC_PER_SEC;
  2844. struct tm *tm = localtime(&time);
  2845. uint len = strftime(buf,buf_size,"%F %T",tm);
  2846. if ( fraction && len + 4 < buf_size )
  2847. {
  2848. len += snprintf(buf+len, buf_size-len, ".%03llu", msec % MSEC_PER_SEC );
  2849. const uint pos = len - 3 + ( fraction < 3 ? fraction : 3 );
  2850. if ( pos < buf_size )
  2851. buf[pos] = 0;
  2852. }
  2853. return buf;
  2854. }
  2855. ///////////////////////////////////////////////////////////////////////////////
  2856. ccp PrintTimeUSec
  2857. (
  2858. char * buf, // result buffer (>26 bytes are good)
  2859. // If NULL, a local circulary static buffer is used
  2860. size_t buf_size, // size of 'buf', ignored if buf==NULL
  2861. u_usec_t usec, // microseconds to print
  2862. uint fraction // number of digits (0-6) to print as fraction
  2863. )
  2864. {
  2865. if (!buf)
  2866. buf = GetCircBuf( buf_size = 28 );
  2867. time_t time = usec / USEC_PER_SEC;
  2868. struct tm *tm = localtime(&time);
  2869. uint len = strftime(buf,buf_size,"%F %T",tm);
  2870. if ( fraction && len + 7 < buf_size )
  2871. {
  2872. len += snprintf(buf+len, buf_size-len, ".%06llu", usec % USEC_PER_SEC );
  2873. const uint pos = len - 6 + ( fraction < 6 ? fraction : 6 );
  2874. if ( pos < buf_size )
  2875. buf[pos] = 0;
  2876. }
  2877. return buf;
  2878. }
  2879. ///////////////////////////////////////////////////////////////////////////////
  2880. ccp PrintTimeNSec
  2881. (
  2882. char * buf, // result buffer (>26 bytes are good)
  2883. // If NULL, a local circulary static buffer is used
  2884. size_t buf_size, // size of 'buf', ignored if buf==NULL
  2885. u_nsec_t nsec, // nanoseconds to print
  2886. uint fraction // number of digits (0-9) to print as fraction
  2887. )
  2888. {
  2889. if (!buf)
  2890. buf = GetCircBuf( buf_size = 32 );
  2891. time_t time = nsec / NSEC_PER_SEC;
  2892. struct tm *tm = localtime(&time);
  2893. uint len = strftime(buf,buf_size,"%F %T",tm);
  2894. if ( fraction && len + 10 < buf_size )
  2895. {
  2896. len += snprintf(buf+len, buf_size-len, ".%09llu", nsec % NSEC_PER_SEC );
  2897. const uint pos = len - 9 + ( fraction < 9 ? fraction : 9 );
  2898. if ( pos < buf_size )
  2899. buf[pos] = 0;
  2900. }
  2901. return buf;
  2902. }
  2903. ///////////////////////////////////////////////////////////////////////////////
  2904. ///////////////////////////////////////////////////////////////////////////////
  2905. ccp PrintTimerMSec
  2906. (
  2907. char * buf, // result buffer (>12 bytes are good)
  2908. // If NULL, a local circulary static buffer is used
  2909. size_t buf_size, // size of 'buf', ignored if buf==NULL
  2910. u32 msec, // milliseconds to print
  2911. uint fraction // number of digits (0-3) to print as fraction
  2912. )
  2913. {
  2914. if (!buf)
  2915. buf = GetCircBuf( buf_size = 16 );
  2916. if (fraction)
  2917. {
  2918. const uint len = snprintf(buf,buf_size,"%02d:%02d:%02d.%03d",
  2919. msec/3600000, msec/60000%60, msec/1000%60, msec%1000 );
  2920. if ( len > 3 && fraction < 3 )
  2921. {
  2922. const uint pos = len - 3 + fraction;
  2923. if ( pos < buf_size )
  2924. buf[pos] = 0;
  2925. }
  2926. }
  2927. else
  2928. snprintf(buf,buf_size,"%02d:%02d:%02d",
  2929. msec/3600000, msec/60000%60, msec/1000%60 );
  2930. ccp ptr = buf;
  2931. int colon_counter = 0;
  2932. while ( *ptr == '0' || *ptr == ':' && !colon_counter++ )
  2933. ptr++;
  2934. return *ptr == ':' ? ptr-1 : ptr;
  2935. }
  2936. ///////////////////////////////////////////////////////////////////////////////
  2937. ccp PrintTimerUSec
  2938. (
  2939. char * buf, // result buffer (>16 bytes are good)
  2940. // If NULL, a local circulary static buffer is used
  2941. size_t buf_size, // size of 'buf', ignored if buf==NULL
  2942. s_usec_t usec, // microseconds to print
  2943. uint fraction // number of digits (0-6) to print as fraction
  2944. )
  2945. {
  2946. if ( !buf || buf_size < 4 )
  2947. buf = GetCircBuf( buf_size = 20 );
  2948. const bool minus = usec < 0;
  2949. if (minus)
  2950. usec = -usec;
  2951. u32 sec = usec / USEC_PER_SEC;
  2952. if (fraction)
  2953. {
  2954. const uint len = snprintf(buf+1,buf_size-1,"%02d:%02d:%02d.%06lld",
  2955. sec/3600, sec/60%60, sec%60, (u64)usec%USEC_PER_SEC );
  2956. if ( len > 6 && fraction < 6 )
  2957. {
  2958. const uint pos = len - 6 + fraction;
  2959. if ( pos < buf_size )
  2960. buf[pos] = 0;
  2961. }
  2962. }
  2963. else
  2964. snprintf(buf+1,buf_size-1,"%02d:%02d:%02d",
  2965. sec/3600, sec/60%60, sec%60 );
  2966. char *ptr = buf+1;
  2967. while ( *ptr == '0' || *ptr == ':' )
  2968. ptr++;
  2969. if ( *ptr == '.' )
  2970. ptr--;
  2971. if (minus)
  2972. *--ptr = '-';
  2973. return ptr;
  2974. }
  2975. ///////////////////////////////////////////////////////////////////////////////
  2976. ccp PrintTimerNSec
  2977. (
  2978. char * buf, // result buffer (>16 bytes are good)
  2979. // If NULL, a local circulary static buffer is used
  2980. size_t buf_size, // size of 'buf', ignored if buf==NULL
  2981. s_nsec_t nsec, // nanoseconds to print
  2982. uint fraction // number of digits (0-9) to print as fraction
  2983. )
  2984. {
  2985. if ( !buf || buf_size < 4 )
  2986. buf = GetCircBuf( buf_size = 24 );
  2987. const bool minus = nsec < 0;
  2988. if (minus)
  2989. nsec = -nsec;
  2990. u32 sec = nsec / NSEC_PER_SEC;
  2991. if (fraction)
  2992. {
  2993. const uint len = snprintf(buf+1,buf_size-1,"%02d:%02d:%02d.%09lld",
  2994. sec/3600, sec/60%60, sec%60, (u64)nsec%NSEC_PER_SEC );
  2995. if ( len > 9 && fraction < 9 )
  2996. {
  2997. const uint pos = len - 9 + fraction;
  2998. if ( pos < buf_size )
  2999. buf[pos] = 0;
  3000. }
  3001. }
  3002. else
  3003. snprintf(buf+1,buf_size-1,"%02d:%02d:%02d",
  3004. sec/3600, sec/60%60, sec%60 );
  3005. char *ptr = buf+1;
  3006. while ( *ptr == '0' || *ptr == ':' )
  3007. ptr++;
  3008. if ( *ptr == '.' )
  3009. ptr--;
  3010. if (minus)
  3011. *--ptr = '-';
  3012. return ptr;
  3013. }
  3014. ///////////////////////////////////////////////////////////////////////////////
  3015. ///////////////////////////////////////////////////////////////////////////////
  3016. // [[nsec]] -> PrintTimer3U(), PrintTimer3N()
  3017. ccp PrintTimer3
  3018. (
  3019. char * buf, // result buffer (>3 bytes)
  3020. // If NULL, a local circulary static buffer is used
  3021. size_t buf_size, // size of 'buf', ignored if buf==NULL
  3022. u64 sec, // seconds to print
  3023. int usec, // 0...999999: usec fraction,
  3024. // otherwise suppress ms/us output
  3025. sizeform_mode_t mode // DC_SFORM_ALIGN | DC_SFORM_DASH
  3026. )
  3027. {
  3028. if (!buf)
  3029. buf = GetCircBuf( buf_size = 4 );
  3030. const bool aligned = mode & DC_SFORM_ALIGN;
  3031. if ( !sec && !usec && mode & DC_SFORM_DASH )
  3032. StringCopyS(buf,buf_size," -");
  3033. else if ( !sec && usec >= 0 && usec <= 999999 )
  3034. {
  3035. if (!usec)
  3036. StringCopyS(buf,buf_size,aligned?" 0":"0");
  3037. else if ( usec < 100 )
  3038. snprintf(buf,buf_size,aligned?"%2uu":"%uu",usec);
  3039. else if ( usec < 1000 )
  3040. snprintf(buf,buf_size,".%ui",usec/100);
  3041. else if ( usec < 100000 )
  3042. snprintf(buf,buf_size,aligned?"%2ui":"%ui",usec/1000);
  3043. else
  3044. snprintf(buf,buf_size,".%us",usec/100000);
  3045. }
  3046. else if ( sec < 100 )
  3047. snprintf(buf,buf_size,aligned?"%2llus":"%llus",sec);
  3048. else if ( sec < 6000 )
  3049. snprintf(buf,buf_size,aligned?"%2llum":"%llum",sec/60);
  3050. else if ( sec < 360000 )
  3051. snprintf(buf,buf_size,aligned?"%2lluh":"%lluh",sec/3600);
  3052. else
  3053. {
  3054. const u64 days = sec / (24*3600);
  3055. if ( days < 100 )
  3056. snprintf(buf,buf_size,aligned?"%2llud":"%llud",days);
  3057. else if ( days < 700 )
  3058. snprintf(buf,buf_size,aligned?"%2lluw":"%lluw",days/7);
  3059. else
  3060. {
  3061. const u32 years = days / 365;
  3062. if ( years < 100 )
  3063. snprintf(buf,buf_size,aligned?"%2uy":"%uy",years);
  3064. else
  3065. buf = "***";
  3066. }
  3067. }
  3068. return buf;
  3069. }
  3070. ///////////////////////////////////////////////////////////////////////////////
  3071. // [[nsec]] -> PrintTimer4U(), PrintTimer4N()
  3072. ccp PrintTimer4
  3073. (
  3074. char * buf, // result buffer (>4 bytes)
  3075. // If NULL, a local circulary static buffer is used
  3076. size_t buf_size, // size of 'buf', ignored if buf==NULL
  3077. u64 sec, // seconds to print
  3078. int usec, // 0...999999: usec fraction,
  3079. // otherwise suppress ms/us output
  3080. sizeform_mode_t mode // DC_SFORM_ALIGN | DC_SFORM_DASH
  3081. )
  3082. {
  3083. if (!buf)
  3084. buf = GetCircBuf( buf_size = 5 );
  3085. const bool aligned = mode & DC_SFORM_ALIGN;
  3086. if ( !sec && !usec && mode & DC_SFORM_DASH )
  3087. StringCopyS(buf,buf_size," -");
  3088. else if ( sec < 10 && usec >= 0 && usec <= 999999 )
  3089. {
  3090. if (sec)
  3091. snprintf(buf,buf_size,"%llu.%us",sec,usec/100000);
  3092. else if (!usec)
  3093. StringCopyS(buf,buf_size,aligned?" 0":"0");
  3094. else if ( usec < 1000 )
  3095. snprintf(buf,buf_size,aligned?"%3uu":"%uu",usec);
  3096. else if ( usec < 10000 )
  3097. snprintf(buf,buf_size,"%u.%ui",usec/1000,usec/100%10);
  3098. else
  3099. snprintf(buf,buf_size,aligned?"%3ui":"%ui",usec/1000);
  3100. }
  3101. else if ( sec < 600 )
  3102. snprintf(buf,buf_size,aligned?"%3llus":"%llus",sec);
  3103. else if ( sec < 36000 )
  3104. snprintf(buf,buf_size,aligned?"%3llum":"%llum",sec/60);
  3105. else if ( sec < 168*3600 )
  3106. snprintf(buf,buf_size,aligned?"%3lluh":"%lluh",sec/3600);
  3107. else
  3108. {
  3109. const u64 days = sec / (24*3600);
  3110. if ( days < 365 )
  3111. snprintf(buf,buf_size,aligned?"%3llud":"%llud",days);
  3112. else if ( days < 10*365 )
  3113. snprintf(buf,buf_size,aligned?"%3lluw":"%lluw",days/7);
  3114. else
  3115. {
  3116. const u32 years = days / 365;
  3117. if ( years < 1000 )
  3118. snprintf(buf,buf_size,aligned?"%3uy":"%uy",years);
  3119. else
  3120. buf = "****";
  3121. }
  3122. }
  3123. return buf;
  3124. }
  3125. ///////////////////////////////////////////////////////////////////////////////
  3126. ccp PrintTimer6N
  3127. (
  3128. char * buf, // result buffer (>6 bytes)
  3129. // If NULL, a local circulary static buffer is used
  3130. size_t buf_size, // size of 'buf', ignored if buf==NULL
  3131. u64 sec, // seconds to print
  3132. int nsec, // 0...999999999: nsec fraction,
  3133. // otherwise suppress ms/us/ns output
  3134. sizeform_mode_t mode // DC_SFORM_ALIGN | DC_SFORM_CENTER | DC_SFORM_DASH
  3135. )
  3136. {
  3137. if ( mode & DC_SFORM_CENTER )
  3138. {
  3139. char buf2[20];
  3140. PrintTimer6N(buf2,sizeof(buf2),sec,nsec,mode&~(DC_SFORM_CENTER|DC_SFORM_ALIGN));
  3141. return StringCenterS(buf,buf_size,buf2,6);
  3142. }
  3143. char temp[20];
  3144. if (!buf)
  3145. {
  3146. buf = temp;
  3147. buf_size = sizeof(temp);
  3148. }
  3149. const bool nsec_valid = nsec >= 0 && nsec <= 999999999;
  3150. if ( mode & DC_SFORM_ALIGN )
  3151. {
  3152. if ( !sec && !nsec && mode & DC_SFORM_DASH )
  3153. StringCopyS(buf,buf_size," -");
  3154. else if ( sec < 10 && nsec_valid )
  3155. {
  3156. u_nsec_t sum = sec *NSEC_PER_SEC + nsec;
  3157. if (!sum)
  3158. StringCopyS(buf,buf_size," 0");
  3159. else if ( sum < 10000 )
  3160. snprintf(buf,buf_size,"%4lluns",sum);
  3161. else if ( sum < 10000000 )
  3162. snprintf(buf,buf_size,"%4lluus",sum/1000);
  3163. else
  3164. snprintf(buf,buf_size,"%4llums",sum/1000000);
  3165. }
  3166. else if ( sec < 100 )
  3167. {
  3168. if (nsec_valid )
  3169. snprintf(buf,buf_size,"%2llu.%02us",sec,nsec/10000000);
  3170. else
  3171. snprintf(buf,buf_size,"%5llus",sec);
  3172. }
  3173. else if ( sec < 100*60 )
  3174. snprintf(buf,buf_size,"%2llum%02llus",sec/60,sec%60);
  3175. else if ( sec < 100*3600 )
  3176. snprintf(buf,buf_size,"%2lluh%02llum",sec/3600,sec/60%60);
  3177. else
  3178. {
  3179. const u64 days = sec / (24*3600);
  3180. if ( days < 100 )
  3181. snprintf(buf,buf_size,"%2llud%02lluh",days,sec/3600%24);
  3182. else if ( days < 7000 )
  3183. snprintf(buf,buf_size,"%3lluw%llud",days/7,days%7);
  3184. else
  3185. {
  3186. const u32 years = days / 365;
  3187. if ( years < 100 )
  3188. snprintf(buf,buf_size,"%2uy%02lluw",years,days%365/7);
  3189. else if ( years < 100000 )
  3190. snprintf(buf,buf_size,"%5uy",years);
  3191. else
  3192. buf = "******";
  3193. }
  3194. }
  3195. }
  3196. else
  3197. {
  3198. if ( !sec && !nsec && mode & DC_SFORM_DASH )
  3199. StringCopyS(buf,buf_size,"-");
  3200. else if ( sec < 10 && nsec_valid )
  3201. {
  3202. u_nsec_t sum = sec *NSEC_PER_SEC + nsec;
  3203. if (!sum)
  3204. StringCopyS(buf,buf_size,"0");
  3205. else if ( sum < 10000 )
  3206. snprintf(buf,buf_size,"%lluns",sum);
  3207. else if ( sum < 10000000 )
  3208. snprintf(buf,buf_size,"%lluus",sum/1000);
  3209. else
  3210. snprintf(buf,buf_size,"%llums",sum/1000000);
  3211. }
  3212. else if ( sec < 100 )
  3213. {
  3214. if ( nsec_valid )
  3215. {
  3216. const uint val2 = nsec/10000000;
  3217. if (val2)
  3218. snprintf(buf,buf_size,"%llu.%02us",sec,val2);
  3219. else
  3220. snprintf(buf,buf_size,"%llus",sec);
  3221. }
  3222. else
  3223. snprintf(buf,buf_size,"%llus",sec);
  3224. }
  3225. else if ( sec < 100*60 )
  3226. {
  3227. const uint val2 = sec%60;
  3228. if (val2)
  3229. snprintf(buf,buf_size,"%llum%02us",sec/60,val2);
  3230. else
  3231. snprintf(buf,buf_size,"%llum",sec/60);
  3232. }
  3233. else if ( sec < 100*3600 )
  3234. {
  3235. const uint val2 = sec/60%60;
  3236. if (val2)
  3237. snprintf(buf,buf_size,"%lluh%02um",sec/3600,val2);
  3238. else
  3239. snprintf(buf,buf_size,"%lluh",sec/3600);
  3240. }
  3241. else
  3242. {
  3243. const u64 days = sec / (24*3600);
  3244. if ( days < 100 )
  3245. {
  3246. const uint val2 = sec/3600%24;
  3247. if (val2)
  3248. snprintf(buf,buf_size,"%llud%02uh",days,val2);
  3249. else
  3250. snprintf(buf,buf_size,"%llud",days);
  3251. }
  3252. else if ( days < 7000 )
  3253. {
  3254. const uint val2 = days%7;
  3255. if (val2)
  3256. snprintf(buf,buf_size,"%lluw%ud",days/7,val2);
  3257. else
  3258. snprintf(buf,buf_size,"%lluw",days/7);
  3259. }
  3260. else
  3261. {
  3262. const u32 years = days / 365;
  3263. if ( years < 100 )
  3264. {
  3265. const uint val2 = days%365/7;
  3266. if (val2)
  3267. snprintf(buf,buf_size,"%uy%02uw",years,val2);
  3268. else
  3269. snprintf(buf,buf_size,"%uy",years);
  3270. }
  3271. else if ( years < 100000 )
  3272. snprintf(buf,buf_size,"%uy",years);
  3273. else
  3274. buf = "******";
  3275. }
  3276. }
  3277. }
  3278. return buf == temp ? CopyCircBuf0(buf,strlen(buf)) : buf;
  3279. }
  3280. ///////////////////////////////////////////////////////////////////////////////
  3281. // [[nsec]] -> PrintTimer4Us(), PrintTimer4Ns()
  3282. ccp PrintTimerUSec4s
  3283. (
  3284. char * buf, // result buffer (>4 bytes)
  3285. // If NULL, a local circulary static buffer is used
  3286. size_t buf_size, // size of 'buf', ignored if buf==NULL
  3287. s_usec_t usec, // microseconds to print
  3288. sizeform_mode_t mode // DC_SFORM_ALIGN | DC_SFORM_PLUS | DC_SFORM_DASH
  3289. )
  3290. {
  3291. if ( !buf || buf_size < 2 )
  3292. buf = GetCircBuf( buf_size = 5 );
  3293. if (!usec)
  3294. {
  3295. if ( mode & DC_SFORM_DASH )
  3296. StringCopyS(buf,buf_size, mode & DC_SFORM_ALIGN ? " -" : "-" );
  3297. else
  3298. StringCopyS(buf,buf_size, mode & DC_SFORM_ALIGN ? " 0" : "0" );
  3299. }
  3300. else
  3301. {
  3302. char sign;
  3303. if ( usec < 0 )
  3304. {
  3305. usec = -usec;
  3306. sign = '-';
  3307. }
  3308. else
  3309. sign = mode & DC_SFORM_PLUS ? '+' : ' ';
  3310. PrintTimerUSec3(buf+1,buf_size-1,usec,mode&~DC_SFORM_PLUS);
  3311. *buf = ' ';
  3312. char *ptr = buf+1;
  3313. while ( *ptr == ' ' )
  3314. ptr++;
  3315. ptr[-1] = sign;
  3316. }
  3317. return buf;
  3318. }
  3319. ///////////////////////////////////////////////////////////////////////////////
  3320. ccp PrintTimerUSec7s
  3321. (
  3322. char * buf, // result buffer (>7 bytes)
  3323. // If NULL, a local circulary static buffer is used
  3324. size_t buf_size, // size of 'buf', ignored if buf==NULL
  3325. s_usec_t usec, // microseconds to print
  3326. sizeform_mode_t mode // DC_SFORM_ALIGN | DC_SFORM_PLUS | DC_SFORM_DASH
  3327. )
  3328. {
  3329. if ( !buf || buf_size < 2 )
  3330. buf = GetCircBuf( buf_size = 8 );
  3331. if (!usec)
  3332. {
  3333. if ( mode & DC_SFORM_DASH )
  3334. StringCopyS(buf,buf_size, mode & DC_SFORM_ALIGN ? " -" : "-" );
  3335. else
  3336. StringCopyS(buf,buf_size, mode & DC_SFORM_ALIGN ? " 0" : "0" );
  3337. }
  3338. else
  3339. {
  3340. char sign;
  3341. if ( usec < 0 )
  3342. {
  3343. usec = -usec;
  3344. sign = '-';
  3345. }
  3346. else
  3347. sign = mode & DC_SFORM_PLUS ? '+' : ' ';
  3348. PrintTimerUSec6(buf+1,buf_size-1,usec, mode & DC_SFORM_ALIGN );
  3349. *buf = ' ';
  3350. char *ptr = buf+1;
  3351. while ( *ptr == ' ' )
  3352. ptr++;
  3353. ptr[-1] = sign;
  3354. }
  3355. return buf;
  3356. }
  3357. ///////////////////////////////////////////////////////////////////////////////
  3358. ccp PrintTimerNSec7s
  3359. (
  3360. char * buf, // result buffer (>7 bytes)
  3361. // If NULL, a local circulary static buffer is used
  3362. size_t buf_size, // size of 'buf', ignored if buf==NULL
  3363. s_nsec_t nsec, // nansoseconds to print
  3364. sizeform_mode_t mode // DC_SFORM_ALIGN | DC_SFORM_PLUS | DC_SFORM_DASH
  3365. )
  3366. {
  3367. if ( !buf || buf_size < 2 )
  3368. buf = GetCircBuf( buf_size = 8 );
  3369. if (!nsec)
  3370. {
  3371. if ( mode & DC_SFORM_DASH )
  3372. StringCopyS(buf,buf_size, mode & DC_SFORM_ALIGN ? " -" : "-" );
  3373. else
  3374. StringCopyS(buf,buf_size, mode & DC_SFORM_ALIGN ? " 0" : "0" );
  3375. }
  3376. else
  3377. {
  3378. char sign;
  3379. if ( nsec < 0 )
  3380. {
  3381. nsec = -nsec;
  3382. sign = '-';
  3383. }
  3384. else
  3385. sign = mode & DC_SFORM_PLUS ? '+' : ' ';
  3386. PrintTimerNSec6(buf+1,buf_size-1, nsec, mode & DC_SFORM_ALIGN );
  3387. *buf = ' ';
  3388. char *ptr = buf+1;
  3389. while ( *ptr == ' ' )
  3390. ptr++;
  3391. ptr[-1] = sign;
  3392. }
  3393. return buf;
  3394. }
  3395. ///////////////////////////////////////////////////////////////////////////////
  3396. ///////////////////////////////////////////////////////////////////////////////
  3397. ccp PrintAge3Sec
  3398. (
  3399. u_sec_t now, // NULL or current time by GetTimeSec(false)
  3400. u_sec_t time // time to print
  3401. )
  3402. {
  3403. if (!time)
  3404. return " -";
  3405. if (!now)
  3406. now = GetTimeSec(false);
  3407. now -= time;
  3408. return now < 0 ? " +" : PrintTimer3(0,0,now,-1,DC_SFORM_ALIGN);
  3409. }
  3410. ///////////////////////////////////////////////////////////////////////////////
  3411. ccp PrintAge4Sec
  3412. (
  3413. u_sec_t now, // NULL or current time by GetTimeSec(false)
  3414. u_sec_t time // time to print
  3415. )
  3416. {
  3417. if (!time)
  3418. return " -";
  3419. if (!now)
  3420. now = GetTimeSec(false);
  3421. now -= time;
  3422. return now < 0
  3423. ? PrintTimerSec4s(0,0,now,DC_SFORM_ALIGN)
  3424. : PrintTimer4(0,0,now,-1,DC_SFORM_ALIGN);
  3425. }
  3426. ///////////////////////////////////////////////////////////////////////////////
  3427. ccp PrintAge6Sec
  3428. (
  3429. u_sec_t now, // NULL or current time by GetTimeSec(false)
  3430. u_sec_t time // time to print
  3431. )
  3432. {
  3433. if (!time)
  3434. return " -";
  3435. if (!now)
  3436. now = GetTimeSec(false);
  3437. now -= time;
  3438. return now < 0 ? " +" : PrintTimerSec6(0,0,now,DC_SFORM_ALIGN);
  3439. }
  3440. ///////////////////////////////////////////////////////////////////////////////
  3441. ccp PrintAge7Sec
  3442. (
  3443. u_sec_t now, // NULL or current time by GetTimeSec(false)
  3444. u_sec_t time // time to print
  3445. )
  3446. {
  3447. if (!time)
  3448. return " -";
  3449. if (!now)
  3450. now = GetTimeSec(false);
  3451. return PrintTimerSec7s(0,0,now-time,DC_SFORM_ALIGN);
  3452. }
  3453. //
  3454. ///////////////////////////////////////////////////////////////////////////////
  3455. /////////////// scan date & time ///////////////
  3456. ///////////////////////////////////////////////////////////////////////////////
  3457. char * ScanIntervalTS
  3458. (
  3459. struct timespec *res_ts, // not NULL: store result here
  3460. ccp source // source text
  3461. )
  3462. {
  3463. uint days = 0, sec = 0, nsec = 0;
  3464. bool day_possible = true;
  3465. uint colon_count = 0;
  3466. char *src = source ? (char*)source : "";
  3467. while ( *src > 0 && *src <= ' ' )
  3468. src++;
  3469. for(;;)
  3470. {
  3471. if ( *src < '0' || *src >= '9' )
  3472. break;
  3473. ulong num = strtoul(src,&src,10);
  3474. if ( *src == 'd' && day_possible )
  3475. {
  3476. src++;
  3477. days = num;
  3478. day_possible = false;
  3479. }
  3480. else if ( *src == ':' && colon_count < 2 )
  3481. {
  3482. src++;
  3483. colon_count++;
  3484. sec = ( sec + num ) * 60;
  3485. }
  3486. else
  3487. {
  3488. sec += num;
  3489. if ( *src == '.' )
  3490. {
  3491. src++;
  3492. uint i;
  3493. for ( i = 0; i < 9; i++ )
  3494. {
  3495. nsec *= 10;
  3496. if ( *src >= '0' && *src <= '9' )
  3497. nsec += *src++ - '0';
  3498. }
  3499. while ( *src >= '0' && *src <= '9' )
  3500. src++;
  3501. }
  3502. else if ( colon_count == 1 )
  3503. sec *= 60;
  3504. }
  3505. }
  3506. if (res_ts)
  3507. {
  3508. res_ts->tv_sec = days * SEC_PER_DAY + sec;
  3509. res_ts->tv_nsec = nsec;
  3510. }
  3511. return src;
  3512. }
  3513. ///////////////////////////////////////////////////////////////////////////////
  3514. char * ScanIntervalUSec
  3515. (
  3516. u_usec_t *res_usec, // not NULL: store total microseconds
  3517. ccp source // source text
  3518. )
  3519. {
  3520. struct timespec ts;
  3521. char *res = ScanIntervalTS(&ts,source);
  3522. if (res_usec)
  3523. *res_usec = ts.tv_sec * USEC_PER_SEC + ts.tv_nsec / NSEC_PER_USEC;
  3524. return res;
  3525. }
  3526. ///////////////////////////////////////////////////////////////////////////////
  3527. char * ScanIntervalNSec
  3528. (
  3529. u_nsec_t *res_nsec, // not NULL: store total nanoseconds
  3530. ccp source // source text
  3531. )
  3532. {
  3533. struct timespec ts;
  3534. char *res = ScanIntervalTS(&ts,source);
  3535. if (res_nsec)
  3536. *res_nsec = ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
  3537. return res;
  3538. }
  3539. ///////////////////////////////////////////////////////////////////////////////
  3540. char * ScanInterval
  3541. (
  3542. time_t *res_time, // not NULL: store seconds
  3543. u32 *res_usec, // not NULL: store microseconds of second
  3544. ccp source // source text
  3545. )
  3546. {
  3547. struct timespec ts;
  3548. char *res = ScanIntervalTS(&ts,source);
  3549. if (res_time)
  3550. *res_time = ts.tv_sec;
  3551. if (res_usec)
  3552. *res_usec = ts.tv_nsec / NSEC_PER_USEC;
  3553. return res;
  3554. }
  3555. ///////////////////////////////////////////////////////////////////////////////
  3556. char * ScanInterval64
  3557. (
  3558. u64 *res_usec, // not NULL: store total microseconds
  3559. ccp source // source text
  3560. )
  3561. {
  3562. u_usec_t usec;
  3563. char *res = ScanIntervalUSec(&usec,source);
  3564. if (res_usec)
  3565. *res_usec = usec;
  3566. return res;
  3567. }
  3568. ///////////////////////////////////////////////////////////////////////////////
  3569. ///////////////////////////////////////////////////////////////////////////////
  3570. // [[nsec]]
  3571. char * ScanDateTime
  3572. (
  3573. time_t *res_time, // not NULL: store seconds here
  3574. u32 *res_usec, // not NULL: store useconds of second here
  3575. ccp source, // source text
  3576. bool allow_delta // true: allow +|- interval
  3577. )
  3578. {
  3579. //--- scan date
  3580. time_t total_time = 0;
  3581. int total_usec = 0;
  3582. ccp src = source ? source : "";
  3583. while ( *src > 0 && *src <= ' ' )
  3584. src++;
  3585. struct tm tm;
  3586. memset(&tm,0,sizeof(tm));
  3587. src = strptime(src,"%Y-%m-%d",&tm);
  3588. noPRINT(" %4u-%02u-%02u %2u:%02u:%02u |%s|\n",
  3589. tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
  3590. tm.tm_hour, tm.tm_min, tm.tm_sec, src );
  3591. if (src)
  3592. total_time = mktime(&tm);
  3593. else
  3594. src = source ? source : "";
  3595. noPRINT_TIME(total_time,"DATE");
  3596. //--- scan time
  3597. time_t time;
  3598. u32 usec;
  3599. src = ScanInterval(&time,&usec,src);
  3600. total_time += time;
  3601. total_usec += usec;
  3602. noPRINT_TIME(total_time,"TIME");
  3603. //--- scan timezone
  3604. ccp src2 = src;
  3605. while ( *src2 > 0 && *src2 <= ' ' )
  3606. src2++;
  3607. if ( ( src2[0] == '-' || src2[0] == '+' )
  3608. && src2[1] >= '0' && src2[1] <= '9'
  3609. && src2[2] >= '0' && src2[2] <= '9'
  3610. && src2[3] >= '0' && src2[3] <= '9'
  3611. && src2[4] >= '0' && src2[4] <= '9'
  3612. && ( src2[5] < '0' || src2[5] > '9' ))
  3613. {
  3614. int delta = 36000 * src2[1]
  3615. + 3600 * src2[2]
  3616. + 600 * src2[3]
  3617. + 60 * src2[4]
  3618. - 40260 * '0';
  3619. if ( src2[0] == '-' )
  3620. delta = -delta;
  3621. noPRINT("GOT TIMEZONE: %.5s => %d\n",src2,delta);
  3622. total_time -= delta + timezone;
  3623. src = src2 + 5;
  3624. }
  3625. else
  3626. {
  3627. PRINT("timezone=%ld\n",timezone);
  3628. struct tm *tm = localtime(&total_time);
  3629. if (tm->tm_isdst)
  3630. total_time -= 3600;
  3631. }
  3632. noPRINT_TIME(total_time,"ZONE");
  3633. //--- scan delta
  3634. if (allow_delta)
  3635. {
  3636. ccp src2 = src;
  3637. while ( *src2 > 0 && *src2 <= ' ' )
  3638. src2++;
  3639. bool minus = *src2 == '-';
  3640. if ( minus || *src2 == '+' )
  3641. {
  3642. src = ScanInterval(&time,&usec,src2+1);
  3643. if (minus)
  3644. {
  3645. total_time -= time;
  3646. total_usec -= usec;
  3647. }
  3648. else
  3649. {
  3650. total_time += time;
  3651. total_usec += usec;
  3652. }
  3653. }
  3654. }
  3655. if ( total_usec < 0 )
  3656. {
  3657. total_time -= ( 999999 - total_usec ) / 1000000;
  3658. total_usec = 1000000 - (-total_usec) % 1000000;
  3659. }
  3660. else if ( total_usec >= 1000000 )
  3661. {
  3662. total_time += total_usec / 1000000;
  3663. total_usec %= 1000000;
  3664. }
  3665. if (res_time)
  3666. *res_time = total_time;
  3667. if (res_usec)
  3668. *res_usec = total_usec;
  3669. return (char*)src;
  3670. }
  3671. ///////////////////////////////////////////////////////////////////////////////
  3672. // [[nsec]]
  3673. char * ScanDateTime64
  3674. (
  3675. u64 *res_usec, // not NULL: store total microseconds
  3676. ccp source, // source text
  3677. bool allow_delta // true: allow +|- interval
  3678. )
  3679. {
  3680. time_t time;
  3681. u32 usec;
  3682. char *src = ScanDateTime(&time,&usec,source,allow_delta);
  3683. if (res_usec)
  3684. *res_usec = time * 1000000ull + usec;
  3685. return src;
  3686. }
  3687. //
  3688. ///////////////////////////////////////////////////////////////////////////////
  3689. /////////////// Since 2001 ///////////////
  3690. ///////////////////////////////////////////////////////////////////////////////
  3691. // hour support
  3692. ccp hour2text
  3693. (
  3694. int hour, // hour to print
  3695. int fw, // wanted field width assuming separators are 1 char
  3696. ccp sep_date, // NULL or separator within date
  3697. // if NULL: use '-'
  3698. ccp sep_dt // NULL or separator of between date and time
  3699. // if NULL: use ' '
  3700. )
  3701. {
  3702. time_t tim = hour2time(hour);
  3703. struct tm tm;
  3704. gmtime_r(&tim,&tm);
  3705. if (!sep_date)
  3706. sep_date = "-";
  3707. if (!sep_dt)
  3708. sep_dt = " ";
  3709. return fw >= 13
  3710. ? PrintCircBuf("%04d%s%02u%s%02u%s%02u",
  3711. tm.tm_year + 1900, sep_date,
  3712. tm.tm_mon + 1, sep_date,
  3713. tm.tm_mday, sep_dt,
  3714. tm.tm_hour
  3715. )
  3716. : fw >= 11
  3717. ? PrintCircBuf("%02d%s%02u%s%02u%s%02u",
  3718. tm.tm_year % 100, sep_date,
  3719. tm.tm_mon + 1, sep_date,
  3720. tm.tm_mday, sep_dt,
  3721. tm.tm_hour
  3722. )
  3723. : fw >= 10
  3724. ? PrintCircBuf("%2u.%s%02u:xx",
  3725. tm.tm_mday, sep_dt,
  3726. tm.tm_hour
  3727. )
  3728. : PrintCircBuf("%02u%s%02u%s%02u",
  3729. tm.tm_mon + 1, sep_date,
  3730. tm.tm_mday, sep_dt,
  3731. tm.tm_hour
  3732. );
  3733. }
  3734. ///////////////////////////////////////////////////////////////////////////
  3735. ///////////////////////////////////////////////////////////////////////////
  3736. // day support
  3737. ccp day2text
  3738. (
  3739. int day, // day to print
  3740. int fw, // wanted field width assuming separators are 1 char
  3741. ccp sep_date, // NULL or separator within date
  3742. // if NULL: use '-'
  3743. ccp sep_dt // ignored
  3744. )
  3745. {
  3746. time_t tim = day2time(day);
  3747. struct tm tm;
  3748. gmtime_r(&tim,&tm);
  3749. if (!sep_date)
  3750. sep_date = "-";
  3751. return fw >= 10
  3752. ? PrintCircBuf("%04d%s%02u%s%02u",
  3753. tm.tm_year + 1900, sep_date,
  3754. tm.tm_mon + 1, sep_date,
  3755. tm.tm_mday )
  3756. : PrintCircBuf("%02d%s%02u%s%02u",
  3757. tm.tm_year % 100, sep_date,
  3758. tm.tm_mon + 1, sep_date,
  3759. tm.tm_mday );
  3760. }
  3761. ///////////////////////////////////////////////////////////////////////////
  3762. ///////////////////////////////////////////////////////////////////////////
  3763. // week support
  3764. ccp week2text
  3765. (
  3766. int week, // week to print
  3767. int fw, // wanted field width assuming separators are 1 char
  3768. ccp sep_date, // NULL or separator within date
  3769. // if NULL: use 'w'
  3770. ccp sep_dt // ignored
  3771. )
  3772. {
  3773. time_t tim = week2time(week) + 4*86400;
  3774. struct tm tm;
  3775. gmtime_r(&tim,&tm);
  3776. return PrintCircBuf("%04d%s%02u",
  3777. tm.tm_year + 1900,
  3778. sep_date ? sep_date : "w",
  3779. tm.tm_yday / 7 + 1 );
  3780. }
  3781. ///////////////////////////////////////////////////////////////////////////
  3782. ///////////////////////////////////////////////////////////////////////////
  3783. // month support
  3784. int time2month ( time_t tim )
  3785. {
  3786. struct tm tm;
  3787. gmtime_r(&tim,&tm);
  3788. return ( tm.tm_mon + 12 * tm.tm_year ) - 101*12;
  3789. }
  3790. ///////////////////////////////////////////////////////////////////////////
  3791. time_t month2time ( int month )
  3792. {
  3793. SetupTimezone(false);
  3794. struct tm tm = {0};
  3795. tm.tm_isdst = -1;
  3796. tm.tm_year = month / 12 + 101;
  3797. tm.tm_mon = month % 12;
  3798. tm.tm_mday = 1;
  3799. int delta = 43200-timezone_adjust_sec;
  3800. if ( delta < 0 )
  3801. {
  3802. delta += 86400;
  3803. tm.tm_mday++;
  3804. }
  3805. tm.tm_hour = delta / 3600;
  3806. tm.tm_min = delta / 60 % 60;
  3807. return mktime(&tm) / 86400 * 86400;
  3808. }
  3809. ///////////////////////////////////////////////////////////////////////////
  3810. ccp month2text
  3811. (
  3812. int month, // month to print
  3813. int fw, // wanted field width assuming separators are 1 char
  3814. ccp sep_date, // NULL or separator within date
  3815. // if NULL: use '-'
  3816. ccp sep_dt // ignored
  3817. )
  3818. {
  3819. month += 2001*12;
  3820. return PrintCircBuf("%4d%s%02u",
  3821. month/12,
  3822. sep_date ? sep_date : "-",
  3823. month%12 + 1 );
  3824. }
  3825. ///////////////////////////////////////////////////////////////////////////
  3826. ///////////////////////////////////////////////////////////////////////////
  3827. // quarter support
  3828. int time2quarter ( time_t tim )
  3829. {
  3830. struct tm tm;
  3831. gmtime_r(&tim,&tm);
  3832. return ( tm.tm_mon/3 + 4 * tm.tm_year ) - 101*4;
  3833. }
  3834. ///////////////////////////////////////////////////////////////////////////
  3835. time_t quarter2time ( int quarter )
  3836. {
  3837. SetupTimezone(false);
  3838. struct tm tm = {0};
  3839. tm.tm_isdst = -1;
  3840. tm.tm_year = quarter / 4 + 101;
  3841. tm.tm_mon = quarter % 4 * 3;
  3842. tm.tm_mday = 1;
  3843. int delta = 43200-timezone_adjust_sec;
  3844. if ( delta < 0 )
  3845. {
  3846. delta += 86400;
  3847. tm.tm_mday++;
  3848. }
  3849. tm.tm_hour = delta / 3600;
  3850. tm.tm_min = delta / 60 % 60;
  3851. return mktime(&tm) / 86400 * 86400;
  3852. }
  3853. ///////////////////////////////////////////////////////////////////////////
  3854. ccp quarter2text
  3855. (
  3856. int quarter, // quarter to print
  3857. int fw, // wanted field width assuming separators are 1 char
  3858. ccp sep_date, // NULL or separator within date
  3859. // if NULL: use 'q'
  3860. ccp sep_dt // ignored
  3861. )
  3862. {
  3863. quarter += 2001*4;
  3864. return PrintCircBuf("%4d%s%u",
  3865. quarter/4,
  3866. sep_date ? sep_date : "q",
  3867. quarter%4 + 1 );
  3868. }
  3869. ///////////////////////////////////////////////////////////////////////////
  3870. ///////////////////////////////////////////////////////////////////////////
  3871. // year support
  3872. int time2year ( time_t tim )
  3873. {
  3874. struct tm tm;
  3875. gmtime_r(&tim,&tm);
  3876. return tm.tm_year + 1900;
  3877. }
  3878. ///////////////////////////////////////////////////////////////////////////
  3879. time_t year2time ( int year )
  3880. {
  3881. SetupTimezone(false);
  3882. struct tm tm = {0};
  3883. tm.tm_isdst = -1;
  3884. tm.tm_year = year - 1900;
  3885. tm.tm_mday = 1;
  3886. int delta = 43200-timezone_adjust_sec;
  3887. if ( delta < 0 )
  3888. {
  3889. delta += 86400;
  3890. tm.tm_mday++;
  3891. }
  3892. tm.tm_hour = delta / 3600;
  3893. tm.tm_min = delta / 60 % 60;
  3894. return mktime(&tm) / 86400 * 86400;
  3895. }
  3896. //
  3897. ///////////////////////////////////////////////////////////////////////////////
  3898. /////////////// usage counter ///////////////
  3899. ///////////////////////////////////////////////////////////////////////////////
  3900. int usage_count_enabled = 0;
  3901. void EnableUsageCount()
  3902. {
  3903. usage_count_enabled++;
  3904. UpdateUsageByMgr(0);
  3905. }
  3906. ///////////////////////////////////////////////////////////////////////////////
  3907. const SaveRestoreTab_t SRT_UsageCount[] =
  3908. {
  3909. #undef SRT_NAME
  3910. #define SRT_NAME UsageCount_t
  3911. DEF_SRT_UINT( par.enabled, "enabled" ),
  3912. DEF_SRT_UINT( par.used, "used" ),
  3913. DEF_SRT_ARRAY_A(entry),
  3914. DEF_SRT_UINT( entry[0].count, "count" ),
  3915. DEF_SRT_UINT( entry[0].elapsed_nsec, "elapsed" ),
  3916. DEF_SRT_UINT( entry[0].time_sec, "time" ),
  3917. DEF_SRT_FLOAT( entry[0].top1s, "top1s" ),
  3918. DEF_SRT_FLOAT( entry[0].top5s, "top5s" ),
  3919. DEF_SRT_ARRAY_END(),
  3920. DEF_SRT_SEPARATOR(),
  3921. DEF_SRT_TERM()
  3922. };
  3923. ///////////////////////////////////////////////////////////////////////////////
  3924. void ClearUsageCount ( UsageCount_t *uc, int count )
  3925. {
  3926. if (!uc)
  3927. return;
  3928. uint index = CheckIndex1(uc->par.used,count);
  3929. if ( index >= uc->par.used - 1 )
  3930. return;
  3931. uc->par.used = index;
  3932. if (!index)
  3933. {
  3934. const bool enabled = uc->par.enabled;
  3935. memset( uc, 0, sizeof(*uc) );
  3936. uc->par.enabled = enabled;
  3937. }
  3938. else
  3939. {
  3940. UsageCountEntry_t *e = uc->entry + index;
  3941. memset( e, 0, PTR_DISTANCE((u8*)uc->entry+sizeof(uc->entry),e) );
  3942. }
  3943. }
  3944. ///////////////////////////////////////////////////////////////////////////////
  3945. // [[UpdateUsageCount]]
  3946. void UpdateUsageCount ( UsageCount_t *uc, u_nsec_t timer_nsec )
  3947. {
  3948. if (!uc)
  3949. return;
  3950. if ( !uc->par.enabled || usage_count_enabled <= 0 )
  3951. {
  3952. uc->ref.elapsed_nsec = 0;
  3953. uc->ref.count = 0;
  3954. uc->par.dirty = false;
  3955. return;
  3956. }
  3957. if ( !uc->par.is_active )
  3958. {
  3959. if ( !uc->par.used && !uc->ref.count )
  3960. return;
  3961. uc->par.is_active = true;
  3962. }
  3963. UsageCountEntry_t cur = {0};
  3964. cur.elapsed_nsec = timer_nsec ? timer_nsec : GetTimerNSec();
  3965. uc->par.update_nsec = uc->ref.elapsed_nsec + NSEC_PER_SEC;
  3966. if ( cur.elapsed_nsec >= uc->par.update_nsec )
  3967. {
  3968. // needed for the case that USAGE_COUNT_ENTRIES was reduced after restart!
  3969. if ( uc->par.used > USAGE_COUNT_ENTRIES )
  3970. uc->par.used = USAGE_COUNT_ENTRIES;
  3971. cur.time_sec = GetTimeSec(false);
  3972. if (uc->ref.elapsed_nsec)
  3973. {
  3974. //--- find index and move data
  3975. int index;
  3976. if ( uc->par.used < USAGE_COUNT_FIRST_ADD )
  3977. index = uc->par.used + 1;
  3978. else
  3979. {
  3980. u_nsec_t min = USAGE_COUNT_NEXT_MIN(NSEC_PER_SEC);
  3981. for ( index = USAGE_COUNT_FIRST_ADD;
  3982. index < uc->par.used;
  3983. index++, min = USAGE_COUNT_NEXT_MIN(min)
  3984. )
  3985. {
  3986. UsageCountEntry_t *e = uc->entry + index;
  3987. if ( e->elapsed_nsec < min )
  3988. {
  3989. AddUsageCountEntry(e,e-1);
  3990. index--;
  3991. break;
  3992. }
  3993. }
  3994. if ( ++index > USAGE_COUNT_ENTRIES )
  3995. index = USAGE_COUNT_ENTRIES;
  3996. }
  3997. if ( index > 1 )
  3998. memmove( uc->entry+1, uc->entry, (index-1) * sizeof(*uc->entry) );
  3999. if ( uc->par.used < index )
  4000. uc->par.used = index;
  4001. //--- update first entry
  4002. UsageCountEntry_t *e = uc->entry;
  4003. *e = uc->ref;
  4004. e->elapsed_nsec = cur.elapsed_nsec - e->elapsed_nsec;
  4005. //--- update top value (1s)
  4006. if (e->elapsed_nsec)
  4007. e->top1s = (double)( NSEC_PER_SEC * e->count ) / e->elapsed_nsec;
  4008. //--- update top value (5s)
  4009. u_nsec_t elapsed5 = 0, count5 = 0;
  4010. UsageCountEntry_t *e5 = uc->entry;
  4011. for ( int i = 0; i < uc->par.used && elapsed5 < 5*NSEC_PER_SEC; i++, e5++ )
  4012. {
  4013. elapsed5 += e5->elapsed_nsec;
  4014. count5 += e5->count;
  4015. }
  4016. if (elapsed5)
  4017. {
  4018. if ( count5 == e->count )
  4019. elapsed5 = 5*NSEC_PER_SEC;
  4020. e->top5s = (double)( NSEC_PER_SEC * count5 ) / elapsed5;
  4021. }
  4022. }
  4023. uc->ref = cur;
  4024. uc->par.update_nsec = uc->ref.elapsed_nsec + NSEC_PER_SEC;
  4025. }
  4026. uc->par.force_update_nsec = uc->ref.elapsed_nsec + NSEC_PER_MIN;
  4027. uc->par.dirty = uc->ref.count > 0;
  4028. }
  4029. ///////////////////////////////////////////////////////////////////////////////
  4030. void UpdateUsageCountIncrement ( UsageCount_t *uc )
  4031. {
  4032. DASSERT(uc);
  4033. uc->par.is_active = true;
  4034. UpdateUsageCount(uc,0);
  4035. if ( usage_count_enabled > 0 )
  4036. {
  4037. uc->ref.count++;
  4038. uc->par.dirty = true;
  4039. }
  4040. }
  4041. ///////////////////////////////////////////////////////////////////////////////
  4042. void UpdateUsageCountAdd ( UsageCount_t *uc, int add )
  4043. {
  4044. DASSERT(uc);
  4045. if ( add > 0 )
  4046. {
  4047. uc->par.is_active = true;
  4048. UpdateUsageCount(uc,0);
  4049. if ( usage_count_enabled > 0 )
  4050. {
  4051. uc->ref.count += add;
  4052. uc->par.dirty = true;
  4053. }
  4054. }
  4055. }
  4056. ///////////////////////////////////////////////////////////////////////////////
  4057. void AddUsageCountEntry ( UsageCountEntry_t *dest, const UsageCountEntry_t *add )
  4058. {
  4059. DASSERT(dest);
  4060. DASSERT(add);
  4061. dest->count += add->count;
  4062. dest->elapsed_nsec += add->elapsed_nsec;
  4063. if ( !dest->time_sec || dest->time_sec > add->time_sec )
  4064. dest->time_sec = add->time_sec;
  4065. if ( dest->top1s < add->top1s )
  4066. dest->top1s = add->top1s;
  4067. if ( dest->top5s < add->top5s )
  4068. dest->top5s = add->top5s;
  4069. }
  4070. ///////////////////////////////////////////////////////////////////////////////
  4071. UsageCountEntry_t GetUsageCount ( const UsageCount_t *uc, s_nsec_t nsec )
  4072. {
  4073. DASSERT(uc);
  4074. UsageCountEntry_t res = {0};
  4075. const UsageCountEntry_t *e = uc->entry;
  4076. for ( int i = 0; i < uc->par.used && nsec > 0; i++, e++ )
  4077. {
  4078. nsec -= e->elapsed_nsec;
  4079. AddUsageCountEntry(&res,e);
  4080. }
  4081. return res;
  4082. }
  4083. ///////////////////////////////////////////////////////////////////////////////
  4084. ///////////////////////////////////////////////////////////////////////////////
  4085. PointerList_t usage_count_mgr = { .used = 0, .grow = 10 };
  4086. ///////////////////////////////////////////////////////////////////////////////
  4087. u_nsec_t MaintainUsageByMgr ( u_nsec_t now_nsec )
  4088. {
  4089. // returns delta time to next maintenance based on GetTimerNSec()
  4090. if (!now_nsec)
  4091. now_nsec = GetTimerNSec();
  4092. u_nsec_t next_nsec = now_nsec + NSEC_PER_MIN;
  4093. for ( int i = 0; i < usage_count_mgr.used; i++ )
  4094. {
  4095. const UsageCtrl_t *uci = usage_count_mgr.list[i];
  4096. if (!uci)
  4097. continue;
  4098. const UsageParam_t *par = GetUsageParam(uci);
  4099. if (par)
  4100. {
  4101. if ( par->dirty && par->update_nsec && par->update_nsec <= now_nsec
  4102. || par->force_update_nsec && par->force_update_nsec <= now_nsec )
  4103. {
  4104. UpdateByUCI(uci,now_nsec);
  4105. }
  4106. if ( par->dirty && par->update_nsec && next_nsec > par->update_nsec )
  4107. next_nsec = par->update_nsec;
  4108. }
  4109. }
  4110. return next_nsec;
  4111. }
  4112. ///////////////////////////////////////////////////////////////////////////////
  4113. void UpdateByUCI ( const UsageCtrl_t *uci, u_nsec_t now_nsec )
  4114. {
  4115. if (uci)
  4116. {
  4117. if (uci->update_func)
  4118. uci->update_func(uci,now_nsec);
  4119. else if (uci->uc)
  4120. UpdateUsageCount(uci->uc,now_nsec);
  4121. else if (uci->ud)
  4122. UpdateUsageDuration(uci->ud,now_nsec);
  4123. }
  4124. }
  4125. ///////////////////////////////////////////////////////////////////////////////
  4126. void UpdateUsageByMgr ( u_nsec_t timer_nsec )
  4127. {
  4128. if (!timer_nsec)
  4129. timer_nsec = GetTimerNSec();
  4130. for ( int i = 0; i < usage_count_mgr.used; i++ )
  4131. {
  4132. const UsageCtrl_t *uci = usage_count_mgr.list[i];
  4133. if (uci)
  4134. {
  4135. if (uci->uc)
  4136. UpdateUsageCount(uci->uc,timer_nsec);
  4137. else if (uci->ud)
  4138. UpdateUsageDuration(uci->ud,timer_nsec);
  4139. }
  4140. }
  4141. }
  4142. ///////////////////////////////////////////////////////////////////////////////
  4143. #if 0
  4144. static int sort_usage_count ( const UsageCtrl_t *a, const UsageCtrl_t *b )
  4145. {
  4146. DASSERT( a && b );
  4147. return strcmp(a->key1,b->key1);
  4148. }
  4149. #endif
  4150. //-----------------------------------------------------------------------------
  4151. void AddToUsageMgr ( const UsageCtrl_t *uci )
  4152. {
  4153. if ( !uci || !uci->key1 )
  4154. return;
  4155. // no duplicates!
  4156. for ( int i = 0; i < usage_count_mgr.used; i++ )
  4157. {
  4158. const UsageCtrl_t *uci2 = usage_count_mgr.list[i];
  4159. if ( uci2 && ( uci2->uc && uci2->uc == uci->uc || uci2->ud && uci2->ud == uci->ud ))
  4160. return;
  4161. }
  4162. AddToPointerMgr(&usage_count_mgr,uci);
  4163. #if 0
  4164. qsort( usage_count_mgr.list, usage_count_mgr.used,
  4165. sizeof(*usage_count_mgr.list), (qsort_func)sort_usage_count );
  4166. #endif
  4167. }
  4168. ///////////////////////////////////////////////////////////////////////////////
  4169. ///////////////////////////////////////////////////////////////////////////////
  4170. void SaveCurrentStateByUsageCountMgr ( FILE *f, uint fw_name )
  4171. {
  4172. DASSERT(f);
  4173. const u_nsec_t timer_nsec = GetTimerNSec();
  4174. void **ucip = usage_count_mgr.list;
  4175. for ( int i = 0; i < usage_count_mgr.used; i++, ucip++ )
  4176. {
  4177. UsageCtrl_t *uci = *ucip;
  4178. if (uci)
  4179. {
  4180. UpdateUsageCount(uci->uc,timer_nsec);
  4181. if (uci->srt_prefix)
  4182. {
  4183. if (uci->uc)
  4184. SaveCurrentStateByTable(f,uci->uc,SRT_UsageCount,uci->srt_prefix,fw_name);
  4185. else if (uci->ud)
  4186. SaveCurrentStateByTable(f,uci->ud,SRT_UsageDuration,uci->srt_prefix,fw_name);
  4187. }
  4188. }
  4189. }
  4190. }
  4191. ///////////////////////////////////////////////////////////////////////////////
  4192. void RestoreStateByUsageCountMgr ( RestoreState_t *rs )
  4193. {
  4194. DASSERT(rs);
  4195. void **ucip = usage_count_mgr.list;
  4196. for ( int i = 0; i < usage_count_mgr.used; i++, ucip++ )
  4197. {
  4198. UsageCtrl_t *uci = *ucip;
  4199. if (uci)
  4200. {
  4201. if (uci->uc)
  4202. {
  4203. UsageCount_t *uc = uci->uc;
  4204. if (uci->srt_load)
  4205. RestoreStateByTable(rs,uc,SRT_UsageCount,uci->srt_load);
  4206. if (uci->srt_prefix)
  4207. RestoreStateByTable(rs,uc,SRT_UsageCount,uci->srt_prefix);
  4208. // needed for the case that USAGE_COUNT_ENTRIES was reduced after restart!
  4209. if ( uc->par.used > USAGE_COUNT_ENTRIES )
  4210. uc->par.used = USAGE_COUNT_ENTRIES;
  4211. }
  4212. else if (uci->ud)
  4213. {
  4214. UsageDuration_t *ud = uci->ud;
  4215. if (uci->srt_load)
  4216. RestoreStateByTable(rs,ud,SRT_UsageDuration,uci->srt_load);
  4217. if (uci->srt_prefix)
  4218. RestoreStateByTable(rs,ud,SRT_UsageDuration,uci->srt_prefix);
  4219. // needed for the case that USAGE_COUNT_ENTRIES was reduced after restart!
  4220. if ( ud->par.used > USAGE_COUNT_ENTRIES )
  4221. ud->par.used = USAGE_COUNT_ENTRIES;
  4222. }
  4223. }
  4224. }
  4225. }
  4226. //
  4227. ///////////////////////////////////////////////////////////////////////////////
  4228. /////////////// wait counter ///////////////
  4229. ///////////////////////////////////////////////////////////////////////////////
  4230. const SaveRestoreTab_t SRT_UsageDuration[] =
  4231. {
  4232. #undef SRT_NAME
  4233. #define SRT_NAME UsageDuration_t
  4234. DEF_SRT_UINT( par.enabled, "enabled" ),
  4235. DEF_SRT_UINT( par.used, "used" ),
  4236. DEF_SRT_ARRAY_A(entry),
  4237. DEF_SRT_UINT( entry[0].elapsed_nsec, "elapsed" ),
  4238. DEF_SRT_UINT( entry[0].total_nsec, "total" ),
  4239. DEF_SRT_UINT( entry[0].top_nsec, "top" ),
  4240. DEF_SRT_UINT( entry[0].count, "count" ),
  4241. DEF_SRT_UINT( entry[0].time_sec, "time" ),
  4242. DEF_SRT_FLOAT( entry[0].top_cnt_1s, "top-c1" ),
  4243. DEF_SRT_FLOAT( entry[0].top_cnt_5s, "top-c5" ),
  4244. DEF_SRT_ARRAY_END(),
  4245. DEF_SRT_SEPARATOR(),
  4246. DEF_SRT_TERM()
  4247. };
  4248. ///////////////////////////////////////////////////////////////////////////////
  4249. // n_rec<0: clear from end, n_rec>=0: clear from index
  4250. void ClearUsageDuration ( UsageDuration_t *ud, int count )
  4251. {
  4252. if (!ud)
  4253. return;
  4254. uint index = CheckIndex1(ud->par.used,count);
  4255. if ( index >= ud->par.used - 1 )
  4256. return;
  4257. ud->par.used = index;
  4258. if (!index)
  4259. {
  4260. const bool enabled = ud->par.enabled;
  4261. memset( ud, 0, sizeof(*ud) );
  4262. ud->par.enabled = enabled;
  4263. }
  4264. else
  4265. {
  4266. UsageDurationEntry_t *e = ud->entry + index;
  4267. memset( e, 0, PTR_DISTANCE((u8*)ud->entry+sizeof(ud->entry),e) );
  4268. }
  4269. }
  4270. ///////////////////////////////////////////////////////////////////////////////
  4271. // [[UpdateUsageDuration]]
  4272. // TIMER_NSEC: 0 or GetTimerNSec(), but not GetTime*()
  4273. void UpdateUsageDuration ( UsageDuration_t *ud, u_nsec_t timer_nsec )
  4274. {
  4275. if (!ud)
  4276. return;
  4277. if ( !ud->par.enabled || usage_count_enabled <= 0 )
  4278. {
  4279. ud->ref.elapsed_nsec = 0;
  4280. ud->ref.count = 0;
  4281. ud->par.dirty = false;
  4282. return;
  4283. }
  4284. if ( !ud->par.is_active )
  4285. {
  4286. if ( !ud->par.used && !ud->ref.count )
  4287. return;
  4288. ud->par.is_active = true;
  4289. }
  4290. UsageDurationEntry_t cur = {0};
  4291. cur.elapsed_nsec = timer_nsec ? timer_nsec : GetTimerNSec();
  4292. ud->par.update_nsec = ud->ref.elapsed_nsec + NSEC_PER_SEC;
  4293. if ( cur.elapsed_nsec >= ud->par.update_nsec )
  4294. {
  4295. // needed for the case that USAGE_COUNT_ENTRIES was reduced after restart!
  4296. if ( ud->par.used > USAGE_COUNT_ENTRIES )
  4297. ud->par.used = USAGE_COUNT_ENTRIES;
  4298. cur.time_sec = GetTimeSec(false);
  4299. if (ud->ref.elapsed_nsec)
  4300. {
  4301. //--- find index and move data
  4302. int index;
  4303. if ( ud->par.used < USAGE_COUNT_FIRST_ADD )
  4304. index = ud->par.used + 1;
  4305. else
  4306. {
  4307. u_nsec_t min = USAGE_COUNT_NEXT_MIN(NSEC_PER_SEC);
  4308. for ( index = USAGE_COUNT_FIRST_ADD;
  4309. index < ud->par.used;
  4310. index++, min = USAGE_COUNT_NEXT_MIN(min)
  4311. )
  4312. {
  4313. UsageDurationEntry_t *e = ud->entry + index;
  4314. if ( e->elapsed_nsec < min )
  4315. {
  4316. AddUsageDurationEntry(e,e-1);
  4317. index--;
  4318. break;
  4319. }
  4320. }
  4321. if ( ++index > USAGE_COUNT_ENTRIES )
  4322. index = USAGE_COUNT_ENTRIES;
  4323. }
  4324. if ( index > 1 )
  4325. memmove( ud->entry+1, ud->entry, (index-1) * sizeof(*ud->entry) );
  4326. if ( ud->par.used < index )
  4327. ud->par.used = index;
  4328. //--- update first entry
  4329. UsageDurationEntry_t *e = ud->entry;
  4330. *e = ud->ref;
  4331. e->elapsed_nsec = cur.elapsed_nsec - e->elapsed_nsec;
  4332. //--- update top value (1s)
  4333. if (e->elapsed_nsec)
  4334. e->top_cnt_1s = (double)( NSEC_PER_SEC * e->count ) / e->elapsed_nsec;
  4335. //--- update top value (5s)
  4336. u_nsec_t elapsed5 = 0, count5 = 0;
  4337. UsageDurationEntry_t *e5 = ud->entry;
  4338. for ( int i = 0; i < ud->par.used && elapsed5 < 5*NSEC_PER_SEC; i++, e5++ )
  4339. {
  4340. elapsed5 += e5->elapsed_nsec;
  4341. count5 += e5->count;
  4342. }
  4343. if (elapsed5)
  4344. {
  4345. if ( count5 == e->count )
  4346. elapsed5 = 5*NSEC_PER_SEC;
  4347. e->top_cnt_5s = (double)( NSEC_PER_SEC * count5 ) / elapsed5;
  4348. }
  4349. }
  4350. ud->ref = cur;
  4351. ud->par.update_nsec = ud->ref.elapsed_nsec + NSEC_PER_SEC;
  4352. }
  4353. ud->par.force_update_nsec = ud->ref.elapsed_nsec + NSEC_PER_MIN;
  4354. ud->par.dirty = ud->ref.count > 0;
  4355. }
  4356. ///////////////////////////////////////////////////////////////////////////////
  4357. void UpdateUsageDurationAdd
  4358. ( UsageDuration_t *ud, int add, u_nsec_t wait_nsec, u_nsec_t top_nsec )
  4359. {
  4360. DASSERT(ud);
  4361. ud->par.is_active = true;
  4362. UpdateUsageDuration(ud,0);
  4363. if ( add > 0 && usage_count_enabled > 0 )
  4364. {
  4365. ud->par.dirty = true;
  4366. ud->ref.count += add;
  4367. ud->ref.total_nsec += wait_nsec;
  4368. if ( ud->ref.top_nsec < top_nsec )
  4369. ud->ref.top_nsec = top_nsec;
  4370. }
  4371. }
  4372. ///////////////////////////////////////////////////////////////////////////////
  4373. void UpdateUsageDurationIncrement ( UsageDuration_t *ud, u_nsec_t wait_nsec )
  4374. {
  4375. DASSERT(ud);
  4376. ud->par.is_active = true;
  4377. UpdateUsageDuration(ud,0);
  4378. if ( usage_count_enabled > 0 )
  4379. {
  4380. ud->par.dirty = true;
  4381. ud->ref.count++;
  4382. ud->ref.total_nsec += wait_nsec;
  4383. if ( ud->ref.top_nsec < wait_nsec )
  4384. ud->ref.top_nsec = wait_nsec;
  4385. }
  4386. }
  4387. ///////////////////////////////////////////////////////////////////////////////
  4388. void UsageDurationIncrement ( UsageDuration_t *ud, u_nsec_t wait_nsec )
  4389. {
  4390. DASSERT(ud);
  4391. ud->par.is_active = true;
  4392. if ( usage_count_enabled > 0 )
  4393. {
  4394. ud->par.dirty = true;
  4395. ud->ref.count++;
  4396. ud->ref.total_nsec += wait_nsec;
  4397. if ( ud->ref.top_nsec < wait_nsec )
  4398. ud->ref.top_nsec = wait_nsec;
  4399. }
  4400. }
  4401. ///////////////////////////////////////////////////////////////////////////////
  4402. UsageDurationEntry_t GetUsageDuration ( const UsageDuration_t *ud, s_nsec_t nsec )
  4403. {
  4404. DASSERT(ud);
  4405. UsageDurationEntry_t res = {0};
  4406. const UsageDurationEntry_t *e = ud->entry;
  4407. for ( int i = 0; i < ud->par.used && nsec > 0; i++, e++ )
  4408. {
  4409. nsec -= e->elapsed_nsec;
  4410. AddUsageDurationEntry(&res,e);
  4411. }
  4412. return res;
  4413. }
  4414. ///////////////////////////////////////////////////////////////////////////////
  4415. void AddUsageDurationEntry ( UsageDurationEntry_t *dest, const UsageDurationEntry_t *add )
  4416. {
  4417. DASSERT(dest);
  4418. DASSERT(add);
  4419. dest->count += add->count;
  4420. dest->elapsed_nsec += add->elapsed_nsec;
  4421. dest->total_nsec += add->total_nsec;
  4422. if ( !dest->time_sec || dest->time_sec > add->time_sec )
  4423. dest->time_sec = add->time_sec;
  4424. if ( dest->top_nsec < add->top_nsec )
  4425. dest->top_nsec = add->top_nsec;
  4426. if ( dest->top_cnt_1s < add->top_cnt_1s )
  4427. dest->top_cnt_1s = add->top_cnt_1s;
  4428. if ( dest->top_cnt_5s < add->top_cnt_5s )
  4429. dest->top_cnt_5s = add->top_cnt_5s;
  4430. }
  4431. //
  4432. ///////////////////////////////////////////////////////////////////////////////
  4433. /////////////// list usage count/wait ///////////////
  4434. ///////////////////////////////////////////////////////////////////////////////
  4435. static ccp print_usage_count_val ( double val, const float *color_val )
  4436. {
  4437. if ( val <= 0 )
  4438. return " -";
  4439. static const float color_val0[] = { 100, 200, 300, 500, 1000, 2000 };
  4440. if (!color_val)
  4441. color_val = color_val0;
  4442. if ( val > color_val[0] || val >= 9999.9994 )
  4443. {
  4444. ccp col = val < color_val[2]
  4445. ? ( val < color_val[1] ? colout->mark : colout->info )
  4446. : val < color_val[4]
  4447. ? ( val < color_val[3] ? colout->hint : colout->warn )
  4448. : ( val < color_val[5] ? colout->err : colout->bad );
  4449. return val < 9999.9994
  4450. ? PrintCircBuf("%s%8.3f%s",col,val,colout->reset)
  4451. : val < 999999.94
  4452. ? PrintCircBuf("%s%8.1f%s",col,val,colout->reset)
  4453. : PrintCircBuf("%s%8.0f%s",col,val,colout->reset);
  4454. }
  4455. char *res = PrintCircBuf("%8.3f",val);
  4456. if ( val < 1.0 && res[3] == '0' )
  4457. res[3] = ' ';
  4458. return res;
  4459. }
  4460. //-----------------------------------------------------------------------------
  4461. static ccp print_usage_count
  4462. ( u32 n_wait, u_nsec_t elapsed_nsec, const float *color_val )
  4463. {
  4464. return elapsed_nsec
  4465. ? print_usage_count_val( (double)( NSEC_PER_SEC * n_wait ) / elapsed_nsec, color_val )
  4466. : " ×";
  4467. }
  4468. //-----------------------------------------------------------------------------
  4469. static ccp print_usage_dur_val ( u_nsec_t dur, const u_nsec_t *color_dur )
  4470. {
  4471. if (!dur)
  4472. return " -";
  4473. ccp res = PrintTimerNSec6(0,0,dur,DC_SFORM_ALIGN);
  4474. static const u_nsec_t color_dur0[] =
  4475. {
  4476. 10 * NSEC_PER_MSEC, // mark
  4477. 50 * NSEC_PER_MSEC, // info
  4478. 200 * NSEC_PER_MSEC, // hint
  4479. NSEC_PER_SEC, // warn
  4480. 8 * NSEC_PER_SEC, // err
  4481. NSEC_PER_MIN, // bad
  4482. };
  4483. if (!color_dur)
  4484. color_dur = color_dur0;
  4485. if ( dur > color_dur[0] )
  4486. {
  4487. ccp col = dur < color_dur[2]
  4488. ? ( dur < color_dur[1] ? colout->mark : colout->info )
  4489. : dur < color_dur[4]
  4490. ? ( dur < color_dur[3] ? colout->hint : colout->warn )
  4491. : ( dur < color_dur[5] ? colout->err : colout->bad );
  4492. return PrintCircBuf("%s%s%s",col,res,colout->reset);
  4493. }
  4494. return res;
  4495. }
  4496. //-----------------------------------------------------------------------------
  4497. static ccp print_usage_dur
  4498. ( u_nsec_t total, u64 count, const u_nsec_t *color_dur )
  4499. {
  4500. return count
  4501. ? print_usage_dur_val( total/count, color_dur )
  4502. : " -";
  4503. }
  4504. //
  4505. ///////////////////////////////////////////////////////////////////////////////
  4506. void ListUsageCount
  4507. (
  4508. PrintMode_t *p_pm, // NULL or print mode
  4509. const UsageCtrl_t *uci, // NULL or object to list
  4510. int print_mode, // see LUC_PM_*
  4511. s_nsec_t limit_nsec // >0: limit output until # is reached
  4512. )
  4513. {
  4514. if (!uci)
  4515. return;
  4516. if (uci->list_func)
  4517. {
  4518. uci->list_func(p_pm,uci,print_mode,limit_nsec);
  4519. return;
  4520. }
  4521. if (!uci->uc)
  4522. {
  4523. if (uci->ud)
  4524. ListUsageDuration(p_pm,uci,print_mode,limit_nsec);
  4525. return;
  4526. }
  4527. //--- setup
  4528. PrintMode_t pm = {0};
  4529. if (p_pm)
  4530. pm = *p_pm;
  4531. SetupPrintMode(&pm);
  4532. if ( limit_nsec <= 0 )
  4533. limit_nsec = S_NSEC_MAX;
  4534. UsageCount_t *uc = uci->uc;
  4535. fprintf(pm.fout,"%s%s%*s %s%s (%u record%s%s%s)%s%s",
  4536. pm.compact ? "" : pm.eol, pm.prefix, pm.indent, "",
  4537. pm.cout->caption, uci->title,
  4538. uc->par.used, uc->par.used == 1 ? "" : "s",
  4539. usage_count_enabled > 0 ? "" : ", global disabled",
  4540. uc->par.enabled ? "" : ", disabled",
  4541. pm.cout->reset, pm.eol );
  4542. if (!uc->par.used)
  4543. return;
  4544. //--- print table
  4545. UsageCountEntry_t sum = {0};
  4546. u_sec_t reftime = 0;
  4547. u_nsec_t min = USAGE_COUNT_NEXT_MIN(NSEC_PER_SEC);
  4548. if ( print_mode == LUC_PM_SUMMARY )
  4549. {
  4550. fprintf(pm.fout,
  4551. "%s%*s%s╔════════╦════════╤═════════╤══════════╦═══════════╤═══════════╗%s"
  4552. "%s%*s%s║ range ║ period │ counter │ count/s ║ top~1s /s │ top~5s /s ║%s"
  4553. "%s%*s%s╠════════╬════════╪═════════╪══════════╬═══════════╪═══════════╣%s%s"
  4554. ,pm.prefix ,pm.indent,"" ,colout->heading ,pm.eol
  4555. ,pm.prefix ,pm.indent,"" ,colout->heading ,pm.eol
  4556. ,pm.prefix ,pm.indent,"" ,colout->heading ,colout->reset ,pm.eol
  4557. );
  4558. const IntervalInfo_t *interval = interval_info;
  4559. const UsageCountEntry_t *e = uc->entry;
  4560. for ( int i = 0; i < uc->par.used; i++, e++ )
  4561. {
  4562. AddUsageCountEntry(&sum,e);
  4563. bool is_last = false;
  4564. const bool is_limit = sum.elapsed_nsec >= limit_nsec;
  4565. if ( sum.elapsed_nsec < interval->nsec )
  4566. {
  4567. is_last = i+1 == uc->par.used;
  4568. if ( !is_last && !is_limit )
  4569. continue;
  4570. }
  4571. ccp name;
  4572. if ( is_last || sum.elapsed_nsec < interval->nsec )
  4573. name = "*";
  4574. else
  4575. {
  4576. while ( sum.elapsed_nsec > interval->nsec )
  4577. interval++;
  4578. name = interval[-1].name;
  4579. }
  4580. fprintf(pm.fout,
  4581. "%s%*s%s║%s %-6.6s %s║%s %s %s│%s %s %s│%s %s %s║%s"
  4582. ,pm.prefix ,pm.indent,""
  4583. ,colout->heading, colout->reset
  4584. ,name
  4585. ,colout->heading, colout->reset
  4586. ,PrintTimerNSec6(0,0,sum.elapsed_nsec,DC_SFORM_ALIGN|DC_SFORM_DASH)
  4587. ,colout->heading, colout->reset
  4588. ,PrintNumberU7(0,0,sum.count,DC_SFORM_ALIGN|DC_SFORM_DASH)
  4589. ,colout->heading, colout->reset
  4590. ,print_usage_count(sum.count,sum.elapsed_nsec,uci->color_val)
  4591. ,colout->heading, colout->reset
  4592. );
  4593. fprintf(pm.fout,
  4594. " %s %s│%s %s %s║%s"
  4595. ,print_usage_count_val(sum.top1s,uci->color_val)
  4596. ,colout->heading, colout->reset
  4597. ,print_usage_count_val(sum.top5s,uci->color_val)
  4598. ,colout->heading, colout->reset
  4599. );
  4600. if (pm.debug)
  4601. fprintf(pm.flog," %2u%s",i,pm.eol);
  4602. else
  4603. fputs(pm.eol,pm.fout);
  4604. if ( is_limit || !interval->name )
  4605. break;
  4606. }
  4607. fprintf(pm.fout,
  4608. "%s ╚════════╩════════╧═════════╧══════════╩═══════════╧═══════════╝%s%s"
  4609. ,colout->heading ,colout->reset ,pm.eol );
  4610. }
  4611. else
  4612. {
  4613. fprintf(pm.fout,
  4614. "%s%*s%s╔═══════════╦═════════════════════════════╦══════════╦══════════╦═════════════════════════════╗%s"
  4615. "%s%*s%s║ ║ Single Record ║ top 1s ║ top 5s ║ Summed Values ║%s"
  4616. "%s%*s%s║ real time ║ period │ counter │ count/s ║ count/s ║ count/s ║ period │ counter │ count/s ║%s"
  4617. "%s%*s%s╠═══════════╬════════╪═════════╪══════════╬══════════╬══════════╬════════╪═════════╪══════════╣%s%s"
  4618. ,pm.prefix ,pm.indent,"" ,colout->heading ,pm.eol
  4619. ,pm.prefix ,pm.indent,"" ,colout->heading ,pm.eol
  4620. ,pm.prefix ,pm.indent,"" ,colout->heading ,pm.eol
  4621. ,pm.prefix ,pm.indent,"" ,colout->heading ,colout->reset ,pm.eol
  4622. );
  4623. const IntervalInfo_t *interval = interval_info+1;
  4624. const UsageCountEntry_t *e = uc->entry;
  4625. #if TEST_USAGE_COUNT
  4626. for ( int i = 0; i <= uc->par.used && sum.elapsed_nsec < limit_nsec; i++, e++ )
  4627. #else
  4628. for ( int i = 0; i < uc->par.used && sum.elapsed_nsec < limit_nsec; i++, e++ )
  4629. #endif
  4630. {
  4631. AddUsageCountEntry(&sum,e);
  4632. if ( i > 0 && ( sum.elapsed_nsec >= interval->nsec || i == USAGE_COUNT_FIRST_ADD ))
  4633. {
  4634. fprintf(pm.fout,
  4635. "%s ╟───────────╫────────┼─────────┼──────────╫"
  4636. "──────────╫──────────╫"
  4637. "────────┼─────────┼──────────╢%s%s",
  4638. colout->heading, colout->reset, pm.eol );
  4639. while ( sum.elapsed_nsec >= interval->nsec )
  4640. interval++;
  4641. }
  4642. fprintf(pm.fout,
  4643. "%s%*s%s║%s%s %s║%s %s %s│%s %s %s│%s %s %s║%s"
  4644. ,pm.prefix ,pm.indent,""
  4645. ,colout->heading, colout->reset
  4646. ,PrintRefTime(e->time_sec,&reftime)
  4647. ,colout->heading, colout->reset
  4648. ,PrintTimerNSec6(0,0,e->elapsed_nsec,DC_SFORM_ALIGN|DC_SFORM_DASH)
  4649. ,colout->heading, colout->reset
  4650. ,PrintNumberU7(0,0,e->count,DC_SFORM_ALIGN|DC_SFORM_DASH)
  4651. ,colout->heading, colout->reset
  4652. ,print_usage_count(e->count,e->elapsed_nsec,uci->color_val)
  4653. ,colout->heading, colout->reset
  4654. );
  4655. fprintf(pm.fout,
  4656. " %s %s║%s %s %s║%s"
  4657. ,print_usage_count_val(e->top1s,uci->color_val)
  4658. ,colout->heading, colout->reset
  4659. ,print_usage_count_val(e->top5s,uci->color_val)
  4660. ,colout->heading, colout->reset
  4661. );
  4662. fprintf(pm.fout,
  4663. " %s %s│%s %s %s│%s %s %s║%s"
  4664. ,PrintTimerNSec6(0,0,sum.elapsed_nsec,DC_SFORM_ALIGN|DC_SFORM_DASH)
  4665. ,colout->heading, colout->reset
  4666. ,PrintNumberU7(0,0,sum.count,DC_SFORM_ALIGN|DC_SFORM_DASH)
  4667. ,colout->heading, colout->reset
  4668. ,print_usage_count(sum.count,sum.elapsed_nsec,uci->color_val)
  4669. ,colout->heading, colout->reset
  4670. );
  4671. if (pm.debug)
  4672. {
  4673. if ( pm.debug >= 2 && i >= USAGE_COUNT_FIRST_ADD )
  4674. {
  4675. fprintf(pm.flog," %2u %s %s%4llu%%%s %s%5llu%%%s%s",
  4676. i,
  4677. PrintTimerNSec6(0,0,min,DC_SFORM_ALIGN|DC_SFORM_DASH),
  4678. e->elapsed_nsec < min ? ""
  4679. : e->elapsed_nsec < min*2 ? colout->hint : colout->warn,
  4680. 100 * e->elapsed_nsec / min, colout->reset,
  4681. sum.elapsed_nsec < min ? colout->info : "",
  4682. 100 * sum.elapsed_nsec / min, colout->reset, pm.eol );
  4683. min = USAGE_COUNT_NEXT_MIN(min);
  4684. }
  4685. else
  4686. fprintf(pm.flog," %2u%s",i,pm.eol);
  4687. }
  4688. else
  4689. fputs(pm.eol,pm.fout);
  4690. }
  4691. fprintf(pm.fout,
  4692. "%s ╚═══════════╩════════╧═════════╧══════════╩"
  4693. "══════════╩══════════╩"
  4694. "════════╧═════════╧══════════╝%s%s"
  4695. ,colout->heading ,colout->reset ,pm.eol );
  4696. }
  4697. }
  4698. //
  4699. ///////////////////////////////////////////////////////////////////////////////
  4700. void ListUsageDuration
  4701. (
  4702. PrintMode_t *p_pm, // NULL or print mode
  4703. const UsageCtrl_t *uci, // NULL or object to list
  4704. int print_mode, // see LUC_PM_*
  4705. s_nsec_t limit_nsec // >0: limit output until # is reached
  4706. )
  4707. {
  4708. if (!uci)
  4709. return;
  4710. if (uci->list_func)
  4711. {
  4712. uci->list_func(p_pm,uci,print_mode,limit_nsec);
  4713. return;
  4714. }
  4715. if (!uci->ud)
  4716. {
  4717. if (uci->uc)
  4718. ListUsageCount(p_pm,uci,print_mode,limit_nsec);
  4719. return;
  4720. }
  4721. //--- setup
  4722. PrintMode_t pm = {0};
  4723. if (p_pm)
  4724. pm = *p_pm;
  4725. SetupPrintMode(&pm);
  4726. if ( limit_nsec <= 0 )
  4727. limit_nsec = S_NSEC_MAX;
  4728. UsageDuration_t *ud = uci->ud;
  4729. fprintf(pm.fout,"%s%s%*s %s%s (%u record%s%s%s)%s%s",
  4730. pm.compact ? "" : pm.eol, pm.prefix, pm.indent, "",
  4731. pm.cout->caption, uci->title,
  4732. ud->par.used, ud->par.used == 1 ? "" : "s",
  4733. usage_count_enabled > 0 ? "" : ", global disabled",
  4734. ud->par.enabled ? "" : ", disabled",
  4735. pm.cout->reset, pm.eol );
  4736. if (!ud->par.used)
  4737. return;
  4738. //--- print table
  4739. UsageDurationEntry_t sum = {0};
  4740. u_sec_t reftime = 0;
  4741. u_nsec_t min = USAGE_COUNT_NEXT_MIN(NSEC_PER_SEC);
  4742. if ( print_mode == LUC_PM_SUMMARY )
  4743. {
  4744. printf(
  4745. "%s ╔════════╦═════════════════════════════════════╦═════════╤═════════╤════════╗%s"
  4746. "%s ║ ║ Summed Record ║ top 1s │ top 5s │ top ║%s"
  4747. "%s ║ range ║ period │ counter │ count/s │ Ø time ║ count/s │ count/s │ time ║%s"
  4748. "%s ╠════════╬════════╪═════════╪═════════╪════════╬═════════╪═════════╪════════╣%s%s"
  4749. ,colout->heading, pm.eol
  4750. ,colout->heading, pm.eol
  4751. ,colout->heading, pm.eol
  4752. ,colout->heading ,colout->reset, pm.eol
  4753. );
  4754. const IntervalInfo_t *interval = interval_info;
  4755. const UsageDurationEntry_t *e = ud->entry;
  4756. for ( int i = 0; i < ud->par.used; i++, e++ )
  4757. {
  4758. AddUsageDurationEntry(&sum,e);
  4759. bool is_last = false;
  4760. const bool is_limit = sum.elapsed_nsec >= limit_nsec;
  4761. if ( sum.elapsed_nsec < interval->nsec )
  4762. {
  4763. is_last = i+1 == ud->par.used;
  4764. if ( !is_last && !is_limit )
  4765. continue;
  4766. }
  4767. ccp name;
  4768. if ( is_last || sum.elapsed_nsec < interval->nsec )
  4769. name = "*";
  4770. else
  4771. {
  4772. while ( sum.elapsed_nsec > interval->nsec )
  4773. interval++;
  4774. name = interval[-1].name;
  4775. }
  4776. if ( i > 0 && ( sum.elapsed_nsec >= interval->nsec || i == USAGE_COUNT_FIRST_ADD ))
  4777. {
  4778. fprintf(pm.fout,
  4779. "%s ╟───────────╫────────┼─────────┼─────────┼────────╫"
  4780. "─────────┼────────╫─────────┼────────╫"
  4781. "────────┼─────────┼─────────┼────────╢%s%s",
  4782. colout->heading, colout->reset, pm.eol );
  4783. while ( sum.elapsed_nsec >= interval->nsec )
  4784. interval++;
  4785. }
  4786. fprintf(pm.fout,
  4787. "%s%*s%s║%s %-6.6s %s║%s %s %s│%s %s %s│%s%s %s│%s %s %s║%s"
  4788. ,pm.prefix ,pm.indent,""
  4789. ,colout->heading, colout->reset
  4790. ,name
  4791. ,colout->heading, colout->reset
  4792. ,PrintTimerNSec6(0,0,sum.elapsed_nsec,DC_SFORM_ALIGN|DC_SFORM_DASH)
  4793. ,colout->heading, colout->reset
  4794. ,PrintNumberU7(0,0,sum.count,DC_SFORM_ALIGN|DC_SFORM_DASH)
  4795. ,colout->heading, colout->reset
  4796. ,print_usage_count(sum.count,sum.elapsed_nsec,uci->color_val)
  4797. ,colout->heading, colout->reset
  4798. ,print_usage_dur(sum.total_nsec,sum.count,uci->color_dur)
  4799. ,colout->heading, colout->reset
  4800. );
  4801. fprintf(pm.fout,
  4802. "%s %s│%s%s %s│%s %s %s║%s"
  4803. ,print_usage_count_val(sum.top_cnt_1s,uci->color_val)
  4804. ,colout->heading, colout->reset
  4805. ,print_usage_count_val(sum.top_cnt_5s,uci->color_val)
  4806. ,colout->heading, colout->reset
  4807. ,print_usage_dur_val(sum.top_nsec,uci->color_dur)
  4808. ,colout->heading, colout->reset
  4809. );
  4810. if (pm.debug)
  4811. fprintf(pm.flog," %2u%s",i,pm.eol);
  4812. else
  4813. fputs(pm.eol,pm.fout);
  4814. if ( is_limit || !interval->name )
  4815. break;
  4816. }
  4817. fprintf(pm.fout,
  4818. "%s ╚════════╩════════╧═════════╧═════════╧════════╩"
  4819. "═════════╧═════════╧════════╝%s%s"
  4820. ,colout->heading ,colout->reset ,pm.eol );
  4821. }
  4822. else
  4823. {
  4824. printf(
  4825. "%s ╔═══════════╦═════════════════════════════════════╦═════════╤═════════╤════════╦═════════════════════════════════════╗%s"
  4826. "%s ║ ║ Single Record ║ top 1s │ top 5s │ top ║ Summed Values ║%s"
  4827. "%s ║ real time ║ period │ counter │ count/s │ Ø time ║ count/s │ count/s │ time ║ period │ counter │ count/s │ Ø time ║%s"
  4828. "%s ╠═══════════╬════════╪═════════╪═════════╪════════╬═════════╪═════════╪════════╬════════╪═════════╪═════════╪════════╣%s%s"
  4829. ,colout->heading, pm.eol
  4830. ,colout->heading, pm.eol
  4831. ,colout->heading, pm.eol
  4832. ,colout->heading ,colout->reset, pm.eol
  4833. );
  4834. const IntervalInfo_t *interval = interval_info+1;
  4835. const UsageDurationEntry_t *e = ud->entry;
  4836. #if TEST_USAGE_COUNT
  4837. for ( int i = 0; i <= ud->par.used && sum.elapsed_nsec < limit_nsec; i++, e++ )
  4838. #else
  4839. for ( int i = 0; i < ud->par.used && sum.elapsed_nsec < limit_nsec; i++, e++ )
  4840. #endif
  4841. {
  4842. AddUsageDurationEntry(&sum,e);
  4843. if ( i > 0 && ( sum.elapsed_nsec >= interval->nsec || i == USAGE_COUNT_FIRST_ADD ))
  4844. {
  4845. fprintf(pm.fout,
  4846. "%s ╟───────────╫────────┼─────────┼─────────┼────────╫"
  4847. "─────────┼─────────┼────────╫"
  4848. "────────┼─────────┼─────────┼────────╢%s%s",
  4849. colout->heading, colout->reset, pm.eol );
  4850. while ( sum.elapsed_nsec >= interval->nsec )
  4851. interval++;
  4852. }
  4853. fprintf(pm.fout,
  4854. "%s%*s%s║%s%s %s║%s %s %s│%s %s %s│%s%s %s│%s %s %s║%s"
  4855. ,pm.prefix ,pm.indent,""
  4856. ,colout->heading, colout->reset
  4857. ,PrintRefTime(e->time_sec,&reftime)
  4858. ,colout->heading, colout->reset
  4859. ,PrintTimerNSec6(0,0,e->elapsed_nsec,DC_SFORM_ALIGN|DC_SFORM_DASH)
  4860. ,colout->heading, colout->reset
  4861. ,PrintNumberU7(0,0,e->count,DC_SFORM_ALIGN|DC_SFORM_DASH)
  4862. ,colout->heading, colout->reset
  4863. ,print_usage_count(e->count,e->elapsed_nsec,uci->color_val)
  4864. ,colout->heading, colout->reset
  4865. ,print_usage_dur(e->total_nsec,e->count,uci->color_dur)
  4866. ,colout->heading, colout->reset
  4867. );
  4868. fprintf(pm.fout,
  4869. "%s %s│%s%s %s│%s %s %s║%s"
  4870. ,print_usage_count_val(e->top_cnt_1s,uci->color_val)
  4871. ,colout->heading, colout->reset
  4872. ,print_usage_count_val(e->top_cnt_5s,uci->color_val)
  4873. ,colout->heading, colout->reset
  4874. ,print_usage_dur_val(e->top_nsec,uci->color_dur)
  4875. ,colout->heading, colout->reset
  4876. );
  4877. fprintf(pm.fout,
  4878. " %s %s│%s %s %s│%s%s %s│%s %s %s║%s"
  4879. ,PrintTimerNSec6(0,0,sum.elapsed_nsec,DC_SFORM_ALIGN|DC_SFORM_DASH)
  4880. ,colout->heading, colout->reset
  4881. ,PrintNumberU7(0,0,sum.count,DC_SFORM_ALIGN|DC_SFORM_DASH)
  4882. ,colout->heading, colout->reset
  4883. ,print_usage_count(sum.count,sum.elapsed_nsec,uci->color_val)
  4884. ,colout->heading, colout->reset
  4885. ,print_usage_dur(sum.total_nsec,sum.count,uci->color_dur)
  4886. ,colout->heading, colout->reset
  4887. );
  4888. if (pm.debug)
  4889. {
  4890. if ( pm.debug >= 2 && i >= USAGE_COUNT_FIRST_ADD )
  4891. {
  4892. fprintf(pm.flog," %2u %s %s%4llu%%%s %s%5llu%%%s%s",
  4893. i,
  4894. PrintTimerNSec6(0,0,min,DC_SFORM_ALIGN|DC_SFORM_DASH),
  4895. e->elapsed_nsec < min ? ""
  4896. : e->elapsed_nsec < min*2 ? colout->hint : colout->warn,
  4897. 100 * e->elapsed_nsec / min, colout->reset,
  4898. sum.elapsed_nsec < min ? colout->info : "",
  4899. 100 * sum.elapsed_nsec / min, colout->reset, pm.eol );
  4900. min = USAGE_COUNT_NEXT_MIN(min);
  4901. }
  4902. else
  4903. fprintf(pm.flog," %2u%s",i,pm.eol);
  4904. }
  4905. else
  4906. fputs(pm.eol,pm.fout);
  4907. }
  4908. fprintf(pm.fout,
  4909. "%s ╚═══════════╩════════╧═════════╧═════════╧════════╩"
  4910. "═════════╧═════════╧════════╩"
  4911. "════════╧═════════╧═════════╧════════╝%s%s"
  4912. ,colout->heading ,colout->reset ,pm.eol );
  4913. }
  4914. }
  4915. //
  4916. ///////////////////////////////////////////////////////////////////////////////
  4917. /////////////// cpu usage ///////////////
  4918. ///////////////////////////////////////////////////////////////////////////////
  4919. CpuUsage_t cpu_usage = { .par.used=0, .par.enabled = CPU_USAGE_ENABLED };
  4920. const UsageCtrl_t cpu_usage_ctrl =
  4921. {
  4922. .par = &cpu_usage.par,
  4923. .update_func = UpdateCpuUsageByUCI,
  4924. .list_func = ListCpuUsage,
  4925. .title = "CPU usage (extern)",
  4926. .key1 = "CPU",
  4927. };
  4928. ///////////////////////////////////////////////////////////////////////////////
  4929. static ccp print_cpu_percent ( double val )
  4930. {
  4931. if (!val)
  4932. return " -";
  4933. //static const double collist[] = { 40, 60, 80, 95 };
  4934. static const double collist[] = { 25, 50, 75, 95 };
  4935. if ( val >= collist[0] )
  4936. {
  4937. ccp col = val < collist[2]
  4938. ? ( val < collist[1] ? colout->info : colout->hint )
  4939. : ( val < collist[3] ? colout->warn : colout->err );
  4940. return PrintCircBuf("%s%6.2f%s", col, val, colout->reset );
  4941. }
  4942. char *res = PrintCircBuf("%6.2f",val);
  4943. if ( val < 1.0 && res[2] == '0' )
  4944. res[2] = ' ';
  4945. return res;
  4946. }
  4947. //-----------------------------------------------------------------------------
  4948. static ccp print_cpu_seconds ( u_usec_t val )
  4949. {
  4950. return !val
  4951. ? " -"
  4952. : val < USEC_PER_SEC
  4953. ? PrintCircBuf("%8llu",val)
  4954. : val < 10*USEC_PER_SEC
  4955. ? PrintCircBuf("%llu.%06llu",val/USEC_PER_SEC,val%USEC_PER_SEC)
  4956. : PrintCircBuf("%4llu.%03llu",val/USEC_PER_SEC,val%USEC_PER_SEC/1000);
  4957. }
  4958. //-----------------------------------------------------------------------------
  4959. static ccp print_cpu_wait_val ( double val )
  4960. {
  4961. static const double collist[] = { 100, 150, 200, 250, 300, 350 };
  4962. if ( val > collist[0] )
  4963. {
  4964. if ( val >= 999.0 )
  4965. return PrintCircBuf(" %s%6.0f%s",colout->fatal,val,colout->reset);
  4966. ccp col = val < collist[2]
  4967. ? ( val < collist[1] ? colout->mark : colout->info )
  4968. : val < collist[4]
  4969. ? ( val < collist[3] ? colout->hint : colout->warn )
  4970. : ( val < collist[5] ? colout->err : colout->bad );
  4971. return PrintCircBuf("%s%7.2f%s",col,val,colout->reset);
  4972. }
  4973. if ( val <= 0 )
  4974. return " -";
  4975. char * res = PrintCircBuf("%7.2f",val);
  4976. if ( val < 1.0 && res[3] == '0' )
  4977. res[3] = ' ';
  4978. return res;
  4979. }
  4980. //-----------------------------------------------------------------------------
  4981. static ccp print_cpu_wait ( u32 n_wait, u_usec_t elapsed_usec )
  4982. {
  4983. return elapsed_usec
  4984. ? print_cpu_wait_val( (double)( USEC_PER_SEC * n_wait ) / elapsed_usec )
  4985. : " ×";
  4986. }
  4987. //-----------------------------------------------------------------------------
  4988. static void print_cpu_debug
  4989. ( int idx, u_usec_t *min, u_usec_t elapsed1, u_usec_t elapsed2 )
  4990. {
  4991. DASSERT(min);
  4992. if ( idx >= CPU_USAGE_FIRST_ADD && *min )
  4993. {
  4994. printf(" %2u %s %s%4llu%%%s %s%4llu%%%s\n",
  4995. idx,
  4996. PrintTimerUSec6(0,0,*min,DC_SFORM_ALIGN|DC_SFORM_DASH),
  4997. elapsed1 < *min ? "" : elapsed1 < *min*2 ? colout->hint : colout->warn,
  4998. 100 * elapsed1 / *min, colout->reset,
  4999. elapsed2 < *min ? colout->info : "", 100 * elapsed2 / *min, colout->reset );
  5000. *min = CPU_USAGE_NEXT_MIN(*min);
  5001. }
  5002. else
  5003. printf(" %2u\n",idx);
  5004. }
  5005. ///////////////////////////////////////////////////////////////////////////////
  5006. void ListCpuUsage
  5007. (
  5008. PrintMode_t *p_pm, // NULL or print mode
  5009. const UsageCtrl_t *uci, // ignored!
  5010. int print_mode, // see LUC_PM_*
  5011. s_nsec_t limit_nsec // >0: limit output until # is reached
  5012. )
  5013. {
  5014. //--- setup
  5015. PrintMode_t pm = {0};
  5016. if (p_pm)
  5017. pm = *p_pm;
  5018. SetupPrintMode(&pm);
  5019. const u_usec_t limit_usec = limit_nsec > 0 ? limit_nsec/NSEC_PER_USEC : S_USEC_MAX;
  5020. //--- print header
  5021. const ccp empty_line = pm.compact ? "" : "\n";
  5022. printf("%s%s CPU Usage (%u record%s%s)%s\n",
  5023. empty_line, colout->caption,
  5024. cpu_usage.par.used, cpu_usage.par.used == 1 ? "" : "s",
  5025. cpu_usage.par.enabled ? "" : ", disabled", colout->reset );
  5026. if (!cpu_usage.par.used)
  5027. return;
  5028. //--- print table
  5029. CpuUsageEntry_t sum = {0};
  5030. u_sec_t reftime = 0;
  5031. u_usec_t min = CPU_USAGE_NEXT_MIN(USEC_PER_SEC);
  5032. if ( print_mode == LUC_PM_SUMMARY )
  5033. {
  5034. printf(
  5035. "%s ╔════════╦═════════════════════════════════════════╦════════════════╦════════════════╗\n"
  5036. "%s ║ ║ Summed Values ║ top 1s ║ top 5s ║\n"
  5037. "%s ║ range ║ period │ user%% │system%%│total%% │ wait/s ║total%% │ wait/s ║total%% │ wait/s ║\n"
  5038. "%s ╠════════╬════════╪═══════╪═══════╪═══════╪════════╬═══════╪════════╬═══════╪════════╣%s\n"
  5039. ,colout->heading
  5040. ,colout->heading
  5041. ,colout->heading
  5042. ,colout->heading ,colout->reset
  5043. );
  5044. const IntervalInfo_t *interval = interval_info;
  5045. const CpuUsageEntry_t *e = cpu_usage.entry;
  5046. for ( int i = 0; i < cpu_usage.par.used; i++, e++ )
  5047. {
  5048. AddCpuEntry(&sum,e);
  5049. bool is_last = false;
  5050. const bool is_limit = sum.elapsed_usec >= limit_usec;
  5051. if ( sum.elapsed_usec < interval->usec )
  5052. {
  5053. is_last = i+1 == cpu_usage.par.used;
  5054. if ( !is_last && !is_limit )
  5055. continue;
  5056. }
  5057. ccp name;
  5058. if ( is_last || sum.elapsed_usec < interval->usec )
  5059. name = "*";
  5060. else
  5061. {
  5062. while ( sum.elapsed_usec > interval->usec )
  5063. interval++;
  5064. name = interval[-1].name;
  5065. }
  5066. const double elapsed = 100.0 / sum.elapsed_usec;
  5067. printf(" %s║%s %-6.6s %s║%s %s %s│%s%s %s│%s%s %s│%s%s %s│%s%s %s║%s"
  5068. ,colout->heading, colout->reset
  5069. ,name
  5070. ,colout->heading, colout->reset
  5071. ,PrintTimerUSec6(0,0,sum.elapsed_usec,DC_SFORM_ALIGN|DC_SFORM_DASH)
  5072. ,colout->heading, colout->reset
  5073. ,print_cpu_percent(sum.utime_usec * elapsed)
  5074. ,colout->heading, colout->reset
  5075. ,print_cpu_percent(sum.stime_usec * elapsed)
  5076. ,colout->heading, colout->reset
  5077. ,print_cpu_percent(( sum.utime_usec + sum.stime_usec) * elapsed)
  5078. ,colout->heading, colout->reset
  5079. ,print_cpu_wait(sum.n_wait,sum.elapsed_usec)
  5080. ,colout->heading, colout->reset
  5081. );
  5082. printf("%s %s│%s%s %s║%s%s %s│%s%s %s║%s"
  5083. ,print_cpu_percent(sum.top1s)
  5084. ,colout->heading, colout->reset
  5085. ,print_cpu_wait_val(sum.topw1s)
  5086. ,colout->heading, colout->reset
  5087. ,print_cpu_percent(sum.top5s)
  5088. ,colout->heading, colout->reset
  5089. ,print_cpu_wait_val(sum.topw5s)
  5090. ,colout->heading, colout->reset
  5091. );
  5092. if (pm.debug)
  5093. fprintf(pm.flog," %2u%s",i,pm.eol);
  5094. else
  5095. fputs(pm.eol,pm.fout);
  5096. if ( is_limit || !interval->name )
  5097. break;
  5098. }
  5099. printf(
  5100. "%s ╚════════╩════════╧═══════╧═══════╧═══════╧════════╩"
  5101. "═══════╧════════╩═══════╧════════╝%s%s%s",
  5102. colout->heading ,colout->reset, pm.eol, empty_line );
  5103. }
  5104. else if ( print_mode == LUC_PM_RAW )
  5105. {
  5106. printf(
  5107. "%s ╔═══════════╦══════════════════════════════════════════════════╦══════════════════════════════════════════════════╗\n"
  5108. "%s ║ ║ Single Record (µs) ║ Summed Values (µs) ║\n"
  5109. "%s ║ real time ║ period │ user │ system │ total │ wait/s ║ period │ user │ system │ total │ wait/s ║\n"
  5110. "%s ╠═══════════╬════════╪══════════╪══════════╪══════════╪════════╬════════╪══════════╪══════════╪══════════╪════════╣%s\n"
  5111. ,colout->heading
  5112. ,colout->heading
  5113. ,colout->heading
  5114. ,colout->heading ,colout->reset
  5115. );
  5116. const IntervalInfo_t *interval = interval_info+1;
  5117. for ( int i = 0; i < cpu_usage.par.used && sum.elapsed_usec < limit_usec; i++ )
  5118. {
  5119. const CpuUsageEntry_t *e = cpu_usage.entry+i;
  5120. AddCpuEntry(&sum,e);
  5121. if ( i > 0 && ( sum.elapsed_usec >= interval->usec || i == CPU_USAGE_FIRST_ADD ))
  5122. {
  5123. printf(
  5124. "%s ╟───────────╫────────┼──────────┼──────────┼──────────┼────────╫"
  5125. "────────┼──────────┼──────────┼──────────┼────────╢%s\n",
  5126. colout->heading, colout->reset );
  5127. while ( sum.elapsed_usec >= interval->usec )
  5128. interval++;
  5129. }
  5130. printf(" %s║%s%s %s║%s %s %s│%s %s %s│%s %s %s│%s %s %s│%s%s %s║%s"
  5131. ,colout->heading, colout->reset
  5132. ,PrintRefTime(e->time_sec,&reftime)
  5133. ,colout->heading, colout->reset
  5134. ,PrintTimerUSec6(0,0,e->elapsed_usec,DC_SFORM_ALIGN|DC_SFORM_DASH)
  5135. ,colout->heading, colout->reset
  5136. ,print_cpu_seconds(e->utime_usec)
  5137. ,colout->heading, colout->reset
  5138. ,print_cpu_seconds(e->stime_usec)
  5139. ,colout->heading, colout->reset
  5140. ,print_cpu_seconds( e->utime_usec + e->stime_usec )
  5141. ,colout->heading, colout->reset
  5142. ,print_cpu_wait(e->n_wait,e->elapsed_usec)
  5143. ,colout->heading, colout->reset
  5144. );
  5145. printf(" %s %s│%s %s %s│%s %s %s│%s %s %s│%s%s %s║%s"
  5146. ,PrintTimerUSec6(0,0,sum.elapsed_usec,DC_SFORM_ALIGN|DC_SFORM_DASH)
  5147. ,colout->heading, colout->reset
  5148. ,print_cpu_seconds(sum.utime_usec)
  5149. ,colout->heading, colout->reset
  5150. ,print_cpu_seconds(sum.stime_usec)
  5151. ,colout->heading, colout->reset
  5152. ,print_cpu_seconds( sum.utime_usec + sum.stime_usec )
  5153. ,colout->heading, colout->reset
  5154. ,print_cpu_wait(sum.n_wait,sum.elapsed_usec)
  5155. ,colout->heading, colout->reset
  5156. );
  5157. if (pm.debug)
  5158. print_cpu_debug(i,&min,e->elapsed_usec,sum.elapsed_usec);
  5159. else
  5160. putchar('\n');
  5161. }
  5162. printf(
  5163. "%s ╚═══════════╩════════╧══════════╧══════════╧══════════╧════════╩"
  5164. "════════╧══════════╧══════════╧══════════╧════════╝%s\n%s",
  5165. colout->heading, colout->reset, empty_line );
  5166. }
  5167. else
  5168. {
  5169. printf(
  5170. "%s ╔═══════════╦═════════════════════════════════════════╦════════════════╦════════════════╦═════════════════════════════════════════╗\n"
  5171. "%s ║ ║ Single Record ║ top 1s ║ top 5s ║ Summed Values ║\n"
  5172. "%s ║ real time ║ period │ user%% │system%%│total%% │ wait/s ║total%% │ wait/s ║total%% │ wait/s ║ period │ user%% │system%%│total%% │ wait/s ║\n"
  5173. "%s ╠═══════════╬════════╪═══════╪═══════╪═══════╪════════╬═══════╪════════╬═══════╪════════╬════════╪═══════╪═══════╪═══════╪════════╣%s\n"
  5174. ,colout->heading
  5175. ,colout->heading
  5176. ,colout->heading
  5177. ,colout->heading ,colout->reset
  5178. );
  5179. const IntervalInfo_t *interval = interval_info+1;
  5180. #if TEST_USAGE_COUNT
  5181. for ( int i = 0; i <= cpu_usage.par.used && sum.elapsed_usec < limit_usec; i++ )
  5182. #else
  5183. for ( int i = 0; i < cpu_usage.par.used && sum.elapsed_usec < limit_usec; i++ )
  5184. #endif
  5185. {
  5186. const CpuUsageEntry_t *e = cpu_usage.entry+i;
  5187. AddCpuEntry(&sum,e);
  5188. if ( i > 0 && ( sum.elapsed_usec >= interval->usec || i == CPU_USAGE_FIRST_ADD ))
  5189. {
  5190. printf(
  5191. "%s ╟───────────╫────────┼───────┼───────┼───────┼────────╫"
  5192. "───────┼────────╫───────┼────────╫"
  5193. "────────┼───────┼───────┼───────┼────────╢%s\n",
  5194. colout->heading, colout->reset );
  5195. while ( sum.elapsed_usec >= interval->usec )
  5196. interval++;
  5197. }
  5198. double elapsed = 100.0 / e->elapsed_usec;
  5199. printf(" %s║%s%s %s║%s %s %s│%s%s %s│%s%s %s│%s%s %s│%s%s %s║%s"
  5200. ,colout->heading, colout->reset
  5201. ,PrintRefTime(e->time_sec,&reftime)
  5202. ,colout->heading, colout->reset
  5203. ,PrintTimerUSec6(0,0,e->elapsed_usec,DC_SFORM_ALIGN|DC_SFORM_DASH)
  5204. ,colout->heading, colout->reset
  5205. ,print_cpu_percent(e->utime_usec * elapsed)
  5206. ,colout->heading, colout->reset
  5207. ,print_cpu_percent(e->stime_usec * elapsed)
  5208. ,colout->heading, colout->reset
  5209. ,print_cpu_percent(( e->utime_usec + e->stime_usec) * elapsed)
  5210. ,colout->heading, colout->reset
  5211. ,print_cpu_wait(e->n_wait,e->elapsed_usec)
  5212. ,colout->heading, colout->reset
  5213. );
  5214. printf("%s %s│%s%s %s║%s%s %s│%s%s %s║%s"
  5215. ,print_cpu_percent(e->top1s)
  5216. ,colout->heading, colout->reset
  5217. ,print_cpu_wait_val(e->topw1s)
  5218. ,colout->heading, colout->reset
  5219. ,print_cpu_percent(e->top5s)
  5220. ,colout->heading, colout->reset
  5221. ,print_cpu_wait_val(e->topw5s)
  5222. ,colout->heading, colout->reset
  5223. );
  5224. elapsed = 100.0 / sum.elapsed_usec;
  5225. printf(" %s %s│%s%s %s│%s%s %s│%s%s %s│%s%s %s║%s"
  5226. ,PrintTimerUSec6(0,0,sum.elapsed_usec,DC_SFORM_ALIGN|DC_SFORM_DASH)
  5227. ,colout->heading, colout->reset
  5228. ,print_cpu_percent(sum.utime_usec * elapsed)
  5229. ,colout->heading, colout->reset
  5230. ,print_cpu_percent(sum.stime_usec * elapsed)
  5231. ,colout->heading, colout->reset
  5232. ,print_cpu_percent(( sum.utime_usec + sum.stime_usec) * elapsed)
  5233. ,colout->heading, colout->reset
  5234. ,print_cpu_wait(sum.n_wait,sum.elapsed_usec)
  5235. ,colout->heading, colout->reset
  5236. );
  5237. if (pm.debug)
  5238. print_cpu_debug(i,&min,e->elapsed_usec,sum.elapsed_usec);
  5239. else
  5240. putchar('\n');
  5241. }
  5242. printf(
  5243. "%s ╚═══════════╩════════╧═══════╧═══════╧═══════╧════════╩"
  5244. "═══════╧════════╩═══════╧════════╩"
  5245. "════════╧═══════╧═══════╧═══════╧════════╝%s%s",
  5246. colout->heading, colout->reset, empty_line );
  5247. }
  5248. }
  5249. ///////////////////////////////////////////////////////////////////////////////
  5250. const SaveRestoreTab_t SRT_CpuUsage[] =
  5251. {
  5252. #undef SRT_NAME
  5253. #define SRT_NAME CpuUsage_t
  5254. DEF_SRT_COMMENT("cpu_usage"),
  5255. DEF_SRT_SEPARATOR(),
  5256. DEF_SRT_INT( par.enabled, "cpu-enabled" ),
  5257. DEF_SRT_UINT( par.used, "cpu-used" ),
  5258. DEF_SRT_ARRAY_A(entry),
  5259. DEF_SRT_UINT( entry[0].elapsed_usec, "cpu-elapsed" ),
  5260. DEF_SRT_UINT( entry[0].utime_usec, "cpu-utime" ),
  5261. DEF_SRT_UINT( entry[0].stime_usec, "cpu-stime" ),
  5262. DEF_SRT_UINT( entry[0].time_sec, "cpu-rtime" ),
  5263. DEF_SRT_FLOAT( entry[0].top1s, "cpu-top1s" ),
  5264. DEF_SRT_FLOAT( entry[0].top5s, "cpu-top5s" ),
  5265. DEF_SRT_UINT( entry[0].n_wait, "cpu-nwait" ),
  5266. DEF_SRT_FLOAT( entry[0].topw1s, "cpu-topw1s" ),
  5267. DEF_SRT_FLOAT( entry[0].topw5s, "cpu-topw5s" ),
  5268. DEF_SRT_ARRAY_END(),
  5269. DEF_SRT_SEPARATOR(),
  5270. DEF_SRT_TERM()
  5271. };
  5272. //-----------------------------------------------------------------------------
  5273. // [[UpdateCpuUsage]]
  5274. void UpdateCpuUsageByUCI ( const UsageCtrl_t *uci, u_nsec_t now_nsec )
  5275. {
  5276. UpdateCpuUsage();
  5277. }
  5278. //-----------------------------------------------------------------------------
  5279. void UpdateCpuUsage()
  5280. {
  5281. if (!cpu_usage.par.enabled)
  5282. {
  5283. cpu_usage.ref.elapsed_usec = 0;
  5284. cpu_usage.ref.n_wait = 0;
  5285. return;
  5286. }
  5287. cpu_usage.par.is_active = true;
  5288. CpuUsageEntry_t cur = {0};
  5289. cur.elapsed_usec = GetTimerUSec();
  5290. if ( cur.elapsed_usec >= cpu_usage.ref.elapsed_usec + USEC_PER_SEC )
  5291. {
  5292. // needed for the case that CPU_USAGE_ENTRIES was reduced after restart!
  5293. if ( cpu_usage.par.used > CPU_USAGE_ENTRIES )
  5294. cpu_usage.par.used = CPU_USAGE_ENTRIES;
  5295. struct rusage ru;
  5296. if (!getrusage(RUSAGE_SELF,&ru))
  5297. {
  5298. cur.time_sec = GetTimeSec(false);
  5299. cur.utime_usec = ru.ru_utime.tv_sec * USEC_PER_SEC + ru.ru_utime.tv_usec;
  5300. cur.stime_usec = ru.ru_stime.tv_sec * USEC_PER_SEC + ru.ru_stime.tv_usec;
  5301. if (cpu_usage.ref.elapsed_usec)
  5302. {
  5303. //--- find index and move data
  5304. int index;
  5305. if ( cpu_usage.par.used < CPU_USAGE_FIRST_ADD )
  5306. index = cpu_usage.par.used + 1;
  5307. else
  5308. {
  5309. u_usec_t min = CPU_USAGE_NEXT_MIN(USEC_PER_SEC);
  5310. for ( index = CPU_USAGE_FIRST_ADD;
  5311. index < cpu_usage.par.used;
  5312. index++, min = CPU_USAGE_NEXT_MIN(min)
  5313. )
  5314. {
  5315. CpuUsageEntry_t *e = cpu_usage.entry + index;
  5316. if ( e->elapsed_usec < min )
  5317. {
  5318. AddCpuEntry(e,e-1);
  5319. index--;
  5320. break;
  5321. }
  5322. }
  5323. if ( ++index > CPU_USAGE_ENTRIES )
  5324. index = CPU_USAGE_ENTRIES;
  5325. }
  5326. if ( index > 1 )
  5327. memmove( cpu_usage.entry+1, cpu_usage.entry,
  5328. (index-1) * sizeof(*cpu_usage.entry) );
  5329. if ( cpu_usage.par.used < index )
  5330. cpu_usage.par.used = index;
  5331. //--- update first entry
  5332. CpuUsageEntry_t *e = cpu_usage.entry;
  5333. *e = cpu_usage.ref;
  5334. e->elapsed_usec = cur.elapsed_usec - cpu_usage.ref.elapsed_usec;
  5335. e->utime_usec = cur.utime_usec - cpu_usage.ref.utime_usec;
  5336. e->stime_usec = cur.stime_usec - cpu_usage.ref.stime_usec;
  5337. //--- update top values (1s)
  5338. if (e->elapsed_usec)
  5339. {
  5340. e->top1s = 100.0 * ( e->utime_usec + e->stime_usec ) / e->elapsed_usec;
  5341. e->topw1s = (double)( USEC_PER_SEC * e->n_wait ) / e->elapsed_usec;
  5342. }
  5343. //--- update top values (5s)
  5344. u_usec_t elapsed5 = 0, total5 = 0, wait5 = 0;
  5345. CpuUsageEntry_t *e5 = cpu_usage.entry;
  5346. for ( int i = 0; i < cpu_usage.par.used && elapsed5 < 5*USEC_PER_SEC; i++, e5++ )
  5347. {
  5348. elapsed5 += e5->elapsed_usec;
  5349. total5 += e5->utime_usec + e5->stime_usec;
  5350. wait5 += e5->n_wait;
  5351. }
  5352. if (elapsed5)
  5353. {
  5354. if ( wait5 == e->n_wait && total5 == e->utime_usec + e->stime_usec )
  5355. elapsed5 = 5*NSEC_PER_SEC;
  5356. e->top5s = 100.0 * total5 / elapsed5;
  5357. e->topw5s = (double)( USEC_PER_SEC * wait5 ) / elapsed5;
  5358. }
  5359. }
  5360. cpu_usage.ref = cur;
  5361. }
  5362. }
  5363. }
  5364. //-----------------------------------------------------------------------------
  5365. void UpdateCpuUsageIncrement()
  5366. {
  5367. UpdateCpuUsage();
  5368. cpu_usage.ref.n_wait++;
  5369. }
  5370. //-----------------------------------------------------------------------------
  5371. void AddCpuEntry ( CpuUsageEntry_t *dest, const CpuUsageEntry_t *add )
  5372. {
  5373. DASSERT(dest);
  5374. DASSERT(add);
  5375. dest->elapsed_usec += add->elapsed_usec;
  5376. dest->utime_usec += add->utime_usec;
  5377. dest->stime_usec += add->stime_usec;
  5378. dest->n_wait += add->n_wait;
  5379. if ( !dest->time_sec || dest->time_sec > add->time_sec )
  5380. dest->time_sec = add->time_sec;
  5381. if ( dest->top1s < add->top1s )
  5382. dest->top1s = add->top1s;
  5383. if ( dest->top5s < add->top5s )
  5384. dest->top5s = add->top5s;
  5385. if ( dest->topw1s < add->topw1s )
  5386. dest->topw1s = add->topw1s;
  5387. if ( dest->topw5s < add->topw5s )
  5388. dest->topw5s = add->topw5s;
  5389. }
  5390. //-----------------------------------------------------------------------------
  5391. CpuUsageEntry_t GetCpuUsage ( s_usec_t usec )
  5392. {
  5393. CpuUsageEntry_t res = {0};
  5394. for ( int i = 0; i < cpu_usage.par.used && usec > 0; i++ )
  5395. {
  5396. const CpuUsageEntry_t *e = cpu_usage.entry + i;
  5397. usec -= e->elapsed_usec;
  5398. AddCpuEntry(&res,e);
  5399. }
  5400. return res;
  5401. }
  5402. //-----------------------------------------------------------------------------
  5403. uint GetCpuUsagePercent ( s_usec_t usec )
  5404. {
  5405. CpuUsageEntry_t e = GetCpuUsage(usec);
  5406. return GetCpuEntryPercent(&e);
  5407. }
  5408. ///////////////////////////////////////////////////////////////////////////////
  5409. double get_rusage_percent (void)
  5410. {
  5411. static u_nsec_t prev_time = 0;
  5412. static u_usec_t prev_rusage = 0;
  5413. static double prev_percent = 0.0;
  5414. const u_nsec_t cur_time = GetTimerNSec();
  5415. if ( cur_time < prev_time + 10*NSEC_PER_MSEC )
  5416. return prev_percent;
  5417. u_usec_t cur_rusage = prev_rusage;
  5418. struct rusage ru;
  5419. if (!getrusage(RUSAGE_SELF,&ru))
  5420. {
  5421. cur_rusage = ru.ru_utime.tv_sec * USEC_PER_SEC + ru.ru_utime.tv_usec
  5422. + ru.ru_stime.tv_sec * USEC_PER_SEC + ru.ru_stime.tv_usec;
  5423. }
  5424. double percent = 0.0;
  5425. if ( prev_time && cur_time > prev_time )
  5426. percent = (double)( 100 * NSEC_PER_USEC * ( cur_rusage - prev_rusage ))
  5427. / ( cur_time - prev_time );
  5428. prev_time = cur_time;
  5429. prev_rusage = cur_rusage;
  5430. return prev_percent = percent;
  5431. }
  5432. //
  5433. ///////////////////////////////////////////////////////////////////////////////
  5434. /////////////// urandom support ///////////////
  5435. ///////////////////////////////////////////////////////////////////////////////
  5436. int urandom_available = 0; // <0:not, =0:not tested, >0:ok
  5437. bool use_urandom_for_myrandom = true;
  5438. uint ReadFromUrandom ( void *dest, uint size )
  5439. {
  5440. static int fd = -1;
  5441. if ( fd == -1 )
  5442. {
  5443. if ( urandom_available < 0 )
  5444. return 0;
  5445. #ifdef O_CLOEXEC
  5446. fd = open("/dev/urandom",O_CLOEXEC|O_NONBLOCK);
  5447. #else
  5448. fd = open("/dev/urandom",O_NONBLOCK);
  5449. #endif
  5450. if ( fd == -1 )
  5451. {
  5452. urandom_available = -1;
  5453. return 0;
  5454. }
  5455. #ifndef O_CLOEXEC
  5456. fcntl(fd,F_SETFD,FD_CLOEXEC);
  5457. #endif
  5458. urandom_available = 1;
  5459. }
  5460. u8 *buf = dest;
  5461. while ( size > 0 )
  5462. {
  5463. ssize_t stat = read(fd,buf,size);
  5464. if ( stat < 0 )
  5465. {
  5466. urandom_available = -1;
  5467. close(fd);
  5468. return 0;
  5469. }
  5470. buf += stat;
  5471. size -= stat;
  5472. }
  5473. return buf - (u8*)dest;
  5474. }
  5475. //
  5476. ///////////////////////////////////////////////////////////////////////////////
  5477. /////////////// random numbers ///////////////
  5478. ///////////////////////////////////////////////////////////////////////////////
  5479. //------------------------------------------------------------------
  5480. // Algorithm: The Art of Computer Programming, part II, section 3.6
  5481. // by Donald E. Knuth
  5482. //------------------------------------------------------------------
  5483. const u32 RANDOM32_C_ADD = 2 * 197731421; // 2 Primzahlen
  5484. const u32 RANDOM32_COUNT_BASE = 4294967; // Primzahl == ~UINT_MAX32/1000;
  5485. static int random32_a_index = -1; // Index in die a-Tabelle
  5486. static u32 random32_count = 1; // Abwärts-Zähler bis zum Wechsel von a,c
  5487. static u32 random32_a,
  5488. random32_c,
  5489. random32_X; // Die letzten Werte
  5490. static u32 random32_a_tab[] = // Init-Tabelle
  5491. {
  5492. 0xbb40e62d, 0x3dc8f2f5, 0xdc024635, 0x7a5b6c8d,
  5493. 0x583feb95, 0x91e06dbd, 0xa7ec03f5, 0
  5494. };
  5495. ///////////////////////////////////////////////////////////////////////////////
  5496. ///////////////////////////////////////////////////////////////////////////////
  5497. u32 MyRandom ( u32 max )
  5498. {
  5499. if (use_urandom_for_myrandom)
  5500. {
  5501. u32 res32;
  5502. if (ReadFromUrandom(&res32,sizeof(res32)))
  5503. {
  5504. if (!max)
  5505. return res32;
  5506. u64 res64 = (u64)max * res32;
  5507. return res64 >> 32;
  5508. }
  5509. use_urandom_for_myrandom = false;
  5510. }
  5511. if (!--random32_count)
  5512. {
  5513. // Neue Berechnung von random32_a und random32_c fällig
  5514. if ( random32_a_index < 0 )
  5515. {
  5516. // allererste Initialisierung auf Zeitbasis
  5517. MySeedByTime();
  5518. }
  5519. else
  5520. {
  5521. random32_c += RANDOM32_C_ADD;
  5522. random32_a = random32_a_tab[++random32_a_index];
  5523. if (!random32_a)
  5524. {
  5525. random32_a_index = 0;
  5526. random32_a = random32_a_tab[0];
  5527. }
  5528. random32_count = RANDOM32_COUNT_BASE;
  5529. }
  5530. }
  5531. // Jetzt erfolgt die eigentliche Berechnung
  5532. random32_X = random32_a * random32_X + random32_c;
  5533. if (!max)
  5534. return random32_X;
  5535. u64 res = (u64)max * random32_X;
  5536. return res >> 32;
  5537. }
  5538. ///////////////////////////////////////////////////////////////////////////////
  5539. u64 MySeed ( u64 base )
  5540. {
  5541. uint a_tab_len = 0;
  5542. while (random32_a_tab[a_tab_len])
  5543. a_tab_len++;
  5544. const u32 base32 = base / a_tab_len;
  5545. random32_a_index = (int)( base % a_tab_len );
  5546. random32_a = random32_a_tab[random32_a_index];
  5547. random32_c = ( base32 & 15 ) * RANDOM32_C_ADD + 1;
  5548. random32_X = base32 ^ ( base >> 32 );
  5549. random32_count = RANDOM32_COUNT_BASE;
  5550. return base;
  5551. }
  5552. ///////////////////////////////////////////////////////////////////////////////
  5553. u64 MySeedByTime()
  5554. {
  5555. #if WIN_SZS_LIB
  5556. u64 time;
  5557. QueryPerformanceCounter((LARGE_INTEGER*)&time);
  5558. return MySeed(time);
  5559. #else
  5560. struct timeval tval;
  5561. gettimeofday(&tval,NULL);
  5562. return MySeed( tval.tv_sec ^ tval.tv_usec );
  5563. #endif
  5564. }
  5565. ///////////////////////////////////////////////////////////////////////////////
  5566. void MyRandomFill ( void * buf, size_t size )
  5567. {
  5568. size_t xsize = size / sizeof(u32);
  5569. if (xsize)
  5570. {
  5571. size -= xsize * sizeof(u32);
  5572. u32 * ptr = buf;
  5573. while ( xsize-- > 0 )
  5574. *ptr++ = MyRandom(0);
  5575. buf = ptr;
  5576. }
  5577. u8 * ptr = buf;
  5578. while ( size-- > 0 )
  5579. *ptr++ = MyRandom(0);
  5580. }
  5581. //
  5582. ///////////////////////////////////////////////////////////////////////////////
  5583. /////////////// UUID ///////////////
  5584. ///////////////////////////////////////////////////////////////////////////////
  5585. void CreateUUID ( uuid_buf_t dest )
  5586. {
  5587. DASSERT(dest);
  5588. const uint stat = ReadFromUrandom(dest,sizeof(uuid_buf_t));
  5589. if (!stat)
  5590. MyRandomFill(dest,sizeof(uuid_buf_t));
  5591. dest[6] = dest[6] & 0x0f | 0x40;
  5592. dest[8] = dest[8] & 0x3f | 0x80;
  5593. }
  5594. ///////////////////////////////////////////////////////////////////////////////
  5595. uint CreateTextUUID ( char *buf, uint bufsize )
  5596. {
  5597. uuid_buf_t uuid;
  5598. CreateUUID(uuid);
  5599. return PrintUUID(buf,bufsize,uuid);
  5600. }
  5601. ///////////////////////////////////////////////////////////////////////////////
  5602. uint PrintUUID ( char *buf, uint bufsize, uuid_buf_t uuid )
  5603. {
  5604. return snprintf(buf,bufsize,
  5605. "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
  5606. uuid[0],uuid[1],uuid[2],uuid[3],
  5607. uuid[4],uuid[5], uuid[6],uuid[7], uuid[8],uuid[9],
  5608. uuid[10],uuid[11],uuid[12],uuid[13],uuid[14],uuid[15] );
  5609. }
  5610. ///////////////////////////////////////////////////////////////////////////////
  5611. char * ScanUUID ( uuid_buf_t uuid, ccp source )
  5612. {
  5613. memset(uuid,0,sizeof(uuid_buf_t));
  5614. uint i;
  5615. ccp src = source;
  5616. for ( i = 0; i < sizeof(uuid_buf_t); i++ )
  5617. {
  5618. if ( *src == '-' )
  5619. src++;
  5620. uint num;
  5621. ccp end = ScanNumber(&num,src,0,16,2);
  5622. if ( end != src+2 )
  5623. return (char*)source;
  5624. uuid[i] = num;
  5625. src = end;
  5626. }
  5627. return (char*)src;
  5628. }
  5629. //
  5630. ///////////////////////////////////////////////////////////////////////////////
  5631. /////////////// gcd(), lcm() ///////////////
  5632. ///////////////////////////////////////////////////////////////////////////////
  5633. uint gcd ( uint n1, uint n2 ) // greatest common divisor, german: ggt
  5634. {
  5635. if ( !n1 || !n2 )
  5636. return 0;
  5637. if ( n1 > n2 )
  5638. {
  5639. uint temp = n1;
  5640. n1 = n2;
  5641. n2 = temp;
  5642. }
  5643. while ( n1 != 1 )
  5644. {
  5645. DASSERT ( n1 > 1 );
  5646. DASSERT ( n2 >= n1 );
  5647. uint temp = n2 % n1;
  5648. if ( !temp )
  5649. break;
  5650. n2 = n1;
  5651. n1 = temp;
  5652. }
  5653. return n1;
  5654. }
  5655. ///////////////////////////////////////////////////////////////////////////////
  5656. u32 gcd32 ( u32 n1, u32 n2 ) // greatest common divisor, german: ggt
  5657. {
  5658. if ( !n1 || !n2 )
  5659. return 0;
  5660. if ( n1 > n2 )
  5661. {
  5662. u32 temp = n1;
  5663. n1 = n2;
  5664. n2 = temp;
  5665. }
  5666. while ( n1 != 1 )
  5667. {
  5668. DASSERT ( n1 > 1 );
  5669. DASSERT ( n2 > n1 );
  5670. u32 temp = n2 % n1;
  5671. if ( !temp )
  5672. break;
  5673. n2 = n1;
  5674. n1 = temp;
  5675. }
  5676. return n1;
  5677. }
  5678. ///////////////////////////////////////////////////////////////////////////////
  5679. u64 gcd64 ( u64 n1, u64 n2 ) // greatest common divisor, german: ggt
  5680. {
  5681. if ( !n1 || !n2 )
  5682. return 0;
  5683. if ( n1 > n2 )
  5684. {
  5685. u64 temp = n1;
  5686. n1 = n2;
  5687. n2 = temp;
  5688. }
  5689. while ( n1 != 1 )
  5690. {
  5691. DASSERT ( n1 > 1 );
  5692. DASSERT ( n2 > n1 );
  5693. u64 temp = n2 % n1;
  5694. if ( !temp )
  5695. break;
  5696. n2 = n1;
  5697. n1 = temp;
  5698. }
  5699. return n1;
  5700. }
  5701. ///////////////////////////////////////////////////////////////////////////////
  5702. ///////////////////////////////////////////////////////////////////////////////
  5703. uint lcm ( uint n1, uint n2 ) // lowest common multiple, german: kgv
  5704. {
  5705. uint g = gcd(n1,n2);
  5706. if ( g > 0 )
  5707. {
  5708. n1 /= g;
  5709. g = n1 * n2;
  5710. if ( g < n1 || g < n2 ) // overflow?
  5711. g = 0;
  5712. }
  5713. return g;
  5714. }
  5715. ///////////////////////////////////////////////////////////////////////////////
  5716. u32 lcm32 ( u32 n1, u32 n2 ) // lowest common multiple, german: kgv
  5717. {
  5718. u32 g = gcd32(n1,n2);
  5719. if ( g > 0 )
  5720. {
  5721. n1 /= g;
  5722. g = n1 * n2;
  5723. if ( g < n1 || g < n2 ) // overflow?
  5724. g = 0;
  5725. }
  5726. return g;
  5727. }
  5728. ///////////////////////////////////////////////////////////////////////////////
  5729. u64 lcm64 ( u64 n1, u64 n2 ) // lowest common multiple, german: kgv
  5730. {
  5731. u64 g = gcd64(n1,n2);
  5732. if ( g > 0 )
  5733. {
  5734. n1 /= g;
  5735. g = n1 * n2;
  5736. if ( g < n1 || g < n2 ) // overflow?
  5737. g = 0;
  5738. }
  5739. return g;
  5740. }
  5741. //
  5742. ///////////////////////////////////////////////////////////////////////////////
  5743. /////////////// scan number ///////////////
  5744. ///////////////////////////////////////////////////////////////////////////////
  5745. #define NN NUMBER_NULL
  5746. #define NC NUMBER_CONTROL
  5747. #define NL NUMBER_LINE
  5748. #define NS NUMBER_SPACE
  5749. #define NT NUMBER_TIE
  5750. #define NP NUMBER_SEPARATE
  5751. #define NX NUMBER_OTHER
  5752. const char DigitTable[] =
  5753. {
  5754. NN, NC, NC, NC, NC, NC, NC, NC, NC, NS, NL, NC, NS, NL, NC, NC,
  5755. NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC, NC,
  5756. NS, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NP, NT, NT, NX, // !"#$%&' ()*+,-./
  5757. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, NT, NP, NX, NX, NX, NX, // 01234567 89:;<=>?
  5758. NX, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // @ABCDEFG HIJKLMNO
  5759. 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, NX, NX, NX, NX, NX, // PQRSTUVW XYZ[\]^_
  5760. NX, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // `abcdefg hijklmno
  5761. 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, NX, NX, NX, NX, NX, // pqrstuvw xyz{|}~
  5762. NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX,
  5763. NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX,
  5764. NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX,
  5765. NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX,
  5766. NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX,
  5767. NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX,
  5768. NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX,
  5769. NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX, NX,
  5770. };
  5771. #undef NN
  5772. #undef NC
  5773. #undef NL
  5774. #undef NS
  5775. #undef NT
  5776. #undef NP
  5777. #undef NX
  5778. ///////////////////////////////////////////////////////////////////////////////
  5779. u64 ScanDigits
  5780. (
  5781. // same as ScanNumber(), but other interface
  5782. // returns the scanned number
  5783. ccp *source, // pointer to source string, modified
  5784. ccp end_source, // NULL or end of 'source'
  5785. uint intbase, // integer base, 2..36
  5786. int maxchar, // max number of digits to read
  5787. uint *count // not NULL: store number of scanned digits here
  5788. )
  5789. {
  5790. DASSERT(source);
  5791. DASSERT( intbase >= 2 && intbase <= 36 );
  5792. ccp src = *source;
  5793. u64 num = 0;
  5794. while ( maxchar-- && ( !end_source || src < end_source ) )
  5795. {
  5796. const u8 digit = (u8)DigitTable[(u8)*src];
  5797. if ( digit >= intbase )
  5798. break;
  5799. num = num * intbase + digit;
  5800. src++;
  5801. }
  5802. if (count)
  5803. *count = src - *source;
  5804. *source = src;
  5805. return num;
  5806. }
  5807. ///////////////////////////////////////////////////////////////////////////////
  5808. char * ScanNumber
  5809. (
  5810. // same as ScanDigits(), but other interface
  5811. // returns a pointer to the first not used character
  5812. uint *dest_num, // store result here, never NULL
  5813. ccp src, // pointer to source string, modified
  5814. ccp src_end, // NULL or end of 'src'
  5815. uint intbase, // integer base, 2..36
  5816. int maxchar // max number of digits to read
  5817. )
  5818. {
  5819. DASSERT(dest_num);
  5820. uint num = 0;
  5821. if (src)
  5822. {
  5823. while ( maxchar-- && ( !src_end || src < src_end ) )
  5824. {
  5825. const uint n = (uint)DigitTable[*(uchar*)src];
  5826. if ( n >= (uint)intbase )
  5827. break;
  5828. num = num * intbase + n;
  5829. src++;
  5830. }
  5831. }
  5832. *dest_num = num;
  5833. return (char*)src;
  5834. }
  5835. ///////////////////////////////////////////////////////////////////////////////
  5836. char * ScanEscape
  5837. (
  5838. // returns a pointer to the first not used character
  5839. uint *dest_code, // store result here, never NULL
  5840. ccp src, // pointer to source string (behind escape char)
  5841. ccp src_end // NULL or end of 'src'
  5842. )
  5843. {
  5844. DASSERT(dest_code);
  5845. DASSERT(src);
  5846. if ( !src || ( src_end ? src >= src_end : !*src ) )
  5847. {
  5848. *dest_code = 0;
  5849. return (char*)src;
  5850. }
  5851. uint code = 0;
  5852. switch (*src++)
  5853. {
  5854. case '\\': code = '\\'; break;
  5855. case 'a': code = '\a'; break;
  5856. case 'b': code = '\b'; break;
  5857. case 'E':
  5858. case 'e': code = '\e'; break;
  5859. case 'f': code = '\f'; break;
  5860. case 'n': code = '\n'; break;
  5861. case 'r': code = '\r'; break;
  5862. case 't': code = '\t'; break;
  5863. case 'v': code = '\v'; break;
  5864. case '!': code = '|'; break;
  5865. case 'x':
  5866. src = ScanNumber(&code,src,src_end,16,2);
  5867. break;
  5868. case 'u':
  5869. src = ScanNumber(&code,src,src_end,16,4);
  5870. break;
  5871. case 'U':
  5872. src = ScanNumber(&code,src,src_end,16,8);
  5873. break;
  5874. case '0':
  5875. case '1':
  5876. case '2':
  5877. case '3':
  5878. case '4':
  5879. case '5':
  5880. case '6':
  5881. case '7':
  5882. src = ScanNumber(&code,src-1,src_end,8,3);
  5883. break;
  5884. default:
  5885. code = src[-1];
  5886. break;
  5887. }
  5888. *dest_code = code;
  5889. return (char*)src;
  5890. }
  5891. ///////////////////////////////////////////////////////////////////////////////
  5892. uint ScanHexString
  5893. (
  5894. // return the number of written bytes
  5895. void *buf, // write scanned data here
  5896. uint buf_size, // size of buf
  5897. ccp *source, // pointer to source string, modified
  5898. ccp end_source, // NULL or end of 'source'
  5899. bool allow_tie // allow chars ' .:-' and TAB,VT as byte separator
  5900. )
  5901. {
  5902. DASSERT(buf);
  5903. DASSERT(source);
  5904. u8 *dest = buf;
  5905. uint count = 0;
  5906. while ( count < buf_size )
  5907. {
  5908. ccp src = *source;
  5909. if (allow_tie)
  5910. {
  5911. while ( !end_source || src < end_source )
  5912. {
  5913. const char res = DigitTable[(u8)*src];
  5914. if ( res != NUMBER_SPACE && res != NUMBER_TIE )
  5915. break;
  5916. src++;
  5917. }
  5918. *source = src;
  5919. }
  5920. while ( !end_source || src < end_source )
  5921. {
  5922. const char res = DigitTable[(u8)*src];
  5923. if ( res < 0 || res >= 16 )
  5924. break;
  5925. src++;
  5926. }
  5927. uint n_digits = src - *source;
  5928. if (!n_digits)
  5929. break;
  5930. while ( n_digits > 0 )
  5931. {
  5932. uint scanned;
  5933. uint num = ScanDigits( source, end_source, 16,
  5934. n_digits & 1 ? 1 : 2, &scanned );
  5935. if (!scanned)
  5936. return count;
  5937. n_digits -= scanned;
  5938. *dest++ = num;
  5939. count++;
  5940. }
  5941. }
  5942. return count;
  5943. }
  5944. ///////////////////////////////////////////////////////////////////////////////
  5945. ///////////////////////////////////////////////////////////////////////////////
  5946. char * ScanS32
  5947. (
  5948. // return 'source' on error
  5949. s32 *res_num, // not NULL: store result (only on success)
  5950. ccp source, // NULL or source text
  5951. uint default_base // base for numbers without '0x' prefix
  5952. // 0: C like with octal support
  5953. // 10: standard value for decimal numbers
  5954. // 16: standard value for hex numbers
  5955. )
  5956. {
  5957. if (!source)
  5958. return 0;
  5959. ccp src = source;
  5960. while ( *src > 0 && *src <= ' ' )
  5961. src++;
  5962. const bool minus = *src == '-';
  5963. if ( minus || *src == '+' )
  5964. {
  5965. src++;
  5966. while ( *src > 0 && *src <= ' ' )
  5967. src++;
  5968. }
  5969. #if 0 // 0b and 0d can be hex numbers => so this doeasn't work
  5970. uint base = default_base;
  5971. if ( src[0] == '0' )
  5972. {
  5973. switch(tolower((int)src[1]))
  5974. {
  5975. case 'x': base = 16; break;
  5976. case 'd': base = 10; src+=2; break;
  5977. case 'o': base = 8; src+=2; break;
  5978. case 'b': base = 2; src+=2; break;
  5979. }
  5980. }
  5981. #else
  5982. const uint base = src[0] == '0' && ( src[1] == 'x' || src[1] == 'X' )
  5983. ? 16 : default_base;
  5984. #endif
  5985. char *end;
  5986. const s32 num = strtoul( src, &end, base );
  5987. if ( (ccp)end > src )
  5988. {
  5989. if (res_num)
  5990. *res_num = minus ? -num : num;
  5991. return end;
  5992. }
  5993. return (char*)source;
  5994. }
  5995. ///////////////////////////////////////////////////////////////////////////////
  5996. char * ScanS64
  5997. (
  5998. // return 'source' on error
  5999. s64 *res_num, // not NULL: store result (only on success)
  6000. ccp source, // NULL or source text
  6001. uint default_base // base for numbers without '0x' prefix
  6002. // 0: C like with octal support
  6003. // 10: standard value for decimal numbers
  6004. // 16: standard value for hex numbers
  6005. )
  6006. {
  6007. if (!source)
  6008. return 0;
  6009. ccp src = source;
  6010. while ( *src > 0 && *src <= ' ' )
  6011. src++;
  6012. const bool minus = *src == '-';
  6013. if ( minus || *src == '+' )
  6014. {
  6015. src++;
  6016. while ( *src > 0 && *src <= ' ' )
  6017. src++;
  6018. }
  6019. const uint base = src[0] == '0' && ( src[1] == 'x' || src[1] == 'X' )
  6020. ? 16 : default_base;
  6021. char *end;
  6022. const s64 num = strtoull( src, &end, base );
  6023. if ( (ccp)end > src )
  6024. {
  6025. if (res_num)
  6026. *res_num = minus ? -num : num;
  6027. return end;
  6028. }
  6029. return (char*)source;
  6030. }
  6031. ///////////////////////////////////////////////////////////////////////////////
  6032. ///////////////////////////////////////////////////////////////////////////////
  6033. // strto*() replacements, base ion Scan*() with better base support
  6034. long int str2l ( const char *nptr, char **endptr, int base )
  6035. {
  6036. s32 res = 0;
  6037. char *end = ScanS32(&res,nptr,base);
  6038. if (endptr)
  6039. *endptr = end;
  6040. return res;
  6041. }
  6042. ///////////////////////////////////////////////////////////////////////////////
  6043. long long int str2ll ( const char *nptr, char **endptr, int base )
  6044. {
  6045. s64 res = 0;
  6046. char *end = ScanS64(&res,nptr,base);
  6047. if (endptr)
  6048. *endptr = end;
  6049. return res;
  6050. }
  6051. ///////////////////////////////////////////////////////////////////////////////
  6052. unsigned long int str2ul ( const char *nptr, char **endptr, int base )
  6053. {
  6054. u32 res = 0;
  6055. char *end = ScanU32(&res,nptr,base);
  6056. if (endptr)
  6057. *endptr = end;
  6058. return res;
  6059. }
  6060. ///////////////////////////////////////////////////////////////////////////////
  6061. unsigned long long int str2ull ( const char *nptr, char **endptr, int base )
  6062. {
  6063. u64 res = 0;
  6064. char *end = ScanU64(&res,nptr,base);
  6065. if (endptr)
  6066. *endptr = end;
  6067. return res;
  6068. }
  6069. //
  6070. ///////////////////////////////////////////////////////////////////////////////
  6071. /////////////// round float/double (zero LSB) ///////////////
  6072. ///////////////////////////////////////////////////////////////////////////////
  6073. float RoundF2bytes ( float f )
  6074. {
  6075. union { float f; u32 u; } x;
  6076. x.f = f;
  6077. if ( x.u & 0x8000 )
  6078. {
  6079. x.u &= 0xffff0000;
  6080. int exp;
  6081. const float frac = frexpf(x.f,&exp);
  6082. x.f = ldexpf(frac+0.00585938,exp);
  6083. }
  6084. x.u &= 0xffff0000;
  6085. return x.f;
  6086. }
  6087. //-----------------------------------------------------------------------------
  6088. float RoundF3bytes ( float f )
  6089. {
  6090. union { float f; u32 u; } x;
  6091. x.f = f;
  6092. if ( x.u & 0x80 )
  6093. {
  6094. x.u &= 0xffffff00;
  6095. int exp;
  6096. const float frac = frexpf(x.f,&exp);
  6097. x.f = ldexpf(frac+0.00002289,exp);
  6098. }
  6099. x.u &= 0xffffff00;
  6100. return x.f;
  6101. }
  6102. //-----------------------------------------------------------------------------
  6103. double RoundD6bytes ( double d )
  6104. {
  6105. union { double d; u64 u; } x;
  6106. x.d = d;
  6107. if ( x.u & 0x8000 )
  6108. {
  6109. x.u &= 0xffffffffffff0000ull;
  6110. int exp;
  6111. const double frac = frexp(x.d,&exp);
  6112. x.d = ldexp(frac+0.000000000010913936,exp);
  6113. }
  6114. x.u &= 0xffffffffffff0000ull;
  6115. return x.d;
  6116. }
  6117. //-----------------------------------------------------------------------------
  6118. double RoundD7bytes ( double d )
  6119. {
  6120. union { double d; u64 u; } x;
  6121. x.d = d;
  6122. if ( x.u & 0x80 )
  6123. {
  6124. x.u &= 0xffffffffffffff00ull;
  6125. int exp;
  6126. const double frac = frexp(x.d,&exp);
  6127. x.d = ldexp(frac+0.000000000000042633,exp);
  6128. }
  6129. x.u &= 0xffffffffffffff00ull;
  6130. return x.d;
  6131. }
  6132. //
  6133. ///////////////////////////////////////////////////////////////////////////////
  6134. /////////////// print number ///////////////
  6135. ///////////////////////////////////////////////////////////////////////////////
  6136. char * PrintNumberU4
  6137. (
  6138. char *buf, // result buffer
  6139. // NULL: use a local circulary static buffer
  6140. size_t buf_size, // size of 'buf', ignored if buf==NULL
  6141. u64 num, // number to print
  6142. sizeform_mode_t mode // any of DC_SFORM_ALIGN, DC_SFORM_DASH
  6143. )
  6144. {
  6145. if (!buf)
  6146. buf = GetCircBuf( buf_size = 5 );
  6147. const sizeform_mode_t aligned = mode & DC_SFORM_ALIGN;
  6148. if ( num < 1000000000 ) // 1e9
  6149. {
  6150. u32 n32 = num;
  6151. if ( !n32 && mode & DC_SFORM_DASH )
  6152. StringCopyS(buf,buf_size, aligned ? " -" : "-" );
  6153. else if ( n32 < 10000 )
  6154. snprintf(buf,buf_size, aligned ? "%4u" : "%u", n32 );
  6155. else if ( n32 < 1000000 )
  6156. snprintf(buf,buf_size, aligned ? "%3uk" : "%uk", n32/1000 );
  6157. else if ( n32 < 10000000 )
  6158. {
  6159. n32 /= 100000;
  6160. snprintf(buf,buf_size,"%u.%uM", n32/10, n32%10 );
  6161. }
  6162. else
  6163. snprintf(buf,buf_size, aligned ? "%3uM" : "%uM", n32/1000000 );
  6164. }
  6165. else
  6166. {
  6167. u32 n32;
  6168. ccp factor = "GTPE";
  6169. if ( num < 1000000000000000ull ) // 1e15
  6170. n32 = num / 100000000; // 1e8
  6171. else
  6172. {
  6173. factor += 2;
  6174. n32 = num / 100000000000000ull; // 1e14
  6175. }
  6176. while (*factor)
  6177. {
  6178. if ( n32 < 100 )
  6179. {
  6180. snprintf(buf,buf_size,"%u.%u%c", n32/10, n32%10, *factor );
  6181. break;
  6182. }
  6183. else if ( n32 < 10000 )
  6184. {
  6185. snprintf(buf,buf_size, aligned ? "%3u%c" : "%u%c", n32/10, *factor );
  6186. break;
  6187. }
  6188. n32 /= 1000;
  6189. factor++;
  6190. }
  6191. }
  6192. return buf;
  6193. }
  6194. ///////////////////////////////////////////////////////////////////////////////
  6195. char * PrintNumberU5
  6196. (
  6197. char *buf, // result buffer
  6198. // NULL: use a local circulary static buffer
  6199. size_t buf_size, // size of 'buf', ignored if buf==NULL
  6200. u64 num, // number to print
  6201. sizeform_mode_t mode // any of DC_SFORM_ALIGN, DC_SFORM_DASH
  6202. )
  6203. {
  6204. if (!buf)
  6205. buf = GetCircBuf( buf_size = 6 );
  6206. const sizeform_mode_t aligned = mode & DC_SFORM_ALIGN;
  6207. if ( num < 1000000000 ) // 1e9
  6208. {
  6209. u32 n32 = num;
  6210. if ( !n32 && mode & DC_SFORM_DASH )
  6211. StringCopyS(buf,buf_size, aligned ? " -" : "-" );
  6212. else if ( n32 < 100000 )
  6213. snprintf(buf,buf_size, aligned ? "%5u" : "%u", n32 );
  6214. else if ( n32 < 10000000 )
  6215. snprintf(buf,buf_size, aligned ? "%4uk" : "%uk", n32/1000 );
  6216. else
  6217. snprintf(buf,buf_size, aligned ? "%4uM" : "%uM", n32/1000000 );
  6218. }
  6219. else
  6220. {
  6221. u32 n32;
  6222. ccp factor = "MGTPE";
  6223. if ( num < 1000000000000000ull ) // 1e15
  6224. n32 = num / 1000000; // 1e6
  6225. else
  6226. {
  6227. factor += 2;
  6228. n32 = num / 1000000000000ull; // 1e12
  6229. }
  6230. while (*factor)
  6231. {
  6232. if ( n32 < 10000 )
  6233. {
  6234. snprintf(buf,buf_size, aligned ? "%4u%c" : "%u%c", n32, *factor );
  6235. break;
  6236. }
  6237. n32 /= 1000;
  6238. factor++;
  6239. }
  6240. }
  6241. return buf;
  6242. }
  6243. ///////////////////////////////////////////////////////////////////////////////
  6244. char * PrintNumberU6
  6245. (
  6246. char *buf, // result buffer
  6247. // NULL: use a local circulary static buffer
  6248. size_t buf_size, // size of 'buf', ignored if buf==NULL
  6249. u64 num, // number to print
  6250. sizeform_mode_t mode // any of DC_SFORM_ALIGN, DC_SFORM_DASH
  6251. )
  6252. {
  6253. if (!buf)
  6254. buf = GetCircBuf( buf_size = 7 );
  6255. const sizeform_mode_t aligned = mode & DC_SFORM_ALIGN;
  6256. if ( num < 1000000000 ) // 1e9
  6257. {
  6258. u32 n32 = num;
  6259. if ( !n32 && mode & DC_SFORM_DASH )
  6260. StringCopyS(buf,buf_size, aligned ? " -" : "-" );
  6261. else if ( n32 < 1000000 )
  6262. snprintf(buf,buf_size, aligned ? "%6u" : "%u", n32 );
  6263. else if ( n32 < 100000000 )
  6264. snprintf(buf,buf_size, aligned ? "%5uk" : "%uk", n32/1000 );
  6265. else
  6266. snprintf(buf,buf_size, aligned ? "%5uM" : "%uM", n32/1000000 );
  6267. }
  6268. else
  6269. {
  6270. u32 n32;
  6271. ccp factor = "MGTPE";
  6272. if ( num < 1000000000000000ull ) // 1e15
  6273. n32 = num / 1000000; // 1e6
  6274. else
  6275. {
  6276. factor += 2;
  6277. n32 = num / 1000000000000ull; // 1e12
  6278. }
  6279. while (*factor)
  6280. {
  6281. if ( n32 < 100000 )
  6282. {
  6283. snprintf(buf,buf_size, aligned ? "%5u%c" : "%u%c", n32, *factor );
  6284. break;
  6285. }
  6286. n32 /= 1000;
  6287. factor++;
  6288. }
  6289. }
  6290. return buf;
  6291. }
  6292. ///////////////////////////////////////////////////////////////////////////////
  6293. char * PrintNumberU7
  6294. (
  6295. char *buf, // result buffer
  6296. // NULL: use a local circulary static buffer
  6297. size_t buf_size, // size of 'buf', ignored if buf==NULL
  6298. u64 num, // number to print
  6299. sizeform_mode_t mode // any of DC_SFORM_ALIGN, DC_SFORM_DASH
  6300. )
  6301. {
  6302. if (!buf)
  6303. buf = GetCircBuf( buf_size = 8 );
  6304. const sizeform_mode_t aligned = mode & DC_SFORM_ALIGN;
  6305. if ( num < 1000000000 ) // 1e9
  6306. {
  6307. u32 n32 = num;
  6308. if ( !n32 && mode & DC_SFORM_DASH )
  6309. StringCopyS(buf,buf_size, aligned ? " -" : "-" );
  6310. else if ( n32 < 10000000 )
  6311. snprintf(buf,buf_size, aligned ? "%7u" : "%u", n32 );
  6312. else
  6313. snprintf(buf,buf_size, aligned ? "%6uk" : "%uk", n32/1000 );
  6314. }
  6315. else
  6316. {
  6317. u32 n32;
  6318. ccp factor = "MGTPE";
  6319. if ( num < 1000000000000000ull ) // 1e15
  6320. n32 = num / 1000000; // 1e6
  6321. else
  6322. {
  6323. factor += 2;
  6324. n32 = num / 1000000000000ull; // 1e12
  6325. }
  6326. while (*factor)
  6327. {
  6328. if ( n32 < 1000000 )
  6329. {
  6330. snprintf(buf,buf_size, aligned ? "%6u%c" : "%u%c", n32, *factor );
  6331. break;
  6332. }
  6333. n32 /= 1000;
  6334. factor++;
  6335. }
  6336. }
  6337. return buf;
  6338. }
  6339. ///////////////////////////////////////////////////////////////////////////////
  6340. ///////////////////////////////////////////////////////////////////////////////
  6341. char * PrintNumberS5
  6342. (
  6343. char *buf, // result buffer
  6344. // NULL: use a local circulary static buffer
  6345. size_t buf_size, // size of 'buf', ignored if buf==NULL
  6346. s64 num, // number to print
  6347. sizeform_mode_t mode // any of DC_SFORM_ALIGN, DC_SFORM_DASH
  6348. )
  6349. {
  6350. if ( num >= 0 )
  6351. return PrintNumberU5(buf,buf_size,num,mode);
  6352. if (!buf)
  6353. buf = GetCircBuf( buf_size = 6 );
  6354. const sizeform_mode_t aligned = mode & DC_SFORM_ALIGN;
  6355. if ( num > -1000000000 ) // -1e9
  6356. {
  6357. s32 n32 = num;
  6358. if ( n32 > -10000 )
  6359. snprintf(buf,buf_size, aligned ? "%5d" : "%d", n32 );
  6360. else if ( n32 > -1000000 )
  6361. snprintf(buf,buf_size, aligned ? "%4dk" : "%dk", n32/1000 );
  6362. else if ( n32 > -10000000 )
  6363. {
  6364. n32 /= -100000;
  6365. snprintf(buf,buf_size,"-%u.%uM", n32/10, n32%10 );
  6366. }
  6367. else
  6368. snprintf(buf,buf_size, aligned ? "%4dM" : "%dM", n32/1000000 );
  6369. }
  6370. else
  6371. {
  6372. s32 n32;
  6373. ccp factor = "GTPE";
  6374. if ( num > -1000000000000000ull ) // -1e15
  6375. n32 = num / 100000000; // -1e8
  6376. else
  6377. {
  6378. factor += 2;
  6379. n32 = num / 100000000000000ull; // -1e14
  6380. }
  6381. while (*factor)
  6382. {
  6383. if ( n32 > -100 )
  6384. {
  6385. snprintf(buf,buf_size,"-%u.%u%c", -n32/10, -n32%10, *factor );
  6386. break;
  6387. }
  6388. else if ( n32 > -10000 )
  6389. {
  6390. snprintf(buf,buf_size, aligned ? "%4d%c" : "%d%c", n32/10, *factor );
  6391. break;
  6392. }
  6393. n32 /= 1000;
  6394. factor++;
  6395. }
  6396. }
  6397. return buf;
  6398. }
  6399. ///////////////////////////////////////////////////////////////////////////////
  6400. char * PrintNumberS6
  6401. (
  6402. char *buf, // result buffer
  6403. // NULL: use a local circulary static buffer
  6404. size_t buf_size, // size of 'buf', ignored if buf==NULL
  6405. s64 num, // number to print
  6406. sizeform_mode_t mode // any of DC_SFORM_ALIGN, DC_SFORM_DASH
  6407. )
  6408. {
  6409. if ( num >= 0 )
  6410. return PrintNumberU6(buf,buf_size,num,mode);
  6411. if (!buf)
  6412. buf = GetCircBuf( buf_size = 7 );
  6413. const sizeform_mode_t aligned = mode & DC_SFORM_ALIGN;
  6414. if ( num > -1000000000 ) // -1e9
  6415. {
  6416. s32 n32 = num;
  6417. if ( n32 > -100000 )
  6418. snprintf(buf,buf_size, aligned ? "%6d" : "%d", n32 );
  6419. else if ( n32 > -10000000 )
  6420. snprintf(buf,buf_size, aligned ? "%5dk" : "%dk", n32/1000 );
  6421. else
  6422. snprintf(buf,buf_size, aligned ? "%5dM" : "%dM", n32/1000000 );
  6423. }
  6424. else
  6425. {
  6426. s32 n32;
  6427. ccp factor = "MGTPE";
  6428. if ( num > -1000000000000000ull ) // -1e15
  6429. n32 = num / 1000000; // -1e6
  6430. else
  6431. {
  6432. factor += 2;
  6433. n32 = num / 1000000000000ull; // -1e12
  6434. }
  6435. while (*factor)
  6436. {
  6437. if ( n32 > -10000 )
  6438. {
  6439. snprintf(buf,buf_size, aligned ? "%5d%c" : "%d%c", n32, *factor );
  6440. break;
  6441. }
  6442. n32 /= 1000;
  6443. factor++;
  6444. }
  6445. }
  6446. return buf;
  6447. }
  6448. ///////////////////////////////////////////////////////////////////////////////
  6449. char * PrintNumberS7
  6450. (
  6451. char *buf, // result buffer
  6452. // NULL: use a local circulary static buffer
  6453. size_t buf_size, // size of 'buf', ignored if buf==NULL
  6454. s64 num, // number to print
  6455. sizeform_mode_t mode // any of DC_SFORM_ALIGN, DC_SFORM_DASH
  6456. )
  6457. {
  6458. if ( num >= 0 )
  6459. return PrintNumberU7(buf,buf_size,num,mode);
  6460. if (!buf)
  6461. buf = GetCircBuf( buf_size = 8 );
  6462. const sizeform_mode_t aligned = mode & DC_SFORM_ALIGN;
  6463. if ( num > -100000000 ) // -1e8
  6464. {
  6465. s32 n32 = num;
  6466. if ( n32 > -1000000 )
  6467. snprintf(buf,buf_size, aligned ? "%7d" : "%d", n32 );
  6468. else
  6469. snprintf(buf,buf_size, aligned ? "%6dk" : "%dk", n32/1000 );
  6470. }
  6471. else
  6472. {
  6473. s32 n32;
  6474. ccp factor = "MGTPE";
  6475. if ( num > -1000000000000000ull ) // -1e15
  6476. n32 = num / 1000000; // -1e6
  6477. else
  6478. {
  6479. factor += 2;
  6480. n32 = num / 1000000000000ull; // -1e12
  6481. }
  6482. while (*factor)
  6483. {
  6484. if ( n32 > -100000 )
  6485. {
  6486. snprintf(buf,buf_size, aligned ? "%6d%c" : "%d%c", n32, *factor );
  6487. break;
  6488. }
  6489. n32 /= 1000;
  6490. factor++;
  6491. }
  6492. }
  6493. return buf;
  6494. }
  6495. ///////////////////////////////////////////////////////////////////////////////
  6496. ///////////////////////////////////////////////////////////////////////////////
  6497. char * PrintNumberD5
  6498. (
  6499. char *buf, // result buffer
  6500. // NULL: use a local circulary static buffer
  6501. size_t buf_size, // size of 'buf', ignored if buf==NULL
  6502. double num, // number to print
  6503. sizeform_mode_t mode // any of DC_SFORM_ALIGN
  6504. )
  6505. {
  6506. if (!buf)
  6507. buf = GetCircBuf( buf_size = 16 );
  6508. const sizeform_mode_t aligned = mode & DC_SFORM_ALIGN;
  6509. double abs = fabs(num);
  6510. if ( abs >= 1e2 )
  6511. {
  6512. if ( num <= 0 )
  6513. {
  6514. if ( abs <= S64_MAX )
  6515. return PrintNumberS5(buf,buf_size,double2int64(num),mode);
  6516. return "-****";
  6517. }
  6518. else
  6519. {
  6520. if ( abs <= U64_MAX )
  6521. return PrintNumberU5(buf,buf_size,double2int64(num),mode);
  6522. }
  6523. snprintf(buf,buf_size,"%5.0e",num);
  6524. return buf;
  6525. }
  6526. if ( num < 0.0 )
  6527. {
  6528. if ( abs < 1e-2 )
  6529. return aligned ? " -0" : "-0";
  6530. if ( abs < 10.0 )
  6531. snprintf(buf,buf_size,"%5.2f",num);
  6532. else
  6533. snprintf(buf,buf_size,"%5.1f",num);
  6534. }
  6535. else
  6536. {
  6537. if ( num < 1e-3 )
  6538. return aligned ? " 0" : "0";
  6539. if ( num < 10.0 )
  6540. snprintf(buf,buf_size,"%5.3f",num);
  6541. else
  6542. snprintf(buf,buf_size,"%5.2f",num);
  6543. }
  6544. return buf;
  6545. }
  6546. ///////////////////////////////////////////////////////////////////////////////
  6547. char * PrintNumberD6
  6548. (
  6549. char *buf, // result buffer
  6550. // NULL: use a local circulary static buffer
  6551. size_t buf_size, // size of 'buf', ignored if buf==NULL
  6552. double num, // number to print
  6553. sizeform_mode_t mode // any of DC_SFORM_ALIGN
  6554. )
  6555. {
  6556. if (!buf)
  6557. buf = GetCircBuf( buf_size = 7 );
  6558. const sizeform_mode_t aligned = mode & DC_SFORM_ALIGN;
  6559. double abs = fabs(num);
  6560. if ( abs >= 1e3 )
  6561. {
  6562. if ( num <= 0 )
  6563. {
  6564. if ( abs <= S64_MAX )
  6565. return PrintNumberS6(buf,buf_size,double2int64(num),mode);
  6566. }
  6567. else
  6568. {
  6569. if ( abs <= U64_MAX )
  6570. return PrintNumberU6(buf,buf_size,double2int64(num),mode);
  6571. }
  6572. snprintf(buf,buf_size,"%6.0e",num);
  6573. return buf;
  6574. }
  6575. if ( num < 0.0 )
  6576. {
  6577. if ( abs < 1e-3 )
  6578. return aligned ? " -0" : "-0";
  6579. if ( abs < 10.0 )
  6580. snprintf(buf,buf_size,"%6.3f",num);
  6581. else if ( abs < 100.0 )
  6582. snprintf(buf,buf_size,"%6.2f",num);
  6583. else
  6584. snprintf(buf,buf_size,"%6.1f",num);
  6585. }
  6586. else
  6587. {
  6588. if ( num < 1e-4 )
  6589. return aligned ? " 0" : "0";
  6590. if ( num < 10.0 )
  6591. snprintf(buf,buf_size,"%6.4f",num);
  6592. else if ( num < 100.0 )
  6593. snprintf(buf,buf_size,"%6.3f",num);
  6594. else
  6595. snprintf(buf,buf_size,"%6.2f",num);
  6596. }
  6597. return buf;
  6598. }
  6599. ///////////////////////////////////////////////////////////////////////////////
  6600. char * PrintNumberD7
  6601. (
  6602. char *buf, // result buffer
  6603. // NULL: use a local circulary static buffer
  6604. size_t buf_size, // size of 'buf', ignored if buf==NULL
  6605. double num, // number to print
  6606. sizeform_mode_t mode // any of DC_SFORM_ALIGN
  6607. )
  6608. {
  6609. if (!buf)
  6610. buf = GetCircBuf( buf_size = 18 );
  6611. const sizeform_mode_t aligned = mode & DC_SFORM_ALIGN;
  6612. double abs = fabs(num);
  6613. if ( abs >= 1e4 )
  6614. {
  6615. if ( num <= 0 )
  6616. {
  6617. if ( abs <= S64_MAX )
  6618. return PrintNumberS7(buf,buf_size,double2int64(num),mode);
  6619. snprintf(buf,buf_size,"%7.0e",num);
  6620. return buf;
  6621. }
  6622. else
  6623. {
  6624. if ( abs <= U64_MAX )
  6625. return PrintNumberU7(buf,buf_size,double2int64(num),mode);
  6626. }
  6627. snprintf(buf,buf_size,"%7.1e",num);
  6628. return buf;
  6629. }
  6630. if ( num < 0.0 )
  6631. {
  6632. if ( abs < 1e-4 )
  6633. return aligned ? " -0" : "-0";
  6634. if ( abs < 10.0 )
  6635. snprintf(buf,buf_size,"%7.4f",num);
  6636. else if ( abs < 100.0 )
  6637. snprintf(buf,buf_size,"%7.3f",num);
  6638. else if ( abs < 1000.0 )
  6639. snprintf(buf,buf_size,"%7.2f",num);
  6640. else
  6641. snprintf(buf,buf_size,"%7.1f",num);
  6642. }
  6643. else
  6644. {
  6645. if ( num < 1e-5 )
  6646. return aligned ? " 0" : "0";
  6647. if ( num < 10.0 )
  6648. snprintf(buf,buf_size,"%7.5f",num);
  6649. else if ( num < 100.0 )
  6650. snprintf(buf,buf_size,"%7.4f",num);
  6651. else if ( num < 1000.0 )
  6652. snprintf(buf,buf_size,"%7.3f",num);
  6653. else
  6654. snprintf(buf,buf_size,"%7.2f",num);
  6655. }
  6656. return buf;
  6657. }
  6658. //
  6659. ///////////////////////////////////////////////////////////////////////////////
  6660. /////////////// print size ///////////////
  6661. ///////////////////////////////////////////////////////////////////////////////
  6662. ccp dc_size_tab_1000[DC_SIZE_N_MODES+1] =
  6663. {
  6664. 0, // DC_SIZE_DEFAULT
  6665. 0, // DC_SIZE_AUTO
  6666. "B", // DC_SIZE_BYTES
  6667. "kB", // DC_SIZE_K
  6668. "MB", // DC_SIZE_M
  6669. "GB", // DC_SIZE_G
  6670. "TB", // DC_SIZE_T
  6671. "PB", // DC_SIZE_P
  6672. "EB", // DC_SIZE_E
  6673. 0 // all others
  6674. };
  6675. //-----------------------------------------------------------------------------
  6676. ccp dc_size_tab_1024[DC_SIZE_N_MODES+1] =
  6677. {
  6678. 0, // DC_SIZE_DEFAULT
  6679. 0, // DC_SIZE_AUTO
  6680. "B", // DC_SIZE_BYTES
  6681. "KiB", // DC_SIZE_K
  6682. "MiB", // DC_SIZE_M
  6683. "GiB", // DC_SIZE_G
  6684. "TiB", // DC_SIZE_T
  6685. "PiB", // DC_SIZE_P
  6686. "EiB", // DC_SIZE_E
  6687. 0 // all others
  6688. };
  6689. ///////////////////////////////////////////////////////////////////////////////
  6690. ccp GetSizeUnit // get a unit for column headers
  6691. (
  6692. size_mode_t mode, // print mode
  6693. ccp if_invalid // output for invalid modes
  6694. )
  6695. {
  6696. const bool force_1000 = ( mode & DC_SIZE_M_BASE ) == DC_SIZE_F_1000;
  6697. switch ( mode & DC_SIZE_M_MODE )
  6698. {
  6699. //---- SI and IEC units
  6700. case DC_SIZE_DEFAULT:
  6701. case DC_SIZE_AUTO: return "size";
  6702. case DC_SIZE_BYTES: return "bytes";
  6703. case DC_SIZE_K: return force_1000 ? "kB" : "KiB";
  6704. case DC_SIZE_M: return force_1000 ? "MB" : "MiB";
  6705. case DC_SIZE_G: return force_1000 ? "GB" : "GiB";
  6706. case DC_SIZE_T: return force_1000 ? "TB" : "TiB";
  6707. case DC_SIZE_P: return force_1000 ? "PB" : "PiB";
  6708. case DC_SIZE_E: return force_1000 ? "EB" : "EiB";
  6709. }
  6710. return if_invalid;
  6711. }
  6712. ///////////////////////////////////////////////////////////////////////////////
  6713. int GetSizeFW // get a good value field width
  6714. (
  6715. size_mode_t mode, // print mode
  6716. int min_fw // minimum fw => return max(calc_fw,min_fw);
  6717. // this value is also returned for invalid modes
  6718. )
  6719. {
  6720. int fw = mode & (DC_SIZE_F_AUTO_UNIT|DC_SIZE_F_NO_UNIT) ? 0 : 4;
  6721. switch ( mode & DC_SIZE_M_MODE )
  6722. {
  6723. case DC_SIZE_DEFAULT:
  6724. case DC_SIZE_AUTO:
  6725. if ( !(mode & DC_SIZE_F_NO_UNIT) )
  6726. fw = 4;
  6727. fw += 4;
  6728. break;
  6729. case DC_SIZE_BYTES: fw += 10; break;
  6730. case DC_SIZE_K: fw += 7; break;
  6731. case DC_SIZE_M: fw += 4; break;
  6732. case DC_SIZE_G: fw += 3; break;
  6733. case DC_SIZE_T: fw += 3; break;
  6734. case DC_SIZE_P: fw += 3; break;
  6735. case DC_SIZE_E: fw += 3; break;
  6736. default: fw = min_fw;
  6737. }
  6738. return fw > min_fw ? fw : min_fw;
  6739. }
  6740. ///////////////////////////////////////////////////////////////////////////////
  6741. // [[PrintSize]]
  6742. char * PrintSize
  6743. (
  6744. char *buf, // result buffer
  6745. // NULL: use a local circulary static buffer
  6746. size_t buf_size, // size of 'buf', ignored if buf==NULL
  6747. u64 size, // size to print
  6748. sizeform_mode_t sform_mode, // output format, bit field
  6749. size_mode_t mode // print mode
  6750. )
  6751. {
  6752. DASSERT( DC_SIZE_N_MODES <= DC_SIZE_M_MODE + 1 );
  6753. if (!buf)
  6754. buf = GetCircBuf( buf_size = 20 );
  6755. const bool force_1000 = ( mode & DC_SIZE_M_BASE ) == DC_SIZE_F_1000;
  6756. // ??? [[2do]] follow 'sform_mode'
  6757. const sizeform_mode_t aligned = sform_mode & DC_SFORM_ALIGN;
  6758. switch ( mode & DC_SIZE_M_MODE )
  6759. {
  6760. //---- SI and IEC units
  6761. case DC_SIZE_BYTES:
  6762. snprintf(buf,buf_size, aligned ? "%6llu B" : "%llu B", size );
  6763. break;
  6764. case DC_SIZE_K:
  6765. if (force_1000)
  6766. snprintf(buf,buf_size, aligned ? "%5llu kB" : "%llu kB",
  6767. ( size + KB_SI/2 ) / KB_SI );
  6768. else
  6769. snprintf(buf,buf_size, aligned ? "%4llu KiB" : "%llu KiB",
  6770. ( size + KiB/2 ) / KiB );
  6771. break;
  6772. case DC_SIZE_M:
  6773. if (force_1000)
  6774. snprintf(buf,buf_size, aligned ? "%5llu MB" : "%llu MB",
  6775. ( size + MB_SI /2 ) / MB_SI );
  6776. else
  6777. snprintf(buf,buf_size, aligned ? "%4llu MiB" : "%llu MiB",
  6778. ( size + MiB /2 ) / MiB );
  6779. break;
  6780. case DC_SIZE_G:
  6781. if (force_1000)
  6782. snprintf(buf,buf_size, aligned ? "%5llu GB" : "%llu GB",
  6783. ( size + GB_SI/2 ) / GB_SI );
  6784. else
  6785. snprintf(buf,buf_size, aligned ? "%4llu GiB" : "%llu GiB",
  6786. ( size + GiB/2 ) / GiB );
  6787. break;
  6788. case DC_SIZE_T:
  6789. if (force_1000)
  6790. snprintf(buf,buf_size, aligned ? "%5llu TB" : "%llu TB",
  6791. ( size + TB_SI/2 ) / TB_SI );
  6792. else
  6793. snprintf(buf,buf_size, aligned ? "%4llu TiB" : "%llu TiB",
  6794. ( size + TiB/2 ) / TiB );
  6795. break;
  6796. case DC_SIZE_P:
  6797. if (force_1000)
  6798. snprintf(buf,buf_size, aligned ? "%5llu PB" : "%llu PB",
  6799. ( size + PB_SI/2 ) / PB_SI );
  6800. else
  6801. snprintf(buf,buf_size, aligned ? "%4llu PiB" : "%llu PiB",
  6802. ( size + PiB/2 ) / PiB );
  6803. break;
  6804. case DC_SIZE_E:
  6805. if (force_1000)
  6806. snprintf(buf,buf_size, aligned ? "%5llu EB" : "%llu EB",
  6807. ( size + EB_SI/2 ) / EB_SI );
  6808. else
  6809. snprintf(buf,buf_size, aligned ? "%4llu EiB" : "%llu EiB",
  6810. ( size + EiB/2 ) / EiB );
  6811. break;
  6812. //----- default == auto
  6813. default:
  6814. buf = force_1000
  6815. ? PrintSize1000(buf,buf_size,size,sform_mode)
  6816. : PrintSize1024(buf,buf_size,size,sform_mode);
  6817. if ( !(mode&DC_SIZE_F_NO_UNIT) )
  6818. return buf;
  6819. }
  6820. if ( mode & (DC_SIZE_F_AUTO_UNIT|DC_SIZE_F_NO_UNIT) )
  6821. {
  6822. char * ptr = buf;
  6823. while ( *ptr == ' ' )
  6824. ptr++;
  6825. while ( *ptr && *ptr != ' ' )
  6826. ptr++;
  6827. *ptr = 0;
  6828. }
  6829. return buf;
  6830. }
  6831. ///////////////////////////////////////////////////////////////////////////////
  6832. // [[PrintSize1000]]
  6833. char * PrintSize1000
  6834. (
  6835. char *buf, // result buffer
  6836. // NULL: use a local circulary static buffer
  6837. size_t buf_size, // size of 'buf', ignored if buf==NULL
  6838. u64 size, // size to print
  6839. sizeform_mode_t sform_mode // output format, bit field
  6840. )
  6841. {
  6842. if (!buf)
  6843. buf = GetCircBuf( buf_size = 20 );
  6844. u64 num;
  6845. size_mode_t unit;
  6846. u64 mb = (size+MB_SI/2)/MB_SI; // maybe an overflow => extra if
  6847. if ( mb < 10000 && size < EB_SI )
  6848. {
  6849. u64 kb = (size+KB_SI/2)/KB_SI;
  6850. if ( kb < 10 )
  6851. {
  6852. num = size;
  6853. unit = DC_SIZE_BYTES;
  6854. }
  6855. else if ( kb < 10000 )
  6856. {
  6857. num = kb;
  6858. unit = DC_SIZE_K;
  6859. }
  6860. else
  6861. {
  6862. num = mb;
  6863. unit = DC_SIZE_M;
  6864. }
  6865. }
  6866. else
  6867. {
  6868. mb = size / MB_SI; // recalc because of possible overflow
  6869. u64 tb = (mb+MB_SI/2)/MB_SI;
  6870. if ( tb < 10000 )
  6871. {
  6872. if ( tb < 10 )
  6873. {
  6874. num = (mb+KB_SI/2)/KB_SI;
  6875. unit = DC_SIZE_G;
  6876. }
  6877. else
  6878. {
  6879. num = tb;
  6880. unit = DC_SIZE_T;
  6881. }
  6882. }
  6883. else
  6884. {
  6885. u64 pb = (mb+GB_SI/2)/GB_SI;
  6886. if ( pb < 10000 )
  6887. {
  6888. num = pb;
  6889. unit = DC_SIZE_P;
  6890. }
  6891. else
  6892. {
  6893. num = (mb+TB_SI/2)/TB_SI;
  6894. unit = DC_SIZE_E;
  6895. }
  6896. }
  6897. }
  6898. if ( sform_mode & DC_SFORM_INC
  6899. && num
  6900. && !( num % 1000 )
  6901. && dc_size_tab_1000[unit+1]
  6902. )
  6903. {
  6904. unit++;
  6905. num /= 1000;
  6906. }
  6907. char unit_buf[8];
  6908. char *dest = unit_buf;
  6909. if ( !(sform_mode & DC_SFORM_NARROW) )
  6910. *dest++ = ' ';
  6911. if ( sform_mode & DC_SFORM_UNIT1 )
  6912. {
  6913. if ( unit != DC_SIZE_BYTES )
  6914. *dest++ = dc_size_tab_1000[unit][0];
  6915. else if ( sform_mode & DC_SFORM_ALIGN )
  6916. *dest++ = ' ';
  6917. else
  6918. dest = unit_buf; // not any char
  6919. *dest = 0;
  6920. }
  6921. else if ( sform_mode & DC_SFORM_ALIGN )
  6922. snprintf(dest,sizeof(unit_buf)-1,"%-3s",dc_size_tab_1000[unit]);
  6923. else
  6924. StringCopyS(dest,sizeof(unit_buf)-1,dc_size_tab_1000[unit]);
  6925. if ( !num && unit == DC_SIZE_BYTES && sform_mode & DC_SFORM_DASH )
  6926. {
  6927. if ( sform_mode & DC_SFORM_ALIGN )
  6928. snprintf(buf,buf_size," -%s",unit_buf);
  6929. else
  6930. StringCopyS(buf,buf_size,"-");
  6931. }
  6932. if ( sform_mode & DC_SFORM_ALIGN )
  6933. snprintf(buf,buf_size,"%4llu%s",num,unit_buf);
  6934. else
  6935. snprintf(buf,buf_size,"%llu%s",num,unit_buf);
  6936. return buf;
  6937. };
  6938. ///////////////////////////////////////////////////////////////////////////////
  6939. // [[PrintSize1024]]
  6940. char * PrintSize1024
  6941. (
  6942. char *buf, // result buffer
  6943. // NULL: use a local circulary static buffer
  6944. size_t buf_size, // size of 'buf', ignored if buf==NULL
  6945. u64 size, // size to print
  6946. sizeform_mode_t sform_mode // output format, bit field
  6947. )
  6948. {
  6949. if (!buf)
  6950. buf = GetCircBuf( buf_size = 20 );
  6951. u64 num;
  6952. size_mode_t unit;
  6953. u64 mib = (size+MiB/2)/MiB; // maybe an overflow => extra if
  6954. if ( mib < 10000 && size < EiB )
  6955. {
  6956. u64 kib = (size+KiB/2)/KiB;
  6957. if ( kib < 10 )
  6958. {
  6959. num = size;
  6960. unit = DC_SIZE_BYTES;
  6961. }
  6962. else if ( kib < 10000 )
  6963. {
  6964. num = kib;
  6965. unit = DC_SIZE_K;
  6966. }
  6967. else
  6968. {
  6969. num = mib;
  6970. unit = DC_SIZE_M;
  6971. }
  6972. }
  6973. else
  6974. {
  6975. mib = size / MiB; // recalc because of possible overflow
  6976. u64 tib = (mib+MiB/2)/MiB;
  6977. if ( tib < 10000 )
  6978. {
  6979. if ( tib < 10 )
  6980. {
  6981. num = (mib+KiB/2)/KiB;
  6982. unit = DC_SIZE_G;
  6983. }
  6984. else
  6985. {
  6986. num = tib;
  6987. unit = DC_SIZE_T;
  6988. }
  6989. }
  6990. else
  6991. {
  6992. u64 pib = (mib+GiB/2)/GiB;
  6993. if ( pib < 10000 )
  6994. {
  6995. num = pib;
  6996. unit = DC_SIZE_P;
  6997. }
  6998. else
  6999. {
  7000. num = (mib+TiB/2)/TiB;
  7001. unit = DC_SIZE_E;
  7002. }
  7003. }
  7004. }
  7005. if ( sform_mode & DC_SFORM_INC
  7006. && num
  7007. && !( num & 0x3ff )
  7008. && dc_size_tab_1024[unit+1]
  7009. )
  7010. {
  7011. unit++;
  7012. num /= 0x400;
  7013. }
  7014. char unit_buf[8];
  7015. char *dest = unit_buf;
  7016. if ( !(sform_mode & DC_SFORM_NARROW) )
  7017. *dest++ = ' ';
  7018. if ( sform_mode & DC_SFORM_UNIT1 )
  7019. {
  7020. if ( unit != DC_SIZE_BYTES )
  7021. *dest++ = dc_size_tab_1000[unit][0];
  7022. else if ( sform_mode & DC_SFORM_ALIGN )
  7023. *dest++ = ' ';
  7024. else
  7025. dest = unit_buf; // not any char
  7026. *dest = 0;
  7027. }
  7028. else if ( sform_mode & DC_SFORM_ALIGN )
  7029. snprintf(dest,sizeof(unit_buf)-1,"%-3s",dc_size_tab_1024[unit]);
  7030. else
  7031. StringCopyS(dest,sizeof(unit_buf)-1,dc_size_tab_1024[unit]);
  7032. if ( !num && unit == DC_SIZE_BYTES && sform_mode & DC_SFORM_DASH )
  7033. {
  7034. if ( sform_mode & DC_SFORM_ALIGN )
  7035. snprintf(buf,buf_size," -%s",unit_buf);
  7036. else
  7037. StringCopyS(buf,buf_size,"-");
  7038. }
  7039. else if ( sform_mode & DC_SFORM_ALIGN )
  7040. snprintf(buf,buf_size,"%4llu%s",num,unit_buf);
  7041. else
  7042. snprintf(buf,buf_size,"%llu%s",num,unit_buf);
  7043. return buf;
  7044. };
  7045. //
  7046. ///////////////////////////////////////////////////////////////////////////////
  7047. /////////////// scan size ///////////////
  7048. ///////////////////////////////////////////////////////////////////////////////
  7049. u64 (*ScanSizeFactorHook)
  7050. (
  7051. char ch_factor, // char to analyze
  7052. int force_base // if 1000|1024: force multiple of this
  7053. ) = 0;
  7054. //-----------------------------------------------------------------------------
  7055. u64 ScanSizeFactor
  7056. (
  7057. char ch_factor, // char to analyze
  7058. int force_base // if 1000|1024: force multiple of this
  7059. )
  7060. {
  7061. if (ScanSizeFactorHook)
  7062. {
  7063. u64 res = ScanSizeFactorHook(ch_factor,force_base);
  7064. if (res)
  7065. return res;
  7066. }
  7067. if ( force_base == 1000 )
  7068. {
  7069. switch (ch_factor)
  7070. {
  7071. case 'b': case 'c': return 1;
  7072. case 'k': case 'K': return KB_SI;
  7073. case 'm': case 'M': return MB_SI;
  7074. case 'g': case 'G': return GB_SI;
  7075. case 't': case 'T': return TB_SI;
  7076. case 'p': case 'P': return PB_SI;
  7077. case 'e': case 'E': return EB_SI;
  7078. }
  7079. }
  7080. else if ( force_base == 1024 )
  7081. {
  7082. switch (ch_factor)
  7083. {
  7084. case 'b': case 'c': return 1;
  7085. case 'k': case 'K': return KiB;
  7086. case 'm': case 'M': return MiB;
  7087. case 'g': case 'G': return GiB;
  7088. case 't': case 'T': return TiB;
  7089. case 'p': case 'P': return PiB;
  7090. case 'e': case 'E': return EiB;
  7091. }
  7092. }
  7093. else
  7094. {
  7095. switch (ch_factor)
  7096. {
  7097. case 'b':
  7098. case 'c': return 1;
  7099. case 'k': return KB_SI;
  7100. case 'm': return MB_SI;
  7101. case 'g': return GB_SI;
  7102. case 't': return TB_SI;
  7103. case 'p': return PB_SI;
  7104. case 'e': return EB_SI;
  7105. case 'K': return KiB;
  7106. case 'M': return MiB;
  7107. case 'G': return GiB;
  7108. case 'T': return TiB;
  7109. case 'P': return PiB;
  7110. case 'E': return EiB;
  7111. }
  7112. }
  7113. return 0;
  7114. }
  7115. ///////////////////////////////////////////////////////////////////////////////
  7116. char * ScanSizeTerm
  7117. (
  7118. double *num, // not NULL: store result
  7119. ccp source, // source text
  7120. u64 default_factor, // use this factor if number hasn't one
  7121. int force_base // if 1000|1024: force multiple of this
  7122. )
  7123. {
  7124. ASSERT(source);
  7125. char * end;
  7126. double d = strtod(source,&end);
  7127. if ( end > source )
  7128. {
  7129. // something was read
  7130. if ( *end == '/' )
  7131. {
  7132. const double div = strtod(end+1,&end);
  7133. if ( div > 0.0 )
  7134. d /= div;
  7135. }
  7136. u64 factor = ScanSizeFactor(*end,force_base);
  7137. if (factor)
  7138. end++;
  7139. else
  7140. factor = default_factor;
  7141. if (factor)
  7142. d *= factor;
  7143. else
  7144. end = (char*)source;
  7145. }
  7146. if (num)
  7147. *num = d;
  7148. return end;
  7149. }
  7150. ///////////////////////////////////////////////////////////////////////////////
  7151. char * ScanSize
  7152. (
  7153. double *num, // not NULL: store result
  7154. ccp source, // source text
  7155. u64 default_factor, // use this factor if number hasn't one
  7156. u64 default_factor_add, // use this factor for summands
  7157. int force_base // if 1000|1024: force multiple of this
  7158. )
  7159. {
  7160. DASSERT(source);
  7161. TRACE("ScanSize(df=%llx,%llx, base=%u)\n",
  7162. default_factor, default_factor_add, force_base );
  7163. double sum = 0.0;
  7164. bool add = true;
  7165. char * end = 0;
  7166. for(;;)
  7167. {
  7168. double term;
  7169. end = ScanSizeTerm(&term,source,default_factor,force_base);
  7170. if ( end == source )
  7171. break;
  7172. if (add)
  7173. sum += term;
  7174. else
  7175. sum -= term;
  7176. while ( *end > 0 && *end <= ' ' )
  7177. end++;
  7178. if ( *end == '+' )
  7179. add = true;
  7180. else if ( *end == '-' )
  7181. add = false;
  7182. else
  7183. break;
  7184. source = end+1;
  7185. while ( *source > 0 && *source <= ' ' )
  7186. source++;
  7187. if ( !*source && default_factor_add )
  7188. {
  7189. if (add)
  7190. sum += default_factor_add;
  7191. else
  7192. sum -= default_factor_add;
  7193. end = (char*)source;
  7194. break;
  7195. }
  7196. default_factor = default_factor_add;
  7197. }
  7198. if (num)
  7199. *num = sum;
  7200. return end;
  7201. }
  7202. ///////////////////////////////////////////////////////////////////////////////
  7203. char * ScanSizeU32
  7204. (
  7205. u32 *num, // not NULL: store result
  7206. ccp source, // source text
  7207. u64 default_factor, // use this factor if number hasn't one
  7208. u64 default_factor_add, // use this factor for summands
  7209. int force_base // if 1000|1024: force multiple of this
  7210. )
  7211. {
  7212. double d;
  7213. char * end = ScanSize(&d,source,default_factor,default_factor_add,force_base);
  7214. if ( d < 0 || d > ~(u32)0 )
  7215. end = (char*)source;
  7216. else if (num)
  7217. *num = (u32)d;
  7218. return end;
  7219. }
  7220. ///////////////////////////////////////////////////////////////////////////////
  7221. char * ScanSizeU64
  7222. (
  7223. u64 *num, // not NULL: store result
  7224. ccp source, // source text
  7225. u64 default_factor, // use this factor if number hasn't one
  7226. u64 default_factor_add, // use this factor for summands
  7227. int force_base // if 1000|1024: force multiple of this
  7228. )
  7229. {
  7230. double d;
  7231. char * end = ScanSize(&d,source,default_factor,default_factor_add,force_base);
  7232. if ( d < 0 || d > ~(u64)0 )
  7233. end = (char*)source;
  7234. else if (num)
  7235. *num = (u64)d;
  7236. return end;
  7237. }
  7238. ///////////////////////////////////////////////////////////////////////////////
  7239. ///////////////////////////////////////////////////////////////////////////////
  7240. char * ScanSizeRange
  7241. (
  7242. int *stat, // if not NULL: store result
  7243. // 0:none, 1:single, 2:range
  7244. double *num1, // not NULL: store 'from' result
  7245. double *num2, // not NULL: store 'to' result
  7246. ccp source, // source text
  7247. u64 default_factor, // use this factor if number hasn't one
  7248. u64 default_factor_add, // use this factor for summands
  7249. int force_base, // if 1000|1024: force multiple of this
  7250. double max_value, // >0: max value for open ranges
  7251. range_opt_t opt // options, if 0 then use RAOPT__DEFAULT
  7252. )
  7253. {
  7254. if (!opt)
  7255. opt = RAOPT__DEFAULT;
  7256. int count = 0;
  7257. double d1 = 0, d2;
  7258. bool have_d1 = false;
  7259. if ( opt & RAOPT_ASSUME_0 )
  7260. {
  7261. have_d1 = *source == ':' && opt & RAOPT_COLON
  7262. || *source == '#' && opt & RAOPT_HASH
  7263. || *source == ',' && opt & RAOPT_COMMA
  7264. || *source == '-' && (opt & (RAOPT_COMMA|RAOPT_NEG)) == RAOPT_COMMA;
  7265. }
  7266. char *end = have_d1 ? (char*)source
  7267. : ScanSize(&d1,source,default_factor,default_factor_add,force_base);
  7268. if ( !have_d1 && end == source )
  7269. {
  7270. d1 = d2 = 0.0;
  7271. count = 0;
  7272. }
  7273. else
  7274. {
  7275. count++;
  7276. d2 = d1;
  7277. const bool have_range = *end == ':' && opt & RAOPT_COLON
  7278. || *end == '-' && opt & RAOPT_MINUS;
  7279. const bool have_size = *end == '#' && opt & RAOPT_HASH
  7280. || *end == ',' && opt & RAOPT_COMMA;
  7281. PRINT0("have_d1=%d, have_range=%d, have_size=%d, %.0g:%.0g |%s|\n",have_d1,have_range,have_size,d1,d2,end);
  7282. if ( have_range || have_size )
  7283. {
  7284. if ( d1 < 0 && max_value > 0 && opt & RAOPT_NEG )
  7285. {
  7286. d1 += max_value;
  7287. if ( d1 < 0 )
  7288. d1 = 0;
  7289. }
  7290. source = end;
  7291. end = ScanSize(&d2,source+1,default_factor,default_factor_add,force_base);
  7292. if ( have_range && d2 < 0 && max_value > 0 && opt & RAOPT_NEG )
  7293. {
  7294. d2 += max_value;
  7295. if ( d2 < 0 )
  7296. d2 = 0;
  7297. }
  7298. if ( end == source+1 )
  7299. {
  7300. if ( have_range && max_value > 0.0 )
  7301. {
  7302. count++;
  7303. d2 = max_value;
  7304. if ( *end == '*' )
  7305. end++;
  7306. }
  7307. else
  7308. {
  7309. end--;
  7310. d2 = d1;
  7311. }
  7312. }
  7313. else
  7314. {
  7315. count++;
  7316. if ( have_size )
  7317. d2 += d1-1;
  7318. }
  7319. if ( d2 < d1 )
  7320. {
  7321. count = 0;
  7322. d2 = d1;
  7323. }
  7324. }
  7325. }
  7326. if (stat)
  7327. *stat = count;
  7328. if (num1)
  7329. *num1 = d1;
  7330. if (num2)
  7331. *num2 = d2;
  7332. return end;
  7333. }
  7334. ///////////////////////////////////////////////////////////////////////////////
  7335. char * ScanSizeRangeU32
  7336. (
  7337. int *stat, // if not NULL: store result
  7338. // 0:none, 1:single, 2:range
  7339. u32 *num1, // not NULL: store 'from' result
  7340. u32 *num2, // not NULL: store 'to' result
  7341. ccp source, // source text
  7342. u64 default_factor, // use this factor if number hasn't one
  7343. u64 default_factor_add, // use this factor for summands
  7344. int force_base, // if 1000|1024: force multiple of this
  7345. u32 max_value, // >0: max value for open ranges
  7346. range_opt_t opt // options, if 0 then use RAOPT__DEFAULT
  7347. )
  7348. {
  7349. double d1, d2;
  7350. char * end = ScanSizeRange(stat,&d1,&d2,source,
  7351. default_factor,default_factor_add,force_base,
  7352. max_value>0 ? max_value : U32_MAX, opt );
  7353. if ( d1 < 0 || d1 > U32_MAX || d2 < 0 || d2 > U32_MAX )
  7354. {
  7355. end = (char*)source;
  7356. if (stat)
  7357. *stat = 0;
  7358. }
  7359. else
  7360. {
  7361. if (num1)
  7362. *num1 = (u32)d1;
  7363. if (num2)
  7364. *num2 = (u32)d2;
  7365. }
  7366. return end;
  7367. }
  7368. ///////////////////////////////////////////////////////////////////////////////
  7369. char * ScanSizeRangeS32
  7370. (
  7371. int *stat, // if not NULL: store result
  7372. // 0:none, 1:single, 2:range
  7373. s32 *num1, // not NULL: store 'from' result
  7374. s32 *num2, // not NULL: store 'to' result
  7375. ccp source, // source text
  7376. u64 default_factor, // use this factor if number hasn't one
  7377. u64 default_factor_add, // use this factor for summands
  7378. int force_base, // if 1000|1024: force multiple of this
  7379. s32 max_value, // >0: max value for open ranges
  7380. range_opt_t opt // options, if 0 then use RAOPT__DEFAULT
  7381. )
  7382. {
  7383. double d1, d2;
  7384. char * end = ScanSizeRange(stat,&d1,&d2,source,
  7385. default_factor,default_factor_add,force_base,
  7386. max_value>0 ? max_value : S32_MAX, opt );
  7387. if ( d1 < S32_MIN || d1 > S32_MAX || d2 < S32_MIN || d2 > U32_MAX )
  7388. {
  7389. end = (char*)source;
  7390. if (stat)
  7391. *stat = 0;
  7392. }
  7393. else
  7394. {
  7395. if (num1)
  7396. *num1 = (s32)d1;
  7397. if (num2)
  7398. *num2 = (s32)d2;
  7399. }
  7400. return end;
  7401. }
  7402. ///////////////////////////////////////////////////////////////////////////////
  7403. char * ScanSizeRangeU64
  7404. (
  7405. int *stat, // if not NULL: store result
  7406. // 0:none, 1:single, 2:range
  7407. u64 *num1, // not NULL: store 'from' result
  7408. u64 *num2, // not NULL: store 'to' result
  7409. ccp source, // source text
  7410. u64 default_factor, // use this factor if number hasn't one
  7411. u64 default_factor_add, // use this factor for summands
  7412. int force_base, // if 1000|1024: force multiple of this
  7413. u64 max_value, // >0: max value for open ranges
  7414. range_opt_t opt // options, if 0 then use RAOPT__DEFAULT
  7415. )
  7416. {
  7417. double d1, d2;
  7418. char * end = ScanSizeRange(stat,&d1,&d2,source,
  7419. default_factor,default_factor_add,force_base,
  7420. max_value>0 ? max_value : U64_MAX, opt );
  7421. if ( d1 < 0 || d1 > U64_MAX || d2 < 0 || d2 > U64_MAX )
  7422. {
  7423. end = (char*)source;
  7424. if (stat)
  7425. *stat = 0;
  7426. }
  7427. else
  7428. {
  7429. if (num1)
  7430. *num1 = (u64)d1;
  7431. if (num2)
  7432. *num2 = (u64)d2;
  7433. }
  7434. return end;
  7435. }
  7436. ///////////////////////////////////////////////////////////////////////////////
  7437. char * ScanSizeRangeS64
  7438. (
  7439. int *stat, // if not NULL: store result
  7440. // 0:none, 1:single, 2:range
  7441. s64 *num1, // not NULL: store 'from' result
  7442. s64 *num2, // not NULL: store 'to' result
  7443. ccp source, // source text
  7444. u64 default_factor, // use this factor if number hasn't one
  7445. u64 default_factor_add, // use this factor for summands
  7446. int force_base, // if 1000|1024: force multiple of this
  7447. s64 max_value, // >0: max value for open ranges
  7448. range_opt_t opt // options, if 0 then use RAOPT__DEFAULT
  7449. )
  7450. {
  7451. double d1, d2;
  7452. char * end = ScanSizeRange(stat,&d1,&d2,source,
  7453. default_factor,default_factor_add,force_base,
  7454. max_value>0 ? max_value : S64_MAX, opt );
  7455. if ( d1 < S64_MIN || d1 > S64_MAX || d2 < S64_MIN || d2 > U64_MAX )
  7456. {
  7457. end = (char*)source;
  7458. if (stat)
  7459. *stat = 0;
  7460. }
  7461. else
  7462. {
  7463. if (num1)
  7464. *num1 = (s64)d1;
  7465. if (num2)
  7466. *num2 = (s64)d2;
  7467. }
  7468. return end;
  7469. }
  7470. ///////////////////////////////////////////////////////////////////////////////
  7471. ///////////////////////////////////////////////////////////////////////////////
  7472. char * ScanSizeRangeList
  7473. (
  7474. uint *n_range, // not NULL: store number of scanned ranges
  7475. double *num, // array with '2*max_range' elements
  7476. // unused elements are filled with 0.0
  7477. uint max_range, // max number of allowed ranges
  7478. ccp source, // source text
  7479. u64 default_factor, // use this factor if number hasn't one
  7480. u64 default_factor_add, // use this factor for summands
  7481. int force_base, // if 1000|1024: force multiple of this
  7482. double max_value, // >0: max value for open ranges
  7483. range_opt_t opt // options, if 0 then use RAOPT__DEFAULT
  7484. )
  7485. {
  7486. DASSERT(num);
  7487. uint i = 0;
  7488. char *ptr = (char*)source;
  7489. while ( i < max_range )
  7490. {
  7491. while ( *ptr > 0 && *ptr <= ' ' || *ptr == ',' )
  7492. ptr++;
  7493. int stat;
  7494. ptr = ScanSizeRange( &stat, num, num+1, ptr,
  7495. default_factor, default_factor_add,
  7496. force_base, max_value, opt );
  7497. if (!stat)
  7498. break;
  7499. num += 2;
  7500. i++;
  7501. char *ptr2 = ptr;
  7502. while ( *ptr2 > 0 && *ptr2 <= ' ' )
  7503. ptr2++;
  7504. if ( *ptr2 != ',' )
  7505. break;
  7506. ptr = ptr2 + 1;
  7507. }
  7508. if (n_range)
  7509. *n_range = i;
  7510. while ( i < max_range )
  7511. {
  7512. *num++ = 0.0;
  7513. *num++ = 0.0;
  7514. i++;
  7515. }
  7516. return ptr;
  7517. }
  7518. ///////////////////////////////////////////////////////////////////////////////
  7519. char * ScanSizeRangeListU32
  7520. (
  7521. uint *n_range, // not NULL: store number of scanned ranges
  7522. u32 *num, // array with '2*max_range' elements
  7523. // unused elements are filled with 0
  7524. uint max_range, // max number of allowed ranges
  7525. ccp source, // source text
  7526. u32 default_factor, // use this factor if number hasn't one
  7527. u32 default_factor_add, // use this factor for summands
  7528. int force_base, // if 1000|1024: force multiple of this
  7529. u32 max_value, // >0: max value for open ranges
  7530. range_opt_t opt // options, if 0 then use RAOPT__DEFAULT
  7531. )
  7532. {
  7533. DASSERT(num);
  7534. const uint max = 100;
  7535. double d_buf[2*max];
  7536. double *d = max_range < max ? d_buf : MALLOC(max_range*2*sizeof(double));
  7537. char *end = ScanSizeRangeList( n_range, d, max_range,
  7538. source, default_factor, default_factor_add,
  7539. force_base, max_value, opt );
  7540. uint i;
  7541. for ( i = 0; i < 2*max_range; i++ )
  7542. num[i] = d[i] < 0.0 ? 0.0 : d[i] < U32_MAX ? d[i] : U32_MAX;
  7543. if ( d != d_buf )
  7544. FREE(d);
  7545. return end;
  7546. }
  7547. ///////////////////////////////////////////////////////////////////////////////
  7548. char * ScanSizeRangeListU64
  7549. (
  7550. uint *n_range, // not NULL: store number of scanned ranges
  7551. u64 *num, // array with '2*max_range' elements
  7552. // unused elements are filled with 0
  7553. uint max_range, // max number of allowed ranges
  7554. ccp source, // source text
  7555. u64 default_factor, // use this factor if number hasn't one
  7556. u64 default_factor_add, // use this factor for summands
  7557. int force_base, // if 1000|1024: force multiple of this
  7558. u64 max_value, // >0: max value for open ranges
  7559. range_opt_t opt // options, if 0 then use RAOPT__DEFAULT
  7560. )
  7561. {
  7562. DASSERT(num);
  7563. const uint max = 100;
  7564. double d_buf[2*max];
  7565. double *d = max_range < max ? d_buf : MALLOC(max_range*2*sizeof(double));
  7566. char *end = ScanSizeRangeList( n_range, d, max_range,
  7567. source, default_factor, default_factor_add,
  7568. force_base, max_value, opt );
  7569. uint i;
  7570. for ( i = 0; i < 2*max_range; i++ )
  7571. num[i] = d[i] < 0.0 ? 0.0 : d[i] < U64_MAX ? d[i] : U64_MAX;
  7572. if ( d != d_buf )
  7573. FREE(d);
  7574. return end;
  7575. }
  7576. ///////////////////////////////////////////////////////////////////////////////
  7577. ///////////////////////////////////////////////////////////////////////////////
  7578. enumError ScanSizeOpt
  7579. (
  7580. double *num, // not NULL: store result
  7581. ccp source, // source text
  7582. u64 default_factor, // use this factor if number hasn't one
  7583. u64 default_factor_add, // use this factor for summands
  7584. int force_base, // if 1000|1024: force multiple of this
  7585. ccp opt_name, // NULL or name of option for error messages
  7586. u64 min, // minimum allowed value
  7587. u64 max, // maximum allowed value
  7588. bool print_err // true: print error messages
  7589. )
  7590. {
  7591. double d;
  7592. char * end = ScanSize(&d,source,default_factor,default_factor_add,force_base);
  7593. #ifdef DEBUG
  7594. {
  7595. u64 size = d;
  7596. TRACE("--%s %8.6g ~ %llu ~ %llu GiB ~ %llu GB\n",
  7597. opt_name, d, size, (size+GiB/2)/GiB, (size+500000000)/1000000000 );
  7598. }
  7599. #endif
  7600. enumError err = ERR_OK;
  7601. if ( source == end || *end )
  7602. {
  7603. err = ERR_SYNTAX;
  7604. if (print_err)
  7605. ERROR0(ERR_SYNTAX,
  7606. "Invalid number for option --%s: %s\n",
  7607. opt_name, source );
  7608. }
  7609. else if ( min > 0 && d < min )
  7610. {
  7611. err = ERR_SYNTAX;
  7612. if (print_err)
  7613. ERROR0(ERR_SEMANTIC,
  7614. "Value of --%s too small (must not <%llu): %s\n",
  7615. opt_name, min, source );
  7616. }
  7617. else if ( max > 0 && d > max )
  7618. {
  7619. err = ERR_SYNTAX;
  7620. if (print_err)
  7621. ERROR0(ERR_SEMANTIC,
  7622. "Value of --%s too large (must not >%llu): %s\n",
  7623. opt_name, max, source );
  7624. }
  7625. if ( num && !err )
  7626. *num = d;
  7627. return err;
  7628. }
  7629. ///////////////////////////////////////////////////////////////////////////////
  7630. enumError ScanSizeOptU64
  7631. (
  7632. u64 *num, // not NULL: store result
  7633. ccp source, // source text
  7634. u64 default_factor, // use this factor if number hasn't one
  7635. int force_base, // if 1000|1024: force multiple of this
  7636. ccp opt_name, // NULL or name of option for error messages
  7637. u64 min, // >0: minimum allowed value
  7638. u64 max, // >0: maximum allowed value
  7639. u32 multiple, // >0: result must be multiple
  7640. u32 pow2, // >0: result must power of '1<<pow2'
  7641. bool print_err // true: print error messages
  7642. )
  7643. {
  7644. if (!max)
  7645. max = ~(u64)0;
  7646. if ( pow2 && !force_base )
  7647. {
  7648. // try base 1024 first without error messages
  7649. u64 val;
  7650. if (!ScanSizeOptU64( &val, source, default_factor, 1024,
  7651. opt_name, min,max, multiple, pow2, false ))
  7652. {
  7653. if (num)
  7654. *num = val;
  7655. return ERR_OK;
  7656. }
  7657. }
  7658. double d = 0.0;
  7659. enumError err = ScanSizeOpt(&d,source,default_factor,
  7660. multiple ? multiple : 1,
  7661. force_base,opt_name,min,max,print_err);
  7662. u64 val;
  7663. if ( d < 0.0 )
  7664. {
  7665. val = 0;
  7666. err = ERR_SEMANTIC;
  7667. if (print_err)
  7668. ERROR0(ERR_SEMANTIC, "--%s: negative values not allowed: %s\n",
  7669. opt_name, source );
  7670. }
  7671. else
  7672. val = d;
  7673. if ( err == ERR_OK && pow2 > 0 )
  7674. {
  7675. int shift_count = 0;
  7676. u64 shift_val = val;
  7677. if (val)
  7678. {
  7679. while (!(shift_val&1))
  7680. {
  7681. shift_count++;
  7682. shift_val >>= 1;
  7683. }
  7684. }
  7685. if ( shift_val != 1 || shift_count/pow2*pow2 != shift_count )
  7686. {
  7687. err = ERR_SEMANTIC;
  7688. if (print_err)
  7689. ERROR0(ERR_SYNTAX,
  7690. "--%s: value must be a power of %d but not %llu\n",
  7691. opt_name, 1<<pow2, val );
  7692. }
  7693. }
  7694. if ( err == ERR_OK && multiple > 1 )
  7695. {
  7696. u64 xval = val / multiple * multiple;
  7697. if ( xval != val )
  7698. {
  7699. if ( min > 0 && xval < min )
  7700. xval += multiple;
  7701. if (print_err)
  7702. ERROR0(ERR_WARNING,
  7703. "--%s: value must be a multiple of %u -> use %llu instead of %llu.\n",
  7704. opt_name, multiple, xval, val );
  7705. val = xval;
  7706. }
  7707. }
  7708. if ( num && !err )
  7709. *num = val;
  7710. return err;
  7711. }
  7712. ///////////////////////////////////////////////////////////////////////////////
  7713. enumError ScanSizeOptU32
  7714. (
  7715. u32 *num, // not NULL: store result
  7716. ccp source, // source text
  7717. u64 default_factor, // use this factor if number hasn't one
  7718. int force_base, // if 1000|1024: force multiple of this
  7719. ccp opt_name, // NULL or name of option for error messages
  7720. u64 min, // >0: minimum allowed value
  7721. u64 max, // >0: maximum allowed value
  7722. u32 multiple, // >0: result must be multiple
  7723. u32 pow2, // >0: result must power of '1<<pow2'
  7724. bool print_err // true: print error messages
  7725. )
  7726. {
  7727. if ( !max || max > ~(u32)0 )
  7728. max = ~(u32)0;
  7729. u64 val = 0;
  7730. enumError err = ScanSizeOptU64( &val, source, default_factor, force_base,
  7731. opt_name, min, max, multiple, pow2, print_err );
  7732. if ( num && !err )
  7733. *num = (u32)val;
  7734. return err;
  7735. }
  7736. ///////////////////////////////////////////////////////////////////////////////
  7737. ///////////////////////////////////////////////////////////////////////////////
  7738. // strto*() like wrappers
  7739. u32 GetSizeU32 ( ccp src, char **end, int force_base )
  7740. {
  7741. u32 num = 0;
  7742. char *ptr = ScanSizeU32(&num,src,1,1,force_base);
  7743. if (end)
  7744. *end = ptr;
  7745. return num;
  7746. }
  7747. ///////////////////////////////////////////////////////////////////////////////
  7748. u64 GetSizeU64 ( ccp src, char **end, int force_base )
  7749. {
  7750. u64 num = 0;
  7751. char *ptr = ScanSizeU64(&num,src,1,1,force_base);
  7752. if (end)
  7753. *end = ptr;
  7754. return num;
  7755. }
  7756. ///////////////////////////////////////////////////////////////////////////////
  7757. double GetSizeD ( ccp src, char **end, int force_base )
  7758. {
  7759. double num = 0.0;
  7760. char *ptr = ScanSize(&num,src,1,1,force_base);
  7761. if (end)
  7762. *end = ptr;
  7763. return num;
  7764. }
  7765. //
  7766. ///////////////////////////////////////////////////////////////////////////////
  7767. /////////////// Scan Duration ///////////////
  7768. ///////////////////////////////////////////////////////////////////////////////
  7769. char * ScanSIFactor
  7770. (
  7771. // returns end of scanned string
  7772. double *num, // not NULL: store result
  7773. ccp source, // source text
  7774. double default_factor // return this if no factor found
  7775. )
  7776. {
  7777. DASSERT(source);
  7778. double i = 0.0;
  7779. switch (*(uchar*)source++)
  7780. {
  7781. case 'y': default_factor = 1e-24; break;
  7782. case 'z': default_factor = 1e-21; break;
  7783. case 'a': default_factor = 1e-18; break;
  7784. case 'f': default_factor = 1e-15; break;
  7785. case 'p': default_factor = 1e-12; break;
  7786. case 'n': default_factor = 1e-9; break;
  7787. case 0xb5: // µ as ASCII
  7788. case 'u': default_factor = 1e-6; break;
  7789. case 'm': default_factor = 1e-3; break;
  7790. case 'c': default_factor = 1e-2; break;
  7791. case 'd': default_factor = 1e-1; break;
  7792. case 'h': default_factor = 1e2; break;
  7793. case 'k':
  7794. case 'K': default_factor = 1e3; i = 1024.0; break;
  7795. case 'M': default_factor = 1e6; i = 1048576.0; break;
  7796. case 'G': default_factor = 1e9; i = 1073741824.0; break;
  7797. case 'T': default_factor = 1e12; i = 1099511627776.0; break;
  7798. case 'P': default_factor = 1e15; i = 1125899906842624.0; break;
  7799. case 'E': default_factor = 1e18; i = 1152921504606846976.0; break;
  7800. case 'Z': default_factor = 1e21; i = 1180591620717411303424.0; break;
  7801. case 'Y': default_factor = 1e24; i = 1208925819614629174706176.0; break;
  7802. case 0xc2:
  7803. if ( (uchar)*source == 0xb5 )
  7804. {
  7805. // µ as UTF-8
  7806. source++;
  7807. default_factor = 1e-6;
  7808. break;
  7809. }
  7810. else
  7811. source--;
  7812. break;
  7813. default:
  7814. source--;
  7815. }
  7816. if ( *source == 'i' && i )
  7817. {
  7818. source++;
  7819. default_factor = i;
  7820. }
  7821. if (num)
  7822. *num = default_factor;
  7823. return (char*)source;
  7824. }
  7825. ///////////////////////////////////////////////////////////////////////////////
  7826. double GetDurationFactor ( char ch )
  7827. {
  7828. switch (ch)
  7829. {
  7830. case 's': return 1.0; break;
  7831. case 'm': return SEC_PER_MIN; break;
  7832. case 'h': return SEC_PER_HOUR; break;
  7833. case 't':
  7834. case 'd': return SEC_PER_DAY; break;
  7835. case 'w': return SEC_PER_WEEK; break;
  7836. case 'j':
  7837. case 'y': return SEC_PER_YEAR; break;
  7838. default: return 0.0;
  7839. }
  7840. }
  7841. ///////////////////////////////////////////////////////////////////////////////
  7842. char * ScanDuration
  7843. (
  7844. // Returns a pointer to the the first not used character.
  7845. // On error, it is 'source' and '*seconds' is set to 0.0.
  7846. double *seconds, // not NULL: store result (number of seconds)
  7847. ccp source, // source text
  7848. double default_factor, // default factor if no SI unit found
  7849. ScanDuration_t mode
  7850. )
  7851. {
  7852. if (!source)
  7853. return 0;
  7854. ccp src, done;
  7855. done = src = source;
  7856. if ( mode & SDUMD_SKIP_BLANKS )
  7857. while ( *src == ' ' || *src == '\t' )
  7858. src++;
  7859. if ( mode & SDUMD_ALLOW_LIST )
  7860. {
  7861. bool valid = false;
  7862. mode &= ~(SDUMD_SKIP_BLANKS|SDUMD_ALLOW_LIST);
  7863. double sum = 0.0;
  7864. bool sub = false;
  7865. for(;;)
  7866. {
  7867. double val;
  7868. ccp end = ScanDuration(&val,src,default_factor,mode);
  7869. if ( src == end )
  7870. break;
  7871. if (sub)
  7872. {
  7873. sub = false;
  7874. sum -= val;
  7875. }
  7876. else
  7877. sum += val;
  7878. done = src = end;
  7879. valid = true;
  7880. if ( mode & SDUMD_ALLOW_SPACE_SEP )
  7881. while ( *src == ' ' || *src == '\t' )
  7882. src++;
  7883. if ( *src == '+' && mode & SDUMD_ALLOW_PLUS_SEP )
  7884. src++;
  7885. else if ( *src == '-' && mode & SDUMD_ALLOW_MINUS_SEP )
  7886. {
  7887. src++;
  7888. sub = true;
  7889. }
  7890. mode |= SDUMD_SKIP_BLANKS;
  7891. }
  7892. if (seconds)
  7893. *seconds = sum;
  7894. return (char*)( valid ? done : source );
  7895. }
  7896. //--- single scan
  7897. char *end;
  7898. double val = strtod(src,&end);
  7899. if ( end > src )
  7900. {
  7901. if ( *end == ':' && mode & SDUMD_ALLOW_COLON )
  7902. {
  7903. // 'H:M' or 'H:M:S'
  7904. src = end + 1;
  7905. val *= 3600;
  7906. double min = strtod(src,&end);
  7907. if ( end > src )
  7908. {
  7909. val += 60*min;
  7910. src = end;
  7911. if ( *src == ':' )
  7912. {
  7913. // 'H:M:S'
  7914. double sec = strtod(++src,&end);
  7915. if ( end > src )
  7916. {
  7917. src = end;
  7918. val += sec;
  7919. }
  7920. }
  7921. }
  7922. }
  7923. else
  7924. {
  7925. if ( *end == '/' && mode & SDUMD_ALLOW_DIV )
  7926. {
  7927. const double div = strtod(end+1,&end);
  7928. if ( div > 0.0 )
  7929. val /= div;
  7930. }
  7931. src = end;
  7932. double si_factor;
  7933. end = ScanSIFactor(&si_factor,src,1.0);
  7934. char factor = *end;
  7935. if ( mode & SDUMD_ALLOW_CAPITALS )
  7936. factor = tolower((int)factor);
  7937. double unit = GetDurationFactor(factor);
  7938. if (unit)
  7939. {
  7940. val *= unit * si_factor;
  7941. src = end+1;
  7942. }
  7943. else
  7944. {
  7945. char factor = *src;
  7946. if ( mode & SDUMD_ALLOW_CAPITALS )
  7947. factor = tolower((int)factor);
  7948. unit = GetDurationFactor(factor);
  7949. if (unit)
  7950. {
  7951. val *= unit;
  7952. src++;
  7953. }
  7954. else
  7955. {
  7956. val *= (end>src) ? si_factor : default_factor;
  7957. src = end;
  7958. }
  7959. }
  7960. }
  7961. if (seconds)
  7962. *seconds = val;
  7963. return (char*)src;
  7964. }
  7965. if (seconds)
  7966. *seconds = 0.0;
  7967. return (char*)source;
  7968. }
  7969. ///////////////////////////////////////////////////////////////////////////////
  7970. double str2duration ( ccp src, char **endptr, double default_factor )
  7971. {
  7972. double dur = 0.0;
  7973. char *end = ScanDuration(&dur,src,default_factor,SDUMD_M_DEFAULT);
  7974. if (endptr)
  7975. *endptr = end;
  7976. return dur;
  7977. }
  7978. //
  7979. ///////////////////////////////////////////////////////////////////////////////
  7980. /////////////// ScanIP4 ///////////////
  7981. ///////////////////////////////////////////////////////////////////////////////
  7982. ipv4_class_t ScanIP4
  7983. (
  7984. ipv4_t *ret_ip4, // not NULL: return numeric IPv4 here
  7985. ccp addr, // address to analyze
  7986. int addr_len // length of addr; if <0: use strlen(addr)
  7987. )
  7988. {
  7989. //--- param check
  7990. if (!addr)
  7991. {
  7992. error:
  7993. if (ret_ip4)
  7994. *ret_ip4 = 0;
  7995. return CIP4_ERROR;
  7996. }
  7997. if ( addr_len < 0 )
  7998. addr_len = strlen(addr);
  7999. ccp addr_end = addr + addr_len;
  8000. //--- skip leading blanks
  8001. while ( addr < addr_end && isblank((int)*addr) )
  8002. addr++;
  8003. //--- scan input
  8004. int count = 0;
  8005. bool trailing_pt = false;
  8006. uint num[4] = {0,0,0,0};
  8007. while ( addr < addr_end )
  8008. {
  8009. if ( *addr < '0' || *addr > '9' )
  8010. break;
  8011. addr = ScanNumber ( num+count++, addr, addr_end, *addr == '0' ? 8 : 10, 3 );
  8012. if ( count == 4 || *addr != '.' )
  8013. {
  8014. trailing_pt = false;
  8015. break;
  8016. }
  8017. addr++;
  8018. trailing_pt = true;
  8019. }
  8020. //printf("N=%u .=%u [%u,%u,%u,%u] addr=%s\n",count,trailing_pt,num[0],num[1],num[2],num[3],addr);
  8021. if ( !count || addr < addr_end )
  8022. goto error;
  8023. //--- calculate IPv4 based on class-X
  8024. ipv4_class_t res = CIP4_INVALID;
  8025. u32 ipv4 = 0;
  8026. switch ( trailing_pt ? 4 : count )
  8027. {
  8028. case 1:
  8029. ipv4 = num[0];
  8030. res = CIP4_NUMERIC;
  8031. break;
  8032. case 2:
  8033. if ( num[0] <= 0xff && num[1] <= 0xffffff )
  8034. {
  8035. ipv4 = num[0] << 24 | num[1];
  8036. res = CIP4_CLASS_A;
  8037. }
  8038. break;
  8039. case 3:
  8040. if ( num[0] <= 0xff && num[1] <= 0xff && num[2] <= 0xffff )
  8041. {
  8042. ipv4 = num[0] << 24 | num[1] << 16 | num[2];
  8043. res = CIP4_CLASS_B;
  8044. }
  8045. break;
  8046. case 4:
  8047. if ( num[0] <= 0xff && num[1] <= 0xff && num[2] <= 0xff && num[3] <= 0xff )
  8048. {
  8049. ipv4 = num[0] << 24 | num[1] << 16 | num[2] << 8 | num[3];
  8050. res = CIP4_CLASS_C;
  8051. }
  8052. break;
  8053. }
  8054. //--- return status
  8055. if (ret_ip4)
  8056. *ret_ip4 = ipv4;
  8057. return res;
  8058. }
  8059. ///////////////////////////////////////////////////////////////////////////////
  8060. char * NormalizeIP4
  8061. (
  8062. // Return a pointer to dest if valid IPv4,
  8063. // Otherwise return 0 and buf is not modifieid.
  8064. char *buf, // result buffer, can be 'addr'
  8065. // if NULL: use a local circulary static buffer
  8066. size_t buf_size, // size of 'buf', ignored if buf==NULL
  8067. bool c_notation, // TRUE: force lass-C notation (a.b.c.d)
  8068. ccp addr, // address to analyze
  8069. int addr_len // length of addr; if <0: use strlen(addr)
  8070. )
  8071. {
  8072. ipv4_t ip4;
  8073. ipv4_class_t stat = ScanIP4(&ip4,addr,-1);
  8074. if ( stat <= CIP4_INVALID )
  8075. return 0;
  8076. return PrintIP4ByMode( buf, buf_size, ip4, c_notation ? CIP4_CLASS_C : stat, -1 );
  8077. }
  8078. ///////////////////////////////////////////////////////////////////////////////
  8079. int dclib_aton ( ccp addr, struct in_addr *inp )
  8080. {
  8081. ipv4_t ip4;
  8082. ipv4_class_t stat = ScanIP4(&ip4,addr,-1);
  8083. if (inp)
  8084. inp->s_addr = htonl(ip4);
  8085. return stat > CIP4_INVALID;
  8086. }
  8087. //
  8088. ///////////////////////////////////////////////////////////////////////////////
  8089. /////////////// PrintIP4*() ///////////////
  8090. ///////////////////////////////////////////////////////////////////////////////
  8091. char * PrintIP4N
  8092. (
  8093. // print as unsigned number (CIP4_NUMERIC)
  8094. char *buf, // result buffer
  8095. // NULL: use a local circulary static buffer
  8096. size_t buf_size, // size of 'buf', ignored if buf==NULL
  8097. u32 ip4, // IP4 to print
  8098. s32 port // 0..0xffff: add ':port'
  8099. )
  8100. {
  8101. if (!buf)
  8102. buf = GetCircBuf( buf_size = FW_IPV4_A_PORT+1 );
  8103. if ( port >= 0 && port <= 0xffff )
  8104. snprintf(buf,buf_size,"%u:%u", ip4, port );
  8105. else
  8106. snprintf(buf,buf_size,"%u",ip4);
  8107. return buf;
  8108. }
  8109. ///////////////////////////////////////////////////////////////////////////////
  8110. char * PrintIP4A
  8111. (
  8112. // print in A-notation (CIP4_CLASS_A)
  8113. char *buf, // result buffer
  8114. // NULL: use a local circulary static buffer
  8115. size_t buf_size, // size of 'buf', ignored if buf==NULL
  8116. u32 ip4, // IP4 to print
  8117. s32 port // 0..0xffff: add ':port'
  8118. )
  8119. {
  8120. if (!buf)
  8121. buf = GetCircBuf( buf_size = FW_IPV4_A_PORT+1 );
  8122. u8 addr[4];
  8123. write_be32(addr,ip4);
  8124. if ( port >= 0 && port <= 0xffff )
  8125. snprintf(buf,buf_size,"%u.%u:%u",
  8126. addr[0], ip4 & 0xffffff, port );
  8127. else
  8128. snprintf(buf,buf_size,"%u.%u",
  8129. addr[0], ip4 & 0xffffff );
  8130. return buf;
  8131. }
  8132. ///////////////////////////////////////////////////////////////////////////////
  8133. char * PrintIP4B
  8134. (
  8135. // print in B-notation (CIP4_CLASS_B)
  8136. char *buf, // result buffer
  8137. // NULL: use a local circulary static buffer
  8138. size_t buf_size, // size of 'buf', ignored if buf==NULL
  8139. u32 ip4, // IP4 to print
  8140. s32 port // 0..0xffff: add ':port'
  8141. )
  8142. {
  8143. if (!buf)
  8144. buf = GetCircBuf( buf_size = FW_IPV4_B_PORT+1 );
  8145. u8 addr[4];
  8146. write_be32(addr,ip4);
  8147. if ( port >= 0 && port <= 0xffff )
  8148. snprintf(buf,buf_size,"%u.%u.%u:%u",
  8149. addr[0], addr[1], ip4 & 0xffff, port );
  8150. else
  8151. snprintf(buf,buf_size,"%u.%u.%u",
  8152. addr[0], addr[1], ip4 & 0xffff );
  8153. return buf;
  8154. }
  8155. ///////////////////////////////////////////////////////////////////////////////
  8156. char * PrintIP4
  8157. (
  8158. char *buf, // result buffer
  8159. // NULL: use a local circulary static buffer
  8160. size_t buf_size, // size of 'buf', ignored if buf==NULL
  8161. u32 ip4, // IP4 to print
  8162. s32 port // 0..0xffff: add ':port'
  8163. )
  8164. {
  8165. if (!buf)
  8166. buf = GetCircBuf( buf_size = FW_IPV4_C_PORT+1 );
  8167. u8 addr[4];
  8168. write_be32(addr,ip4);
  8169. if ( port >= 0 && port <= 0xffff )
  8170. snprintf(buf,buf_size,"%u.%u.%u.%u:%u",
  8171. addr[0], addr[1], addr[2], addr[3], port );
  8172. else
  8173. snprintf(buf,buf_size,"%u.%u.%u.%u",
  8174. addr[0], addr[1], addr[2], addr[3] );
  8175. return buf;
  8176. }
  8177. ///////////////////////////////////////////////////////////////////////////////
  8178. char * PrintLeftIP4
  8179. (
  8180. char *buf, // result buffer
  8181. // NULL: use a local circulary static buffer
  8182. size_t buf_size, // size of 'buf', ignored if buf==NULL
  8183. u32 ip4, // IP4 to print
  8184. s32 port // 0..0xffff: add ':port'
  8185. )
  8186. {
  8187. if (!buf)
  8188. buf = GetCircBuf( buf_size = FW_IPV4_C_PORT+1 );
  8189. u8 addr[4];
  8190. write_be32(addr,ip4);
  8191. uint len, fw;
  8192. if ( port >= 0 && port <= 0xffff )
  8193. {
  8194. fw = 21;
  8195. len = snprintf(buf,buf_size,"%u.%u.%u.%u:%u",
  8196. addr[0], addr[1], addr[2], addr[3], port );
  8197. }
  8198. else
  8199. {
  8200. fw = 15;
  8201. len = snprintf(buf,buf_size,"%u.%u.%u.%u",
  8202. addr[0], addr[1], addr[2], addr[3] );
  8203. }
  8204. char *dest = buf + len;
  8205. char *end = buf + ( fw < buf_size ? fw : buf_size );
  8206. while ( dest < end )
  8207. *dest++ = ' ';
  8208. *dest = 0;
  8209. return buf;
  8210. }
  8211. ///////////////////////////////////////////////////////////////////////////////
  8212. char * PrintRightIP4
  8213. (
  8214. char *buf, // result buffer
  8215. // NULL: use a local circulary static buffer
  8216. size_t buf_size, // size of 'buf', ignored if buf==NULL
  8217. u32 ip4, // IP4 to print
  8218. s32 port, // 0..0xffff: add ':port'
  8219. uint port_mode // 0: 'ip:port', 1: 'ip :port', 2: 'ip : port'
  8220. )
  8221. {
  8222. if (!buf)
  8223. buf = GetCircBuf( buf_size = 24 );
  8224. u8 addr[4];
  8225. write_be32(addr,ip4);
  8226. char tempbuf[16];
  8227. snprintf(tempbuf,sizeof(tempbuf),"%u.%u.%u.%u",
  8228. addr[0], addr[1], addr[2], addr[3] );
  8229. if ( port >= 0 && port <= 0xffff )
  8230. {
  8231. if (!port_mode)
  8232. snprintf(buf,buf_size,"%15s:%-5u",tempbuf,port);
  8233. else if ( port_mode == 1 )
  8234. snprintf(buf,buf_size,"%15s :%-5u",tempbuf,port);
  8235. else
  8236. snprintf(buf,buf_size,"%15s : %-5u",tempbuf,port);
  8237. }
  8238. else
  8239. snprintf(buf,buf_size,"%15s",tempbuf);
  8240. return buf;
  8241. }
  8242. ///////////////////////////////////////////////////////////////////////////////
  8243. char * PrintAlignedIP4
  8244. (
  8245. char *buf, // result buffer
  8246. // NULL: use a local circulary static buffer
  8247. size_t buf_size, // size of 'buf', ignored if buf==NULL
  8248. u32 ip4, // IP4 to print
  8249. s32 port // 0..0xffff: add ':port'
  8250. )
  8251. {
  8252. if (!buf)
  8253. buf = GetCircBuf( buf_size = FW_IPV4_C_PORT+1 );
  8254. u8 addr[4];
  8255. write_be32(addr,ip4);
  8256. if ( port >= 0 && port <= 0xffff )
  8257. snprintf(buf,buf_size,"%3u.%3u.%3u.%3u:%5u",
  8258. addr[0], addr[1], addr[2], addr[3], port );
  8259. else
  8260. snprintf(buf,buf_size,"%3u.%3u.%3u.%3u",
  8261. addr[0], addr[1], addr[2], addr[3] );
  8262. return buf;
  8263. }
  8264. ///////////////////////////////////////////////////////////////////////////////
  8265. char * PrintIP4ByMode
  8266. (
  8267. char *buf, // result buffer
  8268. // NULL: use a local circulary static buffer
  8269. size_t buf_size, // size of 'buf', ignored if buf==NULL
  8270. u32 ip4, // IP4 to print
  8271. ipv4_class_t mode, // CIP4_NUMERIC | CIP4_CLASS_A | CIP4_CLASS_B:
  8272. // force numeric or class-A/B output; otherwise class-C output
  8273. s32 port // 0..0xffff: add ':port'
  8274. )
  8275. {
  8276. switch (mode)
  8277. {
  8278. case CIP4_NUMERIC: return PrintIP4N(buf,buf_size,ip4,port);
  8279. case CIP4_CLASS_A: return PrintIP4A(buf,buf_size,ip4,port);
  8280. case CIP4_CLASS_B: return PrintIP4B(buf,buf_size,ip4,port);
  8281. default: return PrintIP4 (buf,buf_size,ip4,port);
  8282. }
  8283. }
  8284. //
  8285. ///////////////////////////////////////////////////////////////////////////////
  8286. /////////////// CRC16 ///////////////
  8287. ///////////////////////////////////////////////////////////////////////////////
  8288. void CreateCRC16Table ( u16 table[0x100], u16 polynom )
  8289. {
  8290. int i, j;
  8291. for ( i = 0; i < 256; i++ )
  8292. {
  8293. u16 val = i << 8;
  8294. for ( j = 0; j < 8; j++ )
  8295. {
  8296. if ( val & 0x8000 )
  8297. val = val << 1 ^ polynom;
  8298. else
  8299. val <<= 1;
  8300. }
  8301. table[i] = val;
  8302. }
  8303. }
  8304. //-----------------------------------------------------------------------------
  8305. const u16 * GetCRC16Table ( u16 polynom )
  8306. {
  8307. static u16 *table = 0;
  8308. static u16 active_polynom = 0;
  8309. if ( !table || active_polynom != polynom )
  8310. {
  8311. if (!table)
  8312. table = MALLOC(sizeof(u16)*0x100);
  8313. CreateCRC16Table(table,polynom);
  8314. active_polynom = polynom;
  8315. }
  8316. return table;
  8317. }
  8318. //-----------------------------------------------------------------------------
  8319. u16 CalcCRC16 ( cvp data, uint data_size, u16 polynom, u16 preset )
  8320. {
  8321. DASSERT( data || !data_size );
  8322. register u16 crc = preset;
  8323. if ( data_size > 0 )
  8324. {
  8325. const u16 *table = GetCRC16Table(polynom);
  8326. const u8 *ptr = data;
  8327. while ( data_size-- > 0 )
  8328. crc = table[ ( *ptr++ ^ crc >> 8 ) & 0xff ] ^ crc << 8;
  8329. }
  8330. return crc;
  8331. }
  8332. //
  8333. ///////////////////////////////////////////////////////////////////////////////
  8334. /////////////// misc ///////////////
  8335. ///////////////////////////////////////////////////////////////////////////////
  8336. float double2float ( double d )
  8337. {
  8338. // reduce precision
  8339. return d;
  8340. }
  8341. ///////////////////////////////////////////////////////////////////////////////
  8342. ///////////////////////////////////////////////////////////////////////////////
  8343. u64 MulDivU64 ( u64 factor1, u64 factor2, u64 divisor )
  8344. {
  8345. #if HAVE_INT128
  8346. return (u128)factor1 * (u128)factor2 / divisor;
  8347. #else
  8348. if ( !factor1 || !factor2 )
  8349. return 0;
  8350. const double product = (double)factor1 * (double)factor2;
  8351. return product < 0xfffffffffffffff0
  8352. ? factor1 * factor2 / divisor
  8353. : (u64) trunc( product / divisor );
  8354. #endif
  8355. }
  8356. //-----------------------------------------------------------------------------
  8357. s64 MulDivS64 ( s64 factor1, s64 factor2, s64 divisor )
  8358. {
  8359. bool neg = false;
  8360. if ( factor1 < 0 ) { factor1 = -factor1; neg = !neg; }
  8361. if ( factor2 < 0 ) { factor2 = -factor2; neg = !neg; }
  8362. if ( divisor < 0 ) { divisor = -divisor; neg = !neg; }
  8363. s64 r = MulDivU64(factor1,factor2,divisor);
  8364. return neg ? -r : r;
  8365. }
  8366. ///////////////////////////////////////////////////////////////////////////////
  8367. ///////////////////////////////////////////////////////////////////////////////
  8368. ccp PrintNiceID4 ( uint id )
  8369. {
  8370. if (!id)
  8371. return "----";
  8372. char *buf = GetCircBuf(5);
  8373. DASSERT(buf);
  8374. #if 0 // the second solution is much faster!
  8375. buf[4] = 0;
  8376. div_t d = div( (int)( id % (26*26*100) ), 10 );
  8377. buf[3] = '0' + d.rem;
  8378. d = div(d.quot,10);
  8379. buf[2] = '0' + d.rem;
  8380. d = div(d.quot,26);
  8381. buf[1] = 'A' + d.rem;
  8382. buf[0] = 'A' + d.quot;
  8383. #else
  8384. buf[0] = 'A' + id / 2600 % 26;
  8385. buf[1] = 'A' + id / 100 % 26;
  8386. buf[2] = '0' + id / 10 % 10;
  8387. buf[3] = '0' + id % 10;
  8388. buf[4] = 0;
  8389. #endif
  8390. return buf;
  8391. }
  8392. ///////////////////////////////////////////////////////////////////////////////
  8393. char * ScanNiceID4 ( int * res, ccp arg )
  8394. {
  8395. DASSERT(res);
  8396. *res = -1;
  8397. if (!arg)
  8398. return 0;
  8399. char ch = tolower((int)arg[0]);
  8400. if ( ch >= 'a' && ch <= 'z' )
  8401. {
  8402. int num = ch - 'a';
  8403. ch = tolower((int)arg[1]);
  8404. if ( ch >= 'a' && ch <= 'z' )
  8405. {
  8406. num = 26 * num + ch - 'a';
  8407. ch = arg[2];
  8408. if ( ch >= '0' && ch <= '9' )
  8409. {
  8410. num = 10 * num + ch - '0';
  8411. ch = arg[3];
  8412. if ( ch >= '0' && ch <= '9' )
  8413. {
  8414. *res = 10 * num + ch - '0';
  8415. return (char*)arg+4;
  8416. }
  8417. }
  8418. }
  8419. }
  8420. return (char*)arg;
  8421. };
  8422. ///////////////////////////////////////////////////////////////////////////////
  8423. ///////////////////////////////////////////////////////////////////////////////
  8424. ccp PrintNiceID5 ( uint id )
  8425. {
  8426. if (!id)
  8427. return "-----";
  8428. char *buf = GetCircBuf(6);
  8429. DASSERT(buf);
  8430. buf[0] = 'A' + id / 26000 % 26;
  8431. buf[1] = 'A' + id / 1000 % 26;
  8432. buf[2] = '0' + id / 100 % 10;
  8433. buf[3] = '0' + id / 10 % 10;
  8434. buf[4] = '0' + id % 10;
  8435. buf[5] = 0;
  8436. return buf;
  8437. }
  8438. ///////////////////////////////////////////////////////////////////////////////
  8439. char * ScanNiceID5 ( int * res, ccp arg )
  8440. {
  8441. DASSERT(res);
  8442. *res = -1;
  8443. if (!arg)
  8444. return 0;
  8445. char ch = tolower((int)arg[0]);
  8446. if ( ch >= 'a' && ch <= 'z' )
  8447. {
  8448. int num = ch - 'a';
  8449. ch = tolower((int)arg[1]);
  8450. if ( ch >= 'a' && ch <= 'z' )
  8451. {
  8452. num = 26 * num + ch - 'a';
  8453. ch = arg[2];
  8454. if ( ch >= '0' && ch <= '9' )
  8455. {
  8456. num = 10 * num + ch - '0';
  8457. ch = arg[3];
  8458. if ( ch >= '0' && ch <= '9' )
  8459. {
  8460. num = 10 * num + ch - '0';
  8461. ch = arg[4];
  8462. if ( ch >= '0' && ch <= '9' )
  8463. {
  8464. *res = 10 * num + ch - '0';
  8465. return (char*)arg+5;
  8466. }
  8467. }
  8468. }
  8469. }
  8470. }
  8471. return (char*)arg;
  8472. };
  8473. ///////////////////////////////////////////////////////////////////////////////
  8474. ///////////////////////////////////////////////////////////////////////////////
  8475. ccp PrintNiceID6 ( uint id )
  8476. {
  8477. if (!id)
  8478. return "------";
  8479. char *buf = GetCircBuf(7);
  8480. DASSERT(buf);
  8481. buf[0] = 'A' + id / 676000 % 26;
  8482. buf[1] = 'A' + id / 26000 % 26;
  8483. buf[2] = 'A' + id / 1000 % 26;
  8484. buf[3] = '0' + id / 100 % 10;
  8485. buf[4] = '0' + id / 10 % 10;
  8486. buf[5] = '0' + id % 10;
  8487. buf[6] = 0;
  8488. return buf;
  8489. }
  8490. ///////////////////////////////////////////////////////////////////////////////
  8491. char * ScanNiceID6 ( int * res, ccp arg )
  8492. {
  8493. DASSERT(res);
  8494. *res = -1;
  8495. if (!arg)
  8496. return 0;
  8497. char ch = tolower((int)arg[0]);
  8498. if ( ch >= 'a' && ch <= 'z' )
  8499. {
  8500. int num = ch - 'a';
  8501. ch = tolower((int)arg[1]);
  8502. if ( ch >= 'a' && ch <= 'z' )
  8503. {
  8504. num = 26 * num + ch - 'a';
  8505. ch = tolower((int)arg[2]);
  8506. if ( ch >= 'a' && ch <= 'z' )
  8507. {
  8508. num = 26 * num + ch - 'a';
  8509. ch = arg[3];
  8510. if ( ch >= '0' && ch <= '9' )
  8511. {
  8512. num = 10 * num + ch - '0';
  8513. ch = arg[4];
  8514. if ( ch >= '0' && ch <= '9' )
  8515. {
  8516. num = 10 * num + ch - '0';
  8517. ch = arg[5];
  8518. if ( ch >= '0' && ch <= '9' )
  8519. {
  8520. *res = 10 * num + ch - '0';
  8521. return (char*)arg+6;
  8522. }
  8523. }
  8524. }
  8525. }
  8526. }
  8527. }
  8528. return (char*)arg;
  8529. };
  8530. //
  8531. ///////////////////////////////////////////////////////////////////////////////
  8532. /////////////// END ///////////////
  8533. ///////////////////////////////////////////////////////////////////////////////