astyle_main.cpp 115 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991
  1. // astyle_main.cpp
  2. // Copyright (c) 2017 by Jim Pattee <jimp03@email.com>.
  3. // This code is licensed under the MIT License.
  4. // License.md describes the conditions under which this software may be distributed.
  5. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6. * AStyle_main source file map.
  7. * This source file contains several classes.
  8. * They are arranged as follows.
  9. * ---------------------------------------
  10. * namespace astyle {
  11. * ASStreamIterator methods
  12. * ASConsole methods
  13. * // Windows specific
  14. * // Linux specific
  15. * ASLibrary methods
  16. * // Windows specific
  17. * // Linux specific
  18. * ASOptions methods
  19. * ASEncoding methods
  20. * } // end of astyle namespace
  21. * Global Area ---------------------------
  22. * Java Native Interface functions
  23. * AStyleMainUtf16 entry point
  24. * AStyleMain entry point
  25. * AStyleGetVersion entry point
  26. * main entry point
  27. * ---------------------------------------
  28. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  29. */
  30. //-----------------------------------------------------------------------------
  31. // headers
  32. //-----------------------------------------------------------------------------
  33. #include "astyle_main.h"
  34. #include <algorithm>
  35. #include <cerrno>
  36. #include <clocale> // needed by some compilers
  37. #include <cstdlib>
  38. #include <fstream>
  39. #include <sstream>
  40. // includes for recursive getFileNames() function
  41. #ifdef _WIN32
  42. #undef UNICODE // use ASCII windows functions
  43. #include <windows.h>
  44. #else
  45. #include <dirent.h>
  46. #include <unistd.h>
  47. #include <sys/stat.h>
  48. #ifdef __VMS
  49. #include <unixlib.h>
  50. #include <rms.h>
  51. #include <ssdef.h>
  52. #include <stsdef.h>
  53. #include <lib$routines.h>
  54. #include <starlet.h>
  55. #endif /* __VMS */
  56. #endif
  57. //-----------------------------------------------------------------------------
  58. // declarations
  59. //-----------------------------------------------------------------------------
  60. // turn off MinGW automatic file globbing
  61. // this CANNOT be in the astyle namespace
  62. #ifndef ASTYLE_LIB
  63. int _CRT_glob = 0;
  64. #endif
  65. //----------------------------------------------------------------------------
  66. // astyle namespace
  67. //----------------------------------------------------------------------------
  68. namespace astyle {
  69. //
  70. // console build variables
  71. #ifndef ASTYLE_LIB
  72. #ifdef _WIN32
  73. char g_fileSeparator = '\\'; // Windows file separator
  74. bool g_isCaseSensitive = false; // Windows IS NOT case sensitive
  75. #else
  76. char g_fileSeparator = '/'; // Linux file separator
  77. bool g_isCaseSensitive = true; // Linux IS case sensitive
  78. #endif // _WIN32
  79. #endif // ASTYLE_LIB
  80. // java library build variables
  81. #ifdef ASTYLE_JNI
  82. JNIEnv* g_env;
  83. jobject g_obj;
  84. jmethodID g_mid;
  85. #endif
  86. const char* g_version = "3.0";
  87. //-----------------------------------------------------------------------------
  88. // ASStreamIterator class
  89. // typename will be istringstream for GUI and istream otherwise
  90. //-----------------------------------------------------------------------------
  91. template<typename T>
  92. ASStreamIterator<T>::ASStreamIterator(T* in)
  93. {
  94. inStream = in;
  95. buffer.reserve(200);
  96. eolWindows = 0;
  97. eolLinux = 0;
  98. eolMacOld = 0;
  99. peekStart = 0;
  100. prevLineDeleted = false;
  101. checkForEmptyLine = false;
  102. // get length of stream
  103. inStream->seekg(0, inStream->end);
  104. streamLength = inStream->tellg();
  105. inStream->seekg(0, inStream->beg);
  106. }
  107. template<typename T>
  108. ASStreamIterator<T>::~ASStreamIterator()
  109. {
  110. }
  111. /**
  112. * get the length of the input stream.
  113. * streamLength variable is set by the constructor.
  114. *
  115. * @return length of the input file stream, converted to an int.
  116. */
  117. template<typename T>
  118. int ASStreamIterator<T>::getStreamLength() const
  119. {
  120. return static_cast<int>(streamLength);
  121. }
  122. /**
  123. * read the input stream, delete any end of line characters,
  124. * and build a string that contains the input line.
  125. *
  126. * @return string containing the next input line minus any end of line characters
  127. */
  128. template<typename T>
  129. string ASStreamIterator<T>::nextLine(bool emptyLineWasDeleted)
  130. {
  131. // verify that the current position is correct
  132. assert(peekStart == 0);
  133. // a deleted line may be replaced if break-blocks is requested
  134. // this sets up the compare to check for a replaced empty line
  135. if (prevLineDeleted)
  136. {
  137. prevLineDeleted = false;
  138. checkForEmptyLine = true;
  139. }
  140. if (!emptyLineWasDeleted)
  141. prevBuffer = buffer;
  142. else
  143. prevLineDeleted = true;
  144. // read the next record
  145. buffer.clear();
  146. char ch;
  147. inStream->get(ch);
  148. while (!inStream->eof() && ch != '\n' && ch != '\r')
  149. {
  150. buffer.append(1, ch);
  151. inStream->get(ch);
  152. }
  153. if (inStream->eof())
  154. {
  155. return buffer;
  156. }
  157. int peekCh = inStream->peek();
  158. // find input end-of-line characters
  159. if (!inStream->eof())
  160. {
  161. if (ch == '\r') // CR+LF is windows otherwise Mac OS 9
  162. {
  163. if (peekCh == '\n')
  164. {
  165. inStream->get();
  166. eolWindows++;
  167. }
  168. else
  169. eolMacOld++;
  170. }
  171. else // LF is Linux, allow for improbable LF/CR
  172. {
  173. if (peekCh == '\r')
  174. {
  175. inStream->get();
  176. eolWindows++;
  177. }
  178. else
  179. eolLinux++;
  180. }
  181. }
  182. else
  183. {
  184. inStream->clear();
  185. }
  186. // set output end of line characters
  187. if (eolWindows >= eolLinux)
  188. {
  189. if (eolWindows >= eolMacOld)
  190. outputEOL = "\r\n"; // Windows (CR+LF)
  191. else
  192. outputEOL = "\r"; // MacOld (CR)
  193. }
  194. else if (eolLinux >= eolMacOld)
  195. outputEOL = "\n"; // Linux (LF)
  196. else
  197. outputEOL = "\r"; // MacOld (CR)
  198. return buffer;
  199. }
  200. // save the current position and get the next line
  201. // this can be called for multiple reads
  202. // when finished peeking you MUST call peekReset()
  203. // call this function from ASFormatter ONLY
  204. template<typename T>
  205. string ASStreamIterator<T>::peekNextLine()
  206. {
  207. assert(hasMoreLines());
  208. string nextLine_;
  209. char ch;
  210. if (peekStart == 0)
  211. peekStart = inStream->tellg();
  212. // read the next record
  213. inStream->get(ch);
  214. while (!inStream->eof() && ch != '\n' && ch != '\r')
  215. {
  216. nextLine_.append(1, ch);
  217. inStream->get(ch);
  218. }
  219. if (inStream->eof())
  220. {
  221. return nextLine_;
  222. }
  223. int peekCh = inStream->peek();
  224. // remove end-of-line characters
  225. if (!inStream->eof())
  226. {
  227. if ((peekCh == '\n' || peekCh == '\r') && peekCh != ch)
  228. inStream->get();
  229. }
  230. return nextLine_;
  231. }
  232. // reset current position and EOF for peekNextLine()
  233. template<typename T>
  234. void ASStreamIterator<T>::peekReset()
  235. {
  236. assert(peekStart != 0);
  237. inStream->clear();
  238. inStream->seekg(peekStart);
  239. peekStart = 0;
  240. }
  241. // save the last input line after input has reached EOF
  242. template<typename T>
  243. void ASStreamIterator<T>::saveLastInputLine()
  244. {
  245. assert(inStream->eof());
  246. prevBuffer = buffer;
  247. }
  248. // return position of the get pointer
  249. template<typename T>
  250. streamoff ASStreamIterator<T>::tellg()
  251. {
  252. return inStream->tellg();
  253. }
  254. // check for a change in line ends
  255. template<typename T>
  256. bool ASStreamIterator<T>::getLineEndChange(int lineEndFormat) const
  257. {
  258. assert(lineEndFormat == LINEEND_DEFAULT
  259. || lineEndFormat == LINEEND_WINDOWS
  260. || lineEndFormat == LINEEND_LINUX
  261. || lineEndFormat == LINEEND_MACOLD);
  262. bool lineEndChange = false;
  263. if (lineEndFormat == LINEEND_WINDOWS)
  264. lineEndChange = (eolLinux + eolMacOld != 0);
  265. else if (lineEndFormat == LINEEND_LINUX)
  266. lineEndChange = (eolWindows + eolMacOld != 0);
  267. else if (lineEndFormat == LINEEND_MACOLD)
  268. lineEndChange = (eolWindows + eolLinux != 0);
  269. else
  270. {
  271. if (eolWindows > 0)
  272. lineEndChange = (eolLinux + eolMacOld != 0);
  273. else if (eolLinux > 0)
  274. lineEndChange = (eolWindows + eolMacOld != 0);
  275. else if (eolMacOld > 0)
  276. lineEndChange = (eolWindows + eolLinux != 0);
  277. }
  278. return lineEndChange;
  279. }
  280. //-----------------------------------------------------------------------------
  281. // ASConsole class
  282. // main function will be included only in the console build
  283. //-----------------------------------------------------------------------------
  284. #ifndef ASTYLE_LIB
  285. ASConsole::ASConsole(ASFormatter& formatterArg) : formatter(formatterArg)
  286. {
  287. errorStream = &cerr;
  288. // command line options
  289. isRecursive = false;
  290. isDryRun = false;
  291. noBackup = false;
  292. preserveDate = false;
  293. isVerbose = false;
  294. isQuiet = false;
  295. isFormattedOnly = false;
  296. ignoreExcludeErrors = false;
  297. ignoreExcludeErrorsDisplay = false;
  298. optionsFileRequired = false;
  299. useAscii = false;
  300. // other variables
  301. bypassBrowserOpen = false;
  302. hasWildcard = false;
  303. filesAreIdentical = true;
  304. lineEndsMixed = false;
  305. origSuffix = ".orig";
  306. mainDirectoryLength = 0;
  307. filesFormatted = 0;
  308. filesUnchanged = 0;
  309. linesOut = 0;
  310. }
  311. ASConsole::~ASConsole()
  312. {}
  313. // rewrite a stringstream converting the line ends
  314. void ASConsole::convertLineEnds(ostringstream& out, int lineEnd)
  315. {
  316. assert(lineEnd == LINEEND_WINDOWS || lineEnd == LINEEND_LINUX || lineEnd == LINEEND_MACOLD);
  317. const string& inStr = out.str(); // avoids strange looking syntax
  318. string outStr; // the converted output
  319. int inLength = (int)inStr.length();
  320. for (int pos = 0; pos < inLength; pos++)
  321. {
  322. if (inStr[pos] == '\r')
  323. {
  324. if (inStr[pos + 1] == '\n')
  325. {
  326. // CRLF
  327. if (lineEnd == LINEEND_CR)
  328. {
  329. outStr += inStr[pos]; // Delete the LF
  330. pos++;
  331. continue;
  332. }
  333. else if (lineEnd == LINEEND_LF)
  334. {
  335. outStr += inStr[pos + 1]; // Delete the CR
  336. pos++;
  337. continue;
  338. }
  339. else
  340. {
  341. outStr += inStr[pos]; // Do not change
  342. outStr += inStr[pos + 1];
  343. pos++;
  344. continue;
  345. }
  346. }
  347. else
  348. {
  349. // CR
  350. if (lineEnd == LINEEND_CRLF)
  351. {
  352. outStr += inStr[pos]; // Insert the CR
  353. outStr += '\n'; // Insert the LF
  354. continue;
  355. }
  356. else if (lineEnd == LINEEND_LF)
  357. {
  358. outStr += '\n'; // Insert the LF
  359. continue;
  360. }
  361. else
  362. {
  363. outStr += inStr[pos]; // Do not change
  364. continue;
  365. }
  366. }
  367. }
  368. else if (inStr[pos] == '\n')
  369. {
  370. // LF
  371. if (lineEnd == LINEEND_CRLF)
  372. {
  373. outStr += '\r'; // Insert the CR
  374. outStr += inStr[pos]; // Insert the LF
  375. continue;
  376. }
  377. else if (lineEnd == LINEEND_CR)
  378. {
  379. outStr += '\r'; // Insert the CR
  380. continue;
  381. }
  382. else
  383. {
  384. outStr += inStr[pos]; // Do not change
  385. continue;
  386. }
  387. }
  388. else
  389. {
  390. outStr += inStr[pos]; // Write the current char
  391. }
  392. }
  393. // replace the stream
  394. out.str(outStr);
  395. }
  396. void ASConsole::correctMixedLineEnds(ostringstream& out)
  397. {
  398. LineEndFormat lineEndFormat = LINEEND_DEFAULT;
  399. if (outputEOL == "\r\n")
  400. lineEndFormat = LINEEND_WINDOWS;
  401. if (outputEOL == "\n")
  402. lineEndFormat = LINEEND_LINUX;
  403. if (outputEOL == "\r")
  404. lineEndFormat = LINEEND_MACOLD;
  405. convertLineEnds(out, lineEndFormat);
  406. }
  407. // check files for 16 or 32 bit encoding
  408. // the file must have a Byte Order Mark (BOM)
  409. // NOTE: some string functions don't work with NULLs (e.g. length())
  410. FileEncoding ASConsole::detectEncoding(const char* data, size_t dataSize) const
  411. {
  412. FileEncoding encoding = ENCODING_8BIT;
  413. if (dataSize >= 4 && memcmp(data, "\x00\x00\xFE\xFF", 4) == 0)
  414. encoding = UTF_32BE;
  415. else if (dataSize >= 4 && memcmp(data, "\xFF\xFE\x00\x00", 4) == 0)
  416. encoding = UTF_32LE;
  417. else if (dataSize >= 2 && memcmp(data, "\xFE\xFF", 2) == 0)
  418. encoding = UTF_16BE;
  419. else if (dataSize >= 2 && memcmp(data, "\xFF\xFE", 2) == 0)
  420. encoding = UTF_16LE;
  421. return encoding;
  422. }
  423. // error exit without a message
  424. void ASConsole::error() const
  425. {
  426. (*errorStream) << _("\nArtistic Style has terminated") << endl;
  427. exit(EXIT_FAILURE);
  428. }
  429. // error exit with a message
  430. void ASConsole::error(const char* why, const char* what) const
  431. {
  432. (*errorStream) << why << ' ' << what << endl;
  433. error();
  434. }
  435. /**
  436. * If no files have been given, use cin for input and cout for output.
  437. *
  438. * This is used to format text for text editors like TextWrangler (Mac).
  439. * Do NOT display any console messages when this function is used.
  440. */
  441. void ASConsole::formatCinToCout()
  442. {
  443. // check for files from --stdin= and --stdout=
  444. if (!stdPathIn.empty())
  445. {
  446. if (!freopen(stdPathIn.c_str(), "r", stdin))
  447. error("Cannot open input file", stdPathIn.c_str());
  448. }
  449. if (!stdPathOut.empty())
  450. {
  451. if (!freopen(stdPathOut.c_str(), "w", stdout))
  452. error("Cannot open output file", stdPathOut.c_str());
  453. }
  454. // Using cin.tellg() causes problems with both Windows and Linux.
  455. // The Windows problem occurs when the input is not Windows line-ends.
  456. // The tellg() will be out of sequence with the get() statements.
  457. // The Linux cin.tellg() will return -1 (invalid).
  458. // Copying the input sequentially to a stringstream before
  459. // formatting solves the problem for both.
  460. istream* inStream = &cin;
  461. stringstream outStream;
  462. char ch;
  463. inStream->get(ch);
  464. while (!inStream->eof() && !inStream->fail())
  465. {
  466. outStream.put(ch);
  467. inStream->get(ch);
  468. }
  469. ASStreamIterator<stringstream> streamIterator(&outStream);
  470. // Windows pipe or redirection always outputs Windows line-ends.
  471. // Linux pipe or redirection will output any line end.
  472. #ifdef _WIN32
  473. LineEndFormat lineEndFormat = LINEEND_DEFAULT;
  474. #else
  475. LineEndFormat lineEndFormat = formatter.getLineEndFormat();
  476. #endif // _WIN32
  477. initializeOutputEOL(lineEndFormat);
  478. formatter.init(&streamIterator);
  479. while (formatter.hasMoreLines())
  480. {
  481. cout << formatter.nextLine();
  482. if (formatter.hasMoreLines())
  483. {
  484. setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
  485. cout << outputEOL;
  486. }
  487. else
  488. {
  489. // this can happen if the file if missing a closing brace and break-blocks is requested
  490. if (formatter.getIsLineReady())
  491. {
  492. setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
  493. cout << outputEOL;
  494. cout << formatter.nextLine();
  495. }
  496. }
  497. }
  498. cout.flush();
  499. }
  500. /**
  501. * Open input file, format it, and close the output.
  502. *
  503. * @param fileName_ The path and name of the file to be processed.
  504. */
  505. void ASConsole::formatFile(const string& fileName_)
  506. {
  507. stringstream in;
  508. ostringstream out;
  509. FileEncoding encoding = readFile(fileName_, in);
  510. // Unless a specific language mode has been set, set the language mode
  511. // according to the file's suffix.
  512. if (!formatter.getModeManuallySet())
  513. {
  514. if (stringEndsWith(fileName_, string(".java")))
  515. formatter.setJavaStyle();
  516. else if (stringEndsWith(fileName_, string(".cs")))
  517. formatter.setSharpStyle();
  518. else
  519. formatter.setCStyle();
  520. }
  521. // set line end format
  522. string nextLine; // next output line
  523. filesAreIdentical = true; // input and output files are identical
  524. LineEndFormat lineEndFormat = formatter.getLineEndFormat();
  525. initializeOutputEOL(lineEndFormat);
  526. // do this AFTER setting the file mode
  527. ASStreamIterator<stringstream> streamIterator(&in);
  528. formatter.init(&streamIterator);
  529. // format the file
  530. while (formatter.hasMoreLines())
  531. {
  532. nextLine = formatter.nextLine();
  533. out << nextLine;
  534. linesOut++;
  535. if (formatter.hasMoreLines())
  536. {
  537. setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
  538. out << outputEOL;
  539. }
  540. else
  541. {
  542. streamIterator.saveLastInputLine(); // to compare the last input line
  543. // this can happen if the file if missing a closing brace and break-blocks is requested
  544. if (formatter.getIsLineReady())
  545. {
  546. setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
  547. out << outputEOL;
  548. nextLine = formatter.nextLine();
  549. out << nextLine;
  550. linesOut++;
  551. streamIterator.saveLastInputLine();
  552. }
  553. }
  554. if (filesAreIdentical)
  555. {
  556. if (streamIterator.checkForEmptyLine)
  557. {
  558. if (nextLine.find_first_not_of(" \t") != string::npos)
  559. filesAreIdentical = false;
  560. }
  561. else if (!streamIterator.compareToInputBuffer(nextLine))
  562. filesAreIdentical = false;
  563. streamIterator.checkForEmptyLine = false;
  564. }
  565. }
  566. // correct for mixed line ends
  567. if (lineEndsMixed)
  568. {
  569. correctMixedLineEnds(out);
  570. filesAreIdentical = false;
  571. }
  572. // remove targetDirectory from filename if required by print
  573. string displayName;
  574. if (hasWildcard)
  575. displayName = fileName_.substr(targetDirectory.length() + 1);
  576. else
  577. displayName = fileName_;
  578. // if file has changed, write the new file
  579. if (!filesAreIdentical || streamIterator.getLineEndChange(lineEndFormat))
  580. {
  581. if (!isDryRun)
  582. writeFile(fileName_, encoding, out);
  583. printMsg(_("Formatted %s\n"), displayName);
  584. filesFormatted++;
  585. }
  586. else
  587. {
  588. if (!isFormattedOnly)
  589. printMsg(_("Unchanged %s\n"), displayName);
  590. filesUnchanged++;
  591. }
  592. assert(formatter.getChecksumDiff() == 0);
  593. }
  594. // build a vector of argv options
  595. // the program path argv[0] is excluded
  596. vector<string> ASConsole::getArgvOptions(int argc, char** argv) const
  597. {
  598. vector<string> argvOptions;
  599. for (int i = 1; i < argc; i++)
  600. {
  601. argvOptions.emplace_back(string(argv[i]));
  602. }
  603. return argvOptions;
  604. }
  605. // for unit testing
  606. vector<bool> ASConsole::getExcludeHitsVector() const
  607. { return excludeHitsVector; }
  608. // for unit testing
  609. vector<string> ASConsole::getExcludeVector() const
  610. { return excludeVector; }
  611. // for unit testing
  612. vector<string> ASConsole::getFileName() const
  613. { return fileName; }
  614. // for unit testing
  615. vector<string> ASConsole::getFileNameVector() const
  616. { return fileNameVector; }
  617. // for unit testing
  618. vector<string> ASConsole::getFileOptionsVector() const
  619. { return fileOptionsVector; }
  620. // for unit testing
  621. bool ASConsole::getFilesAreIdentical() const
  622. { return filesAreIdentical; }
  623. // for unit testing
  624. int ASConsole::getFilesFormatted() const
  625. { return filesFormatted; }
  626. // for unit testing
  627. bool ASConsole::getIgnoreExcludeErrors() const
  628. { return ignoreExcludeErrors; }
  629. // for unit testing
  630. bool ASConsole::getIgnoreExcludeErrorsDisplay() const
  631. { return ignoreExcludeErrorsDisplay; }
  632. // for unit testing
  633. bool ASConsole::getIsDryRun() const
  634. { return isDryRun; }
  635. // for unit testing
  636. bool ASConsole::getIsFormattedOnly() const
  637. { return isFormattedOnly; }
  638. // for unit testing
  639. string ASConsole::getLanguageID() const
  640. { return localizer.getLanguageID(); }
  641. // for unit testing
  642. bool ASConsole::getIsQuiet() const
  643. { return isQuiet; }
  644. // for unit testing
  645. bool ASConsole::getIsRecursive() const
  646. { return isRecursive; }
  647. // for unit testing
  648. bool ASConsole::getIsVerbose() const
  649. { return isVerbose; }
  650. // for unit testing
  651. bool ASConsole::getLineEndsMixed() const
  652. { return lineEndsMixed; }
  653. // for unit testing
  654. bool ASConsole::getNoBackup() const
  655. { return noBackup; }
  656. // for unit testing
  657. string ASConsole::getOptionsFileName() const
  658. { return optionsFileName; }
  659. // for unit testing
  660. vector<string> ASConsole::getOptionsVector() const
  661. { return optionsVector; }
  662. // for unit testing
  663. string ASConsole::getOrigSuffix() const
  664. { return origSuffix; }
  665. // for unit testing
  666. bool ASConsole::getPreserveDate() const
  667. { return preserveDate; }
  668. // for unit testing
  669. string ASConsole::getStdPathIn() const
  670. { return stdPathIn; }
  671. // for unit testing
  672. string ASConsole::getStdPathOut() const
  673. { return stdPathOut; }
  674. // for unit testing
  675. void ASConsole::setBypassBrowserOpen(bool state)
  676. { bypassBrowserOpen = state; }
  677. // for unit testing
  678. ostream* ASConsole::getErrorStream() const
  679. {
  680. return errorStream;
  681. }
  682. void ASConsole::setErrorStream(ostream* errStreamPtr)
  683. {
  684. errorStream = errStreamPtr;
  685. }
  686. string ASConsole::getParam(const string& arg, const char* op)
  687. {
  688. return arg.substr(strlen(op));
  689. }
  690. // initialize output end of line
  691. void ASConsole::initializeOutputEOL(LineEndFormat lineEndFormat)
  692. {
  693. assert(lineEndFormat == LINEEND_DEFAULT
  694. || lineEndFormat == LINEEND_WINDOWS
  695. || lineEndFormat == LINEEND_LINUX
  696. || lineEndFormat == LINEEND_MACOLD);
  697. outputEOL.clear(); // current line end
  698. prevEOL.clear(); // previous line end
  699. lineEndsMixed = false; // output has mixed line ends, LINEEND_DEFAULT only
  700. if (lineEndFormat == LINEEND_WINDOWS)
  701. outputEOL = "\r\n";
  702. else if (lineEndFormat == LINEEND_LINUX)
  703. outputEOL = "\n";
  704. else if (lineEndFormat == LINEEND_MACOLD)
  705. outputEOL = "\r";
  706. else
  707. outputEOL.clear();
  708. }
  709. FileEncoding ASConsole::readFile(const string& fileName_, stringstream& in) const
  710. {
  711. const int blockSize = 65536; // 64 KB
  712. ifstream fin(fileName_.c_str(), ios::binary);
  713. if (!fin)
  714. error("Cannot open input file", fileName_.c_str());
  715. char* data = new (nothrow) char[blockSize];
  716. if (data == nullptr)
  717. error("Cannot allocate memory for input file", fileName_.c_str());
  718. fin.read(data, blockSize);
  719. if (fin.bad())
  720. error("Cannot read input file", fileName_.c_str());
  721. size_t dataSize = static_cast<size_t>(fin.gcount());
  722. FileEncoding encoding = detectEncoding(data, dataSize);
  723. if (encoding == UTF_32BE || encoding == UTF_32LE)
  724. error(_("Cannot process UTF-32 encoding"), fileName_.c_str());
  725. bool firstBlock = true;
  726. bool isBigEndian = (encoding == UTF_16BE);
  727. while (dataSize != 0)
  728. {
  729. if (encoding == UTF_16LE || encoding == UTF_16BE)
  730. {
  731. // convert utf-16 to utf-8
  732. size_t utf8Size = utf8_16.utf8LengthFromUtf16(data, dataSize, isBigEndian);
  733. char* utf8Out = new (nothrow) char[utf8Size];
  734. if (utf8Out == nullptr)
  735. error("Cannot allocate memory for utf-8 conversion", fileName_.c_str());
  736. size_t utf8Len = utf8_16.utf16ToUtf8(data, dataSize, isBigEndian, firstBlock, utf8Out);
  737. assert(utf8Len == utf8Size);
  738. in << string(utf8Out, utf8Len);
  739. delete[] utf8Out;
  740. }
  741. else
  742. in << string(data, dataSize);
  743. fin.read(data, blockSize);
  744. if (fin.bad())
  745. error("Cannot read input file", fileName_.c_str());
  746. dataSize = static_cast<size_t>(fin.gcount());
  747. firstBlock = false;
  748. }
  749. fin.close();
  750. delete[] data;
  751. return encoding;
  752. }
  753. void ASConsole::setIgnoreExcludeErrors(bool state)
  754. { ignoreExcludeErrors = state; }
  755. void ASConsole::setIgnoreExcludeErrorsAndDisplay(bool state)
  756. { ignoreExcludeErrors = state; ignoreExcludeErrorsDisplay = state; }
  757. void ASConsole::setIsFormattedOnly(bool state)
  758. { isFormattedOnly = state; }
  759. void ASConsole::setIsQuiet(bool state)
  760. { isQuiet = state; }
  761. void ASConsole::setIsRecursive(bool state)
  762. { isRecursive = state; }
  763. void ASConsole::setIsDryRun(bool state)
  764. { isDryRun = state; }
  765. void ASConsole::setIsVerbose(bool state)
  766. { isVerbose = state; }
  767. void ASConsole::setNoBackup(bool state)
  768. { noBackup = state; }
  769. void ASConsole::setOptionsFileName(const string& name)
  770. { optionsFileName = name; }
  771. void ASConsole::setOrigSuffix(const string& suffix)
  772. { origSuffix = suffix; }
  773. void ASConsole::setPreserveDate(bool state)
  774. { preserveDate = state; }
  775. void ASConsole::setStdPathIn(const string& path)
  776. { stdPathIn = path; }
  777. void ASConsole::setStdPathOut(const string& path)
  778. { stdPathOut = path; }
  779. // set outputEOL variable
  780. void ASConsole::setOutputEOL(LineEndFormat lineEndFormat, const string& currentEOL)
  781. {
  782. if (lineEndFormat == LINEEND_DEFAULT)
  783. {
  784. outputEOL = currentEOL;
  785. if (prevEOL.empty())
  786. prevEOL = outputEOL;
  787. if (prevEOL != outputEOL)
  788. {
  789. lineEndsMixed = true;
  790. filesAreIdentical = false;
  791. prevEOL = outputEOL;
  792. }
  793. }
  794. else
  795. {
  796. prevEOL = currentEOL;
  797. if (prevEOL != outputEOL)
  798. filesAreIdentical = false;
  799. }
  800. }
  801. #ifdef _WIN32 // Windows specific
  802. /**
  803. * WINDOWS function to display the last system error.
  804. */
  805. void ASConsole::displayLastError()
  806. {
  807. LPSTR msgBuf;
  808. DWORD lastError = GetLastError();
  809. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  810. nullptr,
  811. lastError,
  812. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  813. (LPSTR) &msgBuf,
  814. 0,
  815. nullptr
  816. );
  817. // Display the string.
  818. (*errorStream) << "Error (" << lastError << ") " << msgBuf << endl;
  819. // Free the buffer.
  820. LocalFree(msgBuf);
  821. }
  822. /**
  823. * WINDOWS function to get the current directory.
  824. * NOTE: getenv("CD") does not work for Windows Vista.
  825. * The Windows function GetCurrentDirectory is used instead.
  826. *
  827. * @return The path of the current directory
  828. */
  829. string ASConsole::getCurrentDirectory(const string& fileName_) const
  830. {
  831. char currdir[MAX_PATH];
  832. currdir[0] = '\0';
  833. if (!GetCurrentDirectory(sizeof(currdir), currdir))
  834. error("Cannot find file", fileName_.c_str());
  835. return string(currdir);
  836. }
  837. /**
  838. * WINDOWS function to resolve wildcards and recurse into sub directories.
  839. * The fileName vector is filled with the path and names of files to process.
  840. *
  841. * @param directory The path of the directory to be processed.
  842. * @param wildcard The wildcard to be processed (e.g. *.cpp).
  843. */
  844. void ASConsole::getFileNames(const string& directory, const string& wildcard)
  845. {
  846. vector<string> subDirectory; // sub directories of directory
  847. WIN32_FIND_DATA findFileData; // for FindFirstFile and FindNextFile
  848. // Find the first file in the directory
  849. // Find will get at least "." and "..".
  850. string firstFile = directory + "\\*";
  851. HANDLE hFind = FindFirstFile(firstFile.c_str(), &findFileData);
  852. if (hFind == INVALID_HANDLE_VALUE)
  853. {
  854. // Error (3) The system cannot find the path specified.
  855. // Error (123) The filename, directory name, or volume label syntax is incorrect.
  856. // ::FindClose(hFind); before exiting
  857. displayLastError();
  858. error(_("Cannot open directory"), directory.c_str());
  859. }
  860. // save files and sub directories
  861. do
  862. {
  863. // skip hidden or read only
  864. if (findFileData.cFileName[0] == '.'
  865. || (findFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
  866. || (findFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
  867. continue;
  868. // is this a sub directory
  869. if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  870. {
  871. if (!isRecursive)
  872. continue;
  873. // if a sub directory and recursive, save sub directory
  874. string subDirectoryPath = directory + g_fileSeparator + findFileData.cFileName;
  875. if (isPathExclued(subDirectoryPath))
  876. printMsg(_("Exclude %s\n"), subDirectoryPath.substr(mainDirectoryLength));
  877. else
  878. subDirectory.emplace_back(subDirectoryPath);
  879. continue;
  880. }
  881. // save the file name
  882. string filePathName = directory + g_fileSeparator + findFileData.cFileName;
  883. // check exclude before wildcmp to avoid "unmatched exclude" error
  884. bool isExcluded = isPathExclued(filePathName);
  885. // save file name if wildcard match
  886. if (wildcmp(wildcard.c_str(), findFileData.cFileName))
  887. {
  888. if (isExcluded)
  889. printMsg(_("Exclude %s\n"), filePathName.substr(mainDirectoryLength));
  890. else
  891. fileName.emplace_back(filePathName);
  892. }
  893. }
  894. while (FindNextFile(hFind, &findFileData) != 0);
  895. // check for processing error
  896. ::FindClose(hFind);
  897. DWORD dwError = GetLastError();
  898. if (dwError != ERROR_NO_MORE_FILES)
  899. error("Error processing directory", directory.c_str());
  900. // recurse into sub directories
  901. // if not doing recursive subDirectory is empty
  902. for (unsigned i = 0; i < subDirectory.size(); i++)
  903. getFileNames(subDirectory[i], wildcard);
  904. return;
  905. }
  906. /**
  907. * WINDOWS function to format a number according to the current locale.
  908. * This formats positive integers only, no float.
  909. *
  910. * @param num The number to be formatted.
  911. * @param lcid The LCID of the locale to be used for testing.
  912. * @return The formatted number.
  913. */
  914. string ASConsole::getNumberFormat(int num, size_t lcid) const
  915. {
  916. #if defined(_MSC_VER) || defined(__MINGW32__) || defined(__BORLANDC__) || defined(__GNUC__)
  917. // Compilers that don't support C++ locales should still support this assert.
  918. // The C locale should be set but not the C++.
  919. // This function is not necessary if the C++ locale is set.
  920. // The locale().name() return value is not portable to all compilers.
  921. assert(locale().name() == "C");
  922. #endif
  923. // convert num to a string
  924. stringstream alphaNum;
  925. alphaNum << num;
  926. string number = alphaNum.str();
  927. if (useAscii)
  928. return number;
  929. // format the number using the Windows API
  930. if (lcid == 0)
  931. lcid = LOCALE_USER_DEFAULT;
  932. int outSize = ::GetNumberFormat(lcid, 0, number.c_str(), nullptr, nullptr, 0);
  933. char* outBuf = new (nothrow) char[outSize];
  934. if (outBuf == nullptr)
  935. return number;
  936. ::GetNumberFormat(lcid, 0, number.c_str(), nullptr, outBuf, outSize);
  937. string formattedNum(outBuf);
  938. delete[] outBuf;
  939. // remove the decimal
  940. int decSize = ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, nullptr, 0);
  941. char* decBuf = new (nothrow) char[decSize];
  942. if (decBuf == nullptr)
  943. return number;
  944. ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, decBuf, decSize);
  945. size_t i = formattedNum.rfind(decBuf);
  946. delete[] decBuf;
  947. if (i != string::npos)
  948. formattedNum.erase(i);
  949. if (!formattedNum.length())
  950. formattedNum = "0";
  951. return formattedNum;
  952. }
  953. /**
  954. * WINDOWS function to open a HTML file in the default browser.
  955. */
  956. void ASConsole::launchDefaultBrowser(const char* filePathIn /*nullptr*/) const
  957. {
  958. struct stat statbuf;
  959. const char* envPaths[] = { "PROGRAMFILES(X86)", "PROGRAMFILES" };
  960. size_t pathsLen = sizeof(envPaths) / sizeof(envPaths[0]);
  961. string htmlDefaultPath;
  962. for (size_t i = 0; i < pathsLen; i++)
  963. {
  964. const char* envPath = getenv(envPaths[i]);
  965. if (envPath == nullptr)
  966. continue;
  967. htmlDefaultPath = envPath;
  968. if (htmlDefaultPath.length() > 0
  969. && htmlDefaultPath[htmlDefaultPath.length() - 1] == g_fileSeparator)
  970. htmlDefaultPath.erase(htmlDefaultPath.length() - 1);
  971. htmlDefaultPath.append("\\AStyle\\doc");
  972. if (stat(htmlDefaultPath.c_str(), &statbuf) == 0 && statbuf.st_mode & S_IFDIR)
  973. break;
  974. }
  975. htmlDefaultPath.append("\\");
  976. // build file path
  977. string htmlFilePath;
  978. if (filePathIn == nullptr)
  979. htmlFilePath = htmlDefaultPath + "astyle.html";
  980. else
  981. {
  982. if (strpbrk(filePathIn, "\\/") == nullptr)
  983. htmlFilePath = htmlDefaultPath + filePathIn;
  984. else
  985. htmlFilePath = filePathIn;
  986. }
  987. standardizePath(htmlFilePath);
  988. if (stat(htmlFilePath.c_str(), &statbuf) != 0 || !(statbuf.st_mode & S_IFREG))
  989. {
  990. printf(_("Cannot open HTML file %s\n"), htmlFilePath.c_str());
  991. return;
  992. }
  993. SHELLEXECUTEINFO sei = { sizeof(sei), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  994. sei.fMask = SEE_MASK_FLAG_NO_UI;
  995. sei.lpVerb = "open";
  996. sei.lpFile = htmlFilePath.c_str();
  997. sei.nShow = SW_SHOWNORMAL;
  998. // browser open will be bypassed in test programs
  999. printf(_("Opening HTML documentation %s\n"), htmlFilePath.c_str());
  1000. if (!bypassBrowserOpen)
  1001. {
  1002. int ret = ShellExecuteEx(&sei);
  1003. if (!ret)
  1004. error(_("Command execute failure"), htmlFilePath.c_str());
  1005. }
  1006. }
  1007. #else // Linux specific
  1008. /**
  1009. * LINUX function to get the current directory.
  1010. * This is done if the fileName does not contain a path.
  1011. * It is probably from an editor sending a single file.
  1012. *
  1013. * @param fileName_ The filename is used only for the error message.
  1014. * @return The path of the current directory
  1015. */
  1016. string ASConsole::getCurrentDirectory(const string& fileName_) const
  1017. {
  1018. char* currdir = getenv("PWD");
  1019. if (currdir == nullptr)
  1020. error("Cannot find file", fileName_.c_str());
  1021. return string(currdir);
  1022. }
  1023. /**
  1024. * LINUX function to resolve wildcards and recurse into sub directories.
  1025. * The fileName vector is filled with the path and names of files to process.
  1026. *
  1027. * @param directory The path of the directory to be processed.
  1028. * @param wildcard The wildcard to be processed (e.g. *.cpp).
  1029. */
  1030. void ASConsole::getFileNames(const string& directory, const string& wildcard)
  1031. {
  1032. struct dirent* entry; // entry from readdir()
  1033. struct stat statbuf; // entry from stat()
  1034. vector<string> subDirectory; // sub directories of this directory
  1035. // errno is defined in <errno.h> and is set for errors in opendir, readdir, or stat
  1036. errno = 0;
  1037. DIR* dp = opendir(directory.c_str());
  1038. if (dp == nullptr)
  1039. error(_("Cannot open directory"), directory.c_str());
  1040. // save the first fileName entry for this recursion
  1041. const unsigned firstEntry = fileName.size();
  1042. // save files and sub directories
  1043. while ((entry = readdir(dp)) != nullptr)
  1044. {
  1045. // get file status
  1046. string entryFilepath = directory + g_fileSeparator + entry->d_name;
  1047. if (stat(entryFilepath.c_str(), &statbuf) != 0)
  1048. {
  1049. if (errno == EOVERFLOW) // file over 2 GB is OK
  1050. {
  1051. errno = 0;
  1052. continue;
  1053. }
  1054. perror("errno message");
  1055. error("Error getting file status in directory", directory.c_str());
  1056. }
  1057. // skip hidden or read only
  1058. if (entry->d_name[0] == '.' || !(statbuf.st_mode & S_IWUSR))
  1059. continue;
  1060. // if a sub directory and recursive, save sub directory
  1061. if (S_ISDIR(statbuf.st_mode) && isRecursive)
  1062. {
  1063. if (isPathExclued(entryFilepath))
  1064. printMsg(_("Exclude %s\n"), entryFilepath.substr(mainDirectoryLength));
  1065. else
  1066. subDirectory.emplace_back(entryFilepath);
  1067. continue;
  1068. }
  1069. // if a file, save file name
  1070. if (S_ISREG(statbuf.st_mode))
  1071. {
  1072. // check exclude before wildcmp to avoid "unmatched exclude" error
  1073. bool isExcluded = isPathExclued(entryFilepath);
  1074. // save file name if wildcard match
  1075. if (wildcmp(wildcard.c_str(), entry->d_name) != 0)
  1076. {
  1077. if (isExcluded)
  1078. printMsg(_("Exclude %s\n"), entryFilepath.substr(mainDirectoryLength));
  1079. else
  1080. fileName.emplace_back(entryFilepath);
  1081. }
  1082. }
  1083. }
  1084. if (closedir(dp) != 0)
  1085. {
  1086. perror("errno message");
  1087. error("Error reading directory", directory.c_str());
  1088. }
  1089. // sort the current entries for fileName
  1090. if (firstEntry < fileName.size())
  1091. sort(&fileName[firstEntry], &fileName[fileName.size()]);
  1092. // recurse into sub directories
  1093. // if not doing recursive, subDirectory is empty
  1094. if (subDirectory.size() > 1)
  1095. sort(subDirectory.begin(), subDirectory.end());
  1096. for (unsigned i = 0; i < subDirectory.size(); i++)
  1097. {
  1098. getFileNames(subDirectory[i], wildcard);
  1099. }
  1100. }
  1101. /**
  1102. * LINUX function to get locale information and call getNumberFormat.
  1103. * This formats positive integers only, no float.
  1104. *
  1105. * @param num The number to be formatted.
  1106. * size_t is for compatibility with the Windows function.
  1107. * @return The formatted number.
  1108. */
  1109. string ASConsole::getNumberFormat(int num, size_t /*lcid*/) const
  1110. {
  1111. #if defined(_MSC_VER) || defined(__MINGW32__) || defined(__BORLANDC__) || defined(__GNUC__)
  1112. // Compilers that don't support C++ locales should still support this assert.
  1113. // The C locale should be set but not the C++.
  1114. // This function is not necessary if the C++ locale is set.
  1115. // The locale().name() return value is not portable to all compilers.
  1116. assert(locale().name() == "C");
  1117. #endif
  1118. // get the locale info
  1119. struct lconv* lc;
  1120. lc = localeconv();
  1121. // format the number
  1122. return getNumberFormat(num, lc->grouping, lc->thousands_sep);
  1123. }
  1124. /**
  1125. * LINUX function to format a number according to the current locale.
  1126. * This formats positive integers only, no float.
  1127. *
  1128. * @param num The number to be formatted.
  1129. * @param groupingArg The grouping string from the locale.
  1130. * @param separator The thousands group separator from the locale.
  1131. * @return The formatted number.
  1132. */
  1133. string ASConsole::getNumberFormat(int num, const char* groupingArg, const char* separator) const
  1134. {
  1135. // convert num to a string
  1136. stringstream alphaNum;
  1137. alphaNum << num;
  1138. string number = alphaNum.str();
  1139. // format the number from right to left
  1140. string formattedNum;
  1141. size_t ig = 0; // grouping index
  1142. int grouping = groupingArg[ig];
  1143. int i = number.length();
  1144. // check for no grouping
  1145. if (grouping == 0)
  1146. grouping = number.length();
  1147. while (i > 0)
  1148. {
  1149. // extract a group of numbers
  1150. string group;
  1151. if (i < grouping)
  1152. group = number;
  1153. else
  1154. group = number.substr(i - grouping);
  1155. // update formatted number
  1156. formattedNum.insert(0, group);
  1157. i -= grouping;
  1158. if (i < 0)
  1159. i = 0;
  1160. if (i > 0)
  1161. formattedNum.insert(0, separator);
  1162. number.erase(i);
  1163. // update grouping
  1164. if (groupingArg[ig] != '\0'
  1165. && groupingArg[ig + 1] != '\0')
  1166. grouping = groupingArg[++ig];
  1167. }
  1168. return formattedNum;
  1169. }
  1170. /**
  1171. * LINUX function to open a HTML file in the default browser.
  1172. * Use xdg-open from freedesktop.org cross-desktop compatibility suite xdg-utils.
  1173. * see http://portland.freedesktop.org/wiki/
  1174. * This is installed on most modern distributions.
  1175. */
  1176. void ASConsole::launchDefaultBrowser(const char* filePathIn /*nullptr*/) const
  1177. {
  1178. struct stat statbuf;
  1179. string htmlDefaultPath = "/usr/share/doc/astyle/html/";
  1180. string htmlDefaultFile = "astyle.html";
  1181. // build file path
  1182. string htmlFilePath;
  1183. if (filePathIn == nullptr)
  1184. htmlFilePath = htmlDefaultPath + htmlDefaultFile;
  1185. else
  1186. {
  1187. if (strpbrk(filePathIn, "\\/") == nullptr)
  1188. htmlFilePath = htmlDefaultPath + filePathIn;
  1189. else
  1190. htmlFilePath = filePathIn;
  1191. }
  1192. standardizePath(htmlFilePath);
  1193. if (stat(htmlFilePath.c_str(), &statbuf) != 0 || !(statbuf.st_mode & S_IFREG))
  1194. {
  1195. printf(_("Cannot open HTML file %s\n"), htmlFilePath.c_str());
  1196. return;
  1197. }
  1198. // get search paths
  1199. const char* envPaths = getenv("PATH");
  1200. if (envPaths == nullptr)
  1201. envPaths = "?";
  1202. size_t envlen = strlen(envPaths);
  1203. char* paths = new char[envlen + 1];
  1204. strcpy(paths, envPaths);
  1205. // find xdg-open (usually in /usr/bin)
  1206. // Mac uses open instead
  1207. #ifdef __APPLE__
  1208. const char* fileOpen = "open";
  1209. #else
  1210. const char* fileOpen = "xdg-open";
  1211. #endif
  1212. string searchPath;
  1213. char* searchDir = strtok(paths, ":");
  1214. while (searchDir != nullptr)
  1215. {
  1216. searchPath = searchDir;
  1217. if (searchPath.length() > 0
  1218. && searchPath[searchPath.length() - 1] != g_fileSeparator)
  1219. searchPath.append(string(1, g_fileSeparator));
  1220. searchPath.append(fileOpen);
  1221. if (stat(searchPath.c_str(), &statbuf) == 0 && (statbuf.st_mode & S_IFREG))
  1222. break;
  1223. searchDir = strtok(nullptr, ":");
  1224. }
  1225. delete[] paths;
  1226. if (searchDir == nullptr)
  1227. error(_("Command is not installed"), fileOpen);
  1228. // browser open will be bypassed in test programs
  1229. printf(_("Opening HTML documentation %s\n"), htmlFilePath.c_str());
  1230. if (!bypassBrowserOpen)
  1231. {
  1232. execlp(fileOpen, fileOpen, htmlFilePath.c_str(), nullptr);
  1233. // execlp will NOT return if successful
  1234. error(_("Command execute failure"), fileOpen);
  1235. }
  1236. }
  1237. #endif // _WIN32
  1238. // get individual file names from the command-line file path
  1239. void ASConsole::getFilePaths(const string& filePath)
  1240. {
  1241. fileName.clear();
  1242. targetDirectory = string();
  1243. targetFilename = string();
  1244. // separate directory and file name
  1245. size_t separator = filePath.find_last_of(g_fileSeparator);
  1246. if (separator == string::npos)
  1247. {
  1248. // if no directory is present, use the currently active directory
  1249. targetDirectory = getCurrentDirectory(filePath);
  1250. targetFilename = filePath;
  1251. mainDirectoryLength = targetDirectory.length() + 1; // +1 includes trailing separator
  1252. }
  1253. else
  1254. {
  1255. targetDirectory = filePath.substr(0, separator);
  1256. targetFilename = filePath.substr(separator + 1);
  1257. mainDirectoryLength = targetDirectory.length() + 1; // +1 includes trailing separator
  1258. }
  1259. if (targetFilename.length() == 0)
  1260. {
  1261. fprintf(stderr, _("Missing filename in %s\n"), filePath.c_str());
  1262. error();
  1263. }
  1264. // check filename for wildcards
  1265. hasWildcard = false;
  1266. if (targetFilename.find_first_of("*?") != string::npos)
  1267. hasWildcard = true;
  1268. // clear exclude hits vector
  1269. size_t excludeHitsVectorSize = excludeHitsVector.size();
  1270. for (size_t ix = 0; ix < excludeHitsVectorSize; ix++)
  1271. excludeHitsVector[ix] = false;
  1272. // If the filename is not quoted on Linux, bash will replace the
  1273. // wildcard instead of passing it to the program.
  1274. if (isRecursive && !hasWildcard)
  1275. {
  1276. fprintf(stderr, "%s\n", _("Recursive option with no wildcard"));
  1277. #ifndef _WIN32
  1278. fprintf(stderr, "%s\n", _("Did you intend quote the filename"));
  1279. #endif
  1280. error();
  1281. }
  1282. // display directory name for wildcard processing
  1283. if (hasWildcard)
  1284. {
  1285. printSeparatingLine();
  1286. printMsg(_("Directory %s\n"), targetDirectory + g_fileSeparator + targetFilename);
  1287. }
  1288. // create a vector of paths and file names to process
  1289. if (hasWildcard || isRecursive)
  1290. getFileNames(targetDirectory, targetFilename);
  1291. else
  1292. {
  1293. // verify a single file is not a directory (needed on Linux)
  1294. string entryFilepath = targetDirectory + g_fileSeparator + targetFilename;
  1295. struct stat statbuf;
  1296. if (stat(entryFilepath.c_str(), &statbuf) == 0 && (statbuf.st_mode & S_IFREG))
  1297. fileName.emplace_back(entryFilepath);
  1298. }
  1299. // check for unprocessed excludes
  1300. bool excludeErr = false;
  1301. for (size_t ix = 0; ix < excludeHitsVector.size(); ix++)
  1302. {
  1303. if (!excludeHitsVector[ix])
  1304. {
  1305. excludeErr = true;
  1306. if (!ignoreExcludeErrorsDisplay)
  1307. {
  1308. if (ignoreExcludeErrors)
  1309. printMsg(_("Exclude (unmatched) %s\n"), excludeVector[ix]);
  1310. else
  1311. fprintf(stderr, _("Exclude (unmatched) %s\n"), excludeVector[ix].c_str());
  1312. }
  1313. else
  1314. {
  1315. if (!ignoreExcludeErrors)
  1316. fprintf(stderr, _("Exclude (unmatched) %s\n"), excludeVector[ix].c_str());
  1317. }
  1318. }
  1319. }
  1320. if (excludeErr && !ignoreExcludeErrors)
  1321. {
  1322. if (hasWildcard && !isRecursive)
  1323. fprintf(stderr, "%s\n", _("Did you intend to use --recursive"));
  1324. error();
  1325. }
  1326. // check if files were found (probably an input error if not)
  1327. if (fileName.empty())
  1328. {
  1329. fprintf(stderr, _("No file to process %s\n"), filePath.c_str());
  1330. if (hasWildcard && !isRecursive)
  1331. fprintf(stderr, "%s\n", _("Did you intend to use --recursive"));
  1332. error();
  1333. }
  1334. if (hasWildcard)
  1335. printSeparatingLine();
  1336. }
  1337. bool ASConsole::fileNameVectorIsEmpty() const
  1338. {
  1339. return fileNameVector.empty();
  1340. }
  1341. bool ASConsole::isOption(const string& arg, const char* op)
  1342. {
  1343. return arg.compare(op) == 0;
  1344. }
  1345. bool ASConsole::isOption(const string& arg, const char* a, const char* b)
  1346. {
  1347. return (isOption(arg, a) || isOption(arg, b));
  1348. }
  1349. bool ASConsole::isParamOption(const string& arg, const char* option)
  1350. {
  1351. bool retVal = arg.compare(0, strlen(option), option) == 0;
  1352. // if comparing for short option, 2nd char of arg must be numeric
  1353. if (retVal && strlen(option) == 1 && arg.length() > 1)
  1354. if (!isdigit((unsigned char)arg[1]))
  1355. retVal = false;
  1356. return retVal;
  1357. }
  1358. // compare a path to the exclude vector
  1359. // used for both directories and filenames
  1360. // updates the g_excludeHitsVector
  1361. // return true if a match
  1362. bool ASConsole::isPathExclued(const string& subPath)
  1363. {
  1364. bool retVal = false;
  1365. // read the exclude vector checking for a match
  1366. for (size_t i = 0; i < excludeVector.size(); i++)
  1367. {
  1368. string exclude = excludeVector[i];
  1369. if (subPath.length() < exclude.length())
  1370. continue;
  1371. size_t compareStart = subPath.length() - exclude.length();
  1372. // subPath compare must start with a directory name
  1373. if (compareStart > 0)
  1374. {
  1375. char lastPathChar = subPath[compareStart - 1];
  1376. if (lastPathChar != g_fileSeparator)
  1377. continue;
  1378. }
  1379. string compare = subPath.substr(compareStart);
  1380. if (!g_isCaseSensitive)
  1381. {
  1382. // make it case insensitive for Windows
  1383. for (size_t j = 0; j < compare.length(); j++)
  1384. compare[j] = (char)tolower(compare[j]);
  1385. for (size_t j = 0; j < exclude.length(); j++)
  1386. exclude[j] = (char)tolower(exclude[j]);
  1387. }
  1388. // compare sub directory to exclude data - must check them all
  1389. if (compare == exclude)
  1390. {
  1391. excludeHitsVector[i] = true;
  1392. retVal = true;
  1393. break;
  1394. }
  1395. }
  1396. return retVal;
  1397. }
  1398. void ASConsole::printHelp() const
  1399. {
  1400. cout << endl;
  1401. cout << " Artistic Style " << g_version << endl;
  1402. cout << " Maintained by: Jim Pattee\n";
  1403. cout << " Original Author: Tal Davidson\n";
  1404. cout << endl;
  1405. cout << "Usage:\n";
  1406. cout << "------\n";
  1407. cout << " astyle [OPTIONS] File1 File2 File3 [...]\n";
  1408. cout << endl;
  1409. cout << " astyle [OPTIONS] < Original > Beautified\n";
  1410. cout << endl;
  1411. cout << " When indenting a specific file, the resulting indented file RETAINS\n";
  1412. cout << " the original file-name. The original pre-indented file is renamed,\n";
  1413. cout << " with a suffix of \'.orig\' added to the original filename.\n";
  1414. cout << endl;
  1415. cout << " Wildcards (* and ?) may be used in the filename.\n";
  1416. cout << " A \'recursive\' option can process directories recursively.\n";
  1417. cout << endl;
  1418. cout << " By default, astyle is set up to indent with four spaces per indent,\n";
  1419. cout << " a maximal indentation of 40 spaces inside continuous statements,\n";
  1420. cout << " a minimum indentation of eight spaces inside conditional statements,\n";
  1421. cout << " and NO formatting options.\n";
  1422. cout << endl;
  1423. cout << "Options:\n";
  1424. cout << "--------\n";
  1425. cout << " This program follows the usual GNU command line syntax.\n";
  1426. cout << " Long options (starting with '--') must be written one at a time.\n";
  1427. cout << " Short options (starting with '-') may be appended together.\n";
  1428. cout << " Thus, -bps4 is the same as -b -p -s4.\n";
  1429. cout << endl;
  1430. cout << "Options File:\n";
  1431. cout << "-------------\n";
  1432. cout << " Artistic Style looks for a default options file in the\n";
  1433. cout << " following order:\n";
  1434. cout << " 1. The contents of the ARTISTIC_STYLE_OPTIONS environment\n";
  1435. cout << " variable if it exists.\n";
  1436. cout << " 2. The file called .astylerc in the directory pointed to by the\n";
  1437. cout << " HOME environment variable ( i.e. $HOME/.astylerc ).\n";
  1438. cout << " 3. The file called astylerc in the directory pointed to by the\n";
  1439. cout << " USERPROFILE environment variable (i.e. %USERPROFILE%\\astylerc).\n";
  1440. cout << " If a default options file is found, the options in this file will\n";
  1441. cout << " be parsed BEFORE the command-line options.\n";
  1442. cout << " Long options within the default option file may be written without\n";
  1443. cout << " the preliminary '--'.\n";
  1444. cout << endl;
  1445. cout << "Disable Formatting:\n";
  1446. cout << "-------------------\n";
  1447. cout << " Disable Block\n";
  1448. cout << " Blocks of code can be disabled with the comment tags *INDENT-OFF*\n";
  1449. cout << " and *INDENT-ON*. It must be contained in a one-line comment.\n";
  1450. cout << endl;
  1451. cout << " Disable Line\n";
  1452. cout << " Padding of operators can be disabled on a single line using the\n";
  1453. cout << " comment tag *NOPAD*. It must be contained in a line-end comment.\n";
  1454. cout << endl;
  1455. cout << "Brace Style Options:\n";
  1456. cout << "--------------------\n";
  1457. cout << " default brace style\n";
  1458. cout << " If no brace style is requested, the opening braces will not be\n";
  1459. cout << " changed and closing braces will be broken from the preceding line.\n";
  1460. cout << endl;
  1461. cout << " --style=allman OR --style=bsd OR --style=break OR -A1\n";
  1462. cout << " Allman style formatting/indenting.\n";
  1463. cout << " Broken braces.\n";
  1464. cout << endl;
  1465. cout << " --style=java OR --style=attach OR -A2\n";
  1466. cout << " Java style formatting/indenting.\n";
  1467. cout << " Attached braces.\n";
  1468. cout << endl;
  1469. cout << " --style=kr OR --style=k&r OR --style=k/r OR -A3\n";
  1470. cout << " Kernighan & Ritchie style formatting/indenting.\n";
  1471. cout << " Linux braces.\n";
  1472. cout << endl;
  1473. cout << " --style=stroustrup OR -A4\n";
  1474. cout << " Stroustrup style formatting/indenting.\n";
  1475. cout << " Linux braces.\n";
  1476. cout << endl;
  1477. cout << " --style=whitesmith OR -A5\n";
  1478. cout << " Whitesmith style formatting/indenting.\n";
  1479. cout << " Broken, indented braces.\n";
  1480. cout << " Indented class blocks and switch blocks.\n";
  1481. cout << endl;
  1482. cout << " --style=vtk OR -A15\n";
  1483. cout << " VTK style formatting/indenting.\n";
  1484. cout << " Broken, indented braces except for the opening braces.\n";
  1485. cout << endl;
  1486. cout << " --style=banner OR -A6\n";
  1487. cout << " Banner style formatting/indenting.\n";
  1488. cout << " Attached, indented braces.\n";
  1489. cout << endl;
  1490. cout << " --style=gnu OR -A7\n";
  1491. cout << " GNU style formatting/indenting.\n";
  1492. cout << " Broken braces, indented blocks.\n";
  1493. cout << endl;
  1494. cout << " --style=linux OR --style=knf OR -A8\n";
  1495. cout << " Linux style formatting/indenting.\n";
  1496. cout << " Linux braces, minimum conditional indent is one-half indent.\n";
  1497. cout << endl;
  1498. cout << " --style=horstmann OR --style=run-in OR -A9\n";
  1499. cout << " Horstmann style formatting/indenting.\n";
  1500. cout << " Run-in braces, indented switches.\n";
  1501. cout << endl;
  1502. cout << " --style=1tbs OR --style=otbs OR -A10\n";
  1503. cout << " One True Brace Style formatting/indenting.\n";
  1504. cout << " Linux braces, add braces to all conditionals.\n";
  1505. cout << endl;
  1506. cout << " --style=google OR -A14\n";
  1507. cout << " Google style formatting/indenting.\n";
  1508. cout << " Attached braces, indented class modifiers.\n";
  1509. cout << endl;
  1510. cout << " --style=mozilla OR -A16\n";
  1511. cout << " Mozilla style formatting/indenting.\n";
  1512. cout << " Linux braces, with broken braces for structs and enums,\n";
  1513. cout << " and attached braces for namespaces.\n";
  1514. cout << endl;
  1515. cout << " --style=pico OR -A11\n";
  1516. cout << " Pico style formatting/indenting.\n";
  1517. cout << " Run-in opening braces and attached closing braces.\n";
  1518. cout << " Uses keep one line blocks and keep one line statements.\n";
  1519. cout << endl;
  1520. cout << " --style=lisp OR -A12\n";
  1521. cout << " Lisp style formatting/indenting.\n";
  1522. cout << " Attached opening braces and attached closing braces.\n";
  1523. cout << " Uses keep one line statements.\n";
  1524. cout << endl;
  1525. cout << "Tab Options:\n";
  1526. cout << "------------\n";
  1527. cout << " default indent option\n";
  1528. cout << " If no indentation option is set, the default\n";
  1529. cout << " option of 4 spaces per indent will be used.\n";
  1530. cout << endl;
  1531. cout << " --indent=spaces=# OR -s#\n";
  1532. cout << " Indent using # spaces per indent. Not specifying #\n";
  1533. cout << " will result in a default of 4 spaces per indent.\n";
  1534. cout << endl;
  1535. cout << " --indent=tab OR --indent=tab=# OR -t OR -t#\n";
  1536. cout << " Indent using tab characters, assuming that each\n";
  1537. cout << " indent is # spaces long. Not specifying # will result\n";
  1538. cout << " in a default assumption of 4 spaces per indent.\n";
  1539. cout << endl;
  1540. cout << " --indent=force-tab=# OR -T#\n";
  1541. cout << " Indent using tab characters, assuming that each\n";
  1542. cout << " indent is # spaces long. Force tabs to be used in areas\n";
  1543. cout << " AStyle would prefer to use spaces.\n";
  1544. cout << endl;
  1545. cout << " --indent=force-tab-x=# OR -xT#\n";
  1546. cout << " Allows the tab length to be set to a length that is different\n";
  1547. cout << " from the indent length. This may cause the indentation to be\n";
  1548. cout << " a mix of both spaces and tabs. This option sets the tab length.\n";
  1549. cout << endl;
  1550. cout << "Brace Modify Options:\n";
  1551. cout << "---------------------\n";
  1552. cout << " --attach-namespaces OR -xn\n";
  1553. cout << " Attach braces to a namespace statement.\n";
  1554. cout << endl;
  1555. cout << " --attach-classes OR -xc\n";
  1556. cout << " Attach braces to a class statement.\n";
  1557. cout << endl;
  1558. cout << " --attach-inlines OR -xl\n";
  1559. cout << " Attach braces to class inline function definitions.\n";
  1560. cout << endl;
  1561. cout << " --attach-extern-c OR -xk\n";
  1562. cout << " Attach braces to an extern \"C\" statement.\n";
  1563. cout << endl;
  1564. cout << " --attach-closing-while OR -xV\n";
  1565. cout << " Attach closing while of do-while to the closing brace.\n";
  1566. cout << endl;
  1567. cout << "Indentation Options:\n";
  1568. cout << "--------------------\n";
  1569. cout << " --indent-classes OR -C\n";
  1570. cout << " Indent 'class' blocks so that the entire block is indented.\n";
  1571. cout << endl;
  1572. cout << " --indent-modifiers OR -xG\n";
  1573. cout << " Indent 'class' access modifiers, 'public:', 'protected:' or\n";
  1574. cout << " 'private:', one half indent. The rest of the class is not\n";
  1575. cout << " indented. \n";
  1576. cout << endl;
  1577. cout << " --indent-switches OR -S\n";
  1578. cout << " Indent 'switch' blocks, so that the inner 'case XXX:'\n";
  1579. cout << " headers are indented in relation to the switch block.\n";
  1580. cout << endl;
  1581. cout << " --indent-cases OR -K\n";
  1582. cout << " Indent case blocks from the 'case XXX:' headers.\n";
  1583. cout << " Case statements not enclosed in blocks are NOT indented.\n";
  1584. cout << endl;
  1585. cout << " --indent-namespaces OR -N\n";
  1586. cout << " Indent the contents of namespace blocks.\n";
  1587. cout << endl;
  1588. cout << " --indent-after-parens OR -xU\n";
  1589. cout << " Indent, instead of align, continuation lines following lines\n";
  1590. cout << " that contain an opening paren '(' or an assignment '='. \n";
  1591. cout << endl;
  1592. cout << " --indent-continuation=# OR -xt#\n";
  1593. cout << " Indent continuation lines an additional # indents.\n";
  1594. cout << " The valid values are 0 thru 4 indents.\n";
  1595. cout << " The default value is 1 indent.\n";
  1596. cout << endl;
  1597. cout << " --indent-labels OR -L\n";
  1598. cout << " Indent labels so that they appear one indent less than\n";
  1599. cout << " the current indentation level, rather than being\n";
  1600. cout << " flushed completely to the left (which is the default).\n";
  1601. cout << endl;
  1602. cout << " --indent-preproc-block OR -xW\n";
  1603. cout << " Indent preprocessor blocks at brace level 0.\n";
  1604. cout << " Without this option the preprocessor block is not indented.\n";
  1605. cout << endl;
  1606. cout << " --indent-preproc-cond OR -xw\n";
  1607. cout << " Indent preprocessor conditional statements #if/#else/#endif\n";
  1608. cout << " to the same level as the source code.\n";
  1609. cout << endl;
  1610. cout << " --indent-preproc-define OR -w\n";
  1611. cout << " Indent multi-line preprocessor #define statements.\n";
  1612. cout << endl;
  1613. cout << " --indent-col1-comments OR -Y\n";
  1614. cout << " Indent line comments that start in column one.\n";
  1615. cout << endl;
  1616. cout << " --min-conditional-indent=# OR -m#\n";
  1617. cout << " Indent a minimal # spaces in a continuous conditional\n";
  1618. cout << " belonging to a conditional header.\n";
  1619. cout << " The valid values are:\n";
  1620. cout << " 0 - no minimal indent.\n";
  1621. cout << " 1 - indent at least one additional indent.\n";
  1622. cout << " 2 - indent at least two additional indents.\n";
  1623. cout << " 3 - indent at least one-half an additional indent.\n";
  1624. cout << " The default value is 2, two additional indents.\n";
  1625. cout << endl;
  1626. cout << " --max-continuation-indent=# OR -M#\n";
  1627. cout << " Indent a maximal # spaces in a continuation line,\n";
  1628. cout << " relative to the previous line.\n";
  1629. cout << " The valid values are 40 thru 120.\n";
  1630. cout << " The default value is 40.\n";
  1631. cout << endl;
  1632. cout << "Padding Options:\n";
  1633. cout << "----------------\n";
  1634. cout << " --break-blocks OR -f\n";
  1635. cout << " Insert empty lines around unrelated blocks, labels, classes, ...\n";
  1636. cout << endl;
  1637. cout << " --break-blocks=all OR -F\n";
  1638. cout << " Like --break-blocks, except also insert empty lines \n";
  1639. cout << " around closing headers (e.g. 'else', 'catch', ...).\n";
  1640. cout << endl;
  1641. cout << " --pad-oper OR -p\n";
  1642. cout << " Insert space padding around operators.\n";
  1643. cout << endl;
  1644. cout << " --pad-comma OR -xg\n";
  1645. cout << " Insert space padding after commas.\n";
  1646. cout << endl;
  1647. cout << " --pad-paren OR -P\n";
  1648. cout << " Insert space padding around parenthesis on both the outside\n";
  1649. cout << " and the inside.\n";
  1650. cout << endl;
  1651. cout << " --pad-paren-out OR -d\n";
  1652. cout << " Insert space padding around parenthesis on the outside only.\n";
  1653. cout << endl;
  1654. cout << " --pad-first-paren-out OR -xd\n";
  1655. cout << " Insert space padding around first parenthesis in a series on\n";
  1656. cout << " the outside only.\n";
  1657. cout << endl;
  1658. cout << " --pad-paren-in OR -D\n";
  1659. cout << " Insert space padding around parenthesis on the inside only.\n";
  1660. cout << endl;
  1661. cout << " --pad-header OR -H\n";
  1662. cout << " Insert space padding after paren headers (e.g. 'if', 'for'...).\n";
  1663. cout << endl;
  1664. cout << " --unpad-paren OR -U\n";
  1665. cout << " Remove unnecessary space padding around parenthesis. This\n";
  1666. cout << " can be used in combination with the 'pad' options above.\n";
  1667. cout << endl;
  1668. cout << " --delete-empty-lines OR -xd\n";
  1669. cout << " Delete empty lines within a function or method.\n";
  1670. cout << " It will NOT delete lines added by the break-blocks options.\n";
  1671. cout << endl;
  1672. cout << " --fill-empty-lines OR -E\n";
  1673. cout << " Fill empty lines with the white space of their\n";
  1674. cout << " previous lines.\n";
  1675. cout << endl;
  1676. cout << " --align-pointer=type OR -k1\n";
  1677. cout << " --align-pointer=middle OR -k2\n";
  1678. cout << " --align-pointer=name OR -k3\n";
  1679. cout << " Attach a pointer or reference operator (*, &, or ^) to either\n";
  1680. cout << " the operator type (left), middle, or operator name (right).\n";
  1681. cout << " To align the reference separately use --align-reference.\n";
  1682. cout << endl;
  1683. cout << " --align-reference=none OR -W0\n";
  1684. cout << " --align-reference=type OR -W1\n";
  1685. cout << " --align-reference=middle OR -W2\n";
  1686. cout << " --align-reference=name OR -W3\n";
  1687. cout << " Attach a reference operator (&) to either\n";
  1688. cout << " the operator type (left), middle, or operator name (right).\n";
  1689. cout << " If not set, follow pointer alignment.\n";
  1690. cout << endl;
  1691. cout << "Formatting Options:\n";
  1692. cout << "-------------------\n";
  1693. cout << " --break-closing-braces OR -y\n";
  1694. cout << " Break braces before closing headers (e.g. 'else', 'catch', ...).\n";
  1695. cout << " Use with --style=java, --style=kr, --style=stroustrup,\n";
  1696. cout << " --style=linux, or --style=1tbs.\n";
  1697. cout << endl;
  1698. cout << " --break-elseifs OR -e\n";
  1699. cout << " Break 'else if()' statements into two different lines.\n";
  1700. cout << endl;
  1701. cout << " --break-one-line-headers OR -xb\n";
  1702. cout << " Break one line headers (e.g. 'if', 'while', 'else', ...) from a\n";
  1703. cout << " statement residing on the same line.\n";
  1704. cout << endl;
  1705. cout << " --add-braces OR -j\n";
  1706. cout << " Add braces to unbraced one line conditional statements.\n";
  1707. cout << endl;
  1708. cout << " --add-one-line-braces OR -J\n";
  1709. cout << " Add one line braces to unbraced one line conditional\n";
  1710. cout << " statements.\n";
  1711. cout << endl;
  1712. cout << " --remove-braces OR -xj\n";
  1713. cout << " Remove braces from a braced one line conditional statements.\n";
  1714. cout << endl;
  1715. cout << " --keep-one-line-blocks OR -O\n";
  1716. cout << " Don't break blocks residing completely on one line.\n";
  1717. cout << endl;
  1718. cout << " --keep-one-line-statements OR -o\n";
  1719. cout << " Don't break lines containing multiple statements into\n";
  1720. cout << " multiple single-statement lines.\n";
  1721. cout << endl;
  1722. cout << " --convert-tabs OR -c\n";
  1723. cout << " Convert tabs to the appropriate number of spaces.\n";
  1724. cout << endl;
  1725. cout << " --close-templates OR -xy\n";
  1726. cout << " Close ending angle brackets on template definitions.\n";
  1727. cout << endl;
  1728. cout << " --remove-comment-prefix OR -xp\n";
  1729. cout << " Remove the leading '*' prefix on multi-line comments and\n";
  1730. cout << " indent the comment text one indent.\n";
  1731. cout << endl;
  1732. cout << " --max-code-length=# OR -xC#\n";
  1733. cout << " --break-after-logical OR -xL\n";
  1734. cout << " max-code-length=# will break the line if it exceeds more than\n";
  1735. cout << " # characters. The valid values are 50 thru 200.\n";
  1736. cout << " If the line contains logical conditionals they will be placed\n";
  1737. cout << " first on the new line. The option break-after-logical will\n";
  1738. cout << " cause the logical conditional to be placed last on the\n";
  1739. cout << " previous line.\n";
  1740. cout << endl;
  1741. cout << " --mode=c\n";
  1742. cout << " Indent a C or C++ source file (this is the default).\n";
  1743. cout << endl;
  1744. cout << " --mode=java\n";
  1745. cout << " Indent a Java source file.\n";
  1746. cout << endl;
  1747. cout << " --mode=cs\n";
  1748. cout << " Indent a C# source file.\n";
  1749. cout << endl;
  1750. cout << "Objective-C Options:\n";
  1751. cout << "--------------------\n";
  1752. cout << " --pad-method-prefix OR -xQ\n";
  1753. cout << " Insert space padding after the '-' or '+' Objective-C\n";
  1754. cout << " method prefix.\n";
  1755. cout << endl;
  1756. cout << " --unpad-method-prefix OR -xR\n";
  1757. cout << " Remove all space padding after the '-' or '+' Objective-C\n";
  1758. cout << " method prefix.\n";
  1759. cout << endl;
  1760. cout << " --pad-return-type OR -xq\n";
  1761. cout << " Insert space padding after the Objective-C return type.\n";
  1762. cout << endl;
  1763. cout << " --unpad-return-type OR -xr\n";
  1764. cout << " Remove all space padding after the Objective-C return type.\n";
  1765. cout << endl;
  1766. cout << " --pad-param-type OR -xS\n";
  1767. cout << " Insert space padding after the Objective-C return type.\n";
  1768. cout << endl;
  1769. cout << " --unpad-param-type OR -xs\n";
  1770. cout << " Remove all space padding after the Objective-C return type.\n";
  1771. cout << endl;
  1772. cout << " --align-method-colon OR -xM\n";
  1773. cout << " Align the colons in an Objective-C method definition.\n";
  1774. cout << endl;
  1775. cout << " --pad-method-colon=none OR -xP\n";
  1776. cout << " --pad-method-colon=all OR -xP1\n";
  1777. cout << " --pad-method-colon=after OR -xP2\n";
  1778. cout << " --pad-method-colon=before OR -xP3\n";
  1779. cout << " Add or remove space padding before or after the colons in an\n";
  1780. cout << " Objective-C method call.\n";
  1781. cout << endl;
  1782. cout << "Other Options:\n";
  1783. cout << "--------------\n";
  1784. cout << " --suffix=####\n";
  1785. cout << " Append the suffix #### instead of '.orig' to original filename.\n";
  1786. cout << endl;
  1787. cout << " --suffix=none OR -n\n";
  1788. cout << " Do not retain a backup of the original file.\n";
  1789. cout << endl;
  1790. cout << " --recursive OR -r OR -R\n";
  1791. cout << " Process subdirectories recursively.\n";
  1792. cout << endl;
  1793. cout << " --dry-run\n";
  1794. cout << " Perform a trial run with no changes made to check for formatting.\n";
  1795. cout << endl;
  1796. cout << " --exclude=####\n";
  1797. cout << " Specify a file or directory #### to be excluded from processing.\n";
  1798. cout << endl;
  1799. cout << " --ignore-exclude-errors OR -i\n";
  1800. cout << " Allow processing to continue if there are errors in the exclude=####\n";
  1801. cout << " options. It will display the unmatched excludes.\n";
  1802. cout << endl;
  1803. cout << " --ignore-exclude-errors-x OR -xi\n";
  1804. cout << " Allow processing to continue if there are errors in the exclude=####\n";
  1805. cout << " options. It will NOT display the unmatched excludes.\n";
  1806. cout << endl;
  1807. cout << " --errors-to-stdout OR -X\n";
  1808. cout << " Print errors and help information to standard-output rather than\n";
  1809. cout << " to standard-error.\n";
  1810. cout << endl;
  1811. cout << " --preserve-date OR -Z\n";
  1812. cout << " Preserve the original file's date and time modified. The time\n";
  1813. cout << " modified will be changed a few micro seconds to force a compile.\n";
  1814. cout << endl;
  1815. cout << " --verbose OR -v\n";
  1816. cout << " Verbose mode. Extra informational messages will be displayed.\n";
  1817. cout << endl;
  1818. cout << " --formatted OR -Q\n";
  1819. cout << " Formatted display mode. Display only the files that have been\n";
  1820. cout << " formatted.\n";
  1821. cout << endl;
  1822. cout << " --quiet OR -q\n";
  1823. cout << " Quiet mode. Suppress all output except error messages.\n";
  1824. cout << endl;
  1825. cout << " --lineend=windows OR -z1\n";
  1826. cout << " --lineend=linux OR -z2\n";
  1827. cout << " --lineend=macold OR -z3\n";
  1828. cout << " Force use of the specified line end style. Valid options\n";
  1829. cout << " are windows (CRLF), linux (LF), and macold (CR).\n";
  1830. cout << endl;
  1831. cout << "Command Line Only:\n";
  1832. cout << "------------------\n";
  1833. cout << " --options=####\n";
  1834. cout << " Specify an options file #### to read and use.\n";
  1835. cout << endl;
  1836. cout << " --options=none\n";
  1837. cout << " Disable the default options file.\n";
  1838. cout << " Only the command-line parameters will be used.\n";
  1839. cout << endl;
  1840. cout << " --ascii OR -I\n";
  1841. cout << " The displayed output will be ascii characters only.\n";
  1842. cout << endl;
  1843. cout << " --version OR -V\n";
  1844. cout << " Print version number.\n";
  1845. cout << endl;
  1846. cout << " --help OR -h OR -?\n";
  1847. cout << " Print this help message.\n";
  1848. cout << endl;
  1849. cout << " --html OR -!\n";
  1850. cout << " Open the HTML help file \"astyle.html\" in the default browser.\n";
  1851. cout << " The documentation must be installed in the standard install path.\n";
  1852. cout << endl;
  1853. cout << " --html=####\n";
  1854. cout << " Open a HTML help file in the default browser using the file path\n";
  1855. cout << " ####. The path may include a directory path and a file name, or a\n";
  1856. cout << " file name only. Paths containing spaces must be enclosed in quotes.\n";
  1857. cout << endl;
  1858. cout << endl;
  1859. }
  1860. /**
  1861. * Process files in the fileNameVector.
  1862. */
  1863. void ASConsole::processFiles()
  1864. {
  1865. if (isVerbose)
  1866. printVerboseHeader();
  1867. clock_t startTime = clock(); // start time of file formatting
  1868. // loop thru input fileNameVector and process the files
  1869. for (size_t i = 0; i < fileNameVector.size(); i++)
  1870. {
  1871. getFilePaths(fileNameVector[i]);
  1872. // loop thru fileName vector formatting the files
  1873. for (size_t j = 0; j < fileName.size(); j++)
  1874. formatFile(fileName[j]);
  1875. }
  1876. // files are processed, display stats
  1877. if (isVerbose)
  1878. printVerboseStats(startTime);
  1879. }
  1880. // process options from the command line and options file
  1881. // build the vectors fileNameVector, excludeVector, optionsVector, and fileOptionsVector
  1882. void ASConsole::processOptions(const vector<string>& argvOptions)
  1883. {
  1884. string arg;
  1885. bool ok = true;
  1886. bool shouldParseOptionsFile = true;
  1887. // get command line options
  1888. for (size_t i = 0; i < argvOptions.size(); i++)
  1889. {
  1890. arg = argvOptions[i];
  1891. if ( isOption(arg, "-I" )
  1892. || isOption(arg, "--ascii") )
  1893. {
  1894. useAscii = true;
  1895. setlocale(LC_ALL, "C"); // use English decimal indicator
  1896. localizer.setLanguageFromName("en");
  1897. }
  1898. else if ( isOption(arg, "--options=none") )
  1899. {
  1900. shouldParseOptionsFile = false;
  1901. }
  1902. else if ( isParamOption(arg, "--options=") )
  1903. {
  1904. optionsFileName = getParam(arg, "--options=");
  1905. optionsFileRequired = true;
  1906. if (optionsFileName.empty())
  1907. setOptionsFileName(" ");
  1908. }
  1909. else if ( isOption(arg, "-h")
  1910. || isOption(arg, "--help")
  1911. || isOption(arg, "-?") )
  1912. {
  1913. printHelp();
  1914. exit(EXIT_SUCCESS);
  1915. }
  1916. else if ( isOption(arg, "-!")
  1917. || isOption(arg, "--html") )
  1918. {
  1919. launchDefaultBrowser();
  1920. exit(EXIT_SUCCESS);
  1921. }
  1922. else if ( isParamOption(arg, "--html=") )
  1923. {
  1924. string htmlFilePath = getParam(arg, "--html=");
  1925. launchDefaultBrowser(htmlFilePath.c_str());
  1926. exit(EXIT_SUCCESS);
  1927. }
  1928. else if ( isOption(arg, "-V" )
  1929. || isOption(arg, "--version") )
  1930. {
  1931. printf("Artistic Style Version %s\n", g_version);
  1932. exit(EXIT_SUCCESS);
  1933. }
  1934. else if (arg[0] == '-')
  1935. {
  1936. optionsVector.emplace_back(arg);
  1937. }
  1938. else // file-name
  1939. {
  1940. standardizePath(arg);
  1941. fileNameVector.emplace_back(arg);
  1942. }
  1943. }
  1944. // get options file path and name
  1945. if (shouldParseOptionsFile)
  1946. {
  1947. if (optionsFileName.empty())
  1948. {
  1949. char* env = getenv("ARTISTIC_STYLE_OPTIONS");
  1950. if (env != nullptr)
  1951. setOptionsFileName(env);
  1952. }
  1953. if (optionsFileName.empty())
  1954. {
  1955. char* env = getenv("HOME");
  1956. if (env != nullptr)
  1957. setOptionsFileName(string(env) + "/.astylerc");
  1958. }
  1959. if (optionsFileName.empty())
  1960. {
  1961. char* env = getenv("USERPROFILE");
  1962. if (env != nullptr)
  1963. setOptionsFileName(string(env) + "/astylerc");
  1964. }
  1965. if (!optionsFileName.empty())
  1966. standardizePath(optionsFileName);
  1967. }
  1968. // create the options file vector and parse the options for errors
  1969. ASOptions options(formatter, *this);
  1970. if (!optionsFileName.empty())
  1971. {
  1972. ifstream optionsIn(optionsFileName.c_str());
  1973. if (optionsIn)
  1974. {
  1975. options.importOptions(optionsIn, fileOptionsVector);
  1976. ok = options.parseOptions(fileOptionsVector,
  1977. string(_("Invalid option file options:")));
  1978. }
  1979. else
  1980. {
  1981. if (optionsFileRequired)
  1982. error(_("Cannot open options file"), optionsFileName.c_str());
  1983. optionsFileName.clear();
  1984. }
  1985. optionsIn.close();
  1986. }
  1987. if (!ok)
  1988. {
  1989. (*errorStream) << options.getOptionErrors() << endl;
  1990. (*errorStream) << _("For help on options type 'astyle -h'") << endl;
  1991. error();
  1992. }
  1993. // parse the command line options vector for errors
  1994. ok = options.parseOptions(optionsVector,
  1995. string(_("Invalid command line options:")));
  1996. if (!ok)
  1997. {
  1998. (*errorStream) << options.getOptionErrors() << endl;
  1999. (*errorStream) << _("For help on options type 'astyle -h'") << endl;
  2000. error();
  2001. }
  2002. }
  2003. // remove a file and check for an error
  2004. void ASConsole::removeFile(const char* fileName_, const char* errMsg) const
  2005. {
  2006. if (remove(fileName_) != 0)
  2007. {
  2008. if (errno == ENOENT) // no file is OK
  2009. errno = 0;
  2010. if (errno)
  2011. {
  2012. perror("errno message");
  2013. error(errMsg, fileName_);
  2014. }
  2015. }
  2016. }
  2017. // rename a file and check for an error
  2018. void ASConsole::renameFile(const char* oldFileName, const char* newFileName, const char* errMsg) const
  2019. {
  2020. int result = rename(oldFileName, newFileName);
  2021. if (result != 0)
  2022. {
  2023. // if file still exists the remove needs more time - retry
  2024. if (errno == EEXIST)
  2025. {
  2026. errno = 0;
  2027. waitForRemove(newFileName);
  2028. result = rename(oldFileName, newFileName);
  2029. }
  2030. if (result != 0)
  2031. {
  2032. perror("errno message");
  2033. error(errMsg, oldFileName);
  2034. }
  2035. }
  2036. }
  2037. // make sure file separators are correct type (Windows or Linux)
  2038. // remove ending file separator
  2039. // remove beginning file separator if requested and NOT a complete file path
  2040. void ASConsole::standardizePath(string& path, bool removeBeginningSeparator /*false*/) const
  2041. {
  2042. #ifdef __VMS
  2043. struct FAB fab;
  2044. struct NAML naml;
  2045. char less[NAML$C_MAXRSS];
  2046. char sess[NAM$C_MAXRSS];
  2047. int r0_status;
  2048. // If we are on a VMS system, translate VMS style filenames to unix
  2049. // style.
  2050. fab = cc$rms_fab;
  2051. fab.fab$l_fna = (char*) -1; // *NOPAD*
  2052. fab.fab$b_fns = 0;
  2053. fab.fab$l_naml = &naml;
  2054. naml = cc$rms_naml;
  2055. strcpy(sess, path.c_str());
  2056. naml.naml$l_long_filename = (char*)sess;
  2057. naml.naml$l_long_filename_size = path.length();
  2058. naml.naml$l_long_expand = less;
  2059. naml.naml$l_long_expand_alloc = sizeof(less);
  2060. naml.naml$l_esa = sess;
  2061. naml.naml$b_ess = sizeof(sess);
  2062. naml.naml$v_no_short_upcase = 1;
  2063. r0_status = sys$parse(&fab);
  2064. if (r0_status == RMS$_SYN)
  2065. {
  2066. error("File syntax error", path.c_str());
  2067. }
  2068. else
  2069. {
  2070. if (!$VMS_STATUS_SUCCESS(r0_status))
  2071. {
  2072. (void)lib$signal (r0_status);
  2073. }
  2074. }
  2075. less[naml.naml$l_long_expand_size - naml.naml$b_ver] = '\0';
  2076. sess[naml.naml$b_esl - naml.naml$b_ver] = '\0';
  2077. if (naml.naml$l_long_expand_size > naml.naml$b_esl)
  2078. {
  2079. path = decc$translate_vms (less);
  2080. }
  2081. else
  2082. {
  2083. path = decc$translate_vms(sess);
  2084. }
  2085. #endif /* __VMS */
  2086. // make sure separators are correct type (Windows or Linux)
  2087. for (size_t i = 0; i < path.length(); i++)
  2088. {
  2089. i = path.find_first_of("/\\", i);
  2090. if (i == string::npos)
  2091. break;
  2092. path[i] = g_fileSeparator;
  2093. }
  2094. // remove beginning separator if requested
  2095. if (removeBeginningSeparator && (path[0] == g_fileSeparator))
  2096. path.erase(0, 1);
  2097. }
  2098. void ASConsole::printMsg(const char* msg, const string& data) const
  2099. {
  2100. if (isQuiet)
  2101. return;
  2102. printf(msg, data.c_str());
  2103. }
  2104. void ASConsole::printSeparatingLine() const
  2105. {
  2106. string line;
  2107. for (size_t i = 0; i < 60; i++)
  2108. line.append("-");
  2109. printMsg("%s\n", line);
  2110. }
  2111. void ASConsole::printVerboseHeader() const
  2112. {
  2113. assert(isVerbose);
  2114. if (isQuiet)
  2115. return;
  2116. // get the date
  2117. time_t lt;
  2118. char str[20];
  2119. lt = time(nullptr);
  2120. struct tm* ptr = localtime(&lt);
  2121. strftime(str, 20, "%x", ptr);
  2122. // print the header
  2123. // 60 is the length of the separator in printSeparatingLine()
  2124. string header = "Artistic Style " + string(g_version);
  2125. size_t numSpaces = 60 - header.length() - strlen(str);
  2126. header.append(numSpaces, ' ');
  2127. header.append(str);
  2128. header.append("\n");
  2129. printf("%s", header.c_str());
  2130. // print options file
  2131. if (!optionsFileName.empty())
  2132. printf(_("Using default options file %s\n"), optionsFileName.c_str());
  2133. }
  2134. void ASConsole::printVerboseStats(clock_t startTime) const
  2135. {
  2136. assert(isVerbose);
  2137. if (isQuiet)
  2138. return;
  2139. if (hasWildcard)
  2140. printSeparatingLine();
  2141. string formatted = getNumberFormat(filesFormatted);
  2142. string unchanged = getNumberFormat(filesUnchanged);
  2143. printf(_(" %s formatted %s unchanged "), formatted.c_str(), unchanged.c_str());
  2144. // show processing time
  2145. clock_t stopTime = clock();
  2146. double secs = (stopTime - startTime) / double (CLOCKS_PER_SEC);
  2147. if (secs < 60)
  2148. {
  2149. if (secs < 2.0)
  2150. printf("%.2f", secs);
  2151. else if (secs < 20.0)
  2152. printf("%.1f", secs);
  2153. else
  2154. printf("%.0f", secs);
  2155. printf("%s", _(" seconds "));
  2156. }
  2157. else
  2158. {
  2159. // show minutes and seconds if time is greater than one minute
  2160. int min = (int) secs / 60;
  2161. secs -= min * 60;
  2162. int minsec = int (secs + .5);
  2163. printf(_("%d min %d sec "), min, minsec);
  2164. }
  2165. string lines = getNumberFormat(linesOut);
  2166. printf(_("%s lines\n"), lines.c_str());
  2167. }
  2168. void ASConsole::sleep(int seconds) const
  2169. {
  2170. clock_t endwait;
  2171. endwait = clock_t (clock () + seconds * CLOCKS_PER_SEC);
  2172. while (clock() < endwait) {}
  2173. }
  2174. bool ASConsole::stringEndsWith(const string& str, const string& suffix) const
  2175. {
  2176. int strIndex = (int) str.length() - 1;
  2177. int suffixIndex = (int) suffix.length() - 1;
  2178. while (strIndex >= 0 && suffixIndex >= 0)
  2179. {
  2180. if (tolower(str[strIndex]) != tolower(suffix[suffixIndex]))
  2181. return false;
  2182. --strIndex;
  2183. --suffixIndex;
  2184. }
  2185. // suffix longer than string
  2186. if (strIndex < 0 && suffixIndex >= 0)
  2187. return false;
  2188. return true;
  2189. }
  2190. void ASConsole::updateExcludeVector(const string& suffixParam)
  2191. {
  2192. excludeVector.emplace_back(suffixParam);
  2193. standardizePath(excludeVector.back(), true);
  2194. excludeHitsVector.push_back(false);
  2195. }
  2196. int ASConsole::waitForRemove(const char* newFileName) const
  2197. {
  2198. struct stat stBuf;
  2199. int seconds;
  2200. // sleep a max of 20 seconds for the remove
  2201. for (seconds = 1; seconds <= 20; seconds++)
  2202. {
  2203. sleep(1);
  2204. if (stat(newFileName, &stBuf) != 0)
  2205. break;
  2206. }
  2207. errno = 0;
  2208. return seconds;
  2209. }
  2210. // From The Code Project http://www.codeproject.com/string/wildcmp.asp
  2211. // Written by Jack Handy - jakkhandy@hotmail.com
  2212. // Modified to compare case insensitive for Windows
  2213. int ASConsole::wildcmp(const char* wild, const char* data) const
  2214. {
  2215. const char* cp = nullptr, *mp = nullptr;
  2216. bool cmpval;
  2217. while ((*data) && (*wild != '*'))
  2218. {
  2219. if (!g_isCaseSensitive)
  2220. cmpval = (tolower(*wild) != tolower(*data)) && (*wild != '?');
  2221. else
  2222. cmpval = (*wild != *data) && (*wild != '?');
  2223. if (cmpval)
  2224. {
  2225. return 0;
  2226. }
  2227. wild++;
  2228. data++;
  2229. }
  2230. while (*data)
  2231. {
  2232. if (*wild == '*')
  2233. {
  2234. if (!*++wild)
  2235. {
  2236. return 1;
  2237. }
  2238. mp = wild;
  2239. cp = data + 1;
  2240. }
  2241. else
  2242. {
  2243. if (!g_isCaseSensitive)
  2244. cmpval = (tolower(*wild) == tolower(*data) || (*wild == '?'));
  2245. else
  2246. cmpval = (*wild == *data) || (*wild == '?');
  2247. if (cmpval)
  2248. {
  2249. wild++;
  2250. data++;
  2251. }
  2252. else
  2253. {
  2254. wild = mp;
  2255. data = cp++;
  2256. }
  2257. }
  2258. }
  2259. while (*wild == '*')
  2260. {
  2261. wild++;
  2262. }
  2263. return !*wild;
  2264. }
  2265. void ASConsole::writeFile(const string& fileName_, FileEncoding encoding, ostringstream& out) const
  2266. {
  2267. // save date accessed and date modified of original file
  2268. struct stat stBuf;
  2269. bool statErr = false;
  2270. if (stat(fileName_.c_str(), &stBuf) == -1)
  2271. statErr = true;
  2272. // create a backup
  2273. if (!noBackup)
  2274. {
  2275. string origFileName = fileName_ + origSuffix;
  2276. removeFile(origFileName.c_str(), "Cannot remove pre-existing backup file");
  2277. renameFile(fileName_.c_str(), origFileName.c_str(), "Cannot create backup file");
  2278. }
  2279. // write the output file
  2280. ofstream fout(fileName_.c_str(), ios::binary | ios::trunc);
  2281. if (!fout)
  2282. error("Cannot open output file", fileName_.c_str());
  2283. if (encoding == UTF_16LE || encoding == UTF_16BE)
  2284. {
  2285. // convert utf-8 to utf-16
  2286. bool isBigEndian = (encoding == UTF_16BE);
  2287. size_t utf16Size = utf8_16.utf16LengthFromUtf8(out.str().c_str(), out.str().length());
  2288. char* utf16Out = new char[utf16Size];
  2289. size_t utf16Len = utf8_16.utf8ToUtf16(const_cast<char*>(out.str().c_str()),
  2290. out.str().length(), isBigEndian, utf16Out);
  2291. assert(utf16Len == utf16Size);
  2292. fout << string(utf16Out, utf16Len);
  2293. delete[] utf16Out;
  2294. }
  2295. else
  2296. fout << out.str();
  2297. fout.close();
  2298. // change date modified to original file date
  2299. // Embarcadero must be linked with cw32mt not cw32
  2300. if (preserveDate)
  2301. {
  2302. if (!statErr)
  2303. {
  2304. struct utimbuf outBuf;
  2305. outBuf.actime = stBuf.st_atime;
  2306. // add ticks so 'make' will recognize a change
  2307. // Visual Studio 2008 needs more than 1
  2308. outBuf.modtime = stBuf.st_mtime + 10;
  2309. if (utime(fileName_.c_str(), &outBuf) == -1)
  2310. statErr = true;
  2311. }
  2312. if (statErr)
  2313. {
  2314. perror("errno message");
  2315. (*errorStream) << "********* Cannot preserve file date" << endl;
  2316. }
  2317. }
  2318. }
  2319. #else // ASTYLE_LIB
  2320. //-----------------------------------------------------------------------------
  2321. // ASLibrary class
  2322. // used by shared object (DLL) calls
  2323. //-----------------------------------------------------------------------------
  2324. utf16_t* ASLibrary::formatUtf16(const utf16_t* pSourceIn, // the source to be formatted
  2325. const utf16_t* pOptions, // AStyle options
  2326. fpError fpErrorHandler, // error handler function
  2327. fpAlloc fpMemoryAlloc) const // memory allocation function)
  2328. {
  2329. const char* utf8In = convertUtf16ToUtf8(pSourceIn);
  2330. if (utf8In == nullptr)
  2331. {
  2332. fpErrorHandler(121, "Cannot convert input utf-16 to utf-8.");
  2333. return nullptr;
  2334. }
  2335. const char* utf8Options = convertUtf16ToUtf8(pOptions);
  2336. if (utf8Options == nullptr)
  2337. {
  2338. delete[] utf8In;
  2339. fpErrorHandler(122, "Cannot convert options utf-16 to utf-8.");
  2340. return nullptr;
  2341. }
  2342. // call the Artistic Style formatting function
  2343. // cannot use the callers memory allocation here
  2344. char* utf8Out = AStyleMain(utf8In,
  2345. utf8Options,
  2346. fpErrorHandler,
  2347. ASLibrary::tempMemoryAllocation);
  2348. // finished with these
  2349. delete[] utf8In;
  2350. delete[] utf8Options;
  2351. utf8In = nullptr;
  2352. utf8Options = nullptr;
  2353. // AStyle error has already been sent
  2354. if (utf8Out == nullptr)
  2355. return nullptr;
  2356. // convert text to wide char and return it
  2357. utf16_t* utf16Out = convertUtf8ToUtf16(utf8Out, fpMemoryAlloc);
  2358. delete[] utf8Out;
  2359. utf8Out = nullptr;
  2360. if (utf16Out == nullptr)
  2361. {
  2362. fpErrorHandler(123, "Cannot convert output utf-8 to utf-16.");
  2363. return nullptr;
  2364. }
  2365. return utf16Out;
  2366. }
  2367. // STATIC method to allocate temporary memory for AStyle formatting.
  2368. // The data will be converted before being returned to the calling program.
  2369. char* STDCALL ASLibrary::tempMemoryAllocation(unsigned long memoryNeeded)
  2370. {
  2371. char* buffer = new (nothrow) char[memoryNeeded];
  2372. return buffer;
  2373. }
  2374. /**
  2375. * Convert utf-8 strings to utf16 strings.
  2376. * Memory is allocated by the calling program memory allocation function.
  2377. * The calling function must check for errors.
  2378. */
  2379. utf16_t* ASLibrary::convertUtf8ToUtf16(const char* utf8In, fpAlloc fpMemoryAlloc) const
  2380. {
  2381. if (utf8In == nullptr)
  2382. return nullptr;
  2383. char* data = const_cast<char*>(utf8In);
  2384. size_t dataSize = strlen(utf8In);
  2385. bool isBigEndian = utf8_16.getBigEndian();
  2386. // return size is in number of CHARs, not utf16_t
  2387. size_t utf16Size = (utf8_16.utf16LengthFromUtf8(data, dataSize) + sizeof(utf16_t));
  2388. char* utf16Out = fpMemoryAlloc((long)utf16Size);
  2389. if (utf16Out == nullptr)
  2390. return nullptr;
  2391. #ifdef NDEBUG
  2392. utf8_16.utf8ToUtf16(data, dataSize + 1, isBigEndian, utf16Out);
  2393. #else
  2394. size_t utf16Len = utf8_16.utf8ToUtf16(data, dataSize + 1, isBigEndian, utf16Out);
  2395. assert(utf16Len == utf16Size);
  2396. #endif
  2397. assert(utf16Size == (utf8_16.utf16len(reinterpret_cast<utf16_t*>(utf16Out)) + 1) * sizeof(utf16_t));
  2398. return reinterpret_cast<utf16_t*>(utf16Out);
  2399. }
  2400. /**
  2401. * Convert utf16 strings to utf-8.
  2402. * The calling function must check for errors and delete the
  2403. * allocated memory.
  2404. */
  2405. char* ASLibrary::convertUtf16ToUtf8(const utf16_t* utf16In) const
  2406. {
  2407. if (utf16In == nullptr)
  2408. return nullptr;
  2409. char* data = reinterpret_cast<char*>(const_cast<utf16_t*>(utf16In));
  2410. // size must be in chars
  2411. size_t dataSize = utf8_16.utf16len(utf16In) * sizeof(utf16_t);
  2412. bool isBigEndian = utf8_16.getBigEndian();
  2413. size_t utf8Size = utf8_16.utf8LengthFromUtf16(data, dataSize, isBigEndian) + 1;
  2414. char* utf8Out = new (nothrow) char[utf8Size];
  2415. if (utf8Out == nullptr)
  2416. return nullptr;
  2417. #ifdef NDEBUG
  2418. utf8_16.utf16ToUtf8(data, dataSize + 1, isBigEndian, true, utf8Out);
  2419. #else
  2420. size_t utf8Len = utf8_16.utf16ToUtf8(data, dataSize + 1, isBigEndian, true, utf8Out);
  2421. assert(utf8Len == utf8Size);
  2422. #endif
  2423. assert(utf8Size == strlen(utf8Out) + 1);
  2424. return utf8Out;
  2425. }
  2426. #endif // ASTYLE_LIB
  2427. //-----------------------------------------------------------------------------
  2428. // ASOptions class
  2429. // used by both console and library builds
  2430. //-----------------------------------------------------------------------------
  2431. #ifdef ASTYLE_LIB
  2432. ASOptions::ASOptions(ASFormatter& formatterArg)
  2433. : formatter(formatterArg)
  2434. { }
  2435. #else
  2436. ASOptions::ASOptions(ASFormatter& formatterArg, ASConsole& consoleArg)
  2437. : formatter(formatterArg), console(consoleArg)
  2438. { }
  2439. #endif
  2440. /**
  2441. * parse the options vector
  2442. * optionsVector can be either a fileOptionsVector (options file) or an optionsVector (command line)
  2443. *
  2444. * @return true if no errors, false if errors
  2445. */
  2446. bool ASOptions::parseOptions(vector<string>& optionsVector, const string& errorInfo)
  2447. {
  2448. vector<string>::iterator option;
  2449. string arg, subArg;
  2450. optionErrors.clear();
  2451. for (option = optionsVector.begin(); option != optionsVector.end(); ++option)
  2452. {
  2453. arg = *option;
  2454. if (arg.compare(0, 2, "--") == 0)
  2455. parseOption(arg.substr(2), errorInfo);
  2456. else if (arg[0] == '-')
  2457. {
  2458. size_t i;
  2459. for (i = 1; i < arg.length(); ++i)
  2460. {
  2461. if (i > 1
  2462. && isalpha((unsigned char)arg[i])
  2463. && arg[i - 1] != 'x')
  2464. {
  2465. // parse the previous option in subArg
  2466. parseOption(subArg, errorInfo);
  2467. subArg = "";
  2468. }
  2469. // append the current option to subArg
  2470. subArg.append(1, arg[i]);
  2471. }
  2472. // parse the last option
  2473. parseOption(subArg, errorInfo);
  2474. subArg = "";
  2475. }
  2476. else
  2477. {
  2478. parseOption(arg, errorInfo);
  2479. subArg = "";
  2480. }
  2481. }
  2482. if (optionErrors.str().length() > 0)
  2483. return false;
  2484. return true;
  2485. }
  2486. void ASOptions::parseOption(const string& arg, const string& errorInfo)
  2487. {
  2488. if ( isOption(arg, "style=allman") || isOption(arg, "style=bsd") || isOption(arg, "style=break") )
  2489. {
  2490. formatter.setFormattingStyle(STYLE_ALLMAN);
  2491. }
  2492. else if ( isOption(arg, "style=java") || isOption(arg, "style=attach") )
  2493. {
  2494. formatter.setFormattingStyle(STYLE_JAVA);
  2495. }
  2496. else if ( isOption(arg, "style=k&r") || isOption(arg, "style=kr") || isOption(arg, "style=k/r") )
  2497. {
  2498. formatter.setFormattingStyle(STYLE_KR);
  2499. }
  2500. else if ( isOption(arg, "style=stroustrup") )
  2501. {
  2502. formatter.setFormattingStyle(STYLE_STROUSTRUP);
  2503. }
  2504. else if ( isOption(arg, "style=whitesmith") )
  2505. {
  2506. formatter.setFormattingStyle(STYLE_WHITESMITH);
  2507. }
  2508. else if ( isOption(arg, "style=vtk") )
  2509. {
  2510. formatter.setFormattingStyle(STYLE_VTK);
  2511. }
  2512. else if ( isOption(arg, "style=banner") )
  2513. {
  2514. formatter.setFormattingStyle(STYLE_BANNER);
  2515. }
  2516. else if ( isOption(arg, "style=gnu") )
  2517. {
  2518. formatter.setFormattingStyle(STYLE_GNU);
  2519. }
  2520. else if ( isOption(arg, "style=linux") || isOption(arg, "style=knf") )
  2521. {
  2522. formatter.setFormattingStyle(STYLE_LINUX);
  2523. }
  2524. else if ( isOption(arg, "style=horstmann") || isOption(arg, "style=run-in") )
  2525. {
  2526. formatter.setFormattingStyle(STYLE_HORSTMANN);
  2527. }
  2528. else if ( isOption(arg, "style=1tbs") || isOption(arg, "style=otbs") )
  2529. {
  2530. formatter.setFormattingStyle(STYLE_1TBS);
  2531. }
  2532. else if ( isOption(arg, "style=google") )
  2533. {
  2534. formatter.setFormattingStyle(STYLE_GOOGLE);
  2535. }
  2536. else if (isOption(arg, "style=mozilla"))
  2537. {
  2538. formatter.setFormattingStyle(STYLE_MOZILLA);
  2539. }
  2540. else if ( isOption(arg, "style=pico") )
  2541. {
  2542. formatter.setFormattingStyle(STYLE_PICO);
  2543. }
  2544. else if ( isOption(arg, "style=lisp") || isOption(arg, "style=python") )
  2545. {
  2546. formatter.setFormattingStyle(STYLE_LISP);
  2547. }
  2548. else if ( isParamOption(arg, "A") )
  2549. {
  2550. int style = 0;
  2551. string styleParam = getParam(arg, "A");
  2552. if (styleParam.length() > 0)
  2553. style = atoi(styleParam.c_str());
  2554. if (style == 1)
  2555. formatter.setFormattingStyle(STYLE_ALLMAN);
  2556. else if (style == 2)
  2557. formatter.setFormattingStyle(STYLE_JAVA);
  2558. else if (style == 3)
  2559. formatter.setFormattingStyle(STYLE_KR);
  2560. else if (style == 4)
  2561. formatter.setFormattingStyle(STYLE_STROUSTRUP);
  2562. else if (style == 5)
  2563. formatter.setFormattingStyle(STYLE_WHITESMITH);
  2564. else if (style == 6)
  2565. formatter.setFormattingStyle(STYLE_BANNER);
  2566. else if (style == 7)
  2567. formatter.setFormattingStyle(STYLE_GNU);
  2568. else if (style == 8)
  2569. formatter.setFormattingStyle(STYLE_LINUX);
  2570. else if (style == 9)
  2571. formatter.setFormattingStyle(STYLE_HORSTMANN);
  2572. else if (style == 10)
  2573. formatter.setFormattingStyle(STYLE_1TBS);
  2574. else if (style == 11)
  2575. formatter.setFormattingStyle(STYLE_PICO);
  2576. else if (style == 12)
  2577. formatter.setFormattingStyle(STYLE_LISP);
  2578. else if (style == 14)
  2579. formatter.setFormattingStyle(STYLE_GOOGLE);
  2580. else if (style == 15)
  2581. formatter.setFormattingStyle(STYLE_VTK);
  2582. else if (style == 16)
  2583. formatter.setFormattingStyle(STYLE_MOZILLA);
  2584. else
  2585. isOptionError(arg, errorInfo);
  2586. }
  2587. // must check for mode=cs before mode=c !!!
  2588. else if ( isOption(arg, "mode=cs") )
  2589. {
  2590. formatter.setSharpStyle();
  2591. formatter.setModeManuallySet(true);
  2592. }
  2593. else if ( isOption(arg, "mode=c") )
  2594. {
  2595. formatter.setCStyle();
  2596. formatter.setModeManuallySet(true);
  2597. }
  2598. else if ( isOption(arg, "mode=java") )
  2599. {
  2600. formatter.setJavaStyle();
  2601. formatter.setModeManuallySet(true);
  2602. }
  2603. else if ( isParamOption(arg, "t", "indent=tab=") )
  2604. {
  2605. int spaceNum = 4;
  2606. string spaceNumParam = getParam(arg, "t", "indent=tab=");
  2607. if (spaceNumParam.length() > 0)
  2608. spaceNum = atoi(spaceNumParam.c_str());
  2609. if (spaceNum < 2 || spaceNum > 20)
  2610. isOptionError(arg, errorInfo);
  2611. else
  2612. {
  2613. formatter.setTabIndentation(spaceNum, false);
  2614. }
  2615. }
  2616. else if ( isOption(arg, "indent=tab") )
  2617. {
  2618. formatter.setTabIndentation(4);
  2619. }
  2620. else if ( isParamOption(arg, "T", "indent=force-tab=") )
  2621. {
  2622. int spaceNum = 4;
  2623. string spaceNumParam = getParam(arg, "T", "indent=force-tab=");
  2624. if (spaceNumParam.length() > 0)
  2625. spaceNum = atoi(spaceNumParam.c_str());
  2626. if (spaceNum < 2 || spaceNum > 20)
  2627. isOptionError(arg, errorInfo);
  2628. else
  2629. {
  2630. formatter.setTabIndentation(spaceNum, true);
  2631. }
  2632. }
  2633. else if ( isOption(arg, "indent=force-tab") )
  2634. {
  2635. formatter.setTabIndentation(4, true);
  2636. }
  2637. else if ( isParamOption(arg, "xT", "indent=force-tab-x=") )
  2638. {
  2639. int tabNum = 8;
  2640. string tabNumParam = getParam(arg, "xT", "indent=force-tab-x=");
  2641. if (tabNumParam.length() > 0)
  2642. tabNum = atoi(tabNumParam.c_str());
  2643. if (tabNum < 2 || tabNum > 20)
  2644. isOptionError(arg, errorInfo);
  2645. else
  2646. {
  2647. formatter.setForceTabXIndentation(tabNum);
  2648. }
  2649. }
  2650. else if ( isOption(arg, "indent=force-tab-x") )
  2651. {
  2652. formatter.setForceTabXIndentation(8);
  2653. }
  2654. else if ( isParamOption(arg, "s", "indent=spaces=") )
  2655. {
  2656. int spaceNum = 4;
  2657. string spaceNumParam = getParam(arg, "s", "indent=spaces=");
  2658. if (spaceNumParam.length() > 0)
  2659. spaceNum = atoi(spaceNumParam.c_str());
  2660. if (spaceNum < 2 || spaceNum > 20)
  2661. isOptionError(arg, errorInfo);
  2662. else
  2663. {
  2664. formatter.setSpaceIndentation(spaceNum);
  2665. }
  2666. }
  2667. else if ( isOption(arg, "indent=spaces") )
  2668. {
  2669. formatter.setSpaceIndentation(4);
  2670. }
  2671. else if (isParamOption(arg, "xt", "indent-continuation="))
  2672. {
  2673. int contIndent = 1;
  2674. string contIndentParam = getParam(arg, "xt", "indent-continuation=");
  2675. if (contIndentParam.length() > 0)
  2676. contIndent = atoi(contIndentParam.c_str());
  2677. if (contIndent < 0)
  2678. isOptionError(arg, errorInfo);
  2679. else if (contIndent > 4)
  2680. isOptionError(arg, errorInfo);
  2681. else
  2682. formatter.setContinuationIndentation(contIndent);
  2683. }
  2684. else if ( isParamOption(arg, "m", "min-conditional-indent=") )
  2685. {
  2686. int minIndent = MINCOND_TWO;
  2687. string minIndentParam = getParam(arg, "m", "min-conditional-indent=");
  2688. if (minIndentParam.length() > 0)
  2689. minIndent = atoi(minIndentParam.c_str());
  2690. if (minIndent >= MINCOND_END)
  2691. isOptionError(arg, errorInfo);
  2692. else
  2693. formatter.setMinConditionalIndentOption(minIndent);
  2694. }
  2695. else if ( isParamOption(arg, "M", "max-continuation-indent=") )
  2696. {
  2697. int maxIndent = 40;
  2698. string maxIndentParam = getParam(arg, "M", "max-continuation-indent=");
  2699. if (maxIndentParam.length() > 0)
  2700. maxIndent = atoi(maxIndentParam.c_str());
  2701. if (maxIndent < 40)
  2702. isOptionError(arg, errorInfo);
  2703. else if (maxIndent > 120)
  2704. isOptionError(arg, errorInfo);
  2705. else
  2706. formatter.setMaxContinuationIndentLength(maxIndent);
  2707. }
  2708. else if ( isOption(arg, "N", "indent-namespaces") )
  2709. {
  2710. formatter.setNamespaceIndent(true);
  2711. }
  2712. else if ( isOption(arg, "C", "indent-classes") )
  2713. {
  2714. formatter.setClassIndent(true);
  2715. }
  2716. else if ( isOption(arg, "xG", "indent-modifiers") )
  2717. {
  2718. formatter.setModifierIndent(true);
  2719. }
  2720. else if ( isOption(arg, "S", "indent-switches") )
  2721. {
  2722. formatter.setSwitchIndent(true);
  2723. }
  2724. else if ( isOption(arg, "K", "indent-cases") )
  2725. {
  2726. formatter.setCaseIndent(true);
  2727. }
  2728. else if ( isOption(arg, "xU", "indent-after-parens") )
  2729. {
  2730. formatter.setAfterParenIndent(true);
  2731. }
  2732. else if ( isOption(arg, "L", "indent-labels") )
  2733. {
  2734. formatter.setLabelIndent(true);
  2735. }
  2736. else if (isOption(arg, "xW", "indent-preproc-block"))
  2737. {
  2738. formatter.setPreprocBlockIndent(true);
  2739. }
  2740. else if ( isOption(arg, "w", "indent-preproc-define") )
  2741. {
  2742. formatter.setPreprocDefineIndent(true);
  2743. }
  2744. else if ( isOption(arg, "xw", "indent-preproc-cond") )
  2745. {
  2746. formatter.setPreprocConditionalIndent(true);
  2747. }
  2748. else if ( isOption(arg, "y", "break-closing-braces") )
  2749. {
  2750. formatter.setBreakClosingHeaderBracesMode(true);
  2751. }
  2752. else if ( isOption(arg, "O", "keep-one-line-blocks") )
  2753. {
  2754. formatter.setBreakOneLineBlocksMode(false);
  2755. }
  2756. else if ( isOption(arg, "o", "keep-one-line-statements") )
  2757. {
  2758. formatter.setBreakOneLineStatementsMode(false);
  2759. }
  2760. else if ( isOption(arg, "P", "pad-paren") )
  2761. {
  2762. formatter.setParensOutsidePaddingMode(true);
  2763. formatter.setParensInsidePaddingMode(true);
  2764. }
  2765. else if ( isOption(arg, "d", "pad-paren-out") )
  2766. {
  2767. formatter.setParensOutsidePaddingMode(true);
  2768. }
  2769. else if ( isOption(arg, "xd", "pad-first-paren-out") )
  2770. {
  2771. formatter.setParensFirstPaddingMode(true);
  2772. }
  2773. else if ( isOption(arg, "D", "pad-paren-in") )
  2774. {
  2775. formatter.setParensInsidePaddingMode(true);
  2776. }
  2777. else if ( isOption(arg, "H", "pad-header") )
  2778. {
  2779. formatter.setParensHeaderPaddingMode(true);
  2780. }
  2781. else if ( isOption(arg, "U", "unpad-paren") )
  2782. {
  2783. formatter.setParensUnPaddingMode(true);
  2784. }
  2785. else if ( isOption(arg, "p", "pad-oper") )
  2786. {
  2787. formatter.setOperatorPaddingMode(true);
  2788. }
  2789. else if (isOption(arg, "xg", "pad-comma"))
  2790. {
  2791. formatter.setCommaPaddingMode(true);
  2792. }
  2793. else if ( isOption(arg, "xe", "delete-empty-lines") )
  2794. {
  2795. formatter.setDeleteEmptyLinesMode(true);
  2796. }
  2797. else if ( isOption(arg, "E", "fill-empty-lines") )
  2798. {
  2799. formatter.setEmptyLineFill(true);
  2800. }
  2801. else if ( isOption(arg, "c", "convert-tabs") )
  2802. {
  2803. formatter.setTabSpaceConversionMode(true);
  2804. }
  2805. else if ( isOption(arg, "xy", "close-templates") )
  2806. {
  2807. formatter.setCloseTemplatesMode(true);
  2808. }
  2809. else if ( isOption(arg, "F", "break-blocks=all") )
  2810. {
  2811. formatter.setBreakBlocksMode(true);
  2812. formatter.setBreakClosingHeaderBlocksMode(true);
  2813. }
  2814. else if ( isOption(arg, "f", "break-blocks") )
  2815. {
  2816. formatter.setBreakBlocksMode(true);
  2817. }
  2818. else if ( isOption(arg, "e", "break-elseifs") )
  2819. {
  2820. formatter.setBreakElseIfsMode(true);
  2821. }
  2822. else if ( isOption(arg, "xb", "break-one-line-headers") )
  2823. {
  2824. formatter.setBreakOneLineHeadersMode(true);
  2825. }
  2826. else if ( isOption(arg, "j", "add-braces") )
  2827. {
  2828. formatter.setAddBracesMode(true);
  2829. }
  2830. else if ( isOption(arg, "J", "add-one-line-braces") )
  2831. {
  2832. formatter.setAddOneLineBracesMode(true);
  2833. }
  2834. else if ( isOption(arg, "xj", "remove-braces") )
  2835. {
  2836. formatter.setRemoveBracesMode(true);
  2837. }
  2838. else if ( isOption(arg, "Y", "indent-col1-comments") )
  2839. {
  2840. formatter.setIndentCol1CommentsMode(true);
  2841. }
  2842. else if ( isOption(arg, "align-pointer=type") )
  2843. {
  2844. formatter.setPointerAlignment(PTR_ALIGN_TYPE);
  2845. }
  2846. else if ( isOption(arg, "align-pointer=middle") )
  2847. {
  2848. formatter.setPointerAlignment(PTR_ALIGN_MIDDLE);
  2849. }
  2850. else if ( isOption(arg, "align-pointer=name") )
  2851. {
  2852. formatter.setPointerAlignment(PTR_ALIGN_NAME);
  2853. }
  2854. else if ( isParamOption(arg, "k") )
  2855. {
  2856. int align = 0;
  2857. string styleParam = getParam(arg, "k");
  2858. if (styleParam.length() > 0)
  2859. align = atoi(styleParam.c_str());
  2860. if (align < 1 || align > 3)
  2861. isOptionError(arg, errorInfo);
  2862. else if (align == 1)
  2863. formatter.setPointerAlignment(PTR_ALIGN_TYPE);
  2864. else if (align == 2)
  2865. formatter.setPointerAlignment(PTR_ALIGN_MIDDLE);
  2866. else if (align == 3)
  2867. formatter.setPointerAlignment(PTR_ALIGN_NAME);
  2868. }
  2869. else if ( isOption(arg, "align-reference=none") )
  2870. {
  2871. formatter.setReferenceAlignment(REF_ALIGN_NONE);
  2872. }
  2873. else if ( isOption(arg, "align-reference=type") )
  2874. {
  2875. formatter.setReferenceAlignment(REF_ALIGN_TYPE);
  2876. }
  2877. else if ( isOption(arg, "align-reference=middle") )
  2878. {
  2879. formatter.setReferenceAlignment(REF_ALIGN_MIDDLE);
  2880. }
  2881. else if ( isOption(arg, "align-reference=name") )
  2882. {
  2883. formatter.setReferenceAlignment(REF_ALIGN_NAME);
  2884. }
  2885. else if ( isParamOption(arg, "W") )
  2886. {
  2887. int align = 0;
  2888. string styleParam = getParam(arg, "W");
  2889. if (styleParam.length() > 0)
  2890. align = atoi(styleParam.c_str());
  2891. if (align < 0 || align > 3)
  2892. isOptionError(arg, errorInfo);
  2893. else if (align == 0)
  2894. formatter.setReferenceAlignment(REF_ALIGN_NONE);
  2895. else if (align == 1)
  2896. formatter.setReferenceAlignment(REF_ALIGN_TYPE);
  2897. else if (align == 2)
  2898. formatter.setReferenceAlignment(REF_ALIGN_MIDDLE);
  2899. else if (align == 3)
  2900. formatter.setReferenceAlignment(REF_ALIGN_NAME);
  2901. }
  2902. else if ( isParamOption(arg, "max-code-length=") )
  2903. {
  2904. int maxLength = 50;
  2905. string maxLengthParam = getParam(arg, "max-code-length=");
  2906. if (maxLengthParam.length() > 0)
  2907. maxLength = atoi(maxLengthParam.c_str());
  2908. if (maxLength < 50)
  2909. isOptionError(arg, errorInfo);
  2910. else if (maxLength > 200)
  2911. isOptionError(arg, errorInfo);
  2912. else
  2913. formatter.setMaxCodeLength(maxLength);
  2914. }
  2915. else if ( isParamOption(arg, "xC") )
  2916. {
  2917. int maxLength = 50;
  2918. string maxLengthParam = getParam(arg, "xC");
  2919. if (maxLengthParam.length() > 0)
  2920. maxLength = atoi(maxLengthParam.c_str());
  2921. if (maxLength > 200)
  2922. isOptionError(arg, errorInfo);
  2923. else
  2924. formatter.setMaxCodeLength(maxLength);
  2925. }
  2926. else if ( isOption(arg, "xL", "break-after-logical") )
  2927. {
  2928. formatter.setBreakAfterMode(true);
  2929. }
  2930. else if ( isOption(arg, "xc", "attach-classes") )
  2931. {
  2932. formatter.setAttachClass(true);
  2933. }
  2934. else if ( isOption(arg, "xV", "attach-closing-while") )
  2935. {
  2936. formatter.setAttachClosingWhile(true);
  2937. }
  2938. else if ( isOption(arg, "xk", "attach-extern-c") )
  2939. {
  2940. formatter.setAttachExternC(true);
  2941. }
  2942. else if ( isOption(arg, "xn", "attach-namespaces") )
  2943. {
  2944. formatter.setAttachNamespace(true);
  2945. }
  2946. else if ( isOption(arg, "xl", "attach-inlines") )
  2947. {
  2948. formatter.setAttachInline(true);
  2949. }
  2950. else if ( isOption(arg, "xp", "remove-comment-prefix") )
  2951. {
  2952. formatter.setStripCommentPrefix(true);
  2953. }
  2954. // Objective-C options
  2955. else if ( isOption(arg, "xQ", "pad-method-prefix") )
  2956. {
  2957. formatter.setMethodPrefixPaddingMode(true);
  2958. }
  2959. else if ( isOption(arg, "xR", "unpad-method-prefix") )
  2960. {
  2961. formatter.setMethodPrefixUnPaddingMode(true);
  2962. }
  2963. else if (isOption(arg, "xq", "pad-return-type"))
  2964. {
  2965. formatter.setReturnTypePaddingMode(true);
  2966. }
  2967. else if (isOption(arg, "xr", "unpad-return-type"))
  2968. {
  2969. formatter.setReturnTypeUnPaddingMode(true);
  2970. }
  2971. else if (isOption(arg, "xS", "pad-param-type"))
  2972. {
  2973. formatter.setParamTypePaddingMode(true);
  2974. }
  2975. else if (isOption(arg, "xs", "unpad-param-type"))
  2976. {
  2977. formatter.setParamTypeUnPaddingMode(true);
  2978. }
  2979. else if (isOption(arg, "xM", "align-method-colon"))
  2980. {
  2981. formatter.setAlignMethodColon(true);
  2982. }
  2983. else if ( isOption(arg, "xP0", "pad-method-colon=none") )
  2984. {
  2985. formatter.setObjCColonPaddingMode(COLON_PAD_NONE);
  2986. }
  2987. else if ( isOption(arg, "xP1", "pad-method-colon=all") )
  2988. {
  2989. formatter.setObjCColonPaddingMode(COLON_PAD_ALL);
  2990. }
  2991. else if ( isOption(arg, "xP2", "pad-method-colon=after") )
  2992. {
  2993. formatter.setObjCColonPaddingMode(COLON_PAD_AFTER);
  2994. }
  2995. else if ( isOption(arg, "xP3", "pad-method-colon=before") )
  2996. {
  2997. formatter.setObjCColonPaddingMode(COLON_PAD_BEFORE);
  2998. }
  2999. // depreciated options ////////////////////////////////////////////////////////////////////////
  3000. else if ( isOption(arg, "indent-preprocessor") ) // depreciated release 2.04
  3001. {
  3002. formatter.setPreprocDefineIndent(true);
  3003. }
  3004. else if ( isOption(arg, "style=ansi") ) // depreciated release 2.05
  3005. {
  3006. formatter.setFormattingStyle(STYLE_ALLMAN);
  3007. }
  3008. // depreciated in release 3.0 /////////////////////////////////////////////////////////////////
  3009. else if ( isOption(arg, "break-closing-brackets") ) // depreciated release 3.0
  3010. {
  3011. formatter.setBreakClosingHeaderBracketsMode(true);
  3012. }
  3013. else if ( isOption(arg, "add-brackets") ) // depreciated release 3.0
  3014. {
  3015. formatter.setAddBracketsMode(true);
  3016. }
  3017. else if ( isOption(arg, "add-one-line-brackets") ) // depreciated release 3.0
  3018. {
  3019. formatter.setAddOneLineBracketsMode(true);
  3020. }
  3021. else if ( isOption(arg, "remove-brackets") ) // depreciated release 3.0
  3022. {
  3023. formatter.setRemoveBracketsMode(true);
  3024. }
  3025. else if ( isParamOption(arg, "max-instatement-indent=") ) // depreciated release 3.0
  3026. {
  3027. int maxIndent = 40;
  3028. string maxIndentParam = getParam(arg, "max-instatement-indent=");
  3029. if (maxIndentParam.length() > 0)
  3030. maxIndent = atoi(maxIndentParam.c_str());
  3031. if (maxIndent < 40)
  3032. isOptionError(arg, errorInfo);
  3033. else if (maxIndent > 120)
  3034. isOptionError(arg, errorInfo);
  3035. else
  3036. formatter.setMaxInStatementIndentLength(maxIndent);
  3037. }
  3038. // NOTE: Removed in release 2.04.
  3039. // else if ( isOption(arg, "b", "brackets=break") )
  3040. // {
  3041. // formatter.setBracketFormatMode(BREAK_MODE);
  3042. // }
  3043. // else if ( isOption(arg, "a", "brackets=attach") )
  3044. // {
  3045. // formatter.setBracketFormatMode(ATTACH_MODE);
  3046. // }
  3047. // else if ( isOption(arg, "l", "brackets=linux") )
  3048. // {
  3049. // formatter.setBracketFormatMode(LINUX_MODE);
  3050. // }
  3051. // else if ( isOption(arg, "u", "brackets=stroustrup") )
  3052. // {
  3053. // formatter.setBracketFormatMode(STROUSTRUP_MODE);
  3054. // }
  3055. // else if ( isOption(arg, "g", "brackets=run-in") )
  3056. // {
  3057. // formatter.setBracketFormatMode(RUN_IN_MODE);
  3058. // }
  3059. // end depreciated options ////////////////////////////////////////////////////////////////////
  3060. #ifdef ASTYLE_LIB
  3061. // End of options used by GUI /////////////////////////////////////////////////////////////////
  3062. else
  3063. isOptionError(arg, errorInfo);
  3064. #else
  3065. // Options used by only console ///////////////////////////////////////////////////////////////
  3066. else if ( isOption(arg, "n", "suffix=none") )
  3067. {
  3068. console.setNoBackup(true);
  3069. }
  3070. else if ( isParamOption(arg, "suffix=") )
  3071. {
  3072. string suffixParam = getParam(arg, "suffix=");
  3073. if (suffixParam.length() > 0)
  3074. {
  3075. console.setOrigSuffix(suffixParam);
  3076. }
  3077. }
  3078. else if ( isParamOption(arg, "exclude=") )
  3079. {
  3080. string suffixParam = getParam(arg, "exclude=");
  3081. if (suffixParam.length() > 0)
  3082. console.updateExcludeVector(suffixParam);
  3083. }
  3084. else if ( isOption(arg, "r", "R") || isOption(arg, "recursive") )
  3085. {
  3086. console.setIsRecursive(true);
  3087. }
  3088. else if (isOption(arg, "dry-run"))
  3089. {
  3090. console.setIsDryRun(true);
  3091. }
  3092. else if ( isOption(arg, "Z", "preserve-date") )
  3093. {
  3094. console.setPreserveDate(true);
  3095. }
  3096. else if ( isOption(arg, "v", "verbose") )
  3097. {
  3098. console.setIsVerbose(true);
  3099. }
  3100. else if ( isOption(arg, "Q", "formatted") )
  3101. {
  3102. console.setIsFormattedOnly(true);
  3103. }
  3104. else if ( isOption(arg, "q", "quiet") )
  3105. {
  3106. console.setIsQuiet(true);
  3107. }
  3108. else if ( isOption(arg, "i", "ignore-exclude-errors") )
  3109. {
  3110. console.setIgnoreExcludeErrors(true);
  3111. }
  3112. else if ( isOption(arg, "xi", "ignore-exclude-errors-x") )
  3113. {
  3114. console.setIgnoreExcludeErrorsAndDisplay(true);
  3115. }
  3116. else if ( isOption(arg, "X", "errors-to-stdout") )
  3117. {
  3118. console.setErrorStream(&cout);
  3119. }
  3120. else if ( isOption(arg, "lineend=windows") )
  3121. {
  3122. formatter.setLineEndFormat(LINEEND_WINDOWS);
  3123. }
  3124. else if ( isOption(arg, "lineend=linux") )
  3125. {
  3126. formatter.setLineEndFormat(LINEEND_LINUX);
  3127. }
  3128. else if ( isOption(arg, "lineend=macold") )
  3129. {
  3130. formatter.setLineEndFormat(LINEEND_MACOLD);
  3131. }
  3132. else if ( isParamOption(arg, "z") )
  3133. {
  3134. int lineendType = 0;
  3135. string lineendParam = getParam(arg, "z");
  3136. if (lineendParam.length() > 0)
  3137. lineendType = atoi(lineendParam.c_str());
  3138. if (lineendType < 1 || lineendType > 3)
  3139. isOptionError(arg, errorInfo);
  3140. else if (lineendType == 1)
  3141. formatter.setLineEndFormat(LINEEND_WINDOWS);
  3142. else if (lineendType == 2)
  3143. formatter.setLineEndFormat(LINEEND_LINUX);
  3144. else if (lineendType == 3)
  3145. formatter.setLineEndFormat(LINEEND_MACOLD);
  3146. }
  3147. else if ( isParamOption(arg, "stdin=") )
  3148. {
  3149. string path = getParam(arg, "stdin=");
  3150. console.standardizePath(path);
  3151. console.setStdPathIn(path);
  3152. }
  3153. else if ( isParamOption(arg, "stdout=") )
  3154. {
  3155. string path = getParam(arg, "stdout=");
  3156. console.standardizePath(path);
  3157. console.setStdPathOut(path);
  3158. }
  3159. else
  3160. isOptionError(arg, errorInfo);
  3161. #endif
  3162. } // End of parseOption function
  3163. // Parse options from the options file.
  3164. void ASOptions::importOptions(istream& in, vector<string>& optionsVector)
  3165. {
  3166. char ch;
  3167. bool isInQuote = false;
  3168. char quoteChar = ' ';
  3169. string currentToken;
  3170. while (in)
  3171. {
  3172. currentToken = "";
  3173. do
  3174. {
  3175. in.get(ch);
  3176. if (in.eof())
  3177. break;
  3178. // treat '#' as line comments
  3179. if (ch == '#')
  3180. while (in)
  3181. {
  3182. in.get(ch);
  3183. if (ch == '\n' || ch == '\r')
  3184. break;
  3185. }
  3186. // break options on new-lines, tabs, commas, or spaces
  3187. // remove quotes from output
  3188. if (in.eof() || ch == '\n' || ch == '\r' || ch == '\t' || ch == ',')
  3189. break;
  3190. if (ch == ' ' && !isInQuote)
  3191. break;
  3192. if (ch == quoteChar && isInQuote)
  3193. break;
  3194. if (ch == '"' || ch == '\'')
  3195. {
  3196. isInQuote = true;
  3197. quoteChar = ch;
  3198. continue;
  3199. }
  3200. currentToken.append(1, ch);
  3201. }
  3202. while (in);
  3203. if (currentToken.length() != 0)
  3204. optionsVector.emplace_back(currentToken);
  3205. isInQuote = false;
  3206. }
  3207. }
  3208. string ASOptions::getOptionErrors() const
  3209. {
  3210. return optionErrors.str();
  3211. }
  3212. string ASOptions::getParam(const string& arg, const char* op)
  3213. {
  3214. return arg.substr(strlen(op));
  3215. }
  3216. string ASOptions::getParam(const string& arg, const char* op1, const char* op2)
  3217. {
  3218. return isParamOption(arg, op1) ? getParam(arg, op1) : getParam(arg, op2);
  3219. }
  3220. bool ASOptions::isOption(const string& arg, const char* op)
  3221. {
  3222. return arg.compare(op) == 0;
  3223. }
  3224. bool ASOptions::isOption(const string& arg, const char* op1, const char* op2)
  3225. {
  3226. return (isOption(arg, op1) || isOption(arg, op2));
  3227. }
  3228. void ASOptions::isOptionError(const string& arg, const string& errorInfo)
  3229. {
  3230. if (optionErrors.str().length() == 0)
  3231. optionErrors << errorInfo << endl; // need main error message
  3232. optionErrors << arg << endl;
  3233. }
  3234. bool ASOptions::isParamOption(const string& arg, const char* option)
  3235. {
  3236. bool retVal = arg.compare(0, strlen(option), option) == 0;
  3237. // if comparing for short option, 2nd char of arg must be numeric
  3238. if (retVal && strlen(option) == 1 && arg.length() > 1)
  3239. if (!isdigit((unsigned char)arg[1]))
  3240. retVal = false;
  3241. return retVal;
  3242. }
  3243. bool ASOptions::isParamOption(const string& arg, const char* option1, const char* option2)
  3244. {
  3245. return isParamOption(arg, option1) || isParamOption(arg, option2);
  3246. }
  3247. //----------------------------------------------------------------------------
  3248. // ASEncoding class
  3249. //----------------------------------------------------------------------------
  3250. // Return true if an int is big endian.
  3251. bool ASEncoding::getBigEndian() const
  3252. {
  3253. short int word = 0x0001;
  3254. char* byte = (char*) &word;
  3255. return (byte[0] ? false : true);
  3256. }
  3257. // Swap the two low order bytes of a 16 bit integer value.
  3258. int ASEncoding::swap16bit(int value) const
  3259. {
  3260. return ( ((value & 0xff) << 8) | ((value & 0xff00) >> 8) );
  3261. }
  3262. // Return the length of a utf-16 C string.
  3263. // The length is in number of utf16_t.
  3264. size_t ASEncoding::utf16len(const utf16* utf16In) const
  3265. {
  3266. size_t length = 0;
  3267. while (*utf16In++ != '\0')
  3268. length++;
  3269. return length;
  3270. }
  3271. // Adapted from SciTE UniConversion.cxx.
  3272. // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
  3273. // Modified for Artistic Style by Jim Pattee.
  3274. // Compute the length of an output utf-8 file given a utf-16 file.
  3275. // Input inLen is the size in BYTES (not wchar_t).
  3276. size_t ASEncoding::utf8LengthFromUtf16(const char* utf16In, size_t inLen, bool isBigEndian) const
  3277. {
  3278. size_t len = 0;
  3279. size_t wcharLen = inLen / 2;
  3280. const short* uptr = reinterpret_cast<const short*>(utf16In);
  3281. for (size_t i = 0; i < wcharLen && uptr[i];)
  3282. {
  3283. size_t uch = isBigEndian ? swap16bit(uptr[i]) : uptr[i];
  3284. if (uch < 0x80)
  3285. len++;
  3286. else if (uch < 0x800)
  3287. len += 2;
  3288. else if ((uch >= SURROGATE_LEAD_FIRST) && (uch <= SURROGATE_TRAIL_LAST))
  3289. {
  3290. len += 4;
  3291. i++;
  3292. }
  3293. else
  3294. len += 3;
  3295. i++;
  3296. }
  3297. return len;
  3298. }
  3299. // Adapted from SciTE Utf8_16.cxx.
  3300. // Copyright (C) 2002 Scott Kirkwood.
  3301. // Modified for Artistic Style by Jim Pattee.
  3302. // Convert a utf-8 file to utf-16.
  3303. size_t ASEncoding::utf8ToUtf16(char* utf8In, size_t inLen, bool isBigEndian, char* utf16Out) const
  3304. {
  3305. int nCur = 0;
  3306. ubyte* pRead = reinterpret_cast<ubyte*>(utf8In);
  3307. utf16* pCur = reinterpret_cast<utf16*>(utf16Out);
  3308. const ubyte* pEnd = pRead + inLen;
  3309. const utf16* pCurStart = pCur;
  3310. eState state = eStart;
  3311. // the BOM will automatically be converted to utf-16
  3312. while (pRead < pEnd)
  3313. {
  3314. switch (state)
  3315. {
  3316. case eStart:
  3317. if ((0xF0 & *pRead) == 0xF0)
  3318. {
  3319. nCur = (0x7 & *pRead) << 18;
  3320. state = eSecondOf4Bytes;
  3321. }
  3322. else if ((0xE0 & *pRead) == 0xE0)
  3323. {
  3324. nCur = (~0xE0 & *pRead) << 12;
  3325. state = ePenultimate;
  3326. }
  3327. else if ((0xC0 & *pRead) == 0xC0)
  3328. {
  3329. nCur = (~0xC0 & *pRead) << 6;
  3330. state = eFinal;
  3331. }
  3332. else
  3333. {
  3334. nCur = *pRead;
  3335. state = eStart;
  3336. }
  3337. break;
  3338. case eSecondOf4Bytes:
  3339. nCur |= (0x3F & *pRead) << 12;
  3340. state = ePenultimate;
  3341. break;
  3342. case ePenultimate:
  3343. nCur |= (0x3F & *pRead) << 6;
  3344. state = eFinal;
  3345. break;
  3346. case eFinal:
  3347. nCur |= (0x3F & *pRead);
  3348. state = eStart;
  3349. break;
  3350. // no default case is needed
  3351. }
  3352. ++pRead;
  3353. if (state == eStart)
  3354. {
  3355. int codePoint = nCur;
  3356. if (codePoint >= SURROGATE_FIRST_VALUE)
  3357. {
  3358. codePoint -= SURROGATE_FIRST_VALUE;
  3359. int lead = (codePoint >> 10) + SURROGATE_LEAD_FIRST;
  3360. *pCur++ = static_cast<utf16>(isBigEndian ? swap16bit(lead) : lead);
  3361. int trail = (codePoint & 0x3ff) + SURROGATE_TRAIL_FIRST;
  3362. *pCur++ = static_cast<utf16>(isBigEndian ? swap16bit(trail) : trail);
  3363. }
  3364. else
  3365. *pCur++ = static_cast<utf16>(isBigEndian ? swap16bit(codePoint) : codePoint);
  3366. }
  3367. }
  3368. // return value is the output length in BYTES (not wchar_t)
  3369. return (pCur - pCurStart) * 2;
  3370. }
  3371. // Adapted from SciTE UniConversion.cxx.
  3372. // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
  3373. // Modified for Artistic Style by Jim Pattee.
  3374. // Compute the length of an output utf-16 file given a utf-8 file.
  3375. // Return value is the size in BYTES (not wchar_t).
  3376. size_t ASEncoding::utf16LengthFromUtf8(const char* utf8In, size_t len) const
  3377. {
  3378. size_t ulen = 0;
  3379. size_t charLen;
  3380. for (size_t i = 0; i < len;)
  3381. {
  3382. unsigned char ch = static_cast<unsigned char>(utf8In[i]);
  3383. if (ch < 0x80)
  3384. charLen = 1;
  3385. else if (ch < 0x80 + 0x40 + 0x20)
  3386. charLen = 2;
  3387. else if (ch < 0x80 + 0x40 + 0x20 + 0x10)
  3388. charLen = 3;
  3389. else
  3390. {
  3391. charLen = 4;
  3392. ulen++;
  3393. }
  3394. i += charLen;
  3395. ulen++;
  3396. }
  3397. // return value is the length in bytes (not wchar_t)
  3398. return ulen * 2;
  3399. }
  3400. // Adapted from SciTE Utf8_16.cxx.
  3401. // Copyright (C) 2002 Scott Kirkwood.
  3402. // Modified for Artistic Style by Jim Pattee.
  3403. // Convert a utf-16 file to utf-8.
  3404. size_t ASEncoding::utf16ToUtf8(char* utf16In, size_t inLen, bool isBigEndian,
  3405. bool firstBlock, char* utf8Out) const
  3406. {
  3407. int nCur16 = 0;
  3408. int nCur = 0;
  3409. ubyte* pRead = reinterpret_cast<ubyte*>(utf16In);
  3410. ubyte* pCur = reinterpret_cast<ubyte*>(utf8Out);
  3411. const ubyte* pEnd = pRead + inLen;
  3412. const ubyte* pCurStart = pCur;
  3413. static eState state = eStart; // state is retained for subsequent blocks
  3414. if (firstBlock)
  3415. state = eStart;
  3416. // the BOM will automatically be converted to utf-8
  3417. while (pRead < pEnd)
  3418. {
  3419. switch (state)
  3420. {
  3421. case eStart:
  3422. if (pRead >= pEnd)
  3423. {
  3424. ++pRead;
  3425. break;
  3426. }
  3427. if (isBigEndian)
  3428. {
  3429. nCur16 = static_cast<utf16>(*pRead++ << 8);
  3430. nCur16 |= static_cast<utf16>(*pRead);
  3431. }
  3432. else
  3433. {
  3434. nCur16 = *pRead++;
  3435. nCur16 |= static_cast<utf16>(*pRead << 8);
  3436. }
  3437. if (nCur16 >= SURROGATE_LEAD_FIRST && nCur16 <= SURROGATE_LEAD_LAST)
  3438. {
  3439. ++pRead;
  3440. int trail;
  3441. if (isBigEndian)
  3442. {
  3443. trail = static_cast<utf16>(*pRead++ << 8);
  3444. trail |= static_cast<utf16>(*pRead);
  3445. }
  3446. else
  3447. {
  3448. trail = *pRead++;
  3449. trail |= static_cast<utf16>(*pRead << 8);
  3450. }
  3451. nCur16 = (((nCur16 & 0x3ff) << 10) | (trail & 0x3ff)) + SURROGATE_FIRST_VALUE;
  3452. }
  3453. ++pRead;
  3454. if (nCur16 < 0x80)
  3455. {
  3456. nCur = static_cast<ubyte>(nCur16 & 0xFF);
  3457. state = eStart;
  3458. }
  3459. else if (nCur16 < 0x800)
  3460. {
  3461. nCur = static_cast<ubyte>(0xC0 | (nCur16 >> 6));
  3462. state = eFinal;
  3463. }
  3464. else if (nCur16 < SURROGATE_FIRST_VALUE)
  3465. {
  3466. nCur = static_cast<ubyte>(0xE0 | (nCur16 >> 12));
  3467. state = ePenultimate;
  3468. }
  3469. else
  3470. {
  3471. nCur = static_cast<ubyte>(0xF0 | (nCur16 >> 18));
  3472. state = eSecondOf4Bytes;
  3473. }
  3474. break;
  3475. case eSecondOf4Bytes:
  3476. nCur = static_cast<ubyte>(0x80 | ((nCur16 >> 12) & 0x3F));
  3477. state = ePenultimate;
  3478. break;
  3479. case ePenultimate:
  3480. nCur = static_cast<ubyte>(0x80 | ((nCur16 >> 6) & 0x3F));
  3481. state = eFinal;
  3482. break;
  3483. case eFinal:
  3484. nCur = static_cast<ubyte>(0x80 | (nCur16 & 0x3F));
  3485. state = eStart;
  3486. break;
  3487. // no default case is needed
  3488. }
  3489. *pCur++ = static_cast<ubyte>(nCur);
  3490. }
  3491. return pCur - pCurStart;
  3492. }
  3493. //----------------------------------------------------------------------------
  3494. } // namespace astyle
  3495. //----------------------------------------------------------------------------
  3496. using namespace astyle;
  3497. //----------------------------------------------------------------------------
  3498. // ASTYLE_JNI functions for Java library builds
  3499. //----------------------------------------------------------------------------
  3500. #ifdef ASTYLE_JNI
  3501. // called by a java program to get the version number
  3502. // the function name is constructed from method names in the calling java program
  3503. extern "C" EXPORT
  3504. jstring STDCALL Java_AStyleInterface_AStyleGetVersion(JNIEnv* env, jclass)
  3505. {
  3506. return env->NewStringUTF(g_version);
  3507. }
  3508. // called by a java program to format the source code
  3509. // the function name is constructed from method names in the calling java program
  3510. extern "C" EXPORT
  3511. jstring STDCALL Java_AStyleInterface_AStyleMain(JNIEnv* env,
  3512. jobject obj,
  3513. jstring textInJava,
  3514. jstring optionsJava)
  3515. {
  3516. g_env = env; // make object available globally
  3517. g_obj = obj; // make object available globally
  3518. jstring textErr = env->NewStringUTF(""); // zero length text returned if an error occurs
  3519. // get the method ID
  3520. jclass cls = env->GetObjectClass(obj);
  3521. g_mid = env->GetMethodID(cls, "ErrorHandler", "(ILjava/lang/String;)V");
  3522. if (g_mid == nullptr)
  3523. {
  3524. cout << "Cannot find java method ErrorHandler" << endl;
  3525. return textErr;
  3526. }
  3527. // convert jstring to char*
  3528. const char* textIn = env->GetStringUTFChars(textInJava, nullptr);
  3529. const char* options = env->GetStringUTFChars(optionsJava, nullptr);
  3530. // call the C++ formatting function
  3531. char* textOut = AStyleMain(textIn, options, javaErrorHandler, javaMemoryAlloc);
  3532. // if an error message occurred it was displayed by errorHandler
  3533. if (textOut == nullptr)
  3534. return textErr;
  3535. // release memory
  3536. jstring textOutJava = env->NewStringUTF(textOut);
  3537. delete[] textOut;
  3538. env->ReleaseStringUTFChars(textInJava, textIn);
  3539. env->ReleaseStringUTFChars(optionsJava, options);
  3540. return textOutJava;
  3541. }
  3542. // Call the Java error handler
  3543. void STDCALL javaErrorHandler(int errorNumber, const char* errorMessage)
  3544. {
  3545. jstring errorMessageJava = g_env->NewStringUTF(errorMessage);
  3546. g_env->CallVoidMethod(g_obj, g_mid, errorNumber, errorMessageJava);
  3547. }
  3548. // Allocate memory for the formatted text
  3549. char* STDCALL javaMemoryAlloc(unsigned long memoryNeeded)
  3550. {
  3551. // error condition is checked after return from AStyleMain
  3552. char* buffer = new (nothrow) char[memoryNeeded];
  3553. return buffer;
  3554. }
  3555. #endif // ASTYLE_JNI
  3556. //----------------------------------------------------------------------------
  3557. // ASTYLE_LIB functions for library builds
  3558. //----------------------------------------------------------------------------
  3559. #ifdef ASTYLE_LIB
  3560. //----------------------------------------------------------------------------
  3561. // ASTYLE_LIB entry point for AStyleMainUtf16 library builds
  3562. //----------------------------------------------------------------------------
  3563. /*
  3564. * IMPORTANT Visual C DLL linker for WIN32 must have the additional options:
  3565. * /EXPORT:AStyleMain=_AStyleMain@16
  3566. * /EXPORT:AStyleMainUtf16=_AStyleMainUtf16@16
  3567. * /EXPORT:AStyleGetVersion=_AStyleGetVersion@0
  3568. * No /EXPORT is required for x64
  3569. */
  3570. extern "C" EXPORT utf16_t* STDCALL AStyleMainUtf16(const utf16_t* pSourceIn, // the source to be formatted
  3571. const utf16_t* pOptions, // AStyle options
  3572. fpError fpErrorHandler, // error handler function
  3573. fpAlloc fpMemoryAlloc) // memory allocation function
  3574. {
  3575. if (fpErrorHandler == nullptr) // cannot display a message if no error handler
  3576. return nullptr;
  3577. if (pSourceIn == nullptr)
  3578. {
  3579. fpErrorHandler(101, "No pointer to source input.");
  3580. return nullptr;
  3581. }
  3582. if (pOptions == nullptr)
  3583. {
  3584. fpErrorHandler(102, "No pointer to AStyle options.");
  3585. return nullptr;
  3586. }
  3587. if (fpMemoryAlloc == nullptr)
  3588. {
  3589. fpErrorHandler(103, "No pointer to memory allocation function.");
  3590. return nullptr;
  3591. }
  3592. #ifndef _WIN32
  3593. // check size of utf16_t on Linux
  3594. int sizeCheck = 2;
  3595. if (sizeof(utf16_t) != sizeCheck)
  3596. {
  3597. fpErrorHandler(104, "Unsigned short is not the correct size.");
  3598. return nullptr;
  3599. }
  3600. #endif
  3601. ASLibrary library;
  3602. utf16_t* utf16Out = library.formatUtf16(pSourceIn, pOptions, fpErrorHandler, fpMemoryAlloc);
  3603. return utf16Out;
  3604. }
  3605. //----------------------------------------------------------------------------
  3606. // ASTYLE_LIB entry point for library builds
  3607. //----------------------------------------------------------------------------
  3608. /*
  3609. * IMPORTANT Visual C DLL linker for WIN32 must have the additional options:
  3610. * /EXPORT:AStyleMain=_AStyleMain@16
  3611. * /EXPORT:AStyleMainUtf16=_AStyleMainUtf16@16
  3612. * /EXPORT:AStyleGetVersion=_AStyleGetVersion@0
  3613. * No /EXPORT is required for x64
  3614. */
  3615. extern "C" EXPORT char* STDCALL AStyleMain(const char* pSourceIn, // the source to be formatted
  3616. const char* pOptions, // AStyle options
  3617. fpError fpErrorHandler, // error handler function
  3618. fpAlloc fpMemoryAlloc) // memory allocation function
  3619. {
  3620. if (fpErrorHandler == nullptr) // cannot display a message if no error handler
  3621. return nullptr;
  3622. if (pSourceIn == nullptr)
  3623. {
  3624. fpErrorHandler(101, "No pointer to source input.");
  3625. return nullptr;
  3626. }
  3627. if (pOptions == nullptr)
  3628. {
  3629. fpErrorHandler(102, "No pointer to AStyle options.");
  3630. return nullptr;
  3631. }
  3632. if (fpMemoryAlloc == nullptr)
  3633. {
  3634. fpErrorHandler(103, "No pointer to memory allocation function.");
  3635. return nullptr;
  3636. }
  3637. ASFormatter formatter;
  3638. ASOptions options(formatter);
  3639. vector<string> optionsVector;
  3640. istringstream opt(pOptions);
  3641. options.importOptions(opt, optionsVector);
  3642. bool ok = options.parseOptions(optionsVector, "Invalid Artistic Style options:");
  3643. if (!ok)
  3644. fpErrorHandler(130, options.getOptionErrors().c_str());
  3645. istringstream in(pSourceIn);
  3646. ASStreamIterator<istringstream> streamIterator(&in);
  3647. ostringstream out;
  3648. formatter.init(&streamIterator);
  3649. while (formatter.hasMoreLines())
  3650. {
  3651. out << formatter.nextLine();
  3652. if (formatter.hasMoreLines())
  3653. out << streamIterator.getOutputEOL();
  3654. else
  3655. {
  3656. // this can happen if the file if missing a closing brace and break-blocks is requested
  3657. if (formatter.getIsLineReady())
  3658. {
  3659. out << streamIterator.getOutputEOL();
  3660. out << formatter.nextLine();
  3661. }
  3662. }
  3663. }
  3664. size_t textSizeOut = out.str().length();
  3665. char* pTextOut = fpMemoryAlloc((long)textSizeOut + 1); // call memory allocation function
  3666. if (pTextOut == nullptr)
  3667. {
  3668. fpErrorHandler(120, "Allocation failure on output.");
  3669. return nullptr;
  3670. }
  3671. strcpy(pTextOut, out.str().c_str());
  3672. #ifndef NDEBUG
  3673. // The checksum is an assert in the console build and ASFormatter.
  3674. // This error returns the incorrectly formatted file to the editor.
  3675. // This is done to allow the file to be saved for debugging purposes.
  3676. if (formatter.getChecksumDiff() != 0)
  3677. fpErrorHandler(220,
  3678. "Checksum error.\n"
  3679. "The incorrectly formatted file will be returned for debugging.");
  3680. #endif
  3681. return pTextOut;
  3682. }
  3683. extern "C" EXPORT const char* STDCALL AStyleGetVersion(void)
  3684. {
  3685. return g_version;
  3686. }
  3687. // ASTYLECON_LIB is defined to exclude "main" from the test programs
  3688. #elif !defined(ASTYLECON_LIB)
  3689. //----------------------------------------------------------------------------
  3690. // main function for ASConsole build
  3691. //----------------------------------------------------------------------------
  3692. int main(int argc, char** argv)
  3693. {
  3694. // create objects
  3695. ASFormatter formatter;
  3696. auto console = make_shared<ASConsole>(formatter);
  3697. // process command line and options file
  3698. // build the vectors fileNameVector, optionsVector, and fileOptionsVector
  3699. vector<string> argvOptions;
  3700. argvOptions = console->getArgvOptions(argc, argv);
  3701. console->processOptions(argvOptions);
  3702. // if no files have been given, use cin for input and cout for output
  3703. if (!console->fileNameVectorIsEmpty())
  3704. console->processFiles();
  3705. else
  3706. console->formatCinToCout();
  3707. return EXIT_SUCCESS;
  3708. }
  3709. #endif // ASTYLE_LIB