1
0

argtable3.c 209 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860
  1. /*******************************************************************************
  2. * This file is part of the argtable3 library.
  3. *
  4. * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
  5. * <sheitmann@users.sourceforge.net>
  6. * All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions are met:
  10. * * Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * * Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * * Neither the name of STEWART HEITMANN nor the names of its contributors
  16. * may be used to endorse or promote products derived from this software
  17. * without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  20. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
  23. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  24. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  25. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  26. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  28. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. ******************************************************************************/
  30. #include "argtable3.h"
  31. #define ARG_AMALGAMATION
  32. /*******************************************************************************
  33. * argtable3_private: Declares private types, constants, and interfaces
  34. *
  35. * This file is part of the argtable3 library.
  36. *
  37. * Copyright (C) 2013-2019 Tom G. Huang
  38. * <tomghuang@gmail.com>
  39. * All rights reserved.
  40. *
  41. * Redistribution and use in source and binary forms, with or without
  42. * modification, are permitted provided that the following conditions are met:
  43. * * Redistributions of source code must retain the above copyright
  44. * notice, this list of conditions and the following disclaimer.
  45. * * Redistributions in binary form must reproduce the above copyright
  46. * notice, this list of conditions and the following disclaimer in the
  47. * documentation and/or other materials provided with the distribution.
  48. * * Neither the name of STEWART HEITMANN nor the names of its contributors
  49. * may be used to endorse or promote products derived from this software
  50. * without specific prior written permission.
  51. *
  52. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  53. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  54. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  55. * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
  56. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  57. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  58. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  59. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  60. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  61. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  62. ******************************************************************************/
  63. #ifndef ARG_UTILS_H
  64. #define ARG_UTILS_H
  65. #include <stdlib.h>
  66. #define ARG_ENABLE_TRACE 0
  67. #define ARG_ENABLE_LOG 1
  68. #ifdef __cplusplus
  69. extern "C" {
  70. #endif
  71. enum { ARG_ERR_MINCOUNT = 1, ARG_ERR_MAXCOUNT, ARG_ERR_BADINT, ARG_ERR_OVERFLOW, ARG_ERR_BADDOUBLE, ARG_ERR_BADDATE, ARG_ERR_REGNOMATCH };
  72. typedef void(arg_panicfn)(const char* fmt, ...);
  73. #if defined(_MSC_VER)
  74. #define ARG_TRACE(x) \
  75. __pragma(warning(push)) __pragma(warning(disable : 4127)) do { \
  76. if (ARG_ENABLE_TRACE) \
  77. dbg_printf x; \
  78. } \
  79. while (0) \
  80. __pragma(warning(pop))
  81. #define ARG_LOG(x) \
  82. __pragma(warning(push)) __pragma(warning(disable : 4127)) do { \
  83. if (ARG_ENABLE_LOG) \
  84. dbg_printf x; \
  85. } \
  86. while (0) \
  87. __pragma(warning(pop))
  88. #else
  89. #define ARG_TRACE(x) \
  90. do { \
  91. if (ARG_ENABLE_TRACE) \
  92. dbg_printf x; \
  93. } while (0)
  94. #define ARG_LOG(x) \
  95. do { \
  96. if (ARG_ENABLE_LOG) \
  97. dbg_printf x; \
  98. } while (0)
  99. #endif
  100. extern void dbg_printf(const char* fmt, ...);
  101. extern void arg_set_panic(arg_panicfn* proc);
  102. extern void* xmalloc(size_t size);
  103. extern void* xcalloc(size_t count, size_t size);
  104. extern void* xrealloc(void* ptr, size_t size);
  105. extern void xfree(void* ptr);
  106. struct arg_hashtable_entry {
  107. void *k, *v;
  108. unsigned int h;
  109. struct arg_hashtable_entry* next;
  110. };
  111. typedef struct arg_hashtable {
  112. unsigned int tablelength;
  113. struct arg_hashtable_entry** table;
  114. unsigned int entrycount;
  115. unsigned int loadlimit;
  116. unsigned int primeindex;
  117. unsigned int (*hashfn)(const void* k);
  118. int (*eqfn)(const void* k1, const void* k2);
  119. } arg_hashtable_t;
  120. /**
  121. * @brief Create a hash table.
  122. *
  123. * @param minsize minimum initial size of hash table
  124. * @param hashfn function for hashing keys
  125. * @param eqfn function for determining key equality
  126. * @return newly created hash table or NULL on failure
  127. */
  128. arg_hashtable_t* arg_hashtable_create(unsigned int minsize, unsigned int (*hashfn)(const void*), int (*eqfn)(const void*, const void*));
  129. /**
  130. * @brief This function will cause the table to expand if the insertion would take
  131. * the ratio of entries to table size over the maximum load factor.
  132. *
  133. * This function does not check for repeated insertions with a duplicate key.
  134. * The value returned when using a duplicate key is undefined -- when
  135. * the hash table changes size, the order of retrieval of duplicate key
  136. * entries is reversed.
  137. * If in doubt, remove before insert.
  138. *
  139. * @param h the hash table to insert into
  140. * @param k the key - hash table claims ownership and will free on removal
  141. * @param v the value - does not claim ownership
  142. * @return non-zero for successful insertion
  143. */
  144. void arg_hashtable_insert(arg_hashtable_t* h, void* k, void* v);
  145. #define ARG_DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \
  146. int fnname(arg_hashtable_t* h, keytype* k, valuetype* v) { return arg_hashtable_insert(h, k, v); }
  147. /**
  148. * @brief Search the specified key in the hash table.
  149. *
  150. * @param h the hash table to search
  151. * @param k the key to search for - does not claim ownership
  152. * @return the value associated with the key, or NULL if none found
  153. */
  154. void* arg_hashtable_search(arg_hashtable_t* h, const void* k);
  155. #define ARG_DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
  156. valuetype* fnname(arg_hashtable_t* h, keytype* k) { return (valuetype*)(arg_hashtable_search(h, k)); }
  157. /**
  158. * @brief Remove the specified key from the hash table.
  159. *
  160. * @param h the hash table to remove the item from
  161. * @param k the key to search for - does not claim ownership
  162. */
  163. void arg_hashtable_remove(arg_hashtable_t* h, const void* k);
  164. #define ARG_DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
  165. valuetype* fnname(arg_hashtable_t* h, keytype* k) { return (valuetype*)(arg_hashtable_remove(h, k)); }
  166. /**
  167. * @brief Return the number of keys in the hash table.
  168. *
  169. * @param h the hash table
  170. * @return the number of items stored in the hash table
  171. */
  172. unsigned int arg_hashtable_count(arg_hashtable_t* h);
  173. /**
  174. * @brief Change the value associated with the key.
  175. *
  176. * function to change the value associated with a key, where there already
  177. * exists a value bound to the key in the hash table.
  178. * Source due to Holger Schemel.
  179. *
  180. * @name hashtable_change
  181. * @param h the hash table
  182. * @param key
  183. * @param value
  184. */
  185. int arg_hashtable_change(arg_hashtable_t* h, void* k, void* v);
  186. /**
  187. * @brief Free the hash table and the memory allocated for each key-value pair.
  188. *
  189. * @param h the hash table
  190. * @param free_values whether to call 'free' on the remaining values
  191. */
  192. void arg_hashtable_destroy(arg_hashtable_t* h, int free_values);
  193. typedef struct arg_hashtable_itr {
  194. arg_hashtable_t* h;
  195. struct arg_hashtable_entry* e;
  196. struct arg_hashtable_entry* parent;
  197. unsigned int index;
  198. } arg_hashtable_itr_t;
  199. arg_hashtable_itr_t* arg_hashtable_itr_create(arg_hashtable_t* h);
  200. void arg_hashtable_itr_destroy(arg_hashtable_itr_t* itr);
  201. /**
  202. * @brief Return the value of the (key,value) pair at the current position.
  203. */
  204. extern void* arg_hashtable_itr_key(arg_hashtable_itr_t* i);
  205. /**
  206. * @brief Return the value of the (key,value) pair at the current position.
  207. */
  208. extern void* arg_hashtable_itr_value(arg_hashtable_itr_t* i);
  209. /**
  210. * @brief Advance the iterator to the next element. Returns zero if advanced to end of table.
  211. */
  212. int arg_hashtable_itr_advance(arg_hashtable_itr_t* itr);
  213. /**
  214. * @brief Remove current element and advance the iterator to the next element.
  215. */
  216. int arg_hashtable_itr_remove(arg_hashtable_itr_t* itr);
  217. /**
  218. * @brief Search and overwrite the supplied iterator, to point to the entry matching the supplied key.
  219. *
  220. * @return Zero if not found.
  221. */
  222. int arg_hashtable_itr_search(arg_hashtable_itr_t* itr, arg_hashtable_t* h, void* k);
  223. #define ARG_DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \
  224. int fnname(arg_hashtable_itr_t* i, arg_hashtable_t* h, keytype* k) { return (arg_hashtable_iterator_search(i, h, k)); }
  225. #ifdef __cplusplus
  226. }
  227. #endif
  228. #endif
  229. /*******************************************************************************
  230. * arg_utils: Implements memory, panic, and other utility functions
  231. *
  232. * This file is part of the argtable3 library.
  233. *
  234. * Copyright (C) 2013-2019 Tom G. Huang
  235. * <tomghuang@gmail.com>
  236. * All rights reserved.
  237. *
  238. * Redistribution and use in source and binary forms, with or without
  239. * modification, are permitted provided that the following conditions are met:
  240. * * Redistributions of source code must retain the above copyright
  241. * notice, this list of conditions and the following disclaimer.
  242. * * Redistributions in binary form must reproduce the above copyright
  243. * notice, this list of conditions and the following disclaimer in the
  244. * documentation and/or other materials provided with the distribution.
  245. * * Neither the name of STEWART HEITMANN nor the names of its contributors
  246. * may be used to endorse or promote products derived from this software
  247. * without specific prior written permission.
  248. *
  249. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  250. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  251. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  252. * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
  253. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  254. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  255. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  256. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  257. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  258. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  259. ******************************************************************************/
  260. #include "argtable3.h"
  261. #ifndef ARG_AMALGAMATION
  262. #include "argtable3_private.h"
  263. #endif
  264. #include <stdarg.h>
  265. #include <stdio.h>
  266. #include <stdlib.h>
  267. #include <string.h>
  268. static void panic(const char* fmt, ...);
  269. static arg_panicfn* s_panic = panic;
  270. void dbg_printf(const char* fmt, ...) {
  271. va_list args;
  272. va_start(args, fmt);
  273. vfprintf(stderr, fmt, args);
  274. va_end(args);
  275. }
  276. static void panic(const char* fmt, ...) {
  277. va_list args;
  278. char* s;
  279. va_start(args, fmt);
  280. vfprintf(stderr, fmt, args);
  281. va_end(args);
  282. #if defined(_MSC_VER)
  283. #pragma warning(push)
  284. #pragma warning(disable : 4996)
  285. #endif
  286. s = getenv("EF_DUMPCORE");
  287. #if defined(_MSC_VER)
  288. #pragma warning(pop)
  289. #endif
  290. if (s != NULL && *s != '\0') {
  291. abort();
  292. } else {
  293. exit(EXIT_FAILURE);
  294. }
  295. }
  296. void arg_set_panic(arg_panicfn* proc) {
  297. s_panic = proc;
  298. }
  299. void* xmalloc(size_t size) {
  300. void* ret = malloc(size);
  301. if (!ret) {
  302. s_panic("Out of memory!\n");
  303. }
  304. return ret;
  305. }
  306. void* xcalloc(size_t count, size_t size) {
  307. size_t allocated_count = count && size ? count : 1;
  308. size_t allocated_size = count && size ? size : 1;
  309. void* ret = calloc(allocated_count, allocated_size);
  310. if (!ret) {
  311. s_panic("Out of memory!\n");
  312. }
  313. return ret;
  314. }
  315. void* xrealloc(void* ptr, size_t size) {
  316. size_t allocated_size = size ? size : 1;
  317. void* ret = realloc(ptr, allocated_size);
  318. if (!ret) {
  319. s_panic("Out of memory!\n");
  320. }
  321. return ret;
  322. }
  323. void xfree(void* ptr) {
  324. free(ptr);
  325. }
  326. static void merge(void* data, int esize, int i, int j, int k, arg_comparefn* comparefn) {
  327. char* a = (char*)data;
  328. char* m;
  329. int ipos, jpos, mpos;
  330. /* Initialize the counters used in merging. */
  331. ipos = i;
  332. jpos = j + 1;
  333. mpos = 0;
  334. /* Allocate storage for the merged elements. */
  335. m = (char*)xmalloc(esize * ((k - i) + 1));
  336. /* Continue while either division has elements to merge. */
  337. while (ipos <= j || jpos <= k) {
  338. if (ipos > j) {
  339. /* The left division has no more elements to merge. */
  340. while (jpos <= k) {
  341. memcpy(&m[mpos * esize], &a[jpos * esize], esize);
  342. jpos++;
  343. mpos++;
  344. }
  345. continue;
  346. } else if (jpos > k) {
  347. /* The right division has no more elements to merge. */
  348. while (ipos <= j) {
  349. memcpy(&m[mpos * esize], &a[ipos * esize], esize);
  350. ipos++;
  351. mpos++;
  352. }
  353. continue;
  354. }
  355. /* Append the next ordered element to the merged elements. */
  356. if (comparefn(&a[ipos * esize], &a[jpos * esize]) < 0) {
  357. memcpy(&m[mpos * esize], &a[ipos * esize], esize);
  358. ipos++;
  359. mpos++;
  360. } else {
  361. memcpy(&m[mpos * esize], &a[jpos * esize], esize);
  362. jpos++;
  363. mpos++;
  364. }
  365. }
  366. /* Prepare to pass back the merged data. */
  367. memcpy(&a[i * esize], m, esize * ((k - i) + 1));
  368. xfree(m);
  369. }
  370. void arg_mgsort(void* data, int size, int esize, int i, int k, arg_comparefn* comparefn) {
  371. int j;
  372. /* Stop the recursion when no more divisions can be made. */
  373. if (i < k) {
  374. /* Determine where to divide the elements. */
  375. j = (int)(((i + k - 1)) / 2);
  376. /* Recursively sort the two divisions. */
  377. arg_mgsort(data, size, esize, i, j, comparefn);
  378. arg_mgsort(data, size, esize, j + 1, k, comparefn);
  379. merge(data, esize, i, j, k, comparefn);
  380. }
  381. }
  382. /*******************************************************************************
  383. * arg_hashtable: Implements the hash table utilities
  384. *
  385. * This file is part of the argtable3 library.
  386. *
  387. * Copyright (C) 2013-2019 Tom G. Huang
  388. * <tomghuang@gmail.com>
  389. * All rights reserved.
  390. *
  391. * Redistribution and use in source and binary forms, with or without
  392. * modification, are permitted provided that the following conditions are met:
  393. * * Redistributions of source code must retain the above copyright
  394. * notice, this list of conditions and the following disclaimer.
  395. * * Redistributions in binary form must reproduce the above copyright
  396. * notice, this list of conditions and the following disclaimer in the
  397. * documentation and/or other materials provided with the distribution.
  398. * * Neither the name of STEWART HEITMANN nor the names of its contributors
  399. * may be used to endorse or promote products derived from this software
  400. * without specific prior written permission.
  401. *
  402. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  403. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  404. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  405. * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
  406. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  407. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  408. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  409. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  410. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  411. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  412. ******************************************************************************/
  413. #ifndef ARG_AMALGAMATION
  414. #include "argtable3_private.h"
  415. #endif
  416. #include <math.h>
  417. #include <stdio.h>
  418. #include <stdlib.h>
  419. #include <string.h>
  420. /*
  421. * This hash table module is adapted from the C hash table implementation by
  422. * Christopher Clark. Here is the copyright notice from the library:
  423. *
  424. * Copyright (c) 2002, Christopher Clark
  425. * All rights reserved.
  426. *
  427. * Redistribution and use in source and binary forms, with or without
  428. * modification, are permitted provided that the following conditions
  429. * are met:
  430. *
  431. * * Redistributions of source code must retain the above copyright
  432. * notice, this list of conditions and the following disclaimer.
  433. *
  434. * * Redistributions in binary form must reproduce the above copyright
  435. * notice, this list of conditions and the following disclaimer in the
  436. * documentation and/or other materials provided with the distribution.
  437. *
  438. * * Neither the name of the original author; nor the names of any contributors
  439. * may be used to endorse or promote products derived from this software
  440. * without specific prior written permission.
  441. *
  442. *
  443. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  444. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  445. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  446. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
  447. * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  448. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  449. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  450. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  451. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  452. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  453. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  454. */
  455. /*
  456. * Credit for primes table: Aaron Krowne
  457. * http://br.endernet.org/~akrowne/
  458. * http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
  459. */
  460. static const unsigned int primes[] = {53, 97, 193, 389, 769, 1543, 3079, 6151, 12289,
  461. 24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
  462. 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741};
  463. const unsigned int prime_table_length = sizeof(primes) / sizeof(primes[0]);
  464. const float max_load_factor = (float)0.65;
  465. static unsigned int enhanced_hash(arg_hashtable_t* h, const void* k) {
  466. /*
  467. * Aim to protect against poor hash functions by adding logic here.
  468. * The logic is taken from Java 1.4 hash table source.
  469. */
  470. unsigned int i = h->hashfn(k);
  471. i += ~(i << 9);
  472. i ^= ((i >> 14) | (i << 18)); /* >>> */
  473. i += (i << 4);
  474. i ^= ((i >> 10) | (i << 22)); /* >>> */
  475. return i;
  476. }
  477. static unsigned int index_for(unsigned int tablelength, unsigned int hashvalue) {
  478. return (hashvalue % tablelength);
  479. }
  480. arg_hashtable_t* arg_hashtable_create(unsigned int minsize, unsigned int (*hashfn)(const void*), int (*eqfn)(const void*, const void*)) {
  481. arg_hashtable_t* h;
  482. unsigned int pindex;
  483. unsigned int size = primes[0];
  484. /* Check requested hash table isn't too large */
  485. if (minsize > (1u << 30))
  486. return NULL;
  487. /*
  488. * Enforce size as prime. The reason is to avoid clustering of values
  489. * into a small number of buckets (yes, distribution). A more even
  490. * distributed hash table will perform more consistently.
  491. */
  492. for (pindex = 0; pindex < prime_table_length; pindex++) {
  493. if (primes[pindex] > minsize) {
  494. size = primes[pindex];
  495. break;
  496. }
  497. }
  498. h = (arg_hashtable_t*)xmalloc(sizeof(arg_hashtable_t));
  499. h->table = (struct arg_hashtable_entry**)xmalloc(sizeof(struct arg_hashtable_entry*) * size);
  500. memset(h->table, 0, size * sizeof(struct arg_hashtable_entry*));
  501. h->tablelength = size;
  502. h->primeindex = pindex;
  503. h->entrycount = 0;
  504. h->hashfn = hashfn;
  505. h->eqfn = eqfn;
  506. h->loadlimit = (unsigned int)ceil(size * max_load_factor);
  507. return h;
  508. }
  509. static int arg_hashtable_expand(arg_hashtable_t* h) {
  510. /* Double the size of the table to accommodate more entries */
  511. struct arg_hashtable_entry** newtable;
  512. struct arg_hashtable_entry* e;
  513. unsigned int newsize;
  514. unsigned int i;
  515. unsigned int index;
  516. /* Check we're not hitting max capacity */
  517. if (h->primeindex == (prime_table_length - 1))
  518. return 0;
  519. newsize = primes[++(h->primeindex)];
  520. newtable = (struct arg_hashtable_entry**)xmalloc(sizeof(struct arg_hashtable_entry*) * newsize);
  521. memset(newtable, 0, newsize * sizeof(struct arg_hashtable_entry*));
  522. /*
  523. * This algorithm is not 'stable': it reverses the list
  524. * when it transfers entries between the tables
  525. */
  526. for (i = 0; i < h->tablelength; i++) {
  527. while (NULL != (e = h->table[i])) {
  528. h->table[i] = e->next;
  529. index = index_for(newsize, e->h);
  530. e->next = newtable[index];
  531. newtable[index] = e;
  532. }
  533. }
  534. xfree(h->table);
  535. h->table = newtable;
  536. h->tablelength = newsize;
  537. h->loadlimit = (unsigned int)ceil(newsize * max_load_factor);
  538. return -1;
  539. }
  540. unsigned int arg_hashtable_count(arg_hashtable_t* h) {
  541. return h->entrycount;
  542. }
  543. void arg_hashtable_insert(arg_hashtable_t* h, void* k, void* v) {
  544. /* This method allows duplicate keys - but they shouldn't be used */
  545. unsigned int index;
  546. struct arg_hashtable_entry* e;
  547. if ((h->entrycount + 1) > h->loadlimit) {
  548. /*
  549. * Ignore the return value. If expand fails, we should
  550. * still try cramming just this value into the existing table
  551. * -- we may not have memory for a larger table, but one more
  552. * element may be ok. Next time we insert, we'll try expanding again.
  553. */
  554. arg_hashtable_expand(h);
  555. }
  556. e = (struct arg_hashtable_entry*)xmalloc(sizeof(struct arg_hashtable_entry));
  557. e->h = enhanced_hash(h, k);
  558. index = index_for(h->tablelength, e->h);
  559. e->k = k;
  560. e->v = v;
  561. e->next = h->table[index];
  562. h->table[index] = e;
  563. h->entrycount++;
  564. }
  565. void* arg_hashtable_search(arg_hashtable_t* h, const void* k) {
  566. struct arg_hashtable_entry* e;
  567. unsigned int hashvalue;
  568. unsigned int index;
  569. hashvalue = enhanced_hash(h, k);
  570. index = index_for(h->tablelength, hashvalue);
  571. e = h->table[index];
  572. while (e != NULL) {
  573. /* Check hash value to short circuit heavier comparison */
  574. if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
  575. return e->v;
  576. e = e->next;
  577. }
  578. return NULL;
  579. }
  580. void arg_hashtable_remove(arg_hashtable_t* h, const void* k) {
  581. /*
  582. * TODO: consider compacting the table when the load factor drops enough,
  583. * or provide a 'compact' method.
  584. */
  585. struct arg_hashtable_entry* e;
  586. struct arg_hashtable_entry** pE;
  587. unsigned int hashvalue;
  588. unsigned int index;
  589. hashvalue = enhanced_hash(h, k);
  590. index = index_for(h->tablelength, hashvalue);
  591. pE = &(h->table[index]);
  592. e = *pE;
  593. while (NULL != e) {
  594. /* Check hash value to short circuit heavier comparison */
  595. if ((hashvalue == e->h) && (h->eqfn(k, e->k))) {
  596. *pE = e->next;
  597. h->entrycount--;
  598. xfree(e->k);
  599. xfree(e->v);
  600. xfree(e);
  601. return;
  602. }
  603. pE = &(e->next);
  604. e = e->next;
  605. }
  606. }
  607. void arg_hashtable_destroy(arg_hashtable_t* h, int free_values) {
  608. unsigned int i;
  609. struct arg_hashtable_entry *e, *f;
  610. struct arg_hashtable_entry** table = h->table;
  611. if (free_values) {
  612. for (i = 0; i < h->tablelength; i++) {
  613. e = table[i];
  614. while (NULL != e) {
  615. f = e;
  616. e = e->next;
  617. xfree(f->k);
  618. xfree(f->v);
  619. xfree(f);
  620. }
  621. }
  622. } else {
  623. for (i = 0; i < h->tablelength; i++) {
  624. e = table[i];
  625. while (NULL != e) {
  626. f = e;
  627. e = e->next;
  628. xfree(f->k);
  629. xfree(f);
  630. }
  631. }
  632. }
  633. xfree(h->table);
  634. xfree(h);
  635. }
  636. arg_hashtable_itr_t* arg_hashtable_itr_create(arg_hashtable_t* h) {
  637. unsigned int i;
  638. unsigned int tablelength;
  639. arg_hashtable_itr_t* itr = (arg_hashtable_itr_t*)xmalloc(sizeof(arg_hashtable_itr_t));
  640. itr->h = h;
  641. itr->e = NULL;
  642. itr->parent = NULL;
  643. tablelength = h->tablelength;
  644. itr->index = tablelength;
  645. if (0 == h->entrycount)
  646. return itr;
  647. for (i = 0; i < tablelength; i++) {
  648. if (h->table[i] != NULL) {
  649. itr->e = h->table[i];
  650. itr->index = i;
  651. break;
  652. }
  653. }
  654. return itr;
  655. }
  656. void arg_hashtable_itr_destroy(arg_hashtable_itr_t* itr) {
  657. xfree(itr);
  658. }
  659. void* arg_hashtable_itr_key(arg_hashtable_itr_t* i) {
  660. return i->e->k;
  661. }
  662. void* arg_hashtable_itr_value(arg_hashtable_itr_t* i) {
  663. return i->e->v;
  664. }
  665. int arg_hashtable_itr_advance(arg_hashtable_itr_t* itr) {
  666. unsigned int j;
  667. unsigned int tablelength;
  668. struct arg_hashtable_entry** table;
  669. struct arg_hashtable_entry* next;
  670. if (itr->e == NULL)
  671. return 0; /* stupidity check */
  672. next = itr->e->next;
  673. if (NULL != next) {
  674. itr->parent = itr->e;
  675. itr->e = next;
  676. return -1;
  677. }
  678. tablelength = itr->h->tablelength;
  679. itr->parent = NULL;
  680. if (tablelength <= (j = ++(itr->index))) {
  681. itr->e = NULL;
  682. return 0;
  683. }
  684. table = itr->h->table;
  685. while (NULL == (next = table[j])) {
  686. if (++j >= tablelength) {
  687. itr->index = tablelength;
  688. itr->e = NULL;
  689. return 0;
  690. }
  691. }
  692. itr->index = j;
  693. itr->e = next;
  694. return -1;
  695. }
  696. int arg_hashtable_itr_remove(arg_hashtable_itr_t* itr) {
  697. struct arg_hashtable_entry* remember_e;
  698. struct arg_hashtable_entry* remember_parent;
  699. int ret;
  700. /* Do the removal */
  701. if ((itr->parent) == NULL) {
  702. /* element is head of a chain */
  703. itr->h->table[itr->index] = itr->e->next;
  704. } else {
  705. /* element is mid-chain */
  706. itr->parent->next = itr->e->next;
  707. }
  708. /* itr->e is now outside the hashtable */
  709. remember_e = itr->e;
  710. itr->h->entrycount--;
  711. xfree(remember_e->k);
  712. xfree(remember_e->v);
  713. /* Advance the iterator, correcting the parent */
  714. remember_parent = itr->parent;
  715. ret = arg_hashtable_itr_advance(itr);
  716. if (itr->parent == remember_e) {
  717. itr->parent = remember_parent;
  718. }
  719. xfree(remember_e);
  720. return ret;
  721. }
  722. int arg_hashtable_itr_search(arg_hashtable_itr_t* itr, arg_hashtable_t* h, void* k) {
  723. struct arg_hashtable_entry* e;
  724. struct arg_hashtable_entry* parent;
  725. unsigned int hashvalue;
  726. unsigned int index;
  727. hashvalue = enhanced_hash(h, k);
  728. index = index_for(h->tablelength, hashvalue);
  729. e = h->table[index];
  730. parent = NULL;
  731. while (e != NULL) {
  732. /* Check hash value to short circuit heavier comparison */
  733. if ((hashvalue == e->h) && (h->eqfn(k, e->k))) {
  734. itr->index = index;
  735. itr->e = e;
  736. itr->parent = parent;
  737. itr->h = h;
  738. return -1;
  739. }
  740. parent = e;
  741. e = e->next;
  742. }
  743. return 0;
  744. }
  745. int arg_hashtable_change(arg_hashtable_t* h, void* k, void* v) {
  746. struct arg_hashtable_entry* e;
  747. unsigned int hashvalue;
  748. unsigned int index;
  749. hashvalue = enhanced_hash(h, k);
  750. index = index_for(h->tablelength, hashvalue);
  751. e = h->table[index];
  752. while (e != NULL) {
  753. /* Check hash value to short circuit heavier comparison */
  754. if ((hashvalue == e->h) && (h->eqfn(k, e->k))) {
  755. xfree(e->v);
  756. e->v = v;
  757. return -1;
  758. }
  759. e = e->next;
  760. }
  761. return 0;
  762. }
  763. /*******************************************************************************
  764. * arg_dstr: Implements the dynamic string utilities
  765. *
  766. * This file is part of the argtable3 library.
  767. *
  768. * Copyright (C) 2013-2019 Tom G. Huang
  769. * <tomghuang@gmail.com>
  770. * All rights reserved.
  771. *
  772. * Redistribution and use in source and binary forms, with or without
  773. * modification, are permitted provided that the following conditions are met:
  774. * * Redistributions of source code must retain the above copyright
  775. * notice, this list of conditions and the following disclaimer.
  776. * * Redistributions in binary form must reproduce the above copyright
  777. * notice, this list of conditions and the following disclaimer in the
  778. * documentation and/or other materials provided with the distribution.
  779. * * Neither the name of STEWART HEITMANN nor the names of its contributors
  780. * may be used to endorse or promote products derived from this software
  781. * without specific prior written permission.
  782. *
  783. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  784. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  785. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  786. * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
  787. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  788. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  789. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  790. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  791. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  792. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  793. ******************************************************************************/
  794. #include "argtable3.h"
  795. #ifndef ARG_AMALGAMATION
  796. #include "argtable3_private.h"
  797. #endif
  798. #include <stdarg.h>
  799. #include <stdlib.h>
  800. #include <string.h>
  801. #if defined(_MSC_VER)
  802. #pragma warning(push)
  803. #pragma warning(disable : 4996)
  804. #endif
  805. #define START_VSNBUFF 16
  806. /*
  807. * This dynamic string module is adapted from TclResult.c in the Tcl library.
  808. * Here is the copyright notice from the library:
  809. *
  810. * This software is copyrighted by the Regents of the University of
  811. * California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
  812. * Corporation and other parties. The following terms apply to all files
  813. * associated with the software unless explicitly disclaimed in
  814. * individual files.
  815. *
  816. * The authors hereby grant permission to use, copy, modify, distribute,
  817. * and license this software and its documentation for any purpose, provided
  818. * that existing copyright notices are retained in all copies and that this
  819. * notice is included verbatim in any distributions. No written agreement,
  820. * license, or royalty fee is required for any of the authorized uses.
  821. * Modifications to this software may be copyrighted by their authors
  822. * and need not follow the licensing terms described here, provided that
  823. * the new terms are clearly indicated on the first page of each file where
  824. * they apply.
  825. *
  826. * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
  827. * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
  828. * ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
  829. * DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
  830. * POSSIBILITY OF SUCH DAMAGE.
  831. *
  832. * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
  833. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
  834. * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
  835. * IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
  836. * NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
  837. * MODIFICATIONS.
  838. *
  839. * GOVERNMENT USE: If you are acquiring this software on behalf of the
  840. * U.S. government, the Government shall have only "Restricted Rights"
  841. * in the software and related documentation as defined in the Federal
  842. * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
  843. * are acquiring the software on behalf of the Department of Defense, the
  844. * software shall be classified as "Commercial Computer Software" and the
  845. * Government shall have only "Restricted Rights" as defined in Clause
  846. * 252.227-7014 (b) (3) of DFARs. Notwithstanding the foregoing, the
  847. * authors grant the U.S. Government and others acting in its behalf
  848. * permission to use and distribute the software in accordance with the
  849. * terms specified in this license.
  850. */
  851. typedef struct _internal_arg_dstr {
  852. char* data;
  853. arg_dstr_freefn* free_proc;
  854. char sbuf[ARG_DSTR_SIZE + 1];
  855. char* append_data;
  856. int append_data_size;
  857. int append_used;
  858. } _internal_arg_dstr_t;
  859. static void setup_append_buf(arg_dstr_t res, int newSpace);
  860. arg_dstr_t arg_dstr_create(void) {
  861. _internal_arg_dstr_t* h = (_internal_arg_dstr_t*)xmalloc(sizeof(_internal_arg_dstr_t));
  862. memset(h, 0, sizeof(_internal_arg_dstr_t));
  863. h->sbuf[0] = 0;
  864. h->data = h->sbuf;
  865. h->free_proc = ARG_DSTR_STATIC;
  866. return h;
  867. }
  868. void arg_dstr_destroy(arg_dstr_t ds) {
  869. if (ds == NULL)
  870. return;
  871. arg_dstr_reset(ds);
  872. xfree(ds);
  873. return;
  874. }
  875. void arg_dstr_set(arg_dstr_t ds, char* str, arg_dstr_freefn* free_proc) {
  876. int length;
  877. register arg_dstr_freefn* old_free_proc = ds->free_proc;
  878. char* old_result = ds->data;
  879. if (str == NULL) {
  880. ds->sbuf[0] = 0;
  881. ds->data = ds->sbuf;
  882. ds->free_proc = ARG_DSTR_STATIC;
  883. } else if (free_proc == ARG_DSTR_VOLATILE) {
  884. length = (int)strlen(str);
  885. if (length > ARG_DSTR_SIZE) {
  886. ds->data = (char*)xmalloc((unsigned)length + 1);
  887. ds->free_proc = ARG_DSTR_DYNAMIC;
  888. } else {
  889. ds->data = ds->sbuf;
  890. ds->free_proc = ARG_DSTR_STATIC;
  891. }
  892. strcpy(ds->data, str);
  893. } else {
  894. ds->data = str;
  895. ds->free_proc = free_proc;
  896. }
  897. /*
  898. * If the old result was dynamically-allocated, free it up. Do it here,
  899. * rather than at the beginning, in case the new result value was part of
  900. * the old result value.
  901. */
  902. if ((old_free_proc != 0) && (old_result != ds->data)) {
  903. if (old_free_proc == ARG_DSTR_DYNAMIC) {
  904. xfree(old_result);
  905. } else {
  906. (*old_free_proc)(old_result);
  907. }
  908. }
  909. if ((ds->append_data != NULL) && (ds->append_data_size > 0)) {
  910. xfree(ds->append_data);
  911. ds->append_data = NULL;
  912. ds->append_data_size = 0;
  913. }
  914. }
  915. char* arg_dstr_cstr(arg_dstr_t ds) /* Interpreter whose result to return. */
  916. {
  917. return ds->data;
  918. }
  919. void arg_dstr_cat(arg_dstr_t ds, const char* str) {
  920. setup_append_buf(ds, (int)strlen(str) + 1);
  921. memcpy(ds->data + strlen(ds->data), str, strlen(str));
  922. }
  923. void arg_dstr_catc(arg_dstr_t ds, char c) {
  924. setup_append_buf(ds, 2);
  925. memcpy(ds->data + strlen(ds->data), &c, 1);
  926. }
  927. /*
  928. * The logic of the `arg_dstr_catf` function is adapted from the `bformat`
  929. * function in The Better String Library by Paul Hsieh. Here is the copyright
  930. * notice from the library:
  931. *
  932. * Copyright (c) 2014, Paul Hsieh
  933. * All rights reserved.
  934. *
  935. * Redistribution and use in source and binary forms, with or without
  936. * modification, are permitted provided that the following conditions are met:
  937. *
  938. * * Redistributions of source code must retain the above copyright notice, this
  939. * list of conditions and the following disclaimer.
  940. *
  941. * * Redistributions in binary form must reproduce the above copyright notice,
  942. * this list of conditions and the following disclaimer in the documentation
  943. * and/or other materials provided with the distribution.
  944. *
  945. * * Neither the name of bstrlib nor the names of its
  946. * contributors may be used to endorse or promote products derived from
  947. * this software without specific prior written permission.
  948. *
  949. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  950. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  951. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  952. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  953. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  954. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  955. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  956. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  957. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  958. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  959. */
  960. void arg_dstr_catf(arg_dstr_t ds, const char* fmt, ...) {
  961. va_list arglist;
  962. char* buff;
  963. int n, r;
  964. size_t slen;
  965. if (fmt == NULL)
  966. return;
  967. /* Since the length is not determinable beforehand, a search is
  968. performed using the truncating "vsnprintf" call (to avoid buffer
  969. overflows) on increasing potential sizes for the output result. */
  970. if ((n = (int)(2 * strlen(fmt))) < START_VSNBUFF)
  971. n = START_VSNBUFF;
  972. buff = (char*)xmalloc(n + 2);
  973. memset(buff, 0, n + 2);
  974. for (;;) {
  975. va_start(arglist, fmt);
  976. r = vsnprintf(buff, n + 1, fmt, arglist);
  977. va_end(arglist);
  978. slen = strlen(buff);
  979. if (slen < (size_t)n)
  980. break;
  981. if (r > n)
  982. n = r;
  983. else
  984. n += n;
  985. xfree(buff);
  986. buff = (char*)xmalloc(n + 2);
  987. memset(buff, 0, n + 2);
  988. }
  989. arg_dstr_cat(ds, buff);
  990. xfree(buff);
  991. }
  992. static void setup_append_buf(arg_dstr_t ds, int new_space) {
  993. int total_space;
  994. /*
  995. * Make the append buffer larger, if that's necessary, then copy the
  996. * data into the append buffer and make the append buffer the official
  997. * data.
  998. */
  999. if (ds->data != ds->append_data) {
  1000. /*
  1001. * If the buffer is too big, then free it up so we go back to a
  1002. * smaller buffer. This avoids tying up memory forever after a large
  1003. * operation.
  1004. */
  1005. if (ds->append_data_size > 500) {
  1006. xfree(ds->append_data);
  1007. ds->append_data = NULL;
  1008. ds->append_data_size = 0;
  1009. }
  1010. ds->append_used = (int)strlen(ds->data);
  1011. } else if (ds->data[ds->append_used] != 0) {
  1012. /*
  1013. * Most likely someone has modified a result created by
  1014. * arg_dstr_cat et al. so that it has a different size. Just
  1015. * recompute the size.
  1016. */
  1017. ds->append_used = (int)strlen(ds->data);
  1018. }
  1019. total_space = new_space + ds->append_used;
  1020. if (total_space >= ds->append_data_size) {
  1021. char* newbuf;
  1022. if (total_space < 100) {
  1023. total_space = 200;
  1024. } else {
  1025. total_space *= 2;
  1026. }
  1027. newbuf = (char*)xmalloc((unsigned)total_space);
  1028. memset(newbuf, 0, total_space);
  1029. strcpy(newbuf, ds->data);
  1030. if (ds->append_data != NULL) {
  1031. xfree(ds->append_data);
  1032. }
  1033. ds->append_data = newbuf;
  1034. ds->append_data_size = total_space;
  1035. } else if (ds->data != ds->append_data) {
  1036. strcpy(ds->append_data, ds->data);
  1037. }
  1038. arg_dstr_free(ds);
  1039. ds->data = ds->append_data;
  1040. }
  1041. void arg_dstr_free(arg_dstr_t ds) {
  1042. if (ds->free_proc != NULL) {
  1043. if (ds->free_proc == ARG_DSTR_DYNAMIC) {
  1044. xfree(ds->data);
  1045. } else {
  1046. (*ds->free_proc)(ds->data);
  1047. }
  1048. ds->free_proc = NULL;
  1049. }
  1050. }
  1051. void arg_dstr_reset(arg_dstr_t ds) {
  1052. arg_dstr_free(ds);
  1053. if ((ds->append_data != NULL) && (ds->append_data_size > 0)) {
  1054. xfree(ds->append_data);
  1055. ds->append_data = NULL;
  1056. ds->append_data_size = 0;
  1057. }
  1058. ds->data = ds->sbuf;
  1059. ds->sbuf[0] = 0;
  1060. }
  1061. #if defined(_MSC_VER)
  1062. #pragma warning(pop)
  1063. #endif
  1064. /* $Id: getopt.h,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */
  1065. /* $OpenBSD: getopt.h,v 1.1 2002/12/03 20:24:29 millert Exp $ */
  1066. /* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */
  1067. /*
  1068. * Copyright (c) 2000 The NetBSD Foundation, Inc.
  1069. * All rights reserved.
  1070. *
  1071. * This code is derived from software contributed to The NetBSD Foundation
  1072. * by Dieter Baron and Thomas Klausner.
  1073. *
  1074. * Redistribution and use in source and binary forms, with or without
  1075. * modification, are permitted provided that the following conditions
  1076. * are met:
  1077. * 1. Redistributions of source code must retain the above copyright
  1078. * notice, this list of conditions and the following disclaimer.
  1079. * 2. Redistributions in binary form must reproduce the above copyright
  1080. * notice, this list of conditions and the following disclaimer in the
  1081. * documentation and/or other materials provided with the distribution.
  1082. * 3. All advertising materials mentioning features or use of this software
  1083. * must display the following acknowledgment:
  1084. * This product includes software developed by the NetBSD
  1085. * Foundation, Inc. and its contributors.
  1086. * 4. Neither the name of The NetBSD Foundation nor the names of its
  1087. * contributors may be used to endorse or promote products derived
  1088. * from this software without specific prior written permission.
  1089. *
  1090. * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  1091. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  1092. * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  1093. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
  1094. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  1095. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  1096. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  1097. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  1098. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  1099. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  1100. * POSSIBILITY OF SUCH DAMAGE.
  1101. */
  1102. #if ARG_REPLACE_GETOPT == 1
  1103. #ifndef _GETOPT_H_
  1104. #define _GETOPT_H_
  1105. /*
  1106. * GNU-like getopt_long() and 4.4BSD getsubopt()/optreset extensions
  1107. */
  1108. #define no_argument 0
  1109. #define required_argument 1
  1110. #define optional_argument 2
  1111. struct option {
  1112. /* name of long option */
  1113. const char* name;
  1114. /*
  1115. * one of no_argument, required_argument, and optional_argument:
  1116. * whether option takes an argument
  1117. */
  1118. int has_arg;
  1119. /* if not NULL, set *flag to val when option found */
  1120. int* flag;
  1121. /* if flag not NULL, value to set *flag to; else return value */
  1122. int val;
  1123. };
  1124. #ifdef __cplusplus
  1125. extern "C" {
  1126. #endif
  1127. int getopt_long(int, char* const*, const char*, const struct option*, int*);
  1128. int getopt_long_only(int, char* const*, const char*, const struct option*, int*);
  1129. #ifndef _GETOPT_DEFINED
  1130. #define _GETOPT_DEFINED
  1131. int getopt(int, char* const*, const char*);
  1132. int getsubopt(char**, char* const*, char**);
  1133. extern char* optarg; /* getopt(3) external variables */
  1134. extern int opterr;
  1135. extern int optind;
  1136. extern int optopt;
  1137. extern int optreset;
  1138. extern char* suboptarg; /* getsubopt(3) external variable */
  1139. #endif /* _GETOPT_DEFINED */
  1140. #ifdef __cplusplus
  1141. }
  1142. #endif
  1143. #endif /* !_GETOPT_H_ */
  1144. #else
  1145. #include <getopt.h>
  1146. #endif /* ARG_REPLACE_GETOPT */
  1147. /* $Id: getopt_long.c,v 1.1 2009/10/16 19:50:28 rodney Exp rodney $ */
  1148. /* $OpenBSD: getopt_long.c,v 1.23 2007/10/31 12:34:57 chl Exp $ */
  1149. /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
  1150. /*
  1151. * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
  1152. *
  1153. * Permission to use, copy, modify, and distribute this software for any
  1154. * purpose with or without fee is hereby granted, provided that the above
  1155. * copyright notice and this permission notice appear in all copies.
  1156. *
  1157. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  1158. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  1159. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  1160. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  1161. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  1162. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  1163. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  1164. *
  1165. * Sponsored in part by the Defense Advanced Research Projects
  1166. * Agency (DARPA) and Air Force Research Laboratory, Air Force
  1167. * Materiel Command, USAF, under agreement number F39502-99-1-0512.
  1168. */
  1169. /*
  1170. * Copyright (c) 2000 The NetBSD Foundation, Inc.
  1171. * All rights reserved.
  1172. *
  1173. * This code is derived from software contributed to The NetBSD Foundation
  1174. * by Dieter Baron and Thomas Klausner.
  1175. *
  1176. * Redistribution and use in source and binary forms, with or without
  1177. * modification, are permitted provided that the following conditions
  1178. * are met:
  1179. * 1. Redistributions of source code must retain the above copyright
  1180. * notice, this list of conditions and the following disclaimer.
  1181. * 2. Redistributions in binary form must reproduce the above copyright
  1182. * notice, this list of conditions and the following disclaimer in the
  1183. * documentation and/or other materials provided with the distribution.
  1184. *
  1185. * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  1186. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  1187. * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  1188. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
  1189. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  1190. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  1191. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  1192. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  1193. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  1194. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  1195. * POSSIBILITY OF SUCH DAMAGE.
  1196. */
  1197. #include "argtable3.h"
  1198. #ifndef ARG_AMALGAMATION
  1199. #include "getopt.h"
  1200. #endif
  1201. #include <errno.h>
  1202. #include <stdlib.h>
  1203. #include <string.h>
  1204. #if ARG_REPLACE_GETOPT == 1
  1205. int opterr = 1; /* if error message should be printed */
  1206. int optind = 1; /* index into parent argv vector */
  1207. int optopt = '?'; /* character checked for validity */
  1208. int optreset; /* reset getopt */
  1209. char* optarg; /* argument associated with option */
  1210. #endif /* ARG_REPLACE_GETOPT */
  1211. #define PRINT_ERROR ((opterr) && (*options != ':'))
  1212. #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
  1213. #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
  1214. #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
  1215. /* return values */
  1216. #define BADCH (int)'?'
  1217. #define BADARG ((*options == ':') ? (int)':' : (int)'?')
  1218. #define INORDER (int)1
  1219. #define EMSG ""
  1220. #if ARG_REPLACE_GETOPT == 1
  1221. static int getopt_internal(int, char* const*, const char*, const struct option*, int*, int);
  1222. #endif /* ARG_REPLACE_GETOPT */
  1223. static int parse_long_options(char* const*, const char*, const struct option*, int*, int);
  1224. static int gcd(int, int);
  1225. static void permute_args(int, int, int, char* const*);
  1226. static char* place = EMSG; /* option letter processing */
  1227. /* XXX: set optreset to 1 rather than these two */
  1228. static int nonopt_start = -1; /* first non option argument (for permute) */
  1229. static int nonopt_end = -1; /* first option after non options (for permute) */
  1230. /* Error messages */
  1231. static const char recargchar[] = "option requires an argument -- %c";
  1232. static const char recargstring[] = "option requires an argument -- %s";
  1233. static const char ambig[] = "ambiguous option -- %.*s";
  1234. static const char noarg[] = "option doesn't take an argument -- %.*s";
  1235. static const char illoptchar[] = "unknown option -- %c";
  1236. static const char illoptstring[] = "unknown option -- %s";
  1237. #ifdef _WIN32
  1238. /*
  1239. * Windows needs warnx(). We change the definition though:
  1240. * 1. (another) global is defined, opterrmsg, which holds the error message
  1241. * 2. errors are always printed out on stderr w/o the program name
  1242. * Note that opterrmsg always gets set no matter what opterr is set to. The
  1243. * error message will not be printed if opterr is 0 as usual.
  1244. */
  1245. #include <stdarg.h>
  1246. #include <stdio.h>
  1247. #define MAX_OPTERRMSG_SIZE 128
  1248. extern char opterrmsg[MAX_OPTERRMSG_SIZE];
  1249. char opterrmsg[MAX_OPTERRMSG_SIZE]; /* buffer for the last error message */
  1250. static void warnx(const char* fmt, ...) {
  1251. va_list ap;
  1252. va_start(ap, fmt);
  1253. /*
  1254. * Make sure opterrmsg is always zero-terminated despite the _vsnprintf()
  1255. * implementation specifics and manually suppress the warning.
  1256. */
  1257. memset(opterrmsg, 0, sizeof(opterrmsg));
  1258. if (fmt != NULL)
  1259. #if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
  1260. _vsnprintf_s(opterrmsg, sizeof(opterrmsg), sizeof(opterrmsg) - 1, fmt, ap);
  1261. #else
  1262. _vsnprintf(opterrmsg, sizeof(opterrmsg) - 1, fmt, ap);
  1263. #endif
  1264. va_end(ap);
  1265. #ifdef _MSC_VER
  1266. #pragma warning(suppress : 6053)
  1267. #endif
  1268. fprintf(stderr, "%s\n", opterrmsg);
  1269. }
  1270. #else
  1271. #include <err.h>
  1272. #endif /*_WIN32*/
  1273. /*
  1274. * Compute the greatest common divisor of a and b.
  1275. */
  1276. static int gcd(int a, int b) {
  1277. int c;
  1278. c = a % b;
  1279. while (c != 0) {
  1280. a = b;
  1281. b = c;
  1282. c = a % b;
  1283. }
  1284. return (b);
  1285. }
  1286. /*
  1287. * Exchange the block from nonopt_start to nonopt_end with the block
  1288. * from nonopt_end to opt_end (keeping the same order of arguments
  1289. * in each block).
  1290. */
  1291. static void permute_args(int panonopt_start, int panonopt_end, int opt_end, char* const* nargv) {
  1292. int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
  1293. char* swap;
  1294. /*
  1295. * compute lengths of blocks and number and size of cycles
  1296. */
  1297. nnonopts = panonopt_end - panonopt_start;
  1298. nopts = opt_end - panonopt_end;
  1299. ncycle = gcd(nnonopts, nopts);
  1300. cyclelen = (opt_end - panonopt_start) / ncycle;
  1301. for (i = 0; i < ncycle; i++) {
  1302. cstart = panonopt_end + i;
  1303. pos = cstart;
  1304. for (j = 0; j < cyclelen; j++) {
  1305. if (pos >= panonopt_end)
  1306. pos -= nnonopts;
  1307. else
  1308. pos += nopts;
  1309. swap = nargv[pos];
  1310. /* LINTED const cast */
  1311. ((char**)nargv)[pos] = nargv[cstart];
  1312. /* LINTED const cast */
  1313. ((char**)nargv)[cstart] = swap;
  1314. }
  1315. }
  1316. }
  1317. /*
  1318. * parse_long_options --
  1319. * Parse long options in argc/argv argument vector.
  1320. * Returns -1 if short_too is set and the option does not match long_options.
  1321. */
  1322. static int parse_long_options(char* const* nargv, const char* options, const struct option* long_options, int* idx, int short_too) {
  1323. char *current_argv, *has_equal;
  1324. size_t current_argv_len;
  1325. int i, match;
  1326. current_argv = place;
  1327. match = -1;
  1328. optind++;
  1329. if ((has_equal = strchr(current_argv, '=')) != NULL) {
  1330. /* argument found (--option=arg) */
  1331. current_argv_len = has_equal - current_argv;
  1332. has_equal++;
  1333. } else
  1334. current_argv_len = strlen(current_argv);
  1335. for (i = 0; long_options[i].name; i++) {
  1336. /* find matching long option */
  1337. if (strncmp(current_argv, long_options[i].name, current_argv_len))
  1338. continue;
  1339. if (strlen(long_options[i].name) == current_argv_len) {
  1340. /* exact match */
  1341. match = i;
  1342. break;
  1343. }
  1344. /*
  1345. * If this is a known short option, don't allow
  1346. * a partial match of a single character.
  1347. */
  1348. if (short_too && current_argv_len == 1)
  1349. continue;
  1350. if (match == -1) /* partial match */
  1351. match = i;
  1352. else {
  1353. /* ambiguous abbreviation */
  1354. if (PRINT_ERROR)
  1355. warnx(ambig, (int)current_argv_len, current_argv);
  1356. optopt = 0;
  1357. return (BADCH);
  1358. }
  1359. }
  1360. if (match != -1) { /* option found */
  1361. if (long_options[match].has_arg == no_argument && has_equal) {
  1362. if (PRINT_ERROR)
  1363. warnx(noarg, (int)current_argv_len, current_argv);
  1364. /*
  1365. * XXX: GNU sets optopt to val regardless of flag
  1366. */
  1367. if (long_options[match].flag == NULL)
  1368. optopt = long_options[match].val;
  1369. else
  1370. optopt = 0;
  1371. return (BADARG);
  1372. }
  1373. if (long_options[match].has_arg == required_argument || long_options[match].has_arg == optional_argument) {
  1374. if (has_equal)
  1375. optarg = has_equal;
  1376. else if (long_options[match].has_arg == required_argument) {
  1377. /*
  1378. * optional argument doesn't use next nargv
  1379. */
  1380. optarg = nargv[optind++];
  1381. }
  1382. }
  1383. if ((long_options[match].has_arg == required_argument) && (optarg == NULL)) {
  1384. /*
  1385. * Missing argument; leading ':' indicates no error
  1386. * should be generated.
  1387. */
  1388. if (PRINT_ERROR)
  1389. warnx(recargstring, current_argv);
  1390. /*
  1391. * XXX: GNU sets optopt to val regardless of flag
  1392. */
  1393. if (long_options[match].flag == NULL)
  1394. optopt = long_options[match].val;
  1395. else
  1396. optopt = 0;
  1397. --optind;
  1398. return (BADARG);
  1399. }
  1400. } else { /* unknown option */
  1401. if (short_too) {
  1402. --optind;
  1403. return (-1);
  1404. }
  1405. if (PRINT_ERROR)
  1406. warnx(illoptstring, current_argv);
  1407. optopt = 0;
  1408. return (BADCH);
  1409. }
  1410. if (idx)
  1411. *idx = match;
  1412. if (long_options[match].flag) {
  1413. *long_options[match].flag = long_options[match].val;
  1414. return (0);
  1415. } else
  1416. return (long_options[match].val);
  1417. }
  1418. #if ARG_REPLACE_GETOPT == 1
  1419. /*
  1420. * getopt_internal --
  1421. * Parse argc/argv argument vector. Called by user level routines.
  1422. */
  1423. static int getopt_internal(int nargc, char* const* nargv, const char* options, const struct option* long_options, int* idx, int flags) {
  1424. char* oli; /* option letter list index */
  1425. int optchar, short_too;
  1426. static int posixly_correct = -1;
  1427. if (options == NULL)
  1428. return (-1);
  1429. /*
  1430. * Disable GNU extensions if POSIXLY_CORRECT is set or options
  1431. * string begins with a '+'.
  1432. */
  1433. if (posixly_correct == -1)
  1434. #if defined(_MSC_VER)
  1435. #pragma warning(push)
  1436. #pragma warning(disable : 4996)
  1437. #endif
  1438. posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
  1439. #if defined(_MSC_VER)
  1440. #pragma warning(pop)
  1441. #endif
  1442. if (posixly_correct || *options == '+')
  1443. flags &= ~FLAG_PERMUTE;
  1444. else if (*options == '-')
  1445. flags |= FLAG_ALLARGS;
  1446. if (*options == '+' || *options == '-')
  1447. options++;
  1448. /*
  1449. * XXX Some GNU programs (like cvs) set optind to 0 instead of
  1450. * XXX using optreset. Work around this braindamage.
  1451. */
  1452. if (optind == 0)
  1453. optind = optreset = 1;
  1454. optarg = NULL;
  1455. if (optreset)
  1456. nonopt_start = nonopt_end = -1;
  1457. start:
  1458. if (optreset || !*place) { /* update scanning pointer */
  1459. optreset = 0;
  1460. if (optind >= nargc) { /* end of argument vector */
  1461. place = EMSG;
  1462. if (nonopt_end != -1) {
  1463. /* do permutation, if we have to */
  1464. permute_args(nonopt_start, nonopt_end, optind, nargv);
  1465. optind -= nonopt_end - nonopt_start;
  1466. } else if (nonopt_start != -1) {
  1467. /*
  1468. * If we skipped non-options, set optind
  1469. * to the first of them.
  1470. */
  1471. optind = nonopt_start;
  1472. }
  1473. nonopt_start = nonopt_end = -1;
  1474. return (-1);
  1475. }
  1476. if (*(place = nargv[optind]) != '-' || (place[1] == '\0' && strchr(options, '-') == NULL)) {
  1477. place = EMSG; /* found non-option */
  1478. if (flags & FLAG_ALLARGS) {
  1479. /*
  1480. * GNU extension:
  1481. * return non-option as argument to option 1
  1482. */
  1483. optarg = nargv[optind++];
  1484. return (INORDER);
  1485. }
  1486. if (!(flags & FLAG_PERMUTE)) {
  1487. /*
  1488. * If no permutation wanted, stop parsing
  1489. * at first non-option.
  1490. */
  1491. return (-1);
  1492. }
  1493. /* do permutation */
  1494. if (nonopt_start == -1)
  1495. nonopt_start = optind;
  1496. else if (nonopt_end != -1) {
  1497. permute_args(nonopt_start, nonopt_end, optind, nargv);
  1498. nonopt_start = optind - (nonopt_end - nonopt_start);
  1499. nonopt_end = -1;
  1500. }
  1501. optind++;
  1502. /* process next argument */
  1503. goto start;
  1504. }
  1505. if (nonopt_start != -1 && nonopt_end == -1)
  1506. nonopt_end = optind;
  1507. /*
  1508. * If we have "-" do nothing, if "--" we are done.
  1509. */
  1510. if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
  1511. optind++;
  1512. place = EMSG;
  1513. /*
  1514. * We found an option (--), so if we skipped
  1515. * non-options, we have to permute.
  1516. */
  1517. if (nonopt_end != -1) {
  1518. permute_args(nonopt_start, nonopt_end, optind, nargv);
  1519. optind -= nonopt_end - nonopt_start;
  1520. }
  1521. nonopt_start = nonopt_end = -1;
  1522. return (-1);
  1523. }
  1524. }
  1525. /*
  1526. * Check long options if:
  1527. * 1) we were passed some
  1528. * 2) the arg is not just "-"
  1529. * 3) either the arg starts with -- we are getopt_long_only()
  1530. */
  1531. if (long_options != NULL && place != nargv[optind] && (*place == '-' || (flags & FLAG_LONGONLY))) {
  1532. short_too = 0;
  1533. if (*place == '-')
  1534. place++; /* --foo long option */
  1535. else if (*place != ':' && strchr(options, *place) != NULL)
  1536. short_too = 1; /* could be short option too */
  1537. optchar = parse_long_options(nargv, options, long_options, idx, short_too);
  1538. if (optchar != -1) {
  1539. place = EMSG;
  1540. return (optchar);
  1541. }
  1542. }
  1543. if ((optchar = (int)*place++) == (int)':' || (optchar == (int)'-' && *place != '\0') || (oli = strchr(options, optchar)) == NULL) {
  1544. /*
  1545. * If the user specified "-" and '-' isn't listed in
  1546. * options, return -1 (non-option) as per POSIX.
  1547. * Otherwise, it is an unknown option character (or ':').
  1548. */
  1549. if (optchar == (int)'-' && *place == '\0')
  1550. return (-1);
  1551. if (!*place)
  1552. ++optind;
  1553. if (PRINT_ERROR)
  1554. warnx(illoptchar, optchar);
  1555. optopt = optchar;
  1556. return (BADCH);
  1557. }
  1558. if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
  1559. /* -W long-option */
  1560. if (*place) /* no space */
  1561. /* NOTHING */;
  1562. else if (++optind >= nargc) { /* no arg */
  1563. place = EMSG;
  1564. if (PRINT_ERROR)
  1565. warnx(recargchar, optchar);
  1566. optopt = optchar;
  1567. return (BADARG);
  1568. } else /* white space */
  1569. place = nargv[optind];
  1570. optchar = parse_long_options(nargv, options, long_options, idx, 0);
  1571. place = EMSG;
  1572. return (optchar);
  1573. }
  1574. if (*++oli != ':') { /* doesn't take argument */
  1575. if (!*place)
  1576. ++optind;
  1577. } else { /* takes (optional) argument */
  1578. optarg = NULL;
  1579. if (*place) /* no white space */
  1580. optarg = place;
  1581. else if (oli[1] != ':') { /* arg not optional */
  1582. if (++optind >= nargc) { /* no arg */
  1583. place = EMSG;
  1584. if (PRINT_ERROR)
  1585. warnx(recargchar, optchar);
  1586. optopt = optchar;
  1587. return (BADARG);
  1588. } else
  1589. optarg = nargv[optind];
  1590. }
  1591. place = EMSG;
  1592. ++optind;
  1593. }
  1594. /* dump back option letter */
  1595. return (optchar);
  1596. }
  1597. /*
  1598. * getopt --
  1599. * Parse argc/argv argument vector.
  1600. *
  1601. * [eventually this will replace the BSD getopt]
  1602. */
  1603. int getopt(int nargc, char* const* nargv, const char* options) {
  1604. /*
  1605. * We don't pass FLAG_PERMUTE to getopt_internal() since
  1606. * the BSD getopt(3) (unlike GNU) has never done this.
  1607. *
  1608. * Furthermore, since many privileged programs call getopt()
  1609. * before dropping privileges it makes sense to keep things
  1610. * as simple (and bug-free) as possible.
  1611. */
  1612. return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
  1613. }
  1614. #endif /* ARG_REPLACE_GETOPT */
  1615. /*
  1616. * getopt_long --
  1617. * Parse argc/argv argument vector.
  1618. */
  1619. int getopt_long(int nargc, char* const* nargv, const char* options, const struct option* long_options, int* idx) {
  1620. return (getopt_internal(nargc, nargv, options, long_options, idx, FLAG_PERMUTE));
  1621. }
  1622. /*
  1623. * getopt_long_only --
  1624. * Parse argc/argv argument vector.
  1625. */
  1626. int getopt_long_only(int nargc, char* const* nargv, const char* options, const struct option* long_options, int* idx) {
  1627. return (getopt_internal(nargc, nargv, options, long_options, idx, FLAG_PERMUTE | FLAG_LONGONLY));
  1628. }
  1629. /*******************************************************************************
  1630. * arg_date: Implements the date command-line option
  1631. *
  1632. * This file is part of the argtable3 library.
  1633. *
  1634. * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
  1635. * <sheitmann@users.sourceforge.net>
  1636. * All rights reserved.
  1637. *
  1638. * Redistribution and use in source and binary forms, with or without
  1639. * modification, are permitted provided that the following conditions are met:
  1640. * * Redistributions of source code must retain the above copyright
  1641. * notice, this list of conditions and the following disclaimer.
  1642. * * Redistributions in binary form must reproduce the above copyright
  1643. * notice, this list of conditions and the following disclaimer in the
  1644. * documentation and/or other materials provided with the distribution.
  1645. * * Neither the name of STEWART HEITMANN nor the names of its contributors
  1646. * may be used to endorse or promote products derived from this software
  1647. * without specific prior written permission.
  1648. *
  1649. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  1650. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  1651. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  1652. * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
  1653. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  1654. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  1655. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  1656. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  1657. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  1658. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  1659. ******************************************************************************/
  1660. #include "argtable3.h"
  1661. #ifndef ARG_AMALGAMATION
  1662. #include "argtable3_private.h"
  1663. #endif
  1664. #include <stdlib.h>
  1665. #include <string.h>
  1666. char* arg_strptime(const char* buf, const char* fmt, struct tm* tm);
  1667. static void arg_date_resetfn(struct arg_date* parent) {
  1668. ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
  1669. parent->count = 0;
  1670. }
  1671. static int arg_date_scanfn(struct arg_date* parent, const char* argval) {
  1672. int errorcode = 0;
  1673. if (parent->count == parent->hdr.maxcount) {
  1674. errorcode = ARG_ERR_MAXCOUNT;
  1675. } else if (!argval) {
  1676. /* no argument value was given, leave parent->tmval[] unaltered but still count it */
  1677. parent->count++;
  1678. } else {
  1679. const char* pend;
  1680. struct tm tm = parent->tmval[parent->count];
  1681. /* parse the given argument value, store result in parent->tmval[] */
  1682. pend = arg_strptime(argval, parent->format, &tm);
  1683. if (pend && pend[0] == '\0')
  1684. parent->tmval[parent->count++] = tm;
  1685. else
  1686. errorcode = ARG_ERR_BADDATE;
  1687. }
  1688. ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
  1689. return errorcode;
  1690. }
  1691. static int arg_date_checkfn(struct arg_date* parent) {
  1692. int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;
  1693. ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
  1694. return errorcode;
  1695. }
  1696. static void arg_date_errorfn(struct arg_date* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {
  1697. const char* shortopts = parent->hdr.shortopts;
  1698. const char* longopts = parent->hdr.longopts;
  1699. const char* datatype = parent->hdr.datatype;
  1700. /* make argval NULL safe */
  1701. argval = argval ? argval : "";
  1702. arg_dstr_catf(ds, "%s: ", progname);
  1703. switch (errorcode) {
  1704. case ARG_ERR_MINCOUNT:
  1705. arg_dstr_cat(ds, "missing option ");
  1706. arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
  1707. break;
  1708. case ARG_ERR_MAXCOUNT:
  1709. arg_dstr_cat(ds, "excess option ");
  1710. arg_print_option_ds(ds, shortopts, longopts, argval, "\n");
  1711. break;
  1712. case ARG_ERR_BADDATE: {
  1713. struct tm tm;
  1714. char buff[200];
  1715. arg_dstr_catf(ds, "illegal timestamp format \"%s\"\n", argval);
  1716. memset(&tm, 0, sizeof(tm));
  1717. arg_strptime("1999-12-31 23:59:59", "%F %H:%M:%S", &tm);
  1718. strftime(buff, sizeof(buff), parent->format, &tm);
  1719. arg_dstr_catf(ds, "correct format is \"%s\"\n", buff);
  1720. break;
  1721. }
  1722. }
  1723. }
  1724. struct arg_date* arg_date0(const char* shortopts, const char* longopts, const char* format, const char* datatype, const char* glossary) {
  1725. return arg_daten(shortopts, longopts, format, datatype, 0, 1, glossary);
  1726. }
  1727. struct arg_date* arg_date1(const char* shortopts, const char* longopts, const char* format, const char* datatype, const char* glossary) {
  1728. return arg_daten(shortopts, longopts, format, datatype, 1, 1, glossary);
  1729. }
  1730. struct arg_date*
  1731. arg_daten(const char* shortopts, const char* longopts, const char* format, const char* datatype, int mincount, int maxcount, const char* glossary) {
  1732. size_t nbytes;
  1733. struct arg_date* result;
  1734. /* foolproof things by ensuring maxcount is not less than mincount */
  1735. maxcount = (maxcount < mincount) ? mincount : maxcount;
  1736. /* default time format is the national date format for the locale */
  1737. if (!format)
  1738. format = "%x";
  1739. nbytes = sizeof(struct arg_date) /* storage for struct arg_date */
  1740. + maxcount * sizeof(struct tm); /* storage for tmval[maxcount] array */
  1741. /* allocate storage for the arg_date struct + tmval[] array. */
  1742. /* we use calloc because we want the tmval[] array zero filled. */
  1743. result = (struct arg_date*)xcalloc(1, nbytes);
  1744. /* init the arg_hdr struct */
  1745. result->hdr.flag = ARG_HASVALUE;
  1746. result->hdr.shortopts = shortopts;
  1747. result->hdr.longopts = longopts;
  1748. result->hdr.datatype = datatype ? datatype : format;
  1749. result->hdr.glossary = glossary;
  1750. result->hdr.mincount = mincount;
  1751. result->hdr.maxcount = maxcount;
  1752. result->hdr.parent = result;
  1753. result->hdr.resetfn = (arg_resetfn*)arg_date_resetfn;
  1754. result->hdr.scanfn = (arg_scanfn*)arg_date_scanfn;
  1755. result->hdr.checkfn = (arg_checkfn*)arg_date_checkfn;
  1756. result->hdr.errorfn = (arg_errorfn*)arg_date_errorfn;
  1757. /* store the tmval[maxcount] array immediately after the arg_date struct */
  1758. result->tmval = (struct tm*)(result + 1);
  1759. /* init the remaining arg_date member variables */
  1760. result->count = 0;
  1761. result->format = format;
  1762. ARG_TRACE(("arg_daten() returns %p\n", result));
  1763. return result;
  1764. }
  1765. /*-
  1766. * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
  1767. * All rights reserved.
  1768. *
  1769. * This code was contributed to The NetBSD Foundation by Klaus Klein.
  1770. * Heavily optimised by David Laight
  1771. *
  1772. * Redistribution and use in source and binary forms, with or without
  1773. * modification, are permitted provided that the following conditions
  1774. * are met:
  1775. * 1. Redistributions of source code must retain the above copyright
  1776. * notice, this list of conditions and the following disclaimer.
  1777. * 2. Redistributions in binary form must reproduce the above copyright
  1778. * notice, this list of conditions and the following disclaimer in the
  1779. * documentation and/or other materials provided with the distribution.
  1780. *
  1781. * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  1782. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  1783. * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  1784. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
  1785. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  1786. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  1787. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  1788. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  1789. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  1790. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  1791. * POSSIBILITY OF SUCH DAMAGE.
  1792. */
  1793. #include <ctype.h>
  1794. #include <string.h>
  1795. #include <time.h>
  1796. /*
  1797. * We do not implement alternate representations. However, we always
  1798. * check whether a given modifier is allowed for a certain conversion.
  1799. */
  1800. #define ALT_E 0x01
  1801. #define ALT_O 0x02
  1802. #define LEGAL_ALT(x) \
  1803. { \
  1804. if (alt_format & ~(x)) \
  1805. return (0); \
  1806. }
  1807. #define TM_YEAR_BASE (1900)
  1808. static int conv_num(const char**, int*, int, int);
  1809. static const char* day[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
  1810. static const char* abday[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  1811. static const char* mon[12] = {"January", "February", "March", "April", "May", "June",
  1812. "July", "August", "September", "October", "November", "December"};
  1813. static const char* abmon[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  1814. static const char* am_pm[2] = {"AM", "PM"};
  1815. static int arg_strcasecmp(const char* s1, const char* s2) {
  1816. const unsigned char* us1 = (const unsigned char*)s1;
  1817. const unsigned char* us2 = (const unsigned char*)s2;
  1818. while (tolower(*us1) == tolower(*us2++))
  1819. if (*us1++ == '\0')
  1820. return 0;
  1821. return tolower(*us1) - tolower(*--us2);
  1822. }
  1823. static int arg_strncasecmp(const char* s1, const char* s2, size_t n) {
  1824. if (n != 0) {
  1825. const unsigned char* us1 = (const unsigned char*)s1;
  1826. const unsigned char* us2 = (const unsigned char*)s2;
  1827. do {
  1828. if (tolower(*us1) != tolower(*us2++))
  1829. return tolower(*us1) - tolower(*--us2);
  1830. if (*us1++ == '\0')
  1831. break;
  1832. } while (--n != 0);
  1833. }
  1834. return 0;
  1835. }
  1836. char* arg_strptime(const char* buf, const char* fmt, struct tm* tm) {
  1837. char c;
  1838. const char* bp;
  1839. size_t len = 0;
  1840. int alt_format, i, split_year = 0;
  1841. bp = buf;
  1842. while ((c = *fmt) != '\0') {
  1843. /* Clear `alternate' modifier prior to new conversion. */
  1844. alt_format = 0;
  1845. /* Eat up white-space. */
  1846. if (isspace(c)) {
  1847. while (isspace(*bp))
  1848. bp++;
  1849. fmt++;
  1850. continue;
  1851. }
  1852. if ((c = *fmt++) != '%')
  1853. goto literal;
  1854. again:
  1855. switch (c = *fmt++) {
  1856. case '%': /* "%%" is converted to "%". */
  1857. literal:
  1858. if (c != *bp++)
  1859. return (0);
  1860. break;
  1861. /*
  1862. * "Alternative" modifiers. Just set the appropriate flag
  1863. * and start over again.
  1864. */
  1865. case 'E': /* "%E?" alternative conversion modifier. */
  1866. LEGAL_ALT(0);
  1867. alt_format |= ALT_E;
  1868. goto again;
  1869. case 'O': /* "%O?" alternative conversion modifier. */
  1870. LEGAL_ALT(0);
  1871. alt_format |= ALT_O;
  1872. goto again;
  1873. /*
  1874. * "Complex" conversion rules, implemented through recursion.
  1875. */
  1876. case 'c': /* Date and time, using the locale's format. */
  1877. LEGAL_ALT(ALT_E);
  1878. bp = arg_strptime(bp, "%x %X", tm);
  1879. if (!bp)
  1880. return (0);
  1881. break;
  1882. case 'D': /* The date as "%m/%d/%y". */
  1883. LEGAL_ALT(0);
  1884. bp = arg_strptime(bp, "%m/%d/%y", tm);
  1885. if (!bp)
  1886. return (0);
  1887. break;
  1888. case 'R': /* The time as "%H:%M". */
  1889. LEGAL_ALT(0);
  1890. bp = arg_strptime(bp, "%H:%M", tm);
  1891. if (!bp)
  1892. return (0);
  1893. break;
  1894. case 'r': /* The time in 12-hour clock representation. */
  1895. LEGAL_ALT(0);
  1896. bp = arg_strptime(bp, "%I:%M:%S %p", tm);
  1897. if (!bp)
  1898. return (0);
  1899. break;
  1900. case 'T': /* The time as "%H:%M:%S". */
  1901. LEGAL_ALT(0);
  1902. bp = arg_strptime(bp, "%H:%M:%S", tm);
  1903. if (!bp)
  1904. return (0);
  1905. break;
  1906. case 'X': /* The time, using the locale's format. */
  1907. LEGAL_ALT(ALT_E);
  1908. bp = arg_strptime(bp, "%H:%M:%S", tm);
  1909. if (!bp)
  1910. return (0);
  1911. break;
  1912. case 'x': /* The date, using the locale's format. */
  1913. LEGAL_ALT(ALT_E);
  1914. bp = arg_strptime(bp, "%m/%d/%y", tm);
  1915. if (!bp)
  1916. return (0);
  1917. break;
  1918. /*
  1919. * "Elementary" conversion rules.
  1920. */
  1921. case 'A': /* The day of week, using the locale's form. */
  1922. case 'a':
  1923. LEGAL_ALT(0);
  1924. for (i = 0; i < 7; i++) {
  1925. /* Full name. */
  1926. len = strlen(day[i]);
  1927. if (arg_strncasecmp(day[i], bp, len) == 0)
  1928. break;
  1929. /* Abbreviated name. */
  1930. len = strlen(abday[i]);
  1931. if (arg_strncasecmp(abday[i], bp, len) == 0)
  1932. break;
  1933. }
  1934. /* Nothing matched. */
  1935. if (i == 7)
  1936. return (0);
  1937. tm->tm_wday = i;
  1938. bp += len;
  1939. break;
  1940. case 'B': /* The month, using the locale's form. */
  1941. case 'b':
  1942. case 'h':
  1943. LEGAL_ALT(0);
  1944. for (i = 0; i < 12; i++) {
  1945. /* Full name. */
  1946. len = strlen(mon[i]);
  1947. if (arg_strncasecmp(mon[i], bp, len) == 0)
  1948. break;
  1949. /* Abbreviated name. */
  1950. len = strlen(abmon[i]);
  1951. if (arg_strncasecmp(abmon[i], bp, len) == 0)
  1952. break;
  1953. }
  1954. /* Nothing matched. */
  1955. if (i == 12)
  1956. return (0);
  1957. tm->tm_mon = i;
  1958. bp += len;
  1959. break;
  1960. case 'C': /* The century number. */
  1961. LEGAL_ALT(ALT_E);
  1962. if (!(conv_num(&bp, &i, 0, 99)))
  1963. return (0);
  1964. if (split_year) {
  1965. tm->tm_year = (tm->tm_year % 100) + (i * 100);
  1966. } else {
  1967. tm->tm_year = i * 100;
  1968. split_year = 1;
  1969. }
  1970. break;
  1971. case 'd': /* The day of month. */
  1972. case 'e':
  1973. LEGAL_ALT(ALT_O);
  1974. if (!(conv_num(&bp, &tm->tm_mday, 1, 31)))
  1975. return (0);
  1976. break;
  1977. case 'k': /* The hour (24-hour clock representation). */
  1978. LEGAL_ALT(0);
  1979. /* FALLTHROUGH */
  1980. case 'H':
  1981. LEGAL_ALT(ALT_O);
  1982. if (!(conv_num(&bp, &tm->tm_hour, 0, 23)))
  1983. return (0);
  1984. break;
  1985. case 'l': /* The hour (12-hour clock representation). */
  1986. LEGAL_ALT(0);
  1987. /* FALLTHROUGH */
  1988. case 'I':
  1989. LEGAL_ALT(ALT_O);
  1990. if (!(conv_num(&bp, &tm->tm_hour, 1, 12)))
  1991. return (0);
  1992. if (tm->tm_hour == 12)
  1993. tm->tm_hour = 0;
  1994. break;
  1995. case 'j': /* The day of year. */
  1996. LEGAL_ALT(0);
  1997. if (!(conv_num(&bp, &i, 1, 366)))
  1998. return (0);
  1999. tm->tm_yday = i - 1;
  2000. break;
  2001. case 'M': /* The minute. */
  2002. LEGAL_ALT(ALT_O);
  2003. if (!(conv_num(&bp, &tm->tm_min, 0, 59)))
  2004. return (0);
  2005. break;
  2006. case 'm': /* The month. */
  2007. LEGAL_ALT(ALT_O);
  2008. if (!(conv_num(&bp, &i, 1, 12)))
  2009. return (0);
  2010. tm->tm_mon = i - 1;
  2011. break;
  2012. case 'p': /* The locale's equivalent of AM/PM. */
  2013. LEGAL_ALT(0);
  2014. /* AM? */
  2015. if (arg_strcasecmp(am_pm[0], bp) == 0) {
  2016. if (tm->tm_hour > 11)
  2017. return (0);
  2018. bp += strlen(am_pm[0]);
  2019. break;
  2020. }
  2021. /* PM? */
  2022. else if (arg_strcasecmp(am_pm[1], bp) == 0) {
  2023. if (tm->tm_hour > 11)
  2024. return (0);
  2025. tm->tm_hour += 12;
  2026. bp += strlen(am_pm[1]);
  2027. break;
  2028. }
  2029. /* Nothing matched. */
  2030. return (0);
  2031. case 'S': /* The seconds. */
  2032. LEGAL_ALT(ALT_O);
  2033. if (!(conv_num(&bp, &tm->tm_sec, 0, 61)))
  2034. return (0);
  2035. break;
  2036. case 'U': /* The week of year, beginning on sunday. */
  2037. case 'W': /* The week of year, beginning on monday. */
  2038. LEGAL_ALT(ALT_O);
  2039. /*
  2040. * XXX This is bogus, as we can not assume any valid
  2041. * information present in the tm structure at this
  2042. * point to calculate a real value, so just check the
  2043. * range for now.
  2044. */
  2045. if (!(conv_num(&bp, &i, 0, 53)))
  2046. return (0);
  2047. break;
  2048. case 'w': /* The day of week, beginning on sunday. */
  2049. LEGAL_ALT(ALT_O);
  2050. if (!(conv_num(&bp, &tm->tm_wday, 0, 6)))
  2051. return (0);
  2052. break;
  2053. case 'Y': /* The year. */
  2054. LEGAL_ALT(ALT_E);
  2055. if (!(conv_num(&bp, &i, 0, 9999)))
  2056. return (0);
  2057. tm->tm_year = i - TM_YEAR_BASE;
  2058. break;
  2059. case 'y': /* The year within 100 years of the epoch. */
  2060. LEGAL_ALT(ALT_E | ALT_O);
  2061. if (!(conv_num(&bp, &i, 0, 99)))
  2062. return (0);
  2063. if (split_year) {
  2064. tm->tm_year = ((tm->tm_year / 100) * 100) + i;
  2065. break;
  2066. }
  2067. split_year = 1;
  2068. if (i <= 68)
  2069. tm->tm_year = i + 2000 - TM_YEAR_BASE;
  2070. else
  2071. tm->tm_year = i + 1900 - TM_YEAR_BASE;
  2072. break;
  2073. /*
  2074. * Miscellaneous conversions.
  2075. */
  2076. case 'n': /* Any kind of white-space. */
  2077. case 't':
  2078. LEGAL_ALT(0);
  2079. while (isspace(*bp))
  2080. bp++;
  2081. break;
  2082. default: /* Unknown/unsupported conversion. */
  2083. return (0);
  2084. }
  2085. }
  2086. /* LINTED functional specification */
  2087. return ((char*)bp);
  2088. }
  2089. static int conv_num(const char** buf, int* dest, int llim, int ulim) {
  2090. int result = 0;
  2091. /* The limit also determines the number of valid digits. */
  2092. int rulim = ulim;
  2093. if (**buf < '0' || **buf > '9')
  2094. return (0);
  2095. do {
  2096. result *= 10;
  2097. result += *(*buf)++ - '0';
  2098. rulim /= 10;
  2099. } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
  2100. if (result < llim || result > ulim)
  2101. return (0);
  2102. *dest = result;
  2103. return (1);
  2104. }
  2105. /*******************************************************************************
  2106. * arg_dbl: Implements the double command-line option
  2107. *
  2108. * This file is part of the argtable3 library.
  2109. *
  2110. * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
  2111. * <sheitmann@users.sourceforge.net>
  2112. * All rights reserved.
  2113. *
  2114. * Redistribution and use in source and binary forms, with or without
  2115. * modification, are permitted provided that the following conditions are met:
  2116. * * Redistributions of source code must retain the above copyright
  2117. * notice, this list of conditions and the following disclaimer.
  2118. * * Redistributions in binary form must reproduce the above copyright
  2119. * notice, this list of conditions and the following disclaimer in the
  2120. * documentation and/or other materials provided with the distribution.
  2121. * * Neither the name of STEWART HEITMANN nor the names of its contributors
  2122. * may be used to endorse or promote products derived from this software
  2123. * without specific prior written permission.
  2124. *
  2125. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  2126. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  2127. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  2128. * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
  2129. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  2130. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  2131. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  2132. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  2133. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  2134. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  2135. ******************************************************************************/
  2136. #include "argtable3.h"
  2137. #ifndef ARG_AMALGAMATION
  2138. #include "argtable3_private.h"
  2139. #endif
  2140. #include <stdlib.h>
  2141. static void arg_dbl_resetfn(struct arg_dbl* parent) {
  2142. ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
  2143. parent->count = 0;
  2144. }
  2145. static int arg_dbl_scanfn(struct arg_dbl* parent, const char* argval) {
  2146. int errorcode = 0;
  2147. if (parent->count == parent->hdr.maxcount) {
  2148. /* maximum number of arguments exceeded */
  2149. errorcode = ARG_ERR_MAXCOUNT;
  2150. } else if (!argval) {
  2151. /* a valid argument with no argument value was given. */
  2152. /* This happens when an optional argument value was invoked. */
  2153. /* leave parent argument value unaltered but still count the argument. */
  2154. parent->count++;
  2155. } else {
  2156. double val;
  2157. char* end;
  2158. /* extract double from argval into val */
  2159. val = strtod(argval, &end);
  2160. /* if success then store result in parent->dval[] array otherwise return error*/
  2161. if (*end == 0)
  2162. parent->dval[parent->count++] = val;
  2163. else
  2164. errorcode = ARG_ERR_BADDOUBLE;
  2165. }
  2166. ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
  2167. return errorcode;
  2168. }
  2169. static int arg_dbl_checkfn(struct arg_dbl* parent) {
  2170. int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;
  2171. ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
  2172. return errorcode;
  2173. }
  2174. static void arg_dbl_errorfn(struct arg_dbl* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {
  2175. const char* shortopts = parent->hdr.shortopts;
  2176. const char* longopts = parent->hdr.longopts;
  2177. const char* datatype = parent->hdr.datatype;
  2178. /* make argval NULL safe */
  2179. argval = argval ? argval : "";
  2180. arg_dstr_catf(ds, "%s: ", progname);
  2181. switch (errorcode) {
  2182. case ARG_ERR_MINCOUNT:
  2183. arg_dstr_cat(ds, "missing option ");
  2184. arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
  2185. break;
  2186. case ARG_ERR_MAXCOUNT:
  2187. arg_dstr_cat(ds, "excess option ");
  2188. arg_print_option_ds(ds, shortopts, longopts, argval, "\n");
  2189. break;
  2190. case ARG_ERR_BADDOUBLE:
  2191. arg_dstr_catf(ds, "invalid argument \"%s\" to option ", argval);
  2192. arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
  2193. break;
  2194. }
  2195. }
  2196. struct arg_dbl* arg_dbl0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {
  2197. return arg_dbln(shortopts, longopts, datatype, 0, 1, glossary);
  2198. }
  2199. struct arg_dbl* arg_dbl1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {
  2200. return arg_dbln(shortopts, longopts, datatype, 1, 1, glossary);
  2201. }
  2202. struct arg_dbl* arg_dbln(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary) {
  2203. size_t nbytes;
  2204. struct arg_dbl* result;
  2205. size_t addr;
  2206. size_t rem;
  2207. /* foolproof things by ensuring maxcount is not less than mincount */
  2208. maxcount = (maxcount < mincount) ? mincount : maxcount;
  2209. nbytes = sizeof(struct arg_dbl) /* storage for struct arg_dbl */
  2210. + (maxcount + 1) * sizeof(double); /* storage for dval[maxcount] array plus one extra for padding to memory boundary */
  2211. result = (struct arg_dbl*)xmalloc(nbytes);
  2212. /* init the arg_hdr struct */
  2213. result->hdr.flag = ARG_HASVALUE;
  2214. result->hdr.shortopts = shortopts;
  2215. result->hdr.longopts = longopts;
  2216. result->hdr.datatype = datatype ? datatype : "<double>";
  2217. result->hdr.glossary = glossary;
  2218. result->hdr.mincount = mincount;
  2219. result->hdr.maxcount = maxcount;
  2220. result->hdr.parent = result;
  2221. result->hdr.resetfn = (arg_resetfn*)arg_dbl_resetfn;
  2222. result->hdr.scanfn = (arg_scanfn*)arg_dbl_scanfn;
  2223. result->hdr.checkfn = (arg_checkfn*)arg_dbl_checkfn;
  2224. result->hdr.errorfn = (arg_errorfn*)arg_dbl_errorfn;
  2225. /* Store the dval[maxcount] array on the first double boundary that
  2226. * immediately follows the arg_dbl struct. We do the memory alignment
  2227. * purely for SPARC and Motorola systems. They require floats and
  2228. * doubles to be aligned on natural boundaries.
  2229. */
  2230. addr = (size_t)(result + 1);
  2231. rem = addr % sizeof(double);
  2232. result->dval = (double*)(addr + sizeof(double) - rem);
  2233. ARG_TRACE(("addr=%p, dval=%p, sizeof(double)=%d rem=%d\n", addr, result->dval, (int)sizeof(double), (int)rem));
  2234. result->count = 0;
  2235. ARG_TRACE(("arg_dbln() returns %p\n", result));
  2236. return result;
  2237. }
  2238. /*******************************************************************************
  2239. * arg_end: Implements the error handling utilities
  2240. *
  2241. * This file is part of the argtable3 library.
  2242. *
  2243. * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
  2244. * <sheitmann@users.sourceforge.net>
  2245. * All rights reserved.
  2246. *
  2247. * Redistribution and use in source and binary forms, with or without
  2248. * modification, are permitted provided that the following conditions are met:
  2249. * * Redistributions of source code must retain the above copyright
  2250. * notice, this list of conditions and the following disclaimer.
  2251. * * Redistributions in binary form must reproduce the above copyright
  2252. * notice, this list of conditions and the following disclaimer in the
  2253. * documentation and/or other materials provided with the distribution.
  2254. * * Neither the name of STEWART HEITMANN nor the names of its contributors
  2255. * may be used to endorse or promote products derived from this software
  2256. * without specific prior written permission.
  2257. *
  2258. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  2259. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  2260. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  2261. * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
  2262. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  2263. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  2264. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  2265. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  2266. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  2267. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  2268. ******************************************************************************/
  2269. #include "argtable3.h"
  2270. #ifndef ARG_AMALGAMATION
  2271. #include "argtable3_private.h"
  2272. #endif
  2273. #include <stdlib.h>
  2274. static void arg_end_resetfn(struct arg_end* parent) {
  2275. ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
  2276. parent->count = 0;
  2277. }
  2278. static void arg_end_errorfn(void* parent, arg_dstr_t ds, int error, const char* argval, const char* progname) {
  2279. /* suppress unreferenced formal parameter warning */
  2280. (void)parent;
  2281. progname = progname ? progname : "";
  2282. argval = argval ? argval : "";
  2283. arg_dstr_catf(ds, "%s: ", progname);
  2284. switch (error) {
  2285. case ARG_ELIMIT:
  2286. arg_dstr_cat(ds, "too many errors to display");
  2287. break;
  2288. case ARG_EMALLOC:
  2289. arg_dstr_cat(ds, "insufficient memory");
  2290. break;
  2291. case ARG_ENOMATCH:
  2292. arg_dstr_catf(ds, "unexpected argument \"%s\"", argval);
  2293. break;
  2294. case ARG_EMISSARG:
  2295. arg_dstr_catf(ds, "option \"%s\" requires an argument", argval);
  2296. break;
  2297. case ARG_ELONGOPT:
  2298. arg_dstr_catf(ds, "invalid option \"%s\"", argval);
  2299. break;
  2300. default:
  2301. arg_dstr_catf(ds, "invalid option \"-%c\"", error);
  2302. break;
  2303. }
  2304. arg_dstr_cat(ds, "\n");
  2305. }
  2306. struct arg_end* arg_end(int maxcount) {
  2307. size_t nbytes;
  2308. struct arg_end* result;
  2309. nbytes = sizeof(struct arg_end) + maxcount * sizeof(int) /* storage for int error[maxcount] array*/
  2310. + maxcount * sizeof(void*) /* storage for void* parent[maxcount] array */
  2311. + maxcount * sizeof(char*); /* storage for char* argval[maxcount] array */
  2312. result = (struct arg_end*)xmalloc(nbytes);
  2313. /* init the arg_hdr struct */
  2314. result->hdr.flag = ARG_TERMINATOR;
  2315. result->hdr.shortopts = NULL;
  2316. result->hdr.longopts = NULL;
  2317. result->hdr.datatype = NULL;
  2318. result->hdr.glossary = NULL;
  2319. result->hdr.mincount = 1;
  2320. result->hdr.maxcount = maxcount;
  2321. result->hdr.parent = result;
  2322. result->hdr.resetfn = (arg_resetfn*)arg_end_resetfn;
  2323. result->hdr.scanfn = NULL;
  2324. result->hdr.checkfn = NULL;
  2325. result->hdr.errorfn = (arg_errorfn*)arg_end_errorfn;
  2326. /* store error[maxcount] array immediately after struct arg_end */
  2327. result->error = (int*)(result + 1);
  2328. /* store parent[maxcount] array immediately after error[] array */
  2329. result->parent = (void**)(result->error + maxcount);
  2330. /* store argval[maxcount] array immediately after parent[] array */
  2331. result->argval = (const char**)(result->parent + maxcount);
  2332. ARG_TRACE(("arg_end(%d) returns %p\n", maxcount, result));
  2333. return result;
  2334. }
  2335. void arg_print_errors_ds(arg_dstr_t ds, struct arg_end* end, const char* progname) {
  2336. int i;
  2337. ARG_TRACE(("arg_errors()\n"));
  2338. for (i = 0; i < end->count; i++) {
  2339. struct arg_hdr* errorparent = (struct arg_hdr*)(end->parent[i]);
  2340. if (errorparent->errorfn)
  2341. errorparent->errorfn(end->parent[i], ds, end->error[i], end->argval[i], progname);
  2342. }
  2343. }
  2344. void arg_print_errors(FILE* fp, struct arg_end* end, const char* progname) {
  2345. arg_dstr_t ds = arg_dstr_create();
  2346. arg_print_errors_ds(ds, end, progname);
  2347. fputs(arg_dstr_cstr(ds), fp);
  2348. arg_dstr_destroy(ds);
  2349. }
  2350. /*******************************************************************************
  2351. * arg_file: Implements the file command-line option
  2352. *
  2353. * This file is part of the argtable3 library.
  2354. *
  2355. * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
  2356. * <sheitmann@users.sourceforge.net>
  2357. * All rights reserved.
  2358. *
  2359. * Redistribution and use in source and binary forms, with or without
  2360. * modification, are permitted provided that the following conditions are met:
  2361. * * Redistributions of source code must retain the above copyright
  2362. * notice, this list of conditions and the following disclaimer.
  2363. * * Redistributions in binary form must reproduce the above copyright
  2364. * notice, this list of conditions and the following disclaimer in the
  2365. * documentation and/or other materials provided with the distribution.
  2366. * * Neither the name of STEWART HEITMANN nor the names of its contributors
  2367. * may be used to endorse or promote products derived from this software
  2368. * without specific prior written permission.
  2369. *
  2370. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  2371. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  2372. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  2373. * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
  2374. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  2375. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  2376. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  2377. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  2378. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  2379. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  2380. ******************************************************************************/
  2381. #include "argtable3.h"
  2382. #ifndef ARG_AMALGAMATION
  2383. #include "argtable3_private.h"
  2384. #endif
  2385. #include <stdlib.h>
  2386. #include <string.h>
  2387. #ifdef WIN32
  2388. #define FILESEPARATOR1 '\\'
  2389. #define FILESEPARATOR2 '/'
  2390. #else
  2391. #define FILESEPARATOR1 '/'
  2392. #define FILESEPARATOR2 '/'
  2393. #endif
  2394. static void arg_file_resetfn(struct arg_file* parent) {
  2395. ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
  2396. parent->count = 0;
  2397. }
  2398. /* Returns ptr to the base filename within *filename */
  2399. static const char* arg_basename(const char* filename) {
  2400. const char *result = NULL, *result1, *result2;
  2401. /* Find the last occurrence of eother file separator character. */
  2402. /* Two alternative file separator chars are supported as legal */
  2403. /* file separators but not both together in the same filename. */
  2404. result1 = (filename ? strrchr(filename, FILESEPARATOR1) : NULL);
  2405. result2 = (filename ? strrchr(filename, FILESEPARATOR2) : NULL);
  2406. if (result2)
  2407. result = result2 + 1; /* using FILESEPARATOR2 (the alternative file separator) */
  2408. if (result1)
  2409. result = result1 + 1; /* using FILESEPARATOR1 (the preferred file separator) */
  2410. if (!result)
  2411. result = filename; /* neither file separator was found so basename is the whole filename */
  2412. /* special cases of "." and ".." are not considered basenames */
  2413. if (result && (strcmp(".", result) == 0 || strcmp("..", result) == 0))
  2414. result = filename + strlen(filename);
  2415. return result;
  2416. }
  2417. /* Returns ptr to the file extension within *basename */
  2418. static const char* arg_extension(const char* basename) {
  2419. /* find the last occurrence of '.' in basename */
  2420. const char* result = (basename ? strrchr(basename, '.') : NULL);
  2421. /* if no '.' was found then return pointer to end of basename */
  2422. if (basename && !result)
  2423. result = basename + strlen(basename);
  2424. /* special case: basenames with a single leading dot (eg ".foo") are not considered as true extensions */
  2425. if (basename && result == basename)
  2426. result = basename + strlen(basename);
  2427. /* special case: empty extensions (eg "foo.","foo..") are not considered as true extensions */
  2428. if (basename && result && result[1] == '\0')
  2429. result = basename + strlen(basename);
  2430. return result;
  2431. }
  2432. static int arg_file_scanfn(struct arg_file* parent, const char* argval) {
  2433. int errorcode = 0;
  2434. if (parent->count == parent->hdr.maxcount) {
  2435. /* maximum number of arguments exceeded */
  2436. errorcode = ARG_ERR_MAXCOUNT;
  2437. } else if (!argval) {
  2438. /* a valid argument with no argument value was given. */
  2439. /* This happens when an optional argument value was invoked. */
  2440. /* leave parent arguiment value unaltered but still count the argument. */
  2441. parent->count++;
  2442. } else {
  2443. parent->filename[parent->count] = argval;
  2444. parent->basename[parent->count] = arg_basename(argval);
  2445. parent->extension[parent->count] =
  2446. arg_extension(parent->basename[parent->count]); /* only seek extensions within the basename (not the file path)*/
  2447. parent->count++;
  2448. }
  2449. ARG_TRACE(("%s4:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
  2450. return errorcode;
  2451. }
  2452. static int arg_file_checkfn(struct arg_file* parent) {
  2453. int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;
  2454. ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
  2455. return errorcode;
  2456. }
  2457. static void arg_file_errorfn(struct arg_file* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {
  2458. const char* shortopts = parent->hdr.shortopts;
  2459. const char* longopts = parent->hdr.longopts;
  2460. const char* datatype = parent->hdr.datatype;
  2461. /* make argval NULL safe */
  2462. argval = argval ? argval : "";
  2463. arg_dstr_catf(ds, "%s: ", progname);
  2464. switch (errorcode) {
  2465. case ARG_ERR_MINCOUNT:
  2466. arg_dstr_cat(ds, "missing option ");
  2467. arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
  2468. break;
  2469. case ARG_ERR_MAXCOUNT:
  2470. arg_dstr_cat(ds, "excess option ");
  2471. arg_print_option_ds(ds, shortopts, longopts, argval, "\n");
  2472. break;
  2473. default:
  2474. arg_dstr_catf(ds, "unknown error at \"%s\"\n", argval);
  2475. }
  2476. }
  2477. struct arg_file* arg_file0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {
  2478. return arg_filen(shortopts, longopts, datatype, 0, 1, glossary);
  2479. }
  2480. struct arg_file* arg_file1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {
  2481. return arg_filen(shortopts, longopts, datatype, 1, 1, glossary);
  2482. }
  2483. struct arg_file* arg_filen(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary) {
  2484. size_t nbytes;
  2485. struct arg_file* result;
  2486. int i;
  2487. /* foolproof things by ensuring maxcount is not less than mincount */
  2488. maxcount = (maxcount < mincount) ? mincount : maxcount;
  2489. nbytes = sizeof(struct arg_file) /* storage for struct arg_file */
  2490. + sizeof(char*) * maxcount /* storage for filename[maxcount] array */
  2491. + sizeof(char*) * maxcount /* storage for basename[maxcount] array */
  2492. + sizeof(char*) * maxcount; /* storage for extension[maxcount] array */
  2493. result = (struct arg_file*)xmalloc(nbytes);
  2494. /* init the arg_hdr struct */
  2495. result->hdr.flag = ARG_HASVALUE;
  2496. result->hdr.shortopts = shortopts;
  2497. result->hdr.longopts = longopts;
  2498. result->hdr.glossary = glossary;
  2499. result->hdr.datatype = datatype ? datatype : "<file>";
  2500. result->hdr.mincount = mincount;
  2501. result->hdr.maxcount = maxcount;
  2502. result->hdr.parent = result;
  2503. result->hdr.resetfn = (arg_resetfn*)arg_file_resetfn;
  2504. result->hdr.scanfn = (arg_scanfn*)arg_file_scanfn;
  2505. result->hdr.checkfn = (arg_checkfn*)arg_file_checkfn;
  2506. result->hdr.errorfn = (arg_errorfn*)arg_file_errorfn;
  2507. /* store the filename,basename,extension arrays immediately after the arg_file struct */
  2508. result->filename = (const char**)(result + 1);
  2509. result->basename = result->filename + maxcount;
  2510. result->extension = result->basename + maxcount;
  2511. result->count = 0;
  2512. /* foolproof the string pointers by initialising them with empty strings */
  2513. for (i = 0; i < maxcount; i++) {
  2514. result->filename[i] = "";
  2515. result->basename[i] = "";
  2516. result->extension[i] = "";
  2517. }
  2518. ARG_TRACE(("arg_filen() returns %p\n", result));
  2519. return result;
  2520. }
  2521. /*******************************************************************************
  2522. * arg_int: Implements the int command-line option
  2523. *
  2524. * This file is part of the argtable3 library.
  2525. *
  2526. * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
  2527. * <sheitmann@users.sourceforge.net>
  2528. * All rights reserved.
  2529. *
  2530. * Redistribution and use in source and binary forms, with or without
  2531. * modification, are permitted provided that the following conditions are met:
  2532. * * Redistributions of source code must retain the above copyright
  2533. * notice, this list of conditions and the following disclaimer.
  2534. * * Redistributions in binary form must reproduce the above copyright
  2535. * notice, this list of conditions and the following disclaimer in the
  2536. * documentation and/or other materials provided with the distribution.
  2537. * * Neither the name of STEWART HEITMANN nor the names of its contributors
  2538. * may be used to endorse or promote products derived from this software
  2539. * without specific prior written permission.
  2540. *
  2541. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  2542. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  2543. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  2544. * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
  2545. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  2546. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  2547. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  2548. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  2549. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  2550. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  2551. ******************************************************************************/
  2552. #include "argtable3.h"
  2553. #ifndef ARG_AMALGAMATION
  2554. #include "argtable3_private.h"
  2555. #endif
  2556. #include <ctype.h>
  2557. #include <limits.h>
  2558. #include <stdlib.h>
  2559. static void arg_int_resetfn(struct arg_int* parent) {
  2560. ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
  2561. parent->count = 0;
  2562. }
  2563. /* strtol0x() is like strtol() except that the numeric string is */
  2564. /* expected to be prefixed by "0X" where X is a user supplied char. */
  2565. /* The string may optionally be prefixed by white space and + or - */
  2566. /* as in +0X123 or -0X123. */
  2567. /* Once the prefix has been scanned, the remainder of the numeric */
  2568. /* string is converted using strtol() with the given base. */
  2569. /* eg: to parse hex str="-0X12324", specify X='X' and base=16. */
  2570. /* eg: to parse oct str="+0o12324", specify X='O' and base=8. */
  2571. /* eg: to parse bin str="-0B01010", specify X='B' and base=2. */
  2572. /* Failure of conversion is indicated by result where *endptr==str. */
  2573. static long int strtol0X(const char* str, const char** endptr, char X, int base) {
  2574. long int val; /* stores result */
  2575. int s = 1; /* sign is +1 or -1 */
  2576. const char* ptr = str; /* ptr to current position in str */
  2577. /* skip leading whitespace */
  2578. while (isspace(*ptr))
  2579. ptr++;
  2580. /* printf("1) %s\n",ptr); */
  2581. /* scan optional sign character */
  2582. switch (*ptr) {
  2583. case '+':
  2584. ptr++;
  2585. s = 1;
  2586. break;
  2587. case '-':
  2588. ptr++;
  2589. s = -1;
  2590. break;
  2591. default:
  2592. s = 1;
  2593. break;
  2594. }
  2595. /* printf("2) %s\n",ptr); */
  2596. /* '0X' prefix */
  2597. if ((*ptr++) != '0') {
  2598. /* printf("failed to detect '0'\n"); */
  2599. *endptr = str;
  2600. return 0;
  2601. }
  2602. /* printf("3) %s\n",ptr); */
  2603. if (toupper(*ptr++) != toupper(X)) {
  2604. /* printf("failed to detect '%c'\n",X); */
  2605. *endptr = str;
  2606. return 0;
  2607. }
  2608. /* printf("4) %s\n",ptr); */
  2609. /* attempt conversion on remainder of string using strtol() */
  2610. val = strtol(ptr, (char**)endptr, base);
  2611. if (*endptr == ptr) {
  2612. /* conversion failed */
  2613. *endptr = str;
  2614. return 0;
  2615. }
  2616. /* success */
  2617. return s * val;
  2618. }
  2619. /* Returns 1 if str matches suffix (case insensitive). */
  2620. /* Str may contain trailing whitespace, but nothing else. */
  2621. static int detectsuffix(const char* str, const char* suffix) {
  2622. /* scan pairwise through strings until mismatch detected */
  2623. while (toupper(*str) == toupper(*suffix)) {
  2624. /* printf("'%c' '%c'\n", *str, *suffix); */
  2625. /* return 1 (success) if match persists until the string terminator */
  2626. if (*str == '\0')
  2627. return 1;
  2628. /* next chars */
  2629. str++;
  2630. suffix++;
  2631. }
  2632. /* printf("'%c' '%c' mismatch\n", *str, *suffix); */
  2633. /* return 0 (fail) if the matching did not consume the entire suffix */
  2634. if (*suffix != 0)
  2635. return 0; /* failed to consume entire suffix */
  2636. /* skip any remaining whitespace in str */
  2637. while (isspace(*str))
  2638. str++;
  2639. /* return 1 (success) if we have reached end of str else return 0 (fail) */
  2640. return (*str == '\0') ? 1 : 0;
  2641. }
  2642. static int arg_int_scanfn(struct arg_int* parent, const char* argval) {
  2643. int errorcode = 0;
  2644. if (parent->count == parent->hdr.maxcount) {
  2645. /* maximum number of arguments exceeded */
  2646. errorcode = ARG_ERR_MAXCOUNT;
  2647. } else if (!argval) {
  2648. /* a valid argument with no argument value was given. */
  2649. /* This happens when an optional argument value was invoked. */
  2650. /* leave parent arguiment value unaltered but still count the argument. */
  2651. parent->count++;
  2652. } else {
  2653. long int val;
  2654. const char* end;
  2655. /* attempt to extract hex integer (eg: +0x123) from argval into val conversion */
  2656. val = strtol0X(argval, &end, 'X', 16);
  2657. if (end == argval) {
  2658. /* hex failed, attempt octal conversion (eg +0o123) */
  2659. val = strtol0X(argval, &end, 'O', 8);
  2660. if (end == argval) {
  2661. /* octal failed, attempt binary conversion (eg +0B101) */
  2662. val = strtol0X(argval, &end, 'B', 2);
  2663. if (end == argval) {
  2664. /* binary failed, attempt decimal conversion with no prefix (eg 1234) */
  2665. val = strtol(argval, (char**)&end, 10);
  2666. if (end == argval) {
  2667. /* all supported number formats failed */
  2668. return ARG_ERR_BADINT;
  2669. }
  2670. }
  2671. }
  2672. }
  2673. /* Safety check for integer overflow. WARNING: this check */
  2674. /* achieves nothing on machines where size(int)==size(long). */
  2675. if (val > INT_MAX || val < INT_MIN)
  2676. errorcode = ARG_ERR_OVERFLOW;
  2677. /* Detect any suffixes (KB,MB,GB) and multiply argument value appropriately. */
  2678. /* We need to be mindful of integer overflows when using such big numbers. */
  2679. if (detectsuffix(end, "KB")) /* kilobytes */
  2680. {
  2681. if (val > (INT_MAX / 1024) || val < (INT_MIN / 1024))
  2682. errorcode = ARG_ERR_OVERFLOW; /* Overflow would occur if we proceed */
  2683. else
  2684. val *= 1024; /* 1KB = 1024 */
  2685. } else if (detectsuffix(end, "MB")) /* megabytes */
  2686. {
  2687. if (val > (INT_MAX / 1048576) || val < (INT_MIN / 1048576))
  2688. errorcode = ARG_ERR_OVERFLOW; /* Overflow would occur if we proceed */
  2689. else
  2690. val *= 1048576; /* 1MB = 1024*1024 */
  2691. } else if (detectsuffix(end, "GB")) /* gigabytes */
  2692. {
  2693. if (val > (INT_MAX / 1073741824) || val < (INT_MIN / 1073741824))
  2694. errorcode = ARG_ERR_OVERFLOW; /* Overflow would occur if we proceed */
  2695. else
  2696. val *= 1073741824; /* 1GB = 1024*1024*1024 */
  2697. } else if (!detectsuffix(end, ""))
  2698. errorcode = ARG_ERR_BADINT; /* invalid suffix detected */
  2699. /* if success then store result in parent->ival[] array */
  2700. if (errorcode == 0)
  2701. parent->ival[parent->count++] = (int)val;
  2702. }
  2703. /* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */
  2704. return errorcode;
  2705. }
  2706. static int arg_int_checkfn(struct arg_int* parent) {
  2707. int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;
  2708. /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
  2709. return errorcode;
  2710. }
  2711. static void arg_int_errorfn(struct arg_int* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {
  2712. const char* shortopts = parent->hdr.shortopts;
  2713. const char* longopts = parent->hdr.longopts;
  2714. const char* datatype = parent->hdr.datatype;
  2715. /* make argval NULL safe */
  2716. argval = argval ? argval : "";
  2717. arg_dstr_catf(ds, "%s: ", progname);
  2718. switch (errorcode) {
  2719. case ARG_ERR_MINCOUNT:
  2720. arg_dstr_cat(ds, "missing option ");
  2721. arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
  2722. break;
  2723. case ARG_ERR_MAXCOUNT:
  2724. arg_dstr_cat(ds, "excess option ");
  2725. arg_print_option_ds(ds, shortopts, longopts, argval, "\n");
  2726. break;
  2727. case ARG_ERR_BADINT:
  2728. arg_dstr_catf(ds, "invalid argument \"%s\" to option ", argval);
  2729. arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
  2730. break;
  2731. case ARG_ERR_OVERFLOW:
  2732. arg_dstr_cat(ds, "integer overflow at option ");
  2733. arg_print_option_ds(ds, shortopts, longopts, datatype, " ");
  2734. arg_dstr_catf(ds, "(%s is too large)\n", argval);
  2735. break;
  2736. }
  2737. }
  2738. struct arg_int* arg_int0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {
  2739. return arg_intn(shortopts, longopts, datatype, 0, 1, glossary);
  2740. }
  2741. struct arg_int* arg_int1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {
  2742. return arg_intn(shortopts, longopts, datatype, 1, 1, glossary);
  2743. }
  2744. struct arg_int* arg_intn(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary) {
  2745. size_t nbytes;
  2746. struct arg_int* result;
  2747. /* foolproof things by ensuring maxcount is not less than mincount */
  2748. maxcount = (maxcount < mincount) ? mincount : maxcount;
  2749. nbytes = sizeof(struct arg_int) /* storage for struct arg_int */
  2750. + maxcount * sizeof(int); /* storage for ival[maxcount] array */
  2751. result = (struct arg_int*)xmalloc(nbytes);
  2752. /* init the arg_hdr struct */
  2753. result->hdr.flag = ARG_HASVALUE;
  2754. result->hdr.shortopts = shortopts;
  2755. result->hdr.longopts = longopts;
  2756. result->hdr.datatype = datatype ? datatype : "<int>";
  2757. result->hdr.glossary = glossary;
  2758. result->hdr.mincount = mincount;
  2759. result->hdr.maxcount = maxcount;
  2760. result->hdr.parent = result;
  2761. result->hdr.resetfn = (arg_resetfn*)arg_int_resetfn;
  2762. result->hdr.scanfn = (arg_scanfn*)arg_int_scanfn;
  2763. result->hdr.checkfn = (arg_checkfn*)arg_int_checkfn;
  2764. result->hdr.errorfn = (arg_errorfn*)arg_int_errorfn;
  2765. /* store the ival[maxcount] array immediately after the arg_int struct */
  2766. result->ival = (int*)(result + 1);
  2767. result->count = 0;
  2768. ARG_TRACE(("arg_intn() returns %p\n", result));
  2769. return result;
  2770. }
  2771. /*******************************************************************************
  2772. * arg_lit: Implements the literature command-line option
  2773. *
  2774. * This file is part of the argtable3 library.
  2775. *
  2776. * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
  2777. * <sheitmann@users.sourceforge.net>
  2778. * All rights reserved.
  2779. *
  2780. * Redistribution and use in source and binary forms, with or without
  2781. * modification, are permitted provided that the following conditions are met:
  2782. * * Redistributions of source code must retain the above copyright
  2783. * notice, this list of conditions and the following disclaimer.
  2784. * * Redistributions in binary form must reproduce the above copyright
  2785. * notice, this list of conditions and the following disclaimer in the
  2786. * documentation and/or other materials provided with the distribution.
  2787. * * Neither the name of STEWART HEITMANN nor the names of its contributors
  2788. * may be used to endorse or promote products derived from this software
  2789. * without specific prior written permission.
  2790. *
  2791. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  2792. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  2793. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  2794. * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
  2795. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  2796. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  2797. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  2798. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  2799. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  2800. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  2801. ******************************************************************************/
  2802. #include "argtable3.h"
  2803. #ifndef ARG_AMALGAMATION
  2804. #include "argtable3_private.h"
  2805. #endif
  2806. #include <stdlib.h>
  2807. static void arg_lit_resetfn(struct arg_lit* parent) {
  2808. ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
  2809. parent->count = 0;
  2810. }
  2811. static int arg_lit_scanfn(struct arg_lit* parent, const char* argval) {
  2812. int errorcode = 0;
  2813. if (parent->count < parent->hdr.maxcount)
  2814. parent->count++;
  2815. else
  2816. errorcode = ARG_ERR_MAXCOUNT;
  2817. ARG_TRACE(("%s:scanfn(%p,%s) returns %d\n", __FILE__, parent, argval, errorcode));
  2818. return errorcode;
  2819. }
  2820. static int arg_lit_checkfn(struct arg_lit* parent) {
  2821. int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;
  2822. ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
  2823. return errorcode;
  2824. }
  2825. static void arg_lit_errorfn(struct arg_lit* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {
  2826. const char* shortopts = parent->hdr.shortopts;
  2827. const char* longopts = parent->hdr.longopts;
  2828. const char* datatype = parent->hdr.datatype;
  2829. switch (errorcode) {
  2830. case ARG_ERR_MINCOUNT:
  2831. arg_dstr_catf(ds, "%s: missing option ", progname);
  2832. arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
  2833. arg_dstr_cat(ds, "\n");
  2834. break;
  2835. case ARG_ERR_MAXCOUNT:
  2836. arg_dstr_catf(ds, "%s: extraneous option ", progname);
  2837. arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
  2838. break;
  2839. }
  2840. ARG_TRACE(("%s:errorfn(%p, %p, %d, %s, %s)\n", __FILE__, parent, ds, errorcode, argval, progname));
  2841. }
  2842. struct arg_lit* arg_lit0(const char* shortopts, const char* longopts, const char* glossary) {
  2843. return arg_litn(shortopts, longopts, 0, 1, glossary);
  2844. }
  2845. struct arg_lit* arg_lit1(const char* shortopts, const char* longopts, const char* glossary) {
  2846. return arg_litn(shortopts, longopts, 1, 1, glossary);
  2847. }
  2848. struct arg_lit* arg_litn(const char* shortopts, const char* longopts, int mincount, int maxcount, const char* glossary) {
  2849. struct arg_lit* result;
  2850. /* foolproof things by ensuring maxcount is not less than mincount */
  2851. maxcount = (maxcount < mincount) ? mincount : maxcount;
  2852. result = (struct arg_lit*)xmalloc(sizeof(struct arg_lit));
  2853. /* init the arg_hdr struct */
  2854. result->hdr.flag = 0;
  2855. result->hdr.shortopts = shortopts;
  2856. result->hdr.longopts = longopts;
  2857. result->hdr.datatype = NULL;
  2858. result->hdr.glossary = glossary;
  2859. result->hdr.mincount = mincount;
  2860. result->hdr.maxcount = maxcount;
  2861. result->hdr.parent = result;
  2862. result->hdr.resetfn = (arg_resetfn*)arg_lit_resetfn;
  2863. result->hdr.scanfn = (arg_scanfn*)arg_lit_scanfn;
  2864. result->hdr.checkfn = (arg_checkfn*)arg_lit_checkfn;
  2865. result->hdr.errorfn = (arg_errorfn*)arg_lit_errorfn;
  2866. /* init local variables */
  2867. result->count = 0;
  2868. ARG_TRACE(("arg_litn() returns %p\n", result));
  2869. return result;
  2870. }
  2871. /*******************************************************************************
  2872. * arg_rem: Implements the rem command-line option
  2873. *
  2874. * This file is part of the argtable3 library.
  2875. *
  2876. * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
  2877. * <sheitmann@users.sourceforge.net>
  2878. * All rights reserved.
  2879. *
  2880. * Redistribution and use in source and binary forms, with or without
  2881. * modification, are permitted provided that the following conditions are met:
  2882. * * Redistributions of source code must retain the above copyright
  2883. * notice, this list of conditions and the following disclaimer.
  2884. * * Redistributions in binary form must reproduce the above copyright
  2885. * notice, this list of conditions and the following disclaimer in the
  2886. * documentation and/or other materials provided with the distribution.
  2887. * * Neither the name of STEWART HEITMANN nor the names of its contributors
  2888. * may be used to endorse or promote products derived from this software
  2889. * without specific prior written permission.
  2890. *
  2891. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  2892. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  2893. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  2894. * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
  2895. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  2896. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  2897. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  2898. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  2899. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  2900. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  2901. ******************************************************************************/
  2902. #include "argtable3.h"
  2903. #ifndef ARG_AMALGAMATION
  2904. #include "argtable3_private.h"
  2905. #endif
  2906. #include <stdlib.h>
  2907. struct arg_rem* arg_rem(const char* datatype, const char* glossary) {
  2908. struct arg_rem* result = (struct arg_rem*)xmalloc(sizeof(struct arg_rem));
  2909. result->hdr.flag = 0;
  2910. result->hdr.shortopts = NULL;
  2911. result->hdr.longopts = NULL;
  2912. result->hdr.datatype = datatype;
  2913. result->hdr.glossary = glossary;
  2914. result->hdr.mincount = 1;
  2915. result->hdr.maxcount = 1;
  2916. result->hdr.parent = result;
  2917. result->hdr.resetfn = NULL;
  2918. result->hdr.scanfn = NULL;
  2919. result->hdr.checkfn = NULL;
  2920. result->hdr.errorfn = NULL;
  2921. ARG_TRACE(("arg_rem() returns %p\n", result));
  2922. return result;
  2923. }
  2924. /*******************************************************************************
  2925. * arg_rex: Implements the regex command-line option
  2926. *
  2927. * This file is part of the argtable3 library.
  2928. *
  2929. * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
  2930. * <sheitmann@users.sourceforge.net>
  2931. * All rights reserved.
  2932. *
  2933. * Redistribution and use in source and binary forms, with or without
  2934. * modification, are permitted provided that the following conditions are met:
  2935. * * Redistributions of source code must retain the above copyright
  2936. * notice, this list of conditions and the following disclaimer.
  2937. * * Redistributions in binary form must reproduce the above copyright
  2938. * notice, this list of conditions and the following disclaimer in the
  2939. * documentation and/or other materials provided with the distribution.
  2940. * * Neither the name of STEWART HEITMANN nor the names of its contributors
  2941. * may be used to endorse or promote products derived from this software
  2942. * without specific prior written permission.
  2943. *
  2944. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  2945. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  2946. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  2947. * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
  2948. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  2949. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  2950. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  2951. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  2952. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  2953. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  2954. ******************************************************************************/
  2955. #include "argtable3.h"
  2956. #ifndef ARG_AMALGAMATION
  2957. #include "argtable3_private.h"
  2958. #endif
  2959. #include <stdlib.h>
  2960. #include <string.h>
  2961. #ifndef _TREX_H_
  2962. #define _TREX_H_
  2963. /*
  2964. * This module uses the T-Rex regular expression library to implement the regex
  2965. * logic. Here is the copyright notice of the library:
  2966. *
  2967. * Copyright (C) 2003-2006 Alberto Demichelis
  2968. *
  2969. * This software is provided 'as-is', without any express
  2970. * or implied warranty. In no event will the authors be held
  2971. * liable for any damages arising from the use of this software.
  2972. *
  2973. * Permission is granted to anyone to use this software for
  2974. * any purpose, including commercial applications, and to alter
  2975. * it and redistribute it freely, subject to the following restrictions:
  2976. *
  2977. * 1. The origin of this software must not be misrepresented;
  2978. * you must not claim that you wrote the original software.
  2979. * If you use this software in a product, an acknowledgment
  2980. * in the product documentation would be appreciated but
  2981. * is not required.
  2982. *
  2983. * 2. Altered source versions must be plainly marked as such,
  2984. * and must not be misrepresented as being the original software.
  2985. *
  2986. * 3. This notice may not be removed or altered from any
  2987. * source distribution.
  2988. */
  2989. #ifdef __cplusplus
  2990. extern "C" {
  2991. #endif
  2992. #define TRexChar char
  2993. #define MAX_CHAR 0xFF
  2994. #define _TREXC(c) (c)
  2995. #define trex_strlen strlen
  2996. #define trex_printf printf
  2997. #ifndef TREX_API
  2998. #define TREX_API extern
  2999. #endif
  3000. #define TRex_True 1
  3001. #define TRex_False 0
  3002. #define TREX_ICASE ARG_REX_ICASE
  3003. typedef unsigned int TRexBool;
  3004. typedef struct TRex TRex;
  3005. typedef struct {
  3006. const TRexChar* begin;
  3007. int len;
  3008. } TRexMatch;
  3009. TREX_API TRex* trex_compile(const TRexChar* pattern, const TRexChar** error, int flags);
  3010. TREX_API void trex_free(TRex* exp);
  3011. TREX_API TRexBool trex_match(TRex* exp, const TRexChar* text);
  3012. TREX_API TRexBool trex_search(TRex* exp, const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end);
  3013. TREX_API TRexBool
  3014. trex_searchrange(TRex* exp, const TRexChar* text_begin, const TRexChar* text_end, const TRexChar** out_begin, const TRexChar** out_end);
  3015. TREX_API int trex_getsubexpcount(TRex* exp);
  3016. TREX_API TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch* subexp);
  3017. #ifdef __cplusplus
  3018. }
  3019. #endif
  3020. #endif
  3021. struct privhdr {
  3022. const char* pattern;
  3023. int flags;
  3024. };
  3025. static void arg_rex_resetfn(struct arg_rex* parent) {
  3026. ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
  3027. parent->count = 0;
  3028. }
  3029. static int arg_rex_scanfn(struct arg_rex* parent, const char* argval) {
  3030. int errorcode = 0;
  3031. const TRexChar* error = NULL;
  3032. TRex* rex = NULL;
  3033. TRexBool is_match = TRex_False;
  3034. if (parent->count == parent->hdr.maxcount) {
  3035. /* maximum number of arguments exceeded */
  3036. errorcode = ARG_ERR_MAXCOUNT;
  3037. } else if (!argval) {
  3038. /* a valid argument with no argument value was given. */
  3039. /* This happens when an optional argument value was invoked. */
  3040. /* leave parent argument value unaltered but still count the argument. */
  3041. parent->count++;
  3042. } else {
  3043. struct privhdr* priv = (struct privhdr*)parent->hdr.priv;
  3044. /* test the current argument value for a match with the regular expression */
  3045. /* if a match is detected, record the argument value in the arg_rex struct */
  3046. rex = trex_compile(priv->pattern, &error, priv->flags);
  3047. is_match = trex_match(rex, argval);
  3048. if (!is_match)
  3049. errorcode = ARG_ERR_REGNOMATCH;
  3050. else
  3051. parent->sval[parent->count++] = argval;
  3052. trex_free(rex);
  3053. }
  3054. ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
  3055. return errorcode;
  3056. }
  3057. static int arg_rex_checkfn(struct arg_rex* parent) {
  3058. int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;
  3059. #if 0
  3060. struct privhdr *priv = (struct privhdr*)parent->hdr.priv;
  3061. /* free the regex "program" we constructed in resetfn */
  3062. regfree(&(priv->regex));
  3063. /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
  3064. #endif
  3065. return errorcode;
  3066. }
  3067. static void arg_rex_errorfn(struct arg_rex* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {
  3068. const char* shortopts = parent->hdr.shortopts;
  3069. const char* longopts = parent->hdr.longopts;
  3070. const char* datatype = parent->hdr.datatype;
  3071. /* make argval NULL safe */
  3072. argval = argval ? argval : "";
  3073. arg_dstr_catf(ds, "%s: ", progname);
  3074. switch (errorcode) {
  3075. case ARG_ERR_MINCOUNT:
  3076. arg_dstr_cat(ds, "missing option ");
  3077. arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
  3078. break;
  3079. case ARG_ERR_MAXCOUNT:
  3080. arg_dstr_cat(ds, "excess option ");
  3081. arg_print_option_ds(ds, shortopts, longopts, argval, "\n");
  3082. break;
  3083. case ARG_ERR_REGNOMATCH:
  3084. arg_dstr_cat(ds, "illegal value ");
  3085. arg_print_option_ds(ds, shortopts, longopts, argval, "\n");
  3086. break;
  3087. default: {
  3088. #if 0
  3089. char errbuff[256];
  3090. regerror(errorcode, NULL, errbuff, sizeof(errbuff));
  3091. printf("%s\n", errbuff);
  3092. #endif
  3093. } break;
  3094. }
  3095. }
  3096. struct arg_rex* arg_rex0(const char* shortopts, const char* longopts, const char* pattern, const char* datatype, int flags, const char* glossary) {
  3097. return arg_rexn(shortopts, longopts, pattern, datatype, 0, 1, flags, glossary);
  3098. }
  3099. struct arg_rex* arg_rex1(const char* shortopts, const char* longopts, const char* pattern, const char* datatype, int flags, const char* glossary) {
  3100. return arg_rexn(shortopts, longopts, pattern, datatype, 1, 1, flags, glossary);
  3101. }
  3102. struct arg_rex* arg_rexn(const char* shortopts,
  3103. const char* longopts,
  3104. const char* pattern,
  3105. const char* datatype,
  3106. int mincount,
  3107. int maxcount,
  3108. int flags,
  3109. const char* glossary) {
  3110. size_t nbytes;
  3111. struct arg_rex* result;
  3112. struct privhdr* priv;
  3113. int i;
  3114. const TRexChar* error = NULL;
  3115. TRex* rex = NULL;
  3116. if (!pattern) {
  3117. printf("argtable: ERROR - illegal regular expression pattern \"(NULL)\"\n");
  3118. printf("argtable: Bad argument table.\n");
  3119. return NULL;
  3120. }
  3121. /* foolproof things by ensuring maxcount is not less than mincount */
  3122. maxcount = (maxcount < mincount) ? mincount : maxcount;
  3123. nbytes = sizeof(struct arg_rex) /* storage for struct arg_rex */
  3124. + sizeof(struct privhdr) /* storage for private arg_rex data */
  3125. + maxcount * sizeof(char*); /* storage for sval[maxcount] array */
  3126. /* init the arg_hdr struct */
  3127. result = (struct arg_rex*)xmalloc(nbytes);
  3128. result->hdr.flag = ARG_HASVALUE;
  3129. result->hdr.shortopts = shortopts;
  3130. result->hdr.longopts = longopts;
  3131. result->hdr.datatype = datatype ? datatype : pattern;
  3132. result->hdr.glossary = glossary;
  3133. result->hdr.mincount = mincount;
  3134. result->hdr.maxcount = maxcount;
  3135. result->hdr.parent = result;
  3136. result->hdr.resetfn = (arg_resetfn*)arg_rex_resetfn;
  3137. result->hdr.scanfn = (arg_scanfn*)arg_rex_scanfn;
  3138. result->hdr.checkfn = (arg_checkfn*)arg_rex_checkfn;
  3139. result->hdr.errorfn = (arg_errorfn*)arg_rex_errorfn;
  3140. /* store the arg_rex_priv struct immediately after the arg_rex struct */
  3141. result->hdr.priv = result + 1;
  3142. priv = (struct privhdr*)(result->hdr.priv);
  3143. priv->pattern = pattern;
  3144. priv->flags = flags;
  3145. /* store the sval[maxcount] array immediately after the arg_rex_priv struct */
  3146. result->sval = (const char**)(priv + 1);
  3147. result->count = 0;
  3148. /* foolproof the string pointers by initializing them to reference empty strings */
  3149. for (i = 0; i < maxcount; i++)
  3150. result->sval[i] = "";
  3151. /* here we construct and destroy a regex representation of the regular
  3152. * expression for no other reason than to force any regex errors to be
  3153. * trapped now rather than later. If we don't, then errors may go undetected
  3154. * until an argument is actually parsed.
  3155. */
  3156. rex = trex_compile(priv->pattern, &error, priv->flags);
  3157. if (rex == NULL) {
  3158. ARG_LOG(("argtable: %s \"%s\"\n", error ? error : _TREXC("undefined"), priv->pattern));
  3159. ARG_LOG(("argtable: Bad argument table.\n"));
  3160. }
  3161. trex_free(rex);
  3162. ARG_TRACE(("arg_rexn() returns %p\n", result));
  3163. return result;
  3164. }
  3165. /* see copyright notice in trex.h */
  3166. #include <ctype.h>
  3167. #include <setjmp.h>
  3168. #include <stdlib.h>
  3169. #include <string.h>
  3170. #ifdef _UINCODE
  3171. #define scisprint iswprint
  3172. #define scstrlen wcslen
  3173. #define scprintf wprintf
  3174. #define _SC(x) L(x)
  3175. #else
  3176. #define scisprint isprint
  3177. #define scstrlen strlen
  3178. #define scprintf printf
  3179. #define _SC(x) (x)
  3180. #endif
  3181. #ifdef _DEBUG
  3182. #include <stdio.h>
  3183. static const TRexChar* g_nnames[] = {_SC("NONE"), _SC("OP_GREEDY"), _SC("OP_OR"), _SC("OP_EXPR"), _SC("OP_NOCAPEXPR"),
  3184. _SC("OP_DOT"), _SC("OP_CLASS"), _SC("OP_CCLASS"), _SC("OP_NCLASS"), _SC("OP_RANGE"),
  3185. _SC("OP_CHAR"), _SC("OP_EOL"), _SC("OP_BOL"), _SC("OP_WB")};
  3186. #endif
  3187. #define OP_GREEDY (MAX_CHAR + 1) /* * + ? {n} */
  3188. #define OP_OR (MAX_CHAR + 2)
  3189. #define OP_EXPR (MAX_CHAR + 3) /* parentesis () */
  3190. #define OP_NOCAPEXPR (MAX_CHAR + 4) /* parentesis (?:) */
  3191. #define OP_DOT (MAX_CHAR + 5)
  3192. #define OP_CLASS (MAX_CHAR + 6)
  3193. #define OP_CCLASS (MAX_CHAR + 7)
  3194. #define OP_NCLASS (MAX_CHAR + 8) /* negates class the [^ */
  3195. #define OP_RANGE (MAX_CHAR + 9)
  3196. #define OP_CHAR (MAX_CHAR + 10)
  3197. #define OP_EOL (MAX_CHAR + 11)
  3198. #define OP_BOL (MAX_CHAR + 12)
  3199. #define OP_WB (MAX_CHAR + 13)
  3200. #define TREX_SYMBOL_ANY_CHAR ('.')
  3201. #define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')
  3202. #define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')
  3203. #define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')
  3204. #define TREX_SYMBOL_BRANCH ('|')
  3205. #define TREX_SYMBOL_END_OF_STRING ('$')
  3206. #define TREX_SYMBOL_BEGINNING_OF_STRING ('^')
  3207. #define TREX_SYMBOL_ESCAPE_CHAR ('\\')
  3208. typedef int TRexNodeType;
  3209. typedef struct tagTRexNode {
  3210. TRexNodeType type;
  3211. int left;
  3212. int right;
  3213. int next;
  3214. } TRexNode;
  3215. struct TRex {
  3216. const TRexChar* _eol;
  3217. const TRexChar* _bol;
  3218. const TRexChar* _p;
  3219. int _first;
  3220. int _op;
  3221. TRexNode* _nodes;
  3222. int _nallocated;
  3223. int _nsize;
  3224. int _nsubexpr;
  3225. TRexMatch* _matches;
  3226. int _currsubexp;
  3227. void* _jmpbuf;
  3228. const TRexChar** _error;
  3229. int _flags;
  3230. };
  3231. static int trex_list(TRex* exp);
  3232. static int trex_newnode(TRex* exp, TRexNodeType type) {
  3233. TRexNode n;
  3234. int newid;
  3235. n.type = type;
  3236. n.next = n.right = n.left = -1;
  3237. if (type == OP_EXPR)
  3238. n.right = exp->_nsubexpr++;
  3239. if (exp->_nallocated < (exp->_nsize + 1)) {
  3240. exp->_nallocated *= 2;
  3241. exp->_nodes = (TRexNode*)xrealloc(exp->_nodes, exp->_nallocated * sizeof(TRexNode));
  3242. }
  3243. exp->_nodes[exp->_nsize++] = n;
  3244. newid = exp->_nsize - 1;
  3245. return (int)newid;
  3246. }
  3247. static void trex_error(TRex* exp, const TRexChar* error) {
  3248. if (exp->_error)
  3249. *exp->_error = error;
  3250. longjmp(*((jmp_buf*)exp->_jmpbuf), -1);
  3251. }
  3252. static void trex_expect(TRex* exp, int n) {
  3253. if ((*exp->_p) != n)
  3254. trex_error(exp, _SC("expected paren"));
  3255. exp->_p++;
  3256. }
  3257. static TRexChar trex_escapechar(TRex* exp) {
  3258. if (*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) {
  3259. exp->_p++;
  3260. switch (*exp->_p) {
  3261. case 'v':
  3262. exp->_p++;
  3263. return '\v';
  3264. case 'n':
  3265. exp->_p++;
  3266. return '\n';
  3267. case 't':
  3268. exp->_p++;
  3269. return '\t';
  3270. case 'r':
  3271. exp->_p++;
  3272. return '\r';
  3273. case 'f':
  3274. exp->_p++;
  3275. return '\f';
  3276. default:
  3277. return (*exp->_p++);
  3278. }
  3279. } else if (!scisprint(*exp->_p))
  3280. trex_error(exp, _SC("letter expected"));
  3281. return (*exp->_p++);
  3282. }
  3283. static int trex_charclass(TRex* exp, int classid) {
  3284. int n = trex_newnode(exp, OP_CCLASS);
  3285. exp->_nodes[n].left = classid;
  3286. return n;
  3287. }
  3288. static int trex_charnode(TRex* exp, TRexBool isclass) {
  3289. TRexChar t;
  3290. if (*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) {
  3291. exp->_p++;
  3292. switch (*exp->_p) {
  3293. case 'n':
  3294. exp->_p++;
  3295. return trex_newnode(exp, '\n');
  3296. case 't':
  3297. exp->_p++;
  3298. return trex_newnode(exp, '\t');
  3299. case 'r':
  3300. exp->_p++;
  3301. return trex_newnode(exp, '\r');
  3302. case 'f':
  3303. exp->_p++;
  3304. return trex_newnode(exp, '\f');
  3305. case 'v':
  3306. exp->_p++;
  3307. return trex_newnode(exp, '\v');
  3308. case 'a':
  3309. case 'A':
  3310. case 'w':
  3311. case 'W':
  3312. case 's':
  3313. case 'S':
  3314. case 'd':
  3315. case 'D':
  3316. case 'x':
  3317. case 'X':
  3318. case 'c':
  3319. case 'C':
  3320. case 'p':
  3321. case 'P':
  3322. case 'l':
  3323. case 'u': {
  3324. t = *exp->_p;
  3325. exp->_p++;
  3326. return trex_charclass(exp, t);
  3327. }
  3328. case 'b':
  3329. case 'B':
  3330. if (!isclass) {
  3331. int node = trex_newnode(exp, OP_WB);
  3332. exp->_nodes[node].left = *exp->_p;
  3333. exp->_p++;
  3334. return node;
  3335. }
  3336. /* fall through */
  3337. default:
  3338. t = *exp->_p;
  3339. exp->_p++;
  3340. return trex_newnode(exp, t);
  3341. }
  3342. } else if (!scisprint(*exp->_p)) {
  3343. trex_error(exp, _SC("letter expected"));
  3344. }
  3345. t = *exp->_p;
  3346. exp->_p++;
  3347. return trex_newnode(exp, t);
  3348. }
  3349. static int trex_class(TRex* exp) {
  3350. int ret = -1;
  3351. int first = -1, chain;
  3352. if (*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) {
  3353. ret = trex_newnode(exp, OP_NCLASS);
  3354. exp->_p++;
  3355. } else
  3356. ret = trex_newnode(exp, OP_CLASS);
  3357. if (*exp->_p == ']')
  3358. trex_error(exp, _SC("empty class"));
  3359. chain = ret;
  3360. while (*exp->_p != ']' && exp->_p != exp->_eol) {
  3361. if (*exp->_p == '-' && first != -1) {
  3362. int r, t;
  3363. if (*exp->_p++ == ']')
  3364. trex_error(exp, _SC("unfinished range"));
  3365. r = trex_newnode(exp, OP_RANGE);
  3366. if (first > *exp->_p)
  3367. trex_error(exp, _SC("invalid range"));
  3368. if (exp->_nodes[first].type == OP_CCLASS)
  3369. trex_error(exp, _SC("cannot use character classes in ranges"));
  3370. exp->_nodes[r].left = exp->_nodes[first].type;
  3371. t = trex_escapechar(exp);
  3372. exp->_nodes[r].right = t;
  3373. exp->_nodes[chain].next = r;
  3374. chain = r;
  3375. first = -1;
  3376. } else {
  3377. if (first != -1) {
  3378. int c = first;
  3379. exp->_nodes[chain].next = c;
  3380. chain = c;
  3381. first = trex_charnode(exp, TRex_True);
  3382. } else {
  3383. first = trex_charnode(exp, TRex_True);
  3384. }
  3385. }
  3386. }
  3387. if (first != -1) {
  3388. int c = first;
  3389. exp->_nodes[chain].next = c;
  3390. chain = c;
  3391. first = -1;
  3392. }
  3393. /* hack? */
  3394. exp->_nodes[ret].left = exp->_nodes[ret].next;
  3395. exp->_nodes[ret].next = -1;
  3396. return ret;
  3397. }
  3398. static int trex_parsenumber(TRex* exp) {
  3399. int ret = *exp->_p - '0';
  3400. int positions = 10;
  3401. exp->_p++;
  3402. while (isdigit(*exp->_p)) {
  3403. ret = ret * 10 + (*exp->_p++ - '0');
  3404. if (positions == 1000000000)
  3405. trex_error(exp, _SC("overflow in numeric constant"));
  3406. positions *= 10;
  3407. };
  3408. return ret;
  3409. }
  3410. static int trex_element(TRex* exp) {
  3411. int ret = -1;
  3412. switch (*exp->_p) {
  3413. case '(': {
  3414. int expr, newn;
  3415. exp->_p++;
  3416. if (*exp->_p == '?') {
  3417. exp->_p++;
  3418. trex_expect(exp, ':');
  3419. expr = trex_newnode(exp, OP_NOCAPEXPR);
  3420. } else
  3421. expr = trex_newnode(exp, OP_EXPR);
  3422. newn = trex_list(exp);
  3423. exp->_nodes[expr].left = newn;
  3424. ret = expr;
  3425. trex_expect(exp, ')');
  3426. } break;
  3427. case '[':
  3428. exp->_p++;
  3429. ret = trex_class(exp);
  3430. trex_expect(exp, ']');
  3431. break;
  3432. case TREX_SYMBOL_END_OF_STRING:
  3433. exp->_p++;
  3434. ret = trex_newnode(exp, OP_EOL);
  3435. break;
  3436. case TREX_SYMBOL_ANY_CHAR:
  3437. exp->_p++;
  3438. ret = trex_newnode(exp, OP_DOT);
  3439. break;
  3440. default:
  3441. ret = trex_charnode(exp, TRex_False);
  3442. break;
  3443. }
  3444. {
  3445. TRexBool isgreedy = TRex_False;
  3446. unsigned short p0 = 0, p1 = 0;
  3447. switch (*exp->_p) {
  3448. case TREX_SYMBOL_GREEDY_ZERO_OR_MORE:
  3449. p0 = 0;
  3450. p1 = 0xFFFF;
  3451. exp->_p++;
  3452. isgreedy = TRex_True;
  3453. break;
  3454. case TREX_SYMBOL_GREEDY_ONE_OR_MORE:
  3455. p0 = 1;
  3456. p1 = 0xFFFF;
  3457. exp->_p++;
  3458. isgreedy = TRex_True;
  3459. break;
  3460. case TREX_SYMBOL_GREEDY_ZERO_OR_ONE:
  3461. p0 = 0;
  3462. p1 = 1;
  3463. exp->_p++;
  3464. isgreedy = TRex_True;
  3465. break;
  3466. case '{':
  3467. exp->_p++;
  3468. if (!isdigit(*exp->_p))
  3469. trex_error(exp, _SC("number expected"));
  3470. p0 = (unsigned short)trex_parsenumber(exp);
  3471. /*******************************/
  3472. switch (*exp->_p) {
  3473. case '}':
  3474. p1 = p0;
  3475. exp->_p++;
  3476. break;
  3477. case ',':
  3478. exp->_p++;
  3479. p1 = 0xFFFF;
  3480. if (isdigit(*exp->_p)) {
  3481. p1 = (unsigned short)trex_parsenumber(exp);
  3482. }
  3483. trex_expect(exp, '}');
  3484. break;
  3485. default:
  3486. trex_error(exp, _SC(", or } expected"));
  3487. }
  3488. /*******************************/
  3489. isgreedy = TRex_True;
  3490. break;
  3491. }
  3492. if (isgreedy) {
  3493. int nnode = trex_newnode(exp, OP_GREEDY);
  3494. exp->_nodes[nnode].left = ret;
  3495. exp->_nodes[nnode].right = ((p0) << 16) | p1;
  3496. ret = nnode;
  3497. }
  3498. }
  3499. if ((*exp->_p != TREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != TREX_SYMBOL_GREEDY_ZERO_OR_MORE) &&
  3500. (*exp->_p != TREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\0')) {
  3501. int nnode = trex_element(exp);
  3502. exp->_nodes[ret].next = nnode;
  3503. }
  3504. return ret;
  3505. }
  3506. static int trex_list(TRex* exp) {
  3507. int ret = -1, e;
  3508. if (*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) {
  3509. exp->_p++;
  3510. ret = trex_newnode(exp, OP_BOL);
  3511. }
  3512. e = trex_element(exp);
  3513. if (ret != -1) {
  3514. exp->_nodes[ret].next = e;
  3515. } else
  3516. ret = e;
  3517. if (*exp->_p == TREX_SYMBOL_BRANCH) {
  3518. int temp, tright;
  3519. exp->_p++;
  3520. temp = trex_newnode(exp, OP_OR);
  3521. exp->_nodes[temp].left = ret;
  3522. tright = trex_list(exp);
  3523. exp->_nodes[temp].right = tright;
  3524. ret = temp;
  3525. }
  3526. return ret;
  3527. }
  3528. static TRexBool trex_matchcclass(int cclass, TRexChar c) {
  3529. switch (cclass) {
  3530. case 'a':
  3531. return isalpha(c) ? TRex_True : TRex_False;
  3532. case 'A':
  3533. return !isalpha(c) ? TRex_True : TRex_False;
  3534. case 'w':
  3535. return (isalnum(c) || c == '_') ? TRex_True : TRex_False;
  3536. case 'W':
  3537. return (!isalnum(c) && c != '_') ? TRex_True : TRex_False;
  3538. case 's':
  3539. return isspace(c) ? TRex_True : TRex_False;
  3540. case 'S':
  3541. return !isspace(c) ? TRex_True : TRex_False;
  3542. case 'd':
  3543. return isdigit(c) ? TRex_True : TRex_False;
  3544. case 'D':
  3545. return !isdigit(c) ? TRex_True : TRex_False;
  3546. case 'x':
  3547. return isxdigit(c) ? TRex_True : TRex_False;
  3548. case 'X':
  3549. return !isxdigit(c) ? TRex_True : TRex_False;
  3550. case 'c':
  3551. return iscntrl(c) ? TRex_True : TRex_False;
  3552. case 'C':
  3553. return !iscntrl(c) ? TRex_True : TRex_False;
  3554. case 'p':
  3555. return ispunct(c) ? TRex_True : TRex_False;
  3556. case 'P':
  3557. return !ispunct(c) ? TRex_True : TRex_False;
  3558. case 'l':
  3559. return islower(c) ? TRex_True : TRex_False;
  3560. case 'u':
  3561. return isupper(c) ? TRex_True : TRex_False;
  3562. }
  3563. return TRex_False; /*cannot happen*/
  3564. }
  3565. static TRexBool trex_matchclass(TRex* exp, TRexNode* node, TRexChar c) {
  3566. do {
  3567. switch (node->type) {
  3568. case OP_RANGE:
  3569. if (exp->_flags & TREX_ICASE) {
  3570. if (c >= toupper(node->left) && c <= toupper(node->right))
  3571. return TRex_True;
  3572. if (c >= tolower(node->left) && c <= tolower(node->right))
  3573. return TRex_True;
  3574. } else {
  3575. if (c >= node->left && c <= node->right)
  3576. return TRex_True;
  3577. }
  3578. break;
  3579. case OP_CCLASS:
  3580. if (trex_matchcclass(node->left, c))
  3581. return TRex_True;
  3582. break;
  3583. default:
  3584. if (exp->_flags & TREX_ICASE) {
  3585. if (c == tolower(node->type) || c == toupper(node->type))
  3586. return TRex_True;
  3587. } else {
  3588. if (c == node->type)
  3589. return TRex_True;
  3590. }
  3591. }
  3592. } while ((node->next != -1) && ((node = &exp->_nodes[node->next]) != NULL));
  3593. return TRex_False;
  3594. }
  3595. static const TRexChar* trex_matchnode(TRex* exp, TRexNode* node, const TRexChar* str, TRexNode* next) {
  3596. TRexNodeType type = node->type;
  3597. switch (type) {
  3598. case OP_GREEDY: {
  3599. /* TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL; */
  3600. TRexNode* greedystop = NULL;
  3601. int p0 = (node->right >> 16) & 0x0000FFFF, p1 = node->right & 0x0000FFFF, nmaches = 0;
  3602. const TRexChar *s = str, *good = str;
  3603. if (node->next != -1) {
  3604. greedystop = &exp->_nodes[node->next];
  3605. } else {
  3606. greedystop = next;
  3607. }
  3608. while ((nmaches == 0xFFFF || nmaches < p1)) {
  3609. const TRexChar* stop;
  3610. if ((s = trex_matchnode(exp, &exp->_nodes[node->left], s, greedystop)) == NULL)
  3611. break;
  3612. nmaches++;
  3613. good = s;
  3614. if (greedystop) {
  3615. /* checks that 0 matches satisfy the expression(if so skips) */
  3616. /* if not would always stop(for instance if is a '?') */
  3617. if (greedystop->type != OP_GREEDY || (greedystop->type == OP_GREEDY && ((greedystop->right >> 16) & 0x0000FFFF) != 0)) {
  3618. TRexNode* gnext = NULL;
  3619. if (greedystop->next != -1) {
  3620. gnext = &exp->_nodes[greedystop->next];
  3621. } else if (next && next->next != -1) {
  3622. gnext = &exp->_nodes[next->next];
  3623. }
  3624. stop = trex_matchnode(exp, greedystop, s, gnext);
  3625. if (stop) {
  3626. /* if satisfied stop it */
  3627. if (p0 == p1 && p0 == nmaches)
  3628. break;
  3629. else if (nmaches >= p0 && p1 == 0xFFFF)
  3630. break;
  3631. else if (nmaches >= p0 && nmaches <= p1)
  3632. break;
  3633. }
  3634. }
  3635. }
  3636. if (s >= exp->_eol)
  3637. break;
  3638. }
  3639. if (p0 == p1 && p0 == nmaches)
  3640. return good;
  3641. else if (nmaches >= p0 && p1 == 0xFFFF)
  3642. return good;
  3643. else if (nmaches >= p0 && nmaches <= p1)
  3644. return good;
  3645. return NULL;
  3646. }
  3647. case OP_OR: {
  3648. const TRexChar* asd = str;
  3649. TRexNode* temp = &exp->_nodes[node->left];
  3650. while ((asd = trex_matchnode(exp, temp, asd, NULL)) != NULL) {
  3651. if (temp->next != -1)
  3652. temp = &exp->_nodes[temp->next];
  3653. else
  3654. return asd;
  3655. }
  3656. asd = str;
  3657. temp = &exp->_nodes[node->right];
  3658. while ((asd = trex_matchnode(exp, temp, asd, NULL)) != NULL) {
  3659. if (temp->next != -1)
  3660. temp = &exp->_nodes[temp->next];
  3661. else
  3662. return asd;
  3663. }
  3664. return NULL;
  3665. break;
  3666. }
  3667. case OP_EXPR:
  3668. case OP_NOCAPEXPR: {
  3669. TRexNode* n = &exp->_nodes[node->left];
  3670. const TRexChar* cur = str;
  3671. int capture = -1;
  3672. if (node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {
  3673. capture = exp->_currsubexp;
  3674. exp->_matches[capture].begin = cur;
  3675. exp->_currsubexp++;
  3676. }
  3677. do {
  3678. TRexNode* subnext = NULL;
  3679. if (n->next != -1) {
  3680. subnext = &exp->_nodes[n->next];
  3681. } else {
  3682. subnext = next;
  3683. }
  3684. if ((cur = trex_matchnode(exp, n, cur, subnext)) == NULL) {
  3685. if (capture != -1) {
  3686. exp->_matches[capture].begin = 0;
  3687. exp->_matches[capture].len = 0;
  3688. }
  3689. return NULL;
  3690. }
  3691. } while ((n->next != -1) && ((n = &exp->_nodes[n->next]) != NULL));
  3692. if (capture != -1)
  3693. exp->_matches[capture].len = (int)(cur - exp->_matches[capture].begin);
  3694. return cur;
  3695. }
  3696. case OP_WB:
  3697. if ((str == exp->_bol && !isspace(*str)) || (str == exp->_eol && !isspace(*(str - 1))) || (!isspace(*str) && isspace(*(str + 1))) ||
  3698. (isspace(*str) && !isspace(*(str + 1)))) {
  3699. return (node->left == 'b') ? str : NULL;
  3700. }
  3701. return (node->left == 'b') ? NULL : str;
  3702. case OP_BOL:
  3703. if (str == exp->_bol)
  3704. return str;
  3705. return NULL;
  3706. case OP_EOL:
  3707. if (str == exp->_eol)
  3708. return str;
  3709. return NULL;
  3710. case OP_DOT: {
  3711. str++;
  3712. }
  3713. return str;
  3714. case OP_NCLASS:
  3715. case OP_CLASS:
  3716. if (trex_matchclass(exp, &exp->_nodes[node->left], *str) ? (type == OP_CLASS ? TRex_True : TRex_False)
  3717. : (type == OP_NCLASS ? TRex_True : TRex_False)) {
  3718. str++;
  3719. return str;
  3720. }
  3721. return NULL;
  3722. case OP_CCLASS:
  3723. if (trex_matchcclass(node->left, *str)) {
  3724. str++;
  3725. return str;
  3726. }
  3727. return NULL;
  3728. default: /* char */
  3729. if (exp->_flags & TREX_ICASE) {
  3730. if (*str != tolower(node->type) && *str != toupper(node->type))
  3731. return NULL;
  3732. } else {
  3733. if (*str != node->type)
  3734. return NULL;
  3735. }
  3736. str++;
  3737. return str;
  3738. }
  3739. }
  3740. /* public api */
  3741. TRex* trex_compile(const TRexChar* pattern, const TRexChar** error, int flags) {
  3742. TRex* exp = (TRex*)xmalloc(sizeof(TRex));
  3743. exp->_eol = exp->_bol = NULL;
  3744. exp->_p = pattern;
  3745. exp->_nallocated = (int)scstrlen(pattern) * sizeof(TRexChar);
  3746. exp->_nodes = (TRexNode*)xmalloc(exp->_nallocated * sizeof(TRexNode));
  3747. exp->_nsize = 0;
  3748. exp->_matches = 0;
  3749. exp->_nsubexpr = 0;
  3750. exp->_first = trex_newnode(exp, OP_EXPR);
  3751. exp->_error = error;
  3752. exp->_jmpbuf = xmalloc(sizeof(jmp_buf));
  3753. exp->_flags = flags;
  3754. if (setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) {
  3755. int res = trex_list(exp);
  3756. exp->_nodes[exp->_first].left = res;
  3757. if (*exp->_p != '\0')
  3758. trex_error(exp, _SC("unexpected character"));
  3759. #ifdef _DEBUG
  3760. {
  3761. int nsize, i;
  3762. TRexNode* t;
  3763. nsize = exp->_nsize;
  3764. t = &exp->_nodes[0];
  3765. scprintf(_SC("\n"));
  3766. for (i = 0; i < nsize; i++) {
  3767. if (exp->_nodes[i].type > MAX_CHAR)
  3768. scprintf(_SC("[%02d] %10s "), i, g_nnames[exp->_nodes[i].type - MAX_CHAR]);
  3769. else
  3770. scprintf(_SC("[%02d] %10c "), i, exp->_nodes[i].type);
  3771. scprintf(_SC("left %02d right %02d next %02d\n"), exp->_nodes[i].left, exp->_nodes[i].right, exp->_nodes[i].next);
  3772. }
  3773. scprintf(_SC("\n"));
  3774. }
  3775. #endif
  3776. exp->_matches = (TRexMatch*)xmalloc(exp->_nsubexpr * sizeof(TRexMatch));
  3777. memset(exp->_matches, 0, exp->_nsubexpr * sizeof(TRexMatch));
  3778. } else {
  3779. trex_free(exp);
  3780. return NULL;
  3781. }
  3782. return exp;
  3783. }
  3784. void trex_free(TRex* exp) {
  3785. if (exp) {
  3786. xfree(exp->_nodes);
  3787. xfree(exp->_jmpbuf);
  3788. xfree(exp->_matches);
  3789. xfree(exp);
  3790. }
  3791. }
  3792. TRexBool trex_match(TRex* exp, const TRexChar* text) {
  3793. const TRexChar* res = NULL;
  3794. exp->_bol = text;
  3795. exp->_eol = text + scstrlen(text);
  3796. exp->_currsubexp = 0;
  3797. res = trex_matchnode(exp, exp->_nodes, text, NULL);
  3798. if (res == NULL || res != exp->_eol)
  3799. return TRex_False;
  3800. return TRex_True;
  3801. }
  3802. TRexBool trex_searchrange(TRex* exp, const TRexChar* text_begin, const TRexChar* text_end, const TRexChar** out_begin, const TRexChar** out_end) {
  3803. const TRexChar* cur = NULL;
  3804. int node = exp->_first;
  3805. if (text_begin >= text_end)
  3806. return TRex_False;
  3807. exp->_bol = text_begin;
  3808. exp->_eol = text_end;
  3809. do {
  3810. cur = text_begin;
  3811. while (node != -1) {
  3812. exp->_currsubexp = 0;
  3813. cur = trex_matchnode(exp, &exp->_nodes[node], cur, NULL);
  3814. if (!cur)
  3815. break;
  3816. node = exp->_nodes[node].next;
  3817. }
  3818. text_begin++;
  3819. } while (cur == NULL && text_begin != text_end);
  3820. if (cur == NULL)
  3821. return TRex_False;
  3822. --text_begin;
  3823. if (out_begin)
  3824. *out_begin = text_begin;
  3825. if (out_end)
  3826. *out_end = cur;
  3827. return TRex_True;
  3828. }
  3829. TRexBool trex_search(TRex* exp, const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end) {
  3830. return trex_searchrange(exp, text, text + scstrlen(text), out_begin, out_end);
  3831. }
  3832. int trex_getsubexpcount(TRex* exp) {
  3833. return exp->_nsubexpr;
  3834. }
  3835. TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch* subexp) {
  3836. if (n < 0 || n >= exp->_nsubexpr)
  3837. return TRex_False;
  3838. *subexp = exp->_matches[n];
  3839. return TRex_True;
  3840. }
  3841. /*******************************************************************************
  3842. * arg_str: Implements the str command-line option
  3843. *
  3844. * This file is part of the argtable3 library.
  3845. *
  3846. * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
  3847. * <sheitmann@users.sourceforge.net>
  3848. * All rights reserved.
  3849. *
  3850. * Redistribution and use in source and binary forms, with or without
  3851. * modification, are permitted provided that the following conditions are met:
  3852. * * Redistributions of source code must retain the above copyright
  3853. * notice, this list of conditions and the following disclaimer.
  3854. * * Redistributions in binary form must reproduce the above copyright
  3855. * notice, this list of conditions and the following disclaimer in the
  3856. * documentation and/or other materials provided with the distribution.
  3857. * * Neither the name of STEWART HEITMANN nor the names of its contributors
  3858. * may be used to endorse or promote products derived from this software
  3859. * without specific prior written permission.
  3860. *
  3861. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  3862. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  3863. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  3864. * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
  3865. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  3866. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  3867. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  3868. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  3869. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  3870. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  3871. ******************************************************************************/
  3872. #include "argtable3.h"
  3873. #ifndef ARG_AMALGAMATION
  3874. #include "argtable3_private.h"
  3875. #endif
  3876. #include <stdlib.h>
  3877. static void arg_str_resetfn(struct arg_str* parent) {
  3878. int i;
  3879. ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
  3880. for (i = 0; i < parent->count; i++) {
  3881. parent->sval[i] = "";
  3882. }
  3883. parent->count = 0;
  3884. }
  3885. static int arg_str_scanfn(struct arg_str* parent, const char* argval) {
  3886. int errorcode = 0;
  3887. if (parent->count == parent->hdr.maxcount) {
  3888. /* maximum number of arguments exceeded */
  3889. errorcode = ARG_ERR_MAXCOUNT;
  3890. } else if (!argval) {
  3891. /* a valid argument with no argument value was given. */
  3892. /* This happens when an optional argument value was invoked. */
  3893. /* leave parent argument value unaltered but still count the argument. */
  3894. parent->count++;
  3895. } else {
  3896. parent->sval[parent->count++] = argval;
  3897. }
  3898. ARG_TRACE(("%s:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
  3899. return errorcode;
  3900. }
  3901. static int arg_str_checkfn(struct arg_str* parent) {
  3902. int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;
  3903. ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
  3904. return errorcode;
  3905. }
  3906. static void arg_str_errorfn(struct arg_str* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {
  3907. const char* shortopts = parent->hdr.shortopts;
  3908. const char* longopts = parent->hdr.longopts;
  3909. const char* datatype = parent->hdr.datatype;
  3910. /* make argval NULL safe */
  3911. argval = argval ? argval : "";
  3912. arg_dstr_catf(ds, "%s: ", progname);
  3913. switch (errorcode) {
  3914. case ARG_ERR_MINCOUNT:
  3915. arg_dstr_cat(ds, "missing option ");
  3916. arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
  3917. break;
  3918. case ARG_ERR_MAXCOUNT:
  3919. arg_dstr_cat(ds, "excess option ");
  3920. arg_print_option_ds(ds, shortopts, longopts, argval, "\n");
  3921. break;
  3922. }
  3923. }
  3924. struct arg_str* arg_str0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {
  3925. return arg_strn(shortopts, longopts, datatype, 0, 1, glossary);
  3926. }
  3927. struct arg_str* arg_str1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {
  3928. return arg_strn(shortopts, longopts, datatype, 1, 1, glossary);
  3929. }
  3930. struct arg_str* arg_strn(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary) {
  3931. size_t nbytes;
  3932. struct arg_str* result;
  3933. int i;
  3934. /* should not allow this stupid error */
  3935. /* we should return an error code warning this logic error */
  3936. /* foolproof things by ensuring maxcount is not less than mincount */
  3937. maxcount = (maxcount < mincount) ? mincount : maxcount;
  3938. nbytes = sizeof(struct arg_str) /* storage for struct arg_str */
  3939. + maxcount * sizeof(char*); /* storage for sval[maxcount] array */
  3940. result = (struct arg_str*)xmalloc(nbytes);
  3941. /* init the arg_hdr struct */
  3942. result->hdr.flag = ARG_HASVALUE;
  3943. result->hdr.shortopts = shortopts;
  3944. result->hdr.longopts = longopts;
  3945. result->hdr.datatype = datatype ? datatype : "<string>";
  3946. result->hdr.glossary = glossary;
  3947. result->hdr.mincount = mincount;
  3948. result->hdr.maxcount = maxcount;
  3949. result->hdr.parent = result;
  3950. result->hdr.resetfn = (arg_resetfn*)arg_str_resetfn;
  3951. result->hdr.scanfn = (arg_scanfn*)arg_str_scanfn;
  3952. result->hdr.checkfn = (arg_checkfn*)arg_str_checkfn;
  3953. result->hdr.errorfn = (arg_errorfn*)arg_str_errorfn;
  3954. /* store the sval[maxcount] array immediately after the arg_str struct */
  3955. result->sval = (const char**)(result + 1);
  3956. result->count = 0;
  3957. /* foolproof the string pointers by initializing them to reference empty strings */
  3958. for (i = 0; i < maxcount; i++)
  3959. result->sval[i] = "";
  3960. ARG_TRACE(("arg_strn() returns %p\n", result));
  3961. return result;
  3962. }
  3963. /*******************************************************************************
  3964. * arg_cmd: Provides the sub-command mechanism
  3965. *
  3966. * This file is part of the argtable3 library.
  3967. *
  3968. * Copyright (C) 2013-2019 Tom G. Huang
  3969. * <tomghuang@gmail.com>
  3970. * All rights reserved.
  3971. *
  3972. * Redistribution and use in source and binary forms, with or without
  3973. * modification, are permitted provided that the following conditions are met:
  3974. * * Redistributions of source code must retain the above copyright
  3975. * notice, this list of conditions and the following disclaimer.
  3976. * * Redistributions in binary form must reproduce the above copyright
  3977. * notice, this list of conditions and the following disclaimer in the
  3978. * documentation and/or other materials provided with the distribution.
  3979. * * Neither the name of STEWART HEITMANN nor the names of its contributors
  3980. * may be used to endorse or promote products derived from this software
  3981. * without specific prior written permission.
  3982. *
  3983. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  3984. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  3985. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  3986. * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
  3987. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  3988. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  3989. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  3990. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  3991. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  3992. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  3993. ******************************************************************************/
  3994. #include "argtable3.h"
  3995. #ifndef ARG_AMALGAMATION
  3996. #include "argtable3_private.h"
  3997. #endif
  3998. #include <assert.h>
  3999. #include <stdlib.h>
  4000. #include <string.h>
  4001. #define MAX_MODULE_VERSION_SIZE 128
  4002. static arg_hashtable_t* s_hashtable = NULL;
  4003. static char* s_module_name = NULL;
  4004. static int s_mod_ver_major = 0;
  4005. static int s_mod_ver_minor = 0;
  4006. static int s_mod_ver_patch = 0;
  4007. static char* s_mod_ver_tag = NULL;
  4008. static char* s_mod_ver = NULL;
  4009. void arg_set_module_name(const char* name) {
  4010. size_t slen;
  4011. xfree(s_module_name);
  4012. slen = strlen(name);
  4013. s_module_name = (char*)xmalloc(slen + 1);
  4014. memset(s_module_name, 0, slen + 1);
  4015. #if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
  4016. strncpy_s(s_module_name, slen + 1, name, slen);
  4017. #else
  4018. memcpy(s_module_name, name, slen);
  4019. #endif
  4020. }
  4021. void arg_set_module_version(int major, int minor, int patch, const char* tag) {
  4022. size_t slen_tag, slen_ds;
  4023. arg_dstr_t ds;
  4024. s_mod_ver_major = major;
  4025. s_mod_ver_minor = minor;
  4026. s_mod_ver_patch = patch;
  4027. xfree(s_mod_ver_tag);
  4028. slen_tag = strlen(tag);
  4029. s_mod_ver_tag = (char*)xmalloc(slen_tag + 1);
  4030. memset(s_mod_ver_tag, 0, slen_tag + 1);
  4031. #if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
  4032. strncpy_s(s_mod_ver_tag, slen_tag + 1, tag, slen_tag);
  4033. #else
  4034. memcpy(s_mod_ver_tag, tag, slen_tag);
  4035. #endif
  4036. ds = arg_dstr_create();
  4037. arg_dstr_catf(ds, "%d.", s_mod_ver_major);
  4038. arg_dstr_catf(ds, "%d.", s_mod_ver_minor);
  4039. arg_dstr_catf(ds, "%d.", s_mod_ver_patch);
  4040. arg_dstr_cat(ds, s_mod_ver_tag);
  4041. xfree(s_mod_ver);
  4042. slen_ds = strlen(arg_dstr_cstr(ds));
  4043. s_mod_ver = (char*)xmalloc(slen_ds + 1);
  4044. memset(s_mod_ver, 0, slen_ds + 1);
  4045. #if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
  4046. strncpy_s(s_mod_ver, slen_ds + 1, arg_dstr_cstr(ds), slen_ds);
  4047. #else
  4048. memcpy(s_mod_ver, arg_dstr_cstr(ds), slen_ds);
  4049. #endif
  4050. arg_dstr_destroy(ds);
  4051. }
  4052. static unsigned int hash_key(const void* key) {
  4053. const char* str = (const char*)key;
  4054. int c;
  4055. unsigned int hash = 5381;
  4056. while ((c = *str++) != 0)
  4057. hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
  4058. return hash;
  4059. }
  4060. static int equal_keys(const void* key1, const void* key2) {
  4061. char* k1 = (char*)key1;
  4062. char* k2 = (char*)key2;
  4063. return (0 == strcmp(k1, k2));
  4064. }
  4065. void arg_cmd_init(void) {
  4066. s_hashtable = arg_hashtable_create(32, hash_key, equal_keys);
  4067. }
  4068. void arg_cmd_uninit(void) {
  4069. arg_hashtable_destroy(s_hashtable, 1);
  4070. }
  4071. void arg_cmd_register(const char* name, arg_cmdfn* proc, const char* description) {
  4072. arg_cmd_info_t* cmd_info;
  4073. size_t slen_name;
  4074. void* k;
  4075. assert(strlen(name) < ARG_CMD_NAME_LEN);
  4076. assert(strlen(description) < ARG_CMD_DESCRIPTION_LEN);
  4077. /* Check if the command already exists. */
  4078. /* If the command exists, replace the existing command. */
  4079. /* If the command doesn't exist, insert the command. */
  4080. cmd_info = (arg_cmd_info_t*)arg_hashtable_search(s_hashtable, name);
  4081. if (cmd_info) {
  4082. arg_hashtable_remove(s_hashtable, name);
  4083. cmd_info = NULL;
  4084. }
  4085. cmd_info = (arg_cmd_info_t*)xmalloc(sizeof(arg_cmd_info_t));
  4086. memset(cmd_info, 0, sizeof(arg_cmd_info_t));
  4087. #if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
  4088. strncpy_s(cmd_info->name, ARG_CMD_NAME_LEN, name, strlen(name));
  4089. strncpy_s(cmd_info->description, ARG_CMD_DESCRIPTION_LEN, description, strlen(description));
  4090. #else
  4091. memcpy(cmd_info->name, name, strlen(name));
  4092. memcpy(cmd_info->description, description, strlen(description));
  4093. #endif
  4094. cmd_info->proc = proc;
  4095. slen_name = strlen(name);
  4096. k = xmalloc(slen_name + 1);
  4097. memset(k, 0, slen_name + 1);
  4098. #if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
  4099. strncpy_s((char*)k, slen_name + 1, name, slen_name);
  4100. #else
  4101. memcpy((char*)k, name, slen_name);
  4102. #endif
  4103. arg_hashtable_insert(s_hashtable, k, cmd_info);
  4104. }
  4105. void arg_cmd_unregister(const char* name) {
  4106. arg_hashtable_remove(s_hashtable, name);
  4107. }
  4108. int arg_cmd_dispatch(const char* name, int argc, char* argv[], arg_dstr_t res) {
  4109. arg_cmd_info_t* cmd_info = arg_cmd_info(name);
  4110. assert(cmd_info != NULL);
  4111. assert(cmd_info->proc != NULL);
  4112. return cmd_info->proc(argc, argv, res);
  4113. }
  4114. arg_cmd_info_t* arg_cmd_info(const char* name) {
  4115. return (arg_cmd_info_t*)arg_hashtable_search(s_hashtable, name);
  4116. }
  4117. unsigned int arg_cmd_count(void) {
  4118. return arg_hashtable_count(s_hashtable);
  4119. }
  4120. arg_cmd_itr_t arg_cmd_itr_create(void) {
  4121. return (arg_cmd_itr_t)arg_hashtable_itr_create(s_hashtable);
  4122. }
  4123. int arg_cmd_itr_advance(arg_cmd_itr_t itr) {
  4124. return arg_hashtable_itr_advance((arg_hashtable_itr_t*)itr);
  4125. }
  4126. char* arg_cmd_itr_key(arg_cmd_itr_t itr) {
  4127. return (char*)arg_hashtable_itr_key((arg_hashtable_itr_t*)itr);
  4128. }
  4129. arg_cmd_info_t* arg_cmd_itr_value(arg_cmd_itr_t itr) {
  4130. return (arg_cmd_info_t*)arg_hashtable_itr_value((arg_hashtable_itr_t*)itr);
  4131. }
  4132. void arg_cmd_itr_destroy(arg_cmd_itr_t itr) {
  4133. arg_hashtable_itr_destroy((arg_hashtable_itr_t*)itr);
  4134. }
  4135. int arg_cmd_itr_search(arg_cmd_itr_t itr, void* k) {
  4136. return arg_hashtable_itr_search((arg_hashtable_itr_t*)itr, s_hashtable, k);
  4137. }
  4138. static const char* module_name(void) {
  4139. if (s_module_name == NULL || strlen(s_module_name) == 0)
  4140. return "<name>";
  4141. return s_module_name;
  4142. }
  4143. static const char* module_version(void) {
  4144. if (s_mod_ver == NULL || strlen(s_mod_ver) == 0)
  4145. return "0.0.0.0";
  4146. return s_mod_ver;
  4147. }
  4148. void arg_make_get_help_msg(arg_dstr_t res) {
  4149. arg_dstr_catf(res, "%s v%s\n", module_name(), module_version());
  4150. arg_dstr_catf(res, "Please type '%s help' to get more information.\n", module_name());
  4151. }
  4152. void arg_make_help_msg(arg_dstr_t ds, char* cmd_name, void** argtable) {
  4153. arg_cmd_info_t* cmd_info = (arg_cmd_info_t*)arg_hashtable_search(s_hashtable, cmd_name);
  4154. if (cmd_info) {
  4155. arg_dstr_catf(ds, "%s: %s\n", cmd_name, cmd_info->description);
  4156. }
  4157. arg_dstr_cat(ds, "Usage:\n");
  4158. arg_dstr_catf(ds, " %s", module_name());
  4159. arg_print_syntaxv_ds(ds, argtable, "\n \nAvailable options:\n");
  4160. arg_print_glossary_ds(ds, argtable, " %-23s %s\n");
  4161. arg_dstr_cat(ds, "\n");
  4162. }
  4163. void arg_make_syntax_err_msg(arg_dstr_t ds, void** argtable, struct arg_end* end) {
  4164. arg_print_errors_ds(ds, end, module_name());
  4165. arg_dstr_cat(ds, "Usage: \n");
  4166. arg_dstr_catf(ds, " %s", module_name());
  4167. arg_print_syntaxv_ds(ds, argtable, "\n");
  4168. arg_dstr_cat(ds, "\n");
  4169. }
  4170. int arg_make_syntax_err_help_msg(arg_dstr_t ds, char* name, int help, int nerrors, void** argtable, struct arg_end* end, int* exitcode) {
  4171. /* help handling
  4172. * note: '-h|--help' takes precedence over error reporting
  4173. */
  4174. if (help > 0) {
  4175. arg_make_help_msg(ds, name, argtable);
  4176. *exitcode = EXIT_SUCCESS;
  4177. return 1;
  4178. }
  4179. /* syntax error handling */
  4180. if (nerrors > 0) {
  4181. arg_make_syntax_err_msg(ds, argtable, end);
  4182. *exitcode = EXIT_FAILURE;
  4183. return 1;
  4184. }
  4185. return 0;
  4186. }
  4187. /*******************************************************************************
  4188. * argtable3: Implements the main interfaces of the library
  4189. *
  4190. * This file is part of the argtable3 library.
  4191. *
  4192. * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
  4193. * <sheitmann@users.sourceforge.net>
  4194. * All rights reserved.
  4195. *
  4196. * Redistribution and use in source and binary forms, with or without
  4197. * modification, are permitted provided that the following conditions are met:
  4198. * * Redistributions of source code must retain the above copyright
  4199. * notice, this list of conditions and the following disclaimer.
  4200. * * Redistributions in binary form must reproduce the above copyright
  4201. * notice, this list of conditions and the following disclaimer in the
  4202. * documentation and/or other materials provided with the distribution.
  4203. * * Neither the name of STEWART HEITMANN nor the names of its contributors
  4204. * may be used to endorse or promote products derived from this software
  4205. * without specific prior written permission.
  4206. *
  4207. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  4208. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  4209. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  4210. * ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
  4211. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  4212. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  4213. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  4214. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  4215. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  4216. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  4217. ******************************************************************************/
  4218. #include "argtable3.h"
  4219. #ifndef ARG_AMALGAMATION
  4220. #include "argtable3_private.h"
  4221. #include "getopt.h"
  4222. #endif
  4223. #ifdef _WIN32
  4224. #define WIN32_LEAN_AND_MEAN
  4225. #include <windows.h>
  4226. #undef WIN32_LEAN_AND_MEAN
  4227. #endif
  4228. #include <assert.h>
  4229. #include <ctype.h>
  4230. #include <limits.h>
  4231. #include <stdlib.h>
  4232. #include <string.h>
  4233. static void arg_register_error(struct arg_end* end, void* parent, int error, const char* argval) {
  4234. /* printf("arg_register_error(%p,%p,%d,%s)\n",end,parent,error,argval); */
  4235. if (end->count < end->hdr.maxcount) {
  4236. end->error[end->count] = error;
  4237. end->parent[end->count] = parent;
  4238. end->argval[end->count] = argval;
  4239. end->count++;
  4240. } else {
  4241. end->error[end->hdr.maxcount - 1] = ARG_ELIMIT;
  4242. end->parent[end->hdr.maxcount - 1] = end;
  4243. end->argval[end->hdr.maxcount - 1] = NULL;
  4244. }
  4245. }
  4246. /*
  4247. * Return index of first table entry with a matching short option
  4248. * or -1 if no match was found.
  4249. */
  4250. static int find_shortoption(struct arg_hdr** table, char shortopt) {
  4251. int tabindex;
  4252. for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {
  4253. if (table[tabindex]->shortopts && strchr(table[tabindex]->shortopts, shortopt))
  4254. return tabindex;
  4255. }
  4256. return -1;
  4257. }
  4258. struct longoptions {
  4259. int getoptval;
  4260. int noptions;
  4261. struct option* options;
  4262. };
  4263. #if 0
  4264. static
  4265. void dump_longoptions(struct longoptions * longoptions)
  4266. {
  4267. int i;
  4268. printf("getoptval = %d\n", longoptions->getoptval);
  4269. printf("noptions = %d\n", longoptions->noptions);
  4270. for (i = 0; i < longoptions->noptions; i++)
  4271. {
  4272. printf("options[%d].name = \"%s\"\n",
  4273. i,
  4274. longoptions->options[i].name);
  4275. printf("options[%d].has_arg = %d\n", i, longoptions->options[i].has_arg);
  4276. printf("options[%d].flag = %p\n", i, longoptions->options[i].flag);
  4277. printf("options[%d].val = %d\n", i, longoptions->options[i].val);
  4278. }
  4279. }
  4280. #endif
  4281. static struct longoptions* alloc_longoptions(struct arg_hdr** table) {
  4282. struct longoptions* result;
  4283. size_t nbytes;
  4284. int noptions = 1;
  4285. size_t longoptlen = 0;
  4286. int tabindex;
  4287. int option_index = 0;
  4288. char* store;
  4289. /*
  4290. * Determine the total number of option structs required
  4291. * by counting the number of comma separated long options
  4292. * in all table entries and return the count in noptions.
  4293. * note: noptions starts at 1 not 0 because we getoptlong
  4294. * requires a NULL option entry to terminate the option array.
  4295. * While we are at it, count the number of chars required
  4296. * to store private copies of all the longoption strings
  4297. * and return that count in logoptlen.
  4298. */
  4299. tabindex = 0;
  4300. do {
  4301. const char* longopts = table[tabindex]->longopts;
  4302. longoptlen += (longopts ? strlen(longopts) : 0) + 1;
  4303. while (longopts) {
  4304. noptions++;
  4305. longopts = strchr(longopts + 1, ',');
  4306. }
  4307. } while (!(table[tabindex++]->flag & ARG_TERMINATOR));
  4308. /*printf("%d long options consuming %d chars in total\n",noptions,longoptlen);*/
  4309. /* allocate storage for return data structure as: */
  4310. /* (struct longoptions) + (struct options)[noptions] + char[longoptlen] */
  4311. nbytes = sizeof(struct longoptions) + sizeof(struct option) * noptions + longoptlen;
  4312. result = (struct longoptions*)xmalloc(nbytes);
  4313. result->getoptval = 0;
  4314. result->noptions = noptions;
  4315. result->options = (struct option*)(result + 1);
  4316. store = (char*)(result->options + noptions);
  4317. for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {
  4318. const char* longopts = table[tabindex]->longopts;
  4319. while (longopts && *longopts) {
  4320. char* storestart = store;
  4321. /* copy progressive longopt strings into the store */
  4322. while (*longopts != 0 && *longopts != ',')
  4323. *store++ = *longopts++;
  4324. *store++ = 0;
  4325. if (*longopts == ',')
  4326. longopts++;
  4327. /*fprintf(stderr,"storestart=\"%s\"\n",storestart);*/
  4328. result->options[option_index].name = storestart;
  4329. result->options[option_index].flag = &(result->getoptval);
  4330. result->options[option_index].val = tabindex;
  4331. if (table[tabindex]->flag & ARG_HASOPTVALUE)
  4332. result->options[option_index].has_arg = 2;
  4333. else if (table[tabindex]->flag & ARG_HASVALUE)
  4334. result->options[option_index].has_arg = 1;
  4335. else
  4336. result->options[option_index].has_arg = 0;
  4337. option_index++;
  4338. }
  4339. }
  4340. /* terminate the options array with a zero-filled entry */
  4341. result->options[option_index].name = 0;
  4342. result->options[option_index].has_arg = 0;
  4343. result->options[option_index].flag = 0;
  4344. result->options[option_index].val = 0;
  4345. /*dump_longoptions(result);*/
  4346. return result;
  4347. }
  4348. static char* alloc_shortoptions(struct arg_hdr** table) {
  4349. char* result;
  4350. size_t len = 2;
  4351. int tabindex;
  4352. char* res;
  4353. /* determine the total number of option chars required */
  4354. for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {
  4355. struct arg_hdr* hdr = table[tabindex];
  4356. len += 3 * (hdr->shortopts ? strlen(hdr->shortopts) : 0);
  4357. }
  4358. result = xmalloc(len);
  4359. res = result;
  4360. /* add a leading ':' so getopt return codes distinguish */
  4361. /* unrecognised option and options missing argument values */
  4362. *res++ = ':';
  4363. for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {
  4364. struct arg_hdr* hdr = table[tabindex];
  4365. const char* shortopts = hdr->shortopts;
  4366. while (shortopts && *shortopts) {
  4367. *res++ = *shortopts++;
  4368. if (hdr->flag & ARG_HASVALUE)
  4369. *res++ = ':';
  4370. if (hdr->flag & ARG_HASOPTVALUE)
  4371. *res++ = ':';
  4372. }
  4373. }
  4374. /* null terminate the string */
  4375. *res = 0;
  4376. /*printf("alloc_shortoptions() returns \"%s\"\n",(result?result:"NULL"));*/
  4377. return result;
  4378. }
  4379. /* return index of the table terminator entry */
  4380. static int arg_endindex(struct arg_hdr** table) {
  4381. int tabindex = 0;
  4382. while (!(table[tabindex]->flag & ARG_TERMINATOR))
  4383. tabindex++;
  4384. return tabindex;
  4385. }
  4386. static void arg_parse_tagged(int argc, char** argv, struct arg_hdr** table, struct arg_end* endtable) {
  4387. struct longoptions* longoptions;
  4388. char* shortoptions;
  4389. int copt;
  4390. /*printf("arg_parse_tagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/
  4391. /* allocate short and long option arrays for the given opttable[]. */
  4392. /* if the allocs fail then put an error msg in the last table entry. */
  4393. longoptions = alloc_longoptions(table);
  4394. shortoptions = alloc_shortoptions(table);
  4395. /*dump_longoptions(longoptions);*/
  4396. /* reset getopts internal option-index to zero, and disable error reporting */
  4397. optind = 0;
  4398. opterr = 0;
  4399. /* fetch and process args using getopt_long */
  4400. while ((copt = getopt_long(argc, argv, shortoptions, longoptions->options, NULL)) != -1) {
  4401. /*
  4402. printf("optarg='%s'\n",optarg);
  4403. printf("optind=%d\n",optind);
  4404. printf("copt=%c\n",(char)copt);
  4405. printf("optopt=%c (%d)\n",optopt, (int)(optopt));
  4406. */
  4407. switch (copt) {
  4408. case 0: {
  4409. int tabindex = longoptions->getoptval;
  4410. void* parent = table[tabindex]->parent;
  4411. /*printf("long option detected from argtable[%d]\n", tabindex);*/
  4412. if (optarg && optarg[0] == 0 && (table[tabindex]->flag & ARG_HASVALUE)) {
  4413. /* printf(": long option %s requires an argument\n",argv[optind-1]); */
  4414. arg_register_error(endtable, endtable, ARG_EMISSARG, argv[optind - 1]);
  4415. /* continue to scan the (empty) argument value to enforce argument count checking */
  4416. }
  4417. if (table[tabindex]->scanfn) {
  4418. int errorcode = table[tabindex]->scanfn(parent, optarg);
  4419. if (errorcode != 0)
  4420. arg_register_error(endtable, parent, errorcode, optarg);
  4421. }
  4422. } break;
  4423. case '?':
  4424. /*
  4425. * getopt_long() found an unrecognised short option.
  4426. * if it was a short option its value is in optopt
  4427. * if it was a long option then optopt=0
  4428. */
  4429. switch (optopt) {
  4430. case 0:
  4431. /*printf("?0 unrecognised long option %s\n",argv[optind-1]);*/
  4432. arg_register_error(endtable, endtable, ARG_ELONGOPT, argv[optind - 1]);
  4433. break;
  4434. default:
  4435. /*printf("?* unrecognised short option '%c'\n",optopt);*/
  4436. arg_register_error(endtable, endtable, optopt, NULL);
  4437. break;
  4438. }
  4439. break;
  4440. case ':':
  4441. /*
  4442. * getopt_long() found an option with its argument missing.
  4443. */
  4444. /*printf(": option %s requires an argument\n",argv[optind-1]); */
  4445. arg_register_error(endtable, endtable, ARG_EMISSARG, argv[optind - 1]);
  4446. break;
  4447. default: {
  4448. /* getopt_long() found a valid short option */
  4449. int tabindex = find_shortoption(table, (char)copt);
  4450. /*printf("short option detected from argtable[%d]\n", tabindex);*/
  4451. if (tabindex == -1) {
  4452. /* should never get here - but handle it just in case */
  4453. /*printf("unrecognised short option %d\n",copt);*/
  4454. arg_register_error(endtable, endtable, copt, NULL);
  4455. } else {
  4456. if (table[tabindex]->scanfn) {
  4457. void* parent = table[tabindex]->parent;
  4458. int errorcode = table[tabindex]->scanfn(parent, optarg);
  4459. if (errorcode != 0)
  4460. arg_register_error(endtable, parent, errorcode, optarg);
  4461. }
  4462. }
  4463. break;
  4464. }
  4465. }
  4466. }
  4467. xfree(shortoptions);
  4468. xfree(longoptions);
  4469. }
  4470. static void arg_parse_untagged(int argc, char** argv, struct arg_hdr** table, struct arg_end* endtable) {
  4471. int tabindex = 0;
  4472. int errorlast = 0;
  4473. const char* optarglast = NULL;
  4474. void* parentlast = NULL;
  4475. /*printf("arg_parse_untagged(%d,%p,%p,%p)\n",argc,argv,table,endtable);*/
  4476. while (!(table[tabindex]->flag & ARG_TERMINATOR)) {
  4477. void* parent;
  4478. int errorcode;
  4479. /* if we have exhausted our argv[optind] entries then we have finished */
  4480. if (optind >= argc) {
  4481. /*printf("arg_parse_untagged(): argv[] exhausted\n");*/
  4482. return;
  4483. }
  4484. /* skip table entries with non-null long or short options (they are not untagged entries) */
  4485. if (table[tabindex]->longopts || table[tabindex]->shortopts) {
  4486. /*printf("arg_parse_untagged(): skipping argtable[%d] (tagged argument)\n",tabindex);*/
  4487. tabindex++;
  4488. continue;
  4489. }
  4490. /* skip table entries with NULL scanfn */
  4491. if (!(table[tabindex]->scanfn)) {
  4492. /*printf("arg_parse_untagged(): skipping argtable[%d] (NULL scanfn)\n",tabindex);*/
  4493. tabindex++;
  4494. continue;
  4495. }
  4496. /* attempt to scan the current argv[optind] with the current */
  4497. /* table[tabindex] entry. If it succeeds then keep it, otherwise */
  4498. /* try again with the next table[] entry. */
  4499. parent = table[tabindex]->parent;
  4500. errorcode = table[tabindex]->scanfn(parent, argv[optind]);
  4501. if (errorcode == 0) {
  4502. /* success, move onto next argv[optind] but stay with same table[tabindex] */
  4503. /*printf("arg_parse_untagged(): argtable[%d] successfully matched\n",tabindex);*/
  4504. optind++;
  4505. /* clear the last tentative error */
  4506. errorlast = 0;
  4507. } else {
  4508. /* failure, try same argv[optind] with next table[tabindex] entry */
  4509. /*printf("arg_parse_untagged(): argtable[%d] failed match\n",tabindex);*/
  4510. tabindex++;
  4511. /* remember this as a tentative error we may wish to reinstate later */
  4512. errorlast = errorcode;
  4513. optarglast = argv[optind];
  4514. parentlast = parent;
  4515. }
  4516. }
  4517. /* if a tenative error still remains at this point then register it as a proper error */
  4518. if (errorlast) {
  4519. arg_register_error(endtable, parentlast, errorlast, optarglast);
  4520. optind++;
  4521. }
  4522. /* only get here when not all argv[] entries were consumed */
  4523. /* register an error for each unused argv[] entry */
  4524. while (optind < argc) {
  4525. /*printf("arg_parse_untagged(): argv[%d]=\"%s\" not consumed\n",optind,argv[optind]);*/
  4526. arg_register_error(endtable, endtable, ARG_ENOMATCH, argv[optind++]);
  4527. }
  4528. return;
  4529. }
  4530. static void arg_parse_check(struct arg_hdr** table, struct arg_end* endtable) {
  4531. int tabindex = 0;
  4532. /* printf("arg_parse_check()\n"); */
  4533. do {
  4534. if (table[tabindex]->checkfn) {
  4535. void* parent = table[tabindex]->parent;
  4536. int errorcode = table[tabindex]->checkfn(parent);
  4537. if (errorcode != 0)
  4538. arg_register_error(endtable, parent, errorcode, NULL);
  4539. }
  4540. } while (!(table[tabindex++]->flag & ARG_TERMINATOR));
  4541. }
  4542. static void arg_reset(void** argtable) {
  4543. struct arg_hdr** table = (struct arg_hdr**)argtable;
  4544. int tabindex = 0;
  4545. /*printf("arg_reset(%p)\n",argtable);*/
  4546. do {
  4547. if (table[tabindex]->resetfn)
  4548. table[tabindex]->resetfn(table[tabindex]->parent);
  4549. } while (!(table[tabindex++]->flag & ARG_TERMINATOR));
  4550. }
  4551. int arg_parse(int argc, char** argv, void** argtable) {
  4552. struct arg_hdr** table = (struct arg_hdr**)argtable;
  4553. struct arg_end* endtable;
  4554. int endindex;
  4555. char** argvcopy = NULL;
  4556. int i;
  4557. /*printf("arg_parse(%d,%p,%p)\n",argc,argv,argtable);*/
  4558. /* reset any argtable data from previous invocations */
  4559. arg_reset(argtable);
  4560. /* locate the first end-of-table marker within the array */
  4561. endindex = arg_endindex(table);
  4562. endtable = (struct arg_end*)table[endindex];
  4563. /* Special case of argc==0. This can occur on Texas Instruments DSP. */
  4564. /* Failure to trap this case results in an unwanted NULL result from */
  4565. /* the malloc for argvcopy (next code block). */
  4566. if (argc == 0) {
  4567. /* We must still perform post-parse checks despite the absence of command line arguments */
  4568. arg_parse_check(table, endtable);
  4569. /* Now we are finished */
  4570. return endtable->count;
  4571. }
  4572. argvcopy = (char**)xmalloc(sizeof(char*) * (argc + 1));
  4573. /*
  4574. Fill in the local copy of argv[]. We need a local copy
  4575. because getopt rearranges argv[] which adversely affects
  4576. susbsequent parsing attempts.
  4577. */
  4578. for (i = 0; i < argc; i++)
  4579. argvcopy[i] = argv[i];
  4580. argvcopy[argc] = NULL;
  4581. /* parse the command line (local copy) for tagged options */
  4582. arg_parse_tagged(argc, argvcopy, table, endtable);
  4583. /* parse the command line (local copy) for untagged options */
  4584. arg_parse_untagged(argc, argvcopy, table, endtable);
  4585. /* if no errors so far then perform post-parse checks otherwise dont bother */
  4586. if (endtable->count == 0)
  4587. arg_parse_check(table, endtable);
  4588. /* release the local copt of argv[] */
  4589. xfree(argvcopy);
  4590. return endtable->count;
  4591. }
  4592. /*
  4593. * Concatenate contents of src[] string onto *pdest[] string.
  4594. * The *pdest pointer is altered to point to the end of the
  4595. * target string and *pndest is decremented by the same number
  4596. * of chars.
  4597. * Does not append more than *pndest chars into *pdest[]
  4598. * so as to prevent buffer overruns.
  4599. * Its something like strncat() but more efficient for repeated
  4600. * calls on the same destination string.
  4601. * Example of use:
  4602. * char dest[30] = "good"
  4603. * size_t ndest = sizeof(dest);
  4604. * char *pdest = dest;
  4605. * arg_char(&pdest,"bye ",&ndest);
  4606. * arg_char(&pdest,"cruel ",&ndest);
  4607. * arg_char(&pdest,"world!",&ndest);
  4608. * Results in:
  4609. * dest[] == "goodbye cruel world!"
  4610. * ndest == 10
  4611. */
  4612. static void arg_cat(char** pdest, const char* src, size_t* pndest) {
  4613. char* dest = *pdest;
  4614. char* end = dest + *pndest;
  4615. /*locate null terminator of dest string */
  4616. while (dest < end && *dest != 0)
  4617. dest++;
  4618. /* concat src string to dest string */
  4619. while (dest < end && *src != 0)
  4620. *dest++ = *src++;
  4621. /* null terminate dest string */
  4622. *dest = 0;
  4623. /* update *pdest and *pndest */
  4624. *pndest = end - dest;
  4625. *pdest = dest;
  4626. }
  4627. static void arg_cat_option(char* dest, size_t ndest, const char* shortopts, const char* longopts, const char* datatype, int optvalue) {
  4628. if (shortopts) {
  4629. char option[3];
  4630. /* note: option array[] is initialiazed dynamically here to satisfy */
  4631. /* a deficiency in the watcom compiler wrt static array initializers. */
  4632. option[0] = '-';
  4633. option[1] = shortopts[0];
  4634. option[2] = 0;
  4635. arg_cat(&dest, option, &ndest);
  4636. if (datatype) {
  4637. arg_cat(&dest, " ", &ndest);
  4638. if (optvalue) {
  4639. arg_cat(&dest, "[", &ndest);
  4640. arg_cat(&dest, datatype, &ndest);
  4641. arg_cat(&dest, "]", &ndest);
  4642. } else
  4643. arg_cat(&dest, datatype, &ndest);
  4644. }
  4645. } else if (longopts) {
  4646. size_t ncspn;
  4647. /* add "--" tag prefix */
  4648. arg_cat(&dest, "--", &ndest);
  4649. /* add comma separated option tag */
  4650. ncspn = strcspn(longopts, ",");
  4651. #if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
  4652. strncat_s(dest, ndest, longopts, (ncspn < ndest) ? ncspn : ndest);
  4653. #else
  4654. strncat(dest, longopts, (ncspn < ndest) ? ncspn : ndest);
  4655. #endif
  4656. if (datatype) {
  4657. arg_cat(&dest, "=", &ndest);
  4658. if (optvalue) {
  4659. arg_cat(&dest, "[", &ndest);
  4660. arg_cat(&dest, datatype, &ndest);
  4661. arg_cat(&dest, "]", &ndest);
  4662. } else
  4663. arg_cat(&dest, datatype, &ndest);
  4664. }
  4665. } else if (datatype) {
  4666. if (optvalue) {
  4667. arg_cat(&dest, "[", &ndest);
  4668. arg_cat(&dest, datatype, &ndest);
  4669. arg_cat(&dest, "]", &ndest);
  4670. } else
  4671. arg_cat(&dest, datatype, &ndest);
  4672. }
  4673. }
  4674. static void
  4675. arg_cat_optionv(char* dest, size_t ndest, const char* shortopts, const char* longopts, const char* datatype, int optvalue, const char* separator) {
  4676. separator = separator ? separator : "";
  4677. if (shortopts) {
  4678. const char* c = shortopts;
  4679. while (*c) {
  4680. /* "-a|-b|-c" */
  4681. char shortopt[3];
  4682. /* note: shortopt array[] is initialiazed dynamically here to satisfy */
  4683. /* a deficiency in the watcom compiler wrt static array initializers. */
  4684. shortopt[0] = '-';
  4685. shortopt[1] = *c;
  4686. shortopt[2] = 0;
  4687. arg_cat(&dest, shortopt, &ndest);
  4688. if (*++c)
  4689. arg_cat(&dest, separator, &ndest);
  4690. }
  4691. }
  4692. /* put separator between long opts and short opts */
  4693. if (shortopts && longopts)
  4694. arg_cat(&dest, separator, &ndest);
  4695. if (longopts) {
  4696. const char* c = longopts;
  4697. while (*c) {
  4698. size_t ncspn;
  4699. /* add "--" tag prefix */
  4700. arg_cat(&dest, "--", &ndest);
  4701. /* add comma separated option tag */
  4702. ncspn = strcspn(c, ",");
  4703. #if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || (defined(__STDC_SECURE_LIB__) && defined(__STDC_WANT_SECURE_LIB__))
  4704. strncat_s(dest, ndest, c, (ncspn < ndest) ? ncspn : ndest);
  4705. #else
  4706. strncat(dest, c, (ncspn < ndest) ? ncspn : ndest);
  4707. #endif
  4708. c += ncspn;
  4709. /* add given separator in place of comma */
  4710. if (*c == ',') {
  4711. arg_cat(&dest, separator, &ndest);
  4712. c++;
  4713. }
  4714. }
  4715. }
  4716. if (datatype) {
  4717. if (longopts)
  4718. arg_cat(&dest, "=", &ndest);
  4719. else if (shortopts)
  4720. arg_cat(&dest, " ", &ndest);
  4721. if (optvalue) {
  4722. arg_cat(&dest, "[", &ndest);
  4723. arg_cat(&dest, datatype, &ndest);
  4724. arg_cat(&dest, "]", &ndest);
  4725. } else
  4726. arg_cat(&dest, datatype, &ndest);
  4727. }
  4728. }
  4729. void arg_print_option_ds(arg_dstr_t ds, const char* shortopts, const char* longopts, const char* datatype, const char* suffix) {
  4730. char syntax[200] = "";
  4731. suffix = suffix ? suffix : "";
  4732. /* there is no way of passing the proper optvalue for optional argument values here, so we must ignore it */
  4733. arg_cat_optionv(syntax, sizeof(syntax), shortopts, longopts, datatype, 0, "|");
  4734. arg_dstr_cat(ds, syntax);
  4735. arg_dstr_cat(ds, (char*)suffix);
  4736. }
  4737. /* this function should be deprecated because it doesn't consider optional argument values (ARG_HASOPTVALUE) */
  4738. void arg_print_option(FILE* fp, const char* shortopts, const char* longopts, const char* datatype, const char* suffix) {
  4739. arg_dstr_t ds = arg_dstr_create();
  4740. arg_print_option_ds(ds, shortopts, longopts, datatype, suffix);
  4741. fputs(arg_dstr_cstr(ds), fp);
  4742. arg_dstr_destroy(ds);
  4743. }
  4744. /*
  4745. * Print a GNU style [OPTION] string in which all short options that
  4746. * do not take argument values are presented in abbreviated form, as
  4747. * in: -xvfsd, or -xvf[sd], or [-xvsfd]
  4748. */
  4749. static void arg_print_gnuswitch_ds(arg_dstr_t ds, struct arg_hdr** table) {
  4750. int tabindex;
  4751. char* format1 = " -%c";
  4752. char* format2 = " [-%c";
  4753. char* suffix = "";
  4754. /* print all mandatory switches that are without argument values */
  4755. for (tabindex = 0; table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {
  4756. /* skip optional options */
  4757. if (table[tabindex]->mincount < 1)
  4758. continue;
  4759. /* skip non-short options */
  4760. if (table[tabindex]->shortopts == NULL)
  4761. continue;
  4762. /* skip options that take argument values */
  4763. if (table[tabindex]->flag & ARG_HASVALUE)
  4764. continue;
  4765. /* print the short option (only the first short option char, ignore multiple choices)*/
  4766. arg_dstr_catf(ds, format1, table[tabindex]->shortopts[0]);
  4767. format1 = "%c";
  4768. format2 = "[%c";
  4769. }
  4770. /* print all optional switches that are without argument values */
  4771. for (tabindex = 0; table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {
  4772. /* skip mandatory args */
  4773. if (table[tabindex]->mincount > 0)
  4774. continue;
  4775. /* skip args without short options */
  4776. if (table[tabindex]->shortopts == NULL)
  4777. continue;
  4778. /* skip args with values */
  4779. if (table[tabindex]->flag & ARG_HASVALUE)
  4780. continue;
  4781. /* print first short option */
  4782. arg_dstr_catf(ds, format2, table[tabindex]->shortopts[0]);
  4783. format2 = "%c";
  4784. suffix = "]";
  4785. }
  4786. arg_dstr_catf(ds, "%s", suffix);
  4787. }
  4788. void arg_print_syntax_ds(arg_dstr_t ds, void** argtable, const char* suffix) {
  4789. struct arg_hdr** table = (struct arg_hdr**)argtable;
  4790. int i, tabindex;
  4791. /* print GNU style [OPTION] string */
  4792. arg_print_gnuswitch_ds(ds, table);
  4793. /* print remaining options in abbreviated style */
  4794. for (tabindex = 0; table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {
  4795. char syntax[200] = "";
  4796. const char *shortopts, *longopts, *datatype;
  4797. /* skip short options without arg values (they were printed by arg_print_gnu_switch) */
  4798. if (table[tabindex]->shortopts && !(table[tabindex]->flag & ARG_HASVALUE))
  4799. continue;
  4800. shortopts = table[tabindex]->shortopts;
  4801. longopts = table[tabindex]->longopts;
  4802. datatype = table[tabindex]->datatype;
  4803. arg_cat_option(syntax, sizeof(syntax), shortopts, longopts, datatype, table[tabindex]->flag & ARG_HASOPTVALUE);
  4804. if (strlen(syntax) > 0) {
  4805. /* print mandatory instances of this option */
  4806. for (i = 0; i < table[tabindex]->mincount; i++) {
  4807. arg_dstr_cat(ds, " ");
  4808. arg_dstr_cat(ds, syntax);
  4809. }
  4810. /* print optional instances enclosed in "[..]" */
  4811. switch (table[tabindex]->maxcount - table[tabindex]->mincount) {
  4812. case 0:
  4813. break;
  4814. case 1:
  4815. arg_dstr_cat(ds, " [");
  4816. arg_dstr_cat(ds, syntax);
  4817. arg_dstr_cat(ds, "]");
  4818. break;
  4819. case 2:
  4820. arg_dstr_cat(ds, " [");
  4821. arg_dstr_cat(ds, syntax);
  4822. arg_dstr_cat(ds, "]");
  4823. arg_dstr_cat(ds, " [");
  4824. arg_dstr_cat(ds, syntax);
  4825. arg_dstr_cat(ds, "]");
  4826. break;
  4827. default:
  4828. arg_dstr_cat(ds, " [");
  4829. arg_dstr_cat(ds, syntax);
  4830. arg_dstr_cat(ds, "]...");
  4831. break;
  4832. }
  4833. }
  4834. }
  4835. if (suffix) {
  4836. arg_dstr_cat(ds, (char*)suffix);
  4837. }
  4838. }
  4839. void arg_print_syntax(FILE* fp, void** argtable, const char* suffix) {
  4840. arg_dstr_t ds = arg_dstr_create();
  4841. arg_print_syntax_ds(ds, argtable, suffix);
  4842. fputs(arg_dstr_cstr(ds), fp);
  4843. arg_dstr_destroy(ds);
  4844. }
  4845. void arg_print_syntaxv_ds(arg_dstr_t ds, void** argtable, const char* suffix) {
  4846. struct arg_hdr** table = (struct arg_hdr**)argtable;
  4847. int i, tabindex;
  4848. /* print remaining options in abbreviated style */
  4849. for (tabindex = 0; table[tabindex] && !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {
  4850. char syntax[200] = "";
  4851. const char *shortopts, *longopts, *datatype;
  4852. shortopts = table[tabindex]->shortopts;
  4853. longopts = table[tabindex]->longopts;
  4854. datatype = table[tabindex]->datatype;
  4855. arg_cat_optionv(syntax, sizeof(syntax), shortopts, longopts, datatype, table[tabindex]->flag & ARG_HASOPTVALUE, "|");
  4856. /* print mandatory options */
  4857. for (i = 0; i < table[tabindex]->mincount; i++) {
  4858. arg_dstr_cat(ds, " ");
  4859. arg_dstr_cat(ds, syntax);
  4860. }
  4861. /* print optional args enclosed in "[..]" */
  4862. switch (table[tabindex]->maxcount - table[tabindex]->mincount) {
  4863. case 0:
  4864. break;
  4865. case 1:
  4866. arg_dstr_cat(ds, " [");
  4867. arg_dstr_cat(ds, syntax);
  4868. arg_dstr_cat(ds, "]");
  4869. break;
  4870. case 2:
  4871. arg_dstr_cat(ds, " [");
  4872. arg_dstr_cat(ds, syntax);
  4873. arg_dstr_cat(ds, "]");
  4874. arg_dstr_cat(ds, " [");
  4875. arg_dstr_cat(ds, syntax);
  4876. arg_dstr_cat(ds, "]");
  4877. break;
  4878. default:
  4879. arg_dstr_cat(ds, " [");
  4880. arg_dstr_cat(ds, syntax);
  4881. arg_dstr_cat(ds, "]...");
  4882. break;
  4883. }
  4884. }
  4885. if (suffix) {
  4886. arg_dstr_cat(ds, (char*)suffix);
  4887. }
  4888. }
  4889. void arg_print_syntaxv(FILE* fp, void** argtable, const char* suffix) {
  4890. arg_dstr_t ds = arg_dstr_create();
  4891. arg_print_syntaxv_ds(ds, argtable, suffix);
  4892. fputs(arg_dstr_cstr(ds), fp);
  4893. arg_dstr_destroy(ds);
  4894. }
  4895. void arg_print_glossary_ds(arg_dstr_t ds, void** argtable, const char* format) {
  4896. struct arg_hdr** table = (struct arg_hdr**)argtable;
  4897. int tabindex;
  4898. format = format ? format : " %-20s %s\n";
  4899. for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {
  4900. if (table[tabindex]->glossary) {
  4901. char syntax[200] = "";
  4902. const char* shortopts = table[tabindex]->shortopts;
  4903. const char* longopts = table[tabindex]->longopts;
  4904. const char* datatype = table[tabindex]->datatype;
  4905. const char* glossary = table[tabindex]->glossary;
  4906. arg_cat_optionv(syntax, sizeof(syntax), shortopts, longopts, datatype, table[tabindex]->flag & ARG_HASOPTVALUE, ", ");
  4907. arg_dstr_catf(ds, format, syntax, glossary);
  4908. }
  4909. }
  4910. }
  4911. void arg_print_glossary(FILE* fp, void** argtable, const char* format) {
  4912. arg_dstr_t ds = arg_dstr_create();
  4913. arg_print_glossary_ds(ds, argtable, format);
  4914. fputs(arg_dstr_cstr(ds), fp);
  4915. arg_dstr_destroy(ds);
  4916. }
  4917. /**
  4918. * Print a piece of text formatted, which means in a column with a
  4919. * left and a right margin. The lines are wrapped at whitspaces next
  4920. * to right margin. The function does not indent the first line, but
  4921. * only the following ones.
  4922. *
  4923. * Example:
  4924. * arg_print_formatted( fp, 0, 5, "Some text that doesn't fit." )
  4925. * will result in the following output:
  4926. *
  4927. * Some
  4928. * text
  4929. * that
  4930. * doesn'
  4931. * t fit.
  4932. *
  4933. * Too long lines will be wrapped in the middle of a word.
  4934. *
  4935. * arg_print_formatted( fp, 2, 7, "Some text that doesn't fit." )
  4936. * will result in the following output:
  4937. *
  4938. * Some
  4939. * text
  4940. * that
  4941. * doesn'
  4942. * t fit.
  4943. *
  4944. * As you see, the first line is not indented. This enables output of
  4945. * lines, which start in a line where output already happened.
  4946. *
  4947. * Author: Uli Fouquet
  4948. */
  4949. static void arg_print_formatted_ds(arg_dstr_t ds, const unsigned lmargin, const unsigned rmargin, const char* text) {
  4950. const unsigned int textlen = (unsigned int)strlen(text);
  4951. unsigned int line_start = 0;
  4952. unsigned int line_end = textlen;
  4953. const unsigned int colwidth = (rmargin - lmargin) + 1;
  4954. assert(strlen(text) < UINT_MAX);
  4955. /* Someone doesn't like us... */
  4956. if (line_end < line_start) {
  4957. arg_dstr_catf(ds, "%s\n", text);
  4958. }
  4959. while (line_end > line_start) {
  4960. /* Eat leading white spaces. This is essential because while
  4961. wrapping lines, there will often be a whitespace at beginning
  4962. of line */
  4963. while (isspace(*(text + line_start))) {
  4964. line_start++;
  4965. }
  4966. /* Find last whitespace, that fits into line */
  4967. if (line_end - line_start > colwidth) {
  4968. line_end = line_start + colwidth;
  4969. while ((line_end > line_start) && !isspace(*(text + line_end))) {
  4970. line_end--;
  4971. }
  4972. /* Consume trailing spaces */
  4973. while ((line_end > line_start) && isspace(*(text + line_end))) {
  4974. line_end--;
  4975. }
  4976. /* Restore the last non-space character */
  4977. line_end++;
  4978. }
  4979. /* Output line of text */
  4980. while (line_start < line_end) {
  4981. char c = *(text + line_start);
  4982. arg_dstr_catc(ds, c);
  4983. line_start++;
  4984. }
  4985. arg_dstr_cat(ds, "\n");
  4986. /* Initialize another line */
  4987. if (line_end < textlen) {
  4988. unsigned i;
  4989. for (i = 0; i < lmargin; i++) {
  4990. arg_dstr_cat(ds, " ");
  4991. }
  4992. line_end = textlen;
  4993. }
  4994. } /* lines of text */
  4995. }
  4996. /**
  4997. * Prints the glossary in strict GNU format.
  4998. * Differences to arg_print_glossary() are:
  4999. * - wraps lines after 80 chars
  5000. * - indents lines without shortops
  5001. * - does not accept formatstrings
  5002. *
  5003. * Contributed by Uli Fouquet
  5004. */
  5005. void arg_print_glossary_gnu_ds(arg_dstr_t ds, void** argtable) {
  5006. struct arg_hdr** table = (struct arg_hdr**)argtable;
  5007. int tabindex;
  5008. for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {
  5009. if (table[tabindex]->glossary) {
  5010. char syntax[200] = "";
  5011. const char* shortopts = table[tabindex]->shortopts;
  5012. const char* longopts = table[tabindex]->longopts;
  5013. const char* datatype = table[tabindex]->datatype;
  5014. const char* glossary = table[tabindex]->glossary;
  5015. if (!shortopts && longopts) {
  5016. /* Indent trailing line by 4 spaces... */
  5017. memset(syntax, ' ', 4);
  5018. *(syntax + 4) = '\0';
  5019. }
  5020. arg_cat_optionv(syntax, sizeof(syntax), shortopts, longopts, datatype, table[tabindex]->flag & ARG_HASOPTVALUE, ", ");
  5021. /* If syntax fits not into column, print glossary in new line... */
  5022. if (strlen(syntax) > 25) {
  5023. arg_dstr_catf(ds, " %-25s %s\n", syntax, "");
  5024. *syntax = '\0';
  5025. }
  5026. arg_dstr_catf(ds, " %-25s ", syntax);
  5027. arg_print_formatted_ds(ds, 28, 79, glossary);
  5028. }
  5029. } /* for each table entry */
  5030. arg_dstr_cat(ds, "\n");
  5031. }
  5032. void arg_print_glossary_gnu(FILE* fp, void** argtable) {
  5033. arg_dstr_t ds = arg_dstr_create();
  5034. arg_print_glossary_gnu_ds(ds, argtable);
  5035. fputs(arg_dstr_cstr(ds), fp);
  5036. arg_dstr_destroy(ds);
  5037. }
  5038. /**
  5039. * Checks the argtable[] array for NULL entries and returns 1
  5040. * if any are found, zero otherwise.
  5041. */
  5042. int arg_nullcheck(void** argtable) {
  5043. struct arg_hdr** table = (struct arg_hdr**)argtable;
  5044. int tabindex;
  5045. /*printf("arg_nullcheck(%p)\n",argtable);*/
  5046. if (!table)
  5047. return 1;
  5048. tabindex = 0;
  5049. do {
  5050. /*printf("argtable[%d]=%p\n",tabindex,argtable[tabindex]);*/
  5051. if (!table[tabindex])
  5052. return 1;
  5053. } while (!(table[tabindex++]->flag & ARG_TERMINATOR));
  5054. return 0;
  5055. }
  5056. /*
  5057. * arg_free() is deprecated in favour of arg_freetable() due to a flaw in its design.
  5058. * The flaw results in memory leak in the (very rare) case that an intermediate
  5059. * entry in the argtable array failed its memory allocation while others following
  5060. * that entry were still allocated ok. Those subsequent allocations will not be
  5061. * deallocated by arg_free().
  5062. * Despite the unlikeliness of the problem occurring, and the even unlikelier event
  5063. * that it has any deliterious effect, it is fixed regardless by replacing arg_free()
  5064. * with the newer arg_freetable() function.
  5065. * We still keep arg_free() for backwards compatibility.
  5066. */
  5067. void arg_free(void** argtable) {
  5068. struct arg_hdr** table = (struct arg_hdr**)argtable;
  5069. int tabindex = 0;
  5070. int flag;
  5071. /*printf("arg_free(%p)\n",argtable);*/
  5072. do {
  5073. /*
  5074. if we encounter a NULL entry then somewhat incorrectly we presume
  5075. we have come to the end of the array. It isnt strictly true because
  5076. an intermediate entry could be NULL with other non-NULL entries to follow.
  5077. The subsequent argtable entries would then not be freed as they should.
  5078. */
  5079. if (table[tabindex] == NULL)
  5080. break;
  5081. flag = table[tabindex]->flag;
  5082. xfree(table[tabindex]);
  5083. table[tabindex++] = NULL;
  5084. } while (!(flag & ARG_TERMINATOR));
  5085. }
  5086. /* frees each non-NULL element of argtable[], where n is the size of the number of entries in the array */
  5087. void arg_freetable(void** argtable, size_t n) {
  5088. struct arg_hdr** table = (struct arg_hdr**)argtable;
  5089. size_t tabindex = 0;
  5090. /*printf("arg_freetable(%p)\n",argtable);*/
  5091. for (tabindex = 0; tabindex < n; tabindex++) {
  5092. if (table[tabindex] == NULL)
  5093. continue;
  5094. xfree(table[tabindex]);
  5095. table[tabindex] = NULL;
  5096. };
  5097. }
  5098. #ifdef _WIN32
  5099. BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
  5100. return TRUE;
  5101. UNREFERENCED_PARAMETER(hinstDLL);
  5102. UNREFERENCED_PARAMETER(fdwReason);
  5103. UNREFERENCED_PARAMETER(lpvReserved);
  5104. }
  5105. #endif