argtable3.c 154 KB

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