nxstyle.c 90 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877
  1. /********************************************************************************
  2. * tools/nxstyle.c
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one or more
  5. * contributor license agreements. See the NOTICE file distributed with
  6. * this work for additional information regarding copyright ownership. The
  7. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. ********************************************************************************/
  20. /********************************************************************************
  21. * Included Files
  22. ********************************************************************************/
  23. #include <stdlib.h>
  24. #include <stdbool.h>
  25. #include <stdio.h>
  26. #include <stdint.h>
  27. #include <string.h>
  28. #include <strings.h>
  29. #include <ctype.h>
  30. #include <limits.h>
  31. #include <unistd.h>
  32. #include <libgen.h>
  33. /********************************************************************************
  34. * Pre-processor Definitions
  35. ********************************************************************************/
  36. #define NXSTYLE_VERSION "0.01"
  37. #define LINE_SIZE 512
  38. #define RANGE_NUMBER 4096
  39. #define DEFAULT_WIDTH 78
  40. #define FIRST_SECTION INCLUDED_FILES
  41. #define LAST_SECTION PUBLIC_FUNCTION_PROTOTYPES
  42. #define FATAL(m, l, o) message(FATAL, (m), (l), (o))
  43. #define FATALFL(m, s) message(FATAL, (m), -1, -1)
  44. #define WARN(m, l, o) message(WARN, (m), (l), (o))
  45. #define ERROR(m, l, o) message(ERROR, (m), (l), (o))
  46. #define ERRORFL(m, s) message(ERROR, (m), -1, -1)
  47. #define INFO(m, l, o) message(INFO, (m), (l), (o))
  48. #define INFOFL(m, s) message(INFO, (m), -1, -1)
  49. /********************************************************************************
  50. * Private types
  51. ********************************************************************************/
  52. enum class_e
  53. {
  54. INFO,
  55. WARN,
  56. ERROR,
  57. FATAL
  58. };
  59. const char *class_text[] =
  60. {
  61. "info",
  62. "warning",
  63. "error",
  64. "fatal"
  65. };
  66. enum file_e
  67. {
  68. UNKNOWN = 0x00,
  69. C_HEADER = 0x01,
  70. C_SOURCE = 0x02
  71. };
  72. enum section_s
  73. {
  74. NO_SECTION = 0,
  75. INCLUDED_FILES,
  76. PRE_PROCESSOR_DEFINITIONS,
  77. PUBLIC_TYPES,
  78. PRIVATE_TYPES,
  79. PRIVATE_DATA,
  80. PUBLIC_DATA,
  81. PRIVATE_FUNCTIONS,
  82. PRIVATE_FUNCTION_PROTOTYPES,
  83. INLINE_FUNCTIONS,
  84. PUBLIC_FUNCTIONS,
  85. PUBLIC_FUNCTION_PROTOTYPES
  86. };
  87. enum pptype_e
  88. {
  89. PPLINE_NONE = 0,
  90. PPLINE_DEFINE,
  91. PPLINE_IF,
  92. PPLINE_ELIF,
  93. PPLINE_ELSE,
  94. PPLINE_ENDIF,
  95. PPLINE_OTHER
  96. };
  97. struct file_section_s
  98. {
  99. const char *name; /* File section name */
  100. uint8_t ftype; /* File type where section found */
  101. };
  102. /********************************************************************************
  103. * Private data
  104. ********************************************************************************/
  105. static enum file_e g_file_type = UNKNOWN;
  106. static enum section_s g_section = NO_SECTION;
  107. static int g_maxline = DEFAULT_WIDTH;
  108. static int g_status = 0;
  109. static int g_verbose = 2;
  110. static int g_rangenumber = 0;
  111. static int g_rangestart[RANGE_NUMBER];
  112. static int g_rangecount[RANGE_NUMBER];
  113. static char g_file_name[PATH_MAX];
  114. static const struct file_section_s g_section_info[] =
  115. {
  116. {
  117. " *\n", /* Index: NO_SECTION */
  118. C_SOURCE | C_HEADER
  119. },
  120. {
  121. " * Included Files\n", /* Index: INCLUDED_FILES */
  122. C_SOURCE | C_HEADER
  123. },
  124. {
  125. " * Pre-processor Definitions\n", /* Index: PRE_PROCESSOR_DEFINITIONS */
  126. C_SOURCE | C_HEADER
  127. },
  128. {
  129. " * Public Types\n", /* Index: PUBLIC_TYPES */
  130. C_HEADER
  131. },
  132. {
  133. " * Private Types\n", /* Index: PRIVATE_TYPES */
  134. C_SOURCE
  135. },
  136. {
  137. " * Private Data\n", /* Index: PRIVATE_DATA */
  138. C_SOURCE
  139. },
  140. {
  141. " * Public Data\n", /* Index: PUBLIC_DATA */
  142. C_SOURCE | C_HEADER
  143. },
  144. {
  145. " * Private Functions\n", /* Index: PRIVATE_FUNCTIONS */
  146. C_SOURCE
  147. },
  148. {
  149. " * Private Function Prototypes\n", /* Index: PRIVATE_FUNCTION_PROTOTYPES */
  150. C_SOURCE
  151. },
  152. {
  153. " * Inline Functions\n", /* Index: INLINE_FUNCTIONS */
  154. C_SOURCE | C_HEADER
  155. },
  156. {
  157. " * Public Functions\n", /* Index: PUBLIC_FUNCTIONS */
  158. C_SOURCE
  159. },
  160. {
  161. " * Public Function Prototypes\n", /* Index: PUBLIC_FUNCTION_PROTOTYPES */
  162. C_SOURCE | C_HEADER
  163. }
  164. };
  165. static const char *g_white_prefix[] =
  166. {
  167. "Elf", /* Ref: include/elf.h, include/elf32.h, include/elf64.h */
  168. "PRId", /* Ref: inttypes.h */
  169. "PRIi", /* Ref: inttypes.h */
  170. "PRIo", /* Ref: inttypes.h */
  171. "PRIu", /* Ref: inttypes.h */
  172. "PRIx", /* Ref: inttypes.h */
  173. "SCNd", /* Ref: inttypes.h */
  174. "SCNi", /* Ref: inttypes.h */
  175. "SCNo", /* Ref: inttypes.h */
  176. "SCNu", /* Ref: inttypes.h */
  177. "SCNx", /* Ref: inttypes.h */
  178. "SYS_", /* Ref: include/sys/syscall.h */
  179. "STUB_", /* Ref: syscall/syscall_lookup.h, syscall/sycall_stublookup.c */
  180. "b8", /* Ref: include/fixedmath.h */
  181. "b16", /* Ref: include/fixedmath.h */
  182. "b32", /* Ref: include/fixedmath.h */
  183. "ub8", /* Ref: include/fixedmath.h */
  184. "ub16", /* Ref: include/fixedmath.h */
  185. "ub32", /* Ref: include/fixedmath.h */
  186. "ASCII_", /* Ref: include/nuttx/ascii.h */
  187. "XK_", /* Ref: include/input/X11_keysymdef.h */
  188. NULL
  189. };
  190. static const char *g_white_list[] =
  191. {
  192. /* Ref: gnu_unwind_find_exidx.c */
  193. "__EIT_entry",
  194. /* Ref: gnu_unwind_find_exidx.c */
  195. "__gnu_Unwind_Find_exidx",
  196. /* Ref: stdlib.h */
  197. "_Exit",
  198. /* Ref: stdatomic.h */
  199. "_Atomic",
  200. /* Ref: unwind-arm-common.h */
  201. "_Unwind",
  202. /* Ref:
  203. * https://pubs.opengroup.org/onlinepubs/9699919799/functions/tempnam.html
  204. */
  205. "P_tmpdir",
  206. /* Ref:
  207. * https://pubs.opengroup.org/onlinepubs/9699919799/functions/tempnam.html
  208. */
  209. "L_tmpnam",
  210. /* Ref:
  211. * nuttx/compiler.h
  212. */
  213. "_Far",
  214. "_Erom",
  215. /* Ref:
  216. * fs/nfs/rpc.h
  217. * fs/nfs/nfs_proto.h
  218. */
  219. "CREATE3args",
  220. "CREATE3resok",
  221. "LOOKUP3args",
  222. "LOOKUP3filename",
  223. "LOOKUP3resok",
  224. "WRITE3args",
  225. "WRITE3resok",
  226. "READ3args",
  227. "READ3resok",
  228. "REMOVE3args",
  229. "REMOVE3resok",
  230. "RENAME3args",
  231. "RENAME3resok",
  232. "MKDIR3args",
  233. "MKDIR3resok",
  234. "RMDIR3args",
  235. "RMDIR3resok",
  236. "READDIR3args",
  237. "READDIR3resok",
  238. "SETATTR3args",
  239. "SETATTR3resok",
  240. "FS3args",
  241. NULL
  242. };
  243. /********************************************************************************
  244. * Private Functions
  245. ********************************************************************************/
  246. /********************************************************************************
  247. * Name: show_usage
  248. *
  249. * Description:
  250. *
  251. ********************************************************************************/
  252. static void show_usage(char *progname, int exitcode, char *what)
  253. {
  254. fprintf(stderr, "%s version %s\n\n", basename(progname), NXSTYLE_VERSION);
  255. if (what)
  256. {
  257. fprintf(stderr, "%s\n", what);
  258. }
  259. fprintf(stderr, "Usage: %s [-m <excess>] [-v <level>] "
  260. "[-r <start,count>] <filename>\n",
  261. basename(progname));
  262. fprintf(stderr, " %s -h this help\n", basename(progname));
  263. fprintf(stderr, " %s -v <level> where level is\n",
  264. basename(progname));
  265. fprintf(stderr, " 0 - no output\n");
  266. fprintf(stderr, " 1 - PASS/FAIL\n");
  267. fprintf(stderr, " 2 - output each line (default)\n");
  268. exit(exitcode);
  269. }
  270. /********************************************************************************
  271. * Name: skip
  272. *
  273. * Description:
  274. *
  275. ********************************************************************************/
  276. static int skip(int lineno)
  277. {
  278. int i;
  279. for (i = 0; i < g_rangenumber; i++)
  280. {
  281. if (lineno >= g_rangestart[i] && lineno < g_rangestart[i] +
  282. g_rangecount[i])
  283. {
  284. return 0;
  285. }
  286. }
  287. return g_rangenumber != 0;
  288. }
  289. /********************************************************************************
  290. * Name: message
  291. *
  292. * Description:
  293. *
  294. ********************************************************************************/
  295. static int message(enum class_e class, const char *text, int lineno, int ndx)
  296. {
  297. FILE *out = stdout;
  298. if (skip(lineno))
  299. {
  300. return g_status;
  301. }
  302. if (class > INFO)
  303. {
  304. out = stderr;
  305. g_status |= 1;
  306. }
  307. if (g_verbose == 2)
  308. {
  309. if (lineno == -1 && ndx == -1)
  310. {
  311. fprintf(out, "%s: %s: %s\n", g_file_name, class_text[class], text);
  312. }
  313. else
  314. {
  315. fprintf(out, "%s:%d:%d: %s: %s\n", g_file_name, lineno, ndx,
  316. class_text[class], text);
  317. }
  318. }
  319. return g_status;
  320. }
  321. /********************************************************************************
  322. * Name: check_spaces_left
  323. *
  324. * Description:
  325. *
  326. ********************************************************************************/
  327. static void check_spaces_left(char *line, int lineno, int ndx)
  328. {
  329. /* Unary operator should generally be preceded by a space but make also
  330. * follow a left parenthesis at the beginning of a parenthetical list or
  331. * expression or follow a right parentheses in the case of a cast.
  332. */
  333. if (ndx-- > 0 && line[ndx] != ' ' && line[ndx] != '(' && line[ndx] != ')')
  334. {
  335. ERROR("Operator/assignment must be preceded with whitespace",
  336. lineno, ndx);
  337. }
  338. }
  339. /********************************************************************************
  340. * Name: check_spaces_leftright
  341. *
  342. * Description:
  343. *
  344. ********************************************************************************/
  345. static void check_spaces_leftright(char *line, int lineno, int ndx1, int ndx2)
  346. {
  347. if (ndx1 > 0 && line[ndx1 - 1] != ' ')
  348. {
  349. ERROR("Operator/assignment must be preceded with whitespace",
  350. lineno, ndx1);
  351. }
  352. if (line[ndx2 + 1] != '\0' && line[ndx2 + 1] != '\n' && line[ndx2 + 1] != ' ')
  353. {
  354. ERROR("Operator/assignment must be followed with whitespace",
  355. lineno, ndx2);
  356. }
  357. }
  358. /********************************************************************************
  359. * Name: block_comment_width
  360. *
  361. * Description:
  362. * Get the width of a block comment
  363. *
  364. ********************************************************************************/
  365. static int block_comment_width(char *line)
  366. {
  367. int b;
  368. int e;
  369. int n;
  370. /* Skip over any leading whitespace on the line */
  371. for (b = 0; isspace(line[b]); b++)
  372. {
  373. }
  374. /* Skip over any trailing whitespace at the end of the line */
  375. for (e = strlen(line) - 1; e >= 0 && isspace(line[e]); e--)
  376. {
  377. }
  378. /* Number of characters on the line */
  379. n = e - b + 1;
  380. if (n < 4)
  381. {
  382. return 0;
  383. }
  384. /* The first line of a block comment starts with "[slash]***" and ends with
  385. * "***"
  386. */
  387. if (strncmp(&line[b], "/***", 4) == 0 &&
  388. strncmp(&line[e - 2], "***", 3) == 0)
  389. {
  390. /* Return the the length of the line up to the final '*' */
  391. return e + 1;
  392. }
  393. /* The last line of a block begins with whitespace then "***" and ends
  394. * with "***[slash]"
  395. */
  396. if (strncmp(&line[b], "***", 3) == 0 &&
  397. strncmp(&line[e - 3], "***/", 4) == 0)
  398. {
  399. /* Return the the length of the line up to the final '*' */
  400. return e;
  401. }
  402. /* But there is also a special single line comment that begins with "[slash]* "
  403. * and ends with "***[slash]"
  404. */
  405. if (strncmp(&line[b], "/*", 2) == 0 &&
  406. strncmp(&line[e - 3], "***/", 4) == 0)
  407. {
  408. /* Return the the length of the line up to the final '*' */
  409. return e;
  410. }
  411. /* Return zero if the line is not the first or last line of a block
  412. * comment.
  413. */
  414. return 0;
  415. }
  416. /********************************************************************************
  417. * Name: get_line_width
  418. *
  419. * Description:
  420. * Get the maximum line width by examining the width of the block comments.
  421. *
  422. ********************************************************************************/
  423. static int get_line_width(FILE *instream)
  424. {
  425. char line[LINE_SIZE]; /* The current line being examined */
  426. int max = 0;
  427. int min = INT_MAX;
  428. int lineno = 0;
  429. int lineno_max = 0;
  430. int lineno_min = 0;
  431. int len;
  432. while (fgets(line, LINE_SIZE, instream))
  433. {
  434. lineno++;
  435. len = block_comment_width(line);
  436. if (len > 0)
  437. {
  438. if (len > max)
  439. {
  440. max = len;
  441. lineno_max = lineno;
  442. }
  443. if (len < min)
  444. {
  445. min = len;
  446. lineno_min = lineno;
  447. }
  448. }
  449. }
  450. if (max < min)
  451. {
  452. ERRORFL("No block comments found", g_file_name);
  453. return DEFAULT_WIDTH;
  454. }
  455. else if (max != min)
  456. {
  457. ERROR("Block comments have different lengths", lineno_max, max);
  458. ERROR("Block comments have different lengths", lineno_min, min);
  459. return DEFAULT_WIDTH;
  460. }
  461. return min;
  462. }
  463. /********************************************************************************
  464. * Name: check_section_header
  465. *
  466. * Description:
  467. * Check if the current line holds a section header
  468. *
  469. ********************************************************************************/
  470. static bool check_section_header(const char *line, int lineno)
  471. {
  472. int i;
  473. /* Search g_section_info[] to find a matching section header line */
  474. for (i = FIRST_SECTION; i <= LAST_SECTION; i++)
  475. {
  476. if (strcmp(line, g_section_info[i].name) == 0)
  477. {
  478. g_section = (enum section_s)i;
  479. /* Verify that this section is appropriate for this file type */
  480. if ((g_file_type & g_section_info[i].ftype) == 0)
  481. {
  482. ERROR("Invalid section for this file type", lineno, 3);
  483. }
  484. return true;
  485. }
  486. }
  487. return false;
  488. }
  489. /********************************************************************************
  490. * Name: white_prefix
  491. *
  492. * Description:
  493. * Return true if the identifier string begins with a white-listed prefix
  494. *
  495. ********************************************************************************/
  496. static bool white_list(const char *ident, int lineno)
  497. {
  498. const char **pptr;
  499. const char *str;
  500. for (pptr = g_white_prefix;
  501. (str = *pptr) != NULL;
  502. pptr++)
  503. {
  504. if (strncmp(ident, str, strlen(str)) == 0)
  505. {
  506. return true;
  507. }
  508. }
  509. for (pptr = g_white_list;
  510. (str = *pptr) != NULL;
  511. pptr++)
  512. {
  513. size_t len = strlen(str);
  514. if (strncmp(ident, str, len) == 0 &&
  515. isalnum(ident[len]) == 0)
  516. {
  517. return true;
  518. }
  519. }
  520. return false;
  521. }
  522. /********************************************************************************
  523. * Public Functions
  524. ********************************************************************************/
  525. int main(int argc, char **argv, char **envp)
  526. {
  527. FILE *instream; /* File input stream */
  528. char line[LINE_SIZE]; /* The current line being examined */
  529. char buffer[100]; /* Localy format error strings */
  530. char *lptr; /* Temporary pointer into line[] */
  531. char *ext; /* Temporary file extension */
  532. bool btabs; /* True: TAB characters found on the line */
  533. bool bcrs; /* True: Carriage return found on the line */
  534. bool bfunctions; /* True: In private or public functions */
  535. bool bstatm; /* True: This line is beginning of a statement */
  536. bool bfor; /* True: This line is beginning of a 'for' statement */
  537. bool bswitch; /* True: Within a switch statement */
  538. bool bstring; /* True: Within a string */
  539. bool bquote; /* True: Backslash quoted character next */
  540. bool bblank; /* Used to verify block comment terminator */
  541. bool bexternc; /* True: Within 'extern "C"' */
  542. enum pptype_e ppline; /* > 0: The next line the continuation of a
  543. * pre-processor command */
  544. int rhcomment; /* Indentation of Comment to the right of code
  545. * (-1 -> don't check position) */
  546. int prevrhcmt; /* Indentation of previous Comment to the right
  547. * of code (-1 -> don't check position) */
  548. int lineno; /* Current line number */
  549. int indent; /* Indentation level */
  550. int ncomment; /* Comment nesting level on this line */
  551. int prevncomment; /* Comment nesting level on the previous line */
  552. int bnest; /* Brace nesting level on this line */
  553. int prevbnest; /* Brace nesting level on the previous line */
  554. int dnest; /* Data declaration nesting level on this line */
  555. int prevdnest; /* Data declaration nesting level on the previous line */
  556. int pnest; /* Parenthesis nesting level on this line */
  557. int ppifnest; /* #if nesting level on this line */
  558. int inasm; /* > 0: Within #ifdef __ASSEMBLY__ */
  559. int comment_lineno; /* Line on which the last comment was closed */
  560. int blank_lineno; /* Line number of the last blank line */
  561. int noblank_lineno; /* A blank line is not needed after this line */
  562. int lbrace_lineno; /* Line number of last left brace */
  563. int rbrace_lineno; /* Last line containing a right brace */
  564. int externc_lineno; /* Last line where 'extern "C"' declared */
  565. int linelen; /* Length of the line */
  566. int excess;
  567. int n;
  568. int i;
  569. int c;
  570. excess = 0;
  571. while ((c = getopt(argc, argv, ":hv:gm:r:")) != -1)
  572. {
  573. switch (c)
  574. {
  575. case 'm':
  576. excess = atoi(optarg);
  577. if (excess < 1)
  578. {
  579. show_usage(argv[0], 1, "Bad value for <excess>.");
  580. excess = 0;
  581. }
  582. break;
  583. case 'v':
  584. g_verbose = atoi(optarg);
  585. if (g_verbose < 0 || g_verbose > 2)
  586. {
  587. show_usage(argv[0], 1, "Bad value for <level>.");
  588. }
  589. break;
  590. case 'r':
  591. g_rangestart[g_rangenumber] = atoi(strtok(optarg, ","));
  592. g_rangecount[g_rangenumber++] = atoi(strtok(NULL, ","));
  593. break;
  594. case 'h':
  595. show_usage(argv[0], 0, NULL);
  596. break;
  597. case ':':
  598. show_usage(argv[0], 1, "Missing argument.");
  599. break;
  600. case '?':
  601. show_usage(argv[0], 1, "Unrecognized option.");
  602. break;
  603. default:
  604. show_usage(argv[0], 0, NULL);
  605. break;
  606. }
  607. }
  608. if (optind < argc - 1 || argv[optind] == NULL)
  609. {
  610. show_usage(argv[0], 1, "No file name given.");
  611. }
  612. /* Resolve the absolute path for the input file */
  613. if (realpath(argv[optind], g_file_name) == NULL)
  614. {
  615. FATALFL("Failed to resolve absolute path.", g_file_name);
  616. return 1;
  617. }
  618. /* Are we parsing a header file? */
  619. ext = strrchr(g_file_name, '.');
  620. if (ext == 0)
  621. {
  622. }
  623. else if (strcmp(ext, ".h") == 0)
  624. {
  625. g_file_type = C_HEADER;
  626. }
  627. else if (strcmp(ext, ".c") == 0)
  628. {
  629. g_file_type = C_SOURCE;
  630. }
  631. if (g_file_type == UNKNOWN)
  632. {
  633. return 0;
  634. }
  635. instream = fopen(g_file_name, "r");
  636. if (!instream)
  637. {
  638. FATALFL("Failed to open", g_file_name);
  639. return 1;
  640. }
  641. /* Determine the line width */
  642. g_maxline = get_line_width(instream) + excess;
  643. rewind(instream);
  644. btabs = false; /* True: TAB characters found on the line */
  645. bcrs = false; /* True: Carriage return found on the line */
  646. bfunctions = false; /* True: In private or public functions */
  647. bswitch = false; /* True: Within a switch statement */
  648. bstring = false; /* True: Within a string */
  649. bexternc = false; /* True: Within 'extern "C"' */
  650. ppline = PPLINE_NONE; /* > 0: The next line the continuation of a
  651. * pre-processor command */
  652. rhcomment = 0; /* Indentation of Comment to the right of code
  653. * (-1 -> don't check position) */
  654. prevrhcmt = 0; /* Indentation of previous Comment to the right
  655. * of code (-1 -> don't check position) */
  656. lineno = 0; /* Current line number */
  657. ncomment = 0; /* Comment nesting level on this line */
  658. bnest = 0; /* Brace nesting level on this line */
  659. dnest = 0; /* Data declaration nesting level on this line */
  660. pnest = 0; /* Parenthesis nesting level on this line */
  661. ppifnest = 0; /* #if nesting level on this line */
  662. inasm = 0; /* > 0: Within #ifdef __ASSEMBLY__ */
  663. comment_lineno = -1; /* Line on which the last comment was closed */
  664. blank_lineno = -1; /* Line number of the last blank line */
  665. noblank_lineno = -1; /* A blank line is not needed after this line */
  666. lbrace_lineno = -1; /* Line number of last left brace */
  667. rbrace_lineno = -1; /* Last line containing a right brace */
  668. externc_lineno = -1; /* Last line where 'extern "C"' declared */
  669. /* Process each line in the input stream */
  670. while (fgets(line, LINE_SIZE, instream))
  671. {
  672. lineno++;
  673. indent = 0;
  674. prevbnest = bnest; /* Brace nesting level on the previous line */
  675. prevdnest = dnest; /* Data declaration nesting level on the
  676. * previous line */
  677. prevncomment = ncomment; /* Comment nesting level on the previous line */
  678. bstatm = false; /* True: This line is beginning of a
  679. * statement */
  680. bfor = false; /* REVISIT: Implies for() is all on one line */
  681. /* If we are not in a comment, then this certainly is not a right-hand
  682. * comment.
  683. */
  684. prevrhcmt = rhcomment;
  685. if (ncomment <= 0)
  686. {
  687. rhcomment = 0;
  688. }
  689. /* Check for a blank line */
  690. for (n = 0; line[n] != '\n' && isspace((int)line[n]); n++)
  691. {
  692. }
  693. if (line[n] == '\n')
  694. {
  695. if (n > 0)
  696. {
  697. ERROR("Blank line contains whitespace", lineno, 1);
  698. }
  699. if (lineno == 1)
  700. {
  701. ERROR("File begins with a blank line", 1, 1);
  702. }
  703. else if (lineno == blank_lineno + 1)
  704. {
  705. ERROR("Too many blank lines", lineno, 1);
  706. }
  707. else if (lineno == lbrace_lineno + 1)
  708. {
  709. ERROR("Blank line follows left brace", lineno, 1);
  710. }
  711. blank_lineno = lineno;
  712. continue;
  713. }
  714. else /* This line is non-blank */
  715. {
  716. /* Check for a missing blank line after a comment */
  717. if (lineno == comment_lineno + 1)
  718. {
  719. /* No blank line should be present if the current line contains
  720. * a right brace, a pre-processor line, the start of another
  721. * comment.
  722. *
  723. * REVISIT: Generates a false alarm if the current line is also
  724. * a comment. Generally it is acceptable for one comment to
  725. * follow another with no space separation.
  726. *
  727. * REVISIT: prevrhcmt is tested to case the preceding line
  728. * contained comments to the right of the code. In such cases,
  729. * the comments are normally aligned and do not follow normal
  730. * indentation rules. However, this code will generate a false
  731. * alarm if the comments are aligned to the right BUT the
  732. * preceding line has no comment.
  733. */
  734. if (line[n] != '}' && line[n] != '#' && prevrhcmt == 0)
  735. {
  736. ERROR("Missing blank line after comment", comment_lineno,
  737. 1);
  738. }
  739. }
  740. /* Files must begin with a comment (the file header).
  741. * REVISIT: Logically, this belongs in the STEP 2 operations
  742. * below.
  743. */
  744. if (lineno == 1 && (line[n] != '/' || line[n + 1] != '*'))
  745. {
  746. ERROR("Missing file header comment block", lineno, 1);
  747. }
  748. if (lineno == 2)
  749. {
  750. if (line[n] == '*' && line[n + 1] == '\n')
  751. {
  752. ERROR("Missing relative file path in file header", lineno,
  753. n);
  754. }
  755. else if (isspace(line[n + 2]))
  756. {
  757. ERROR("Too many whitespaces before relative file path",
  758. lineno, n);
  759. }
  760. else
  761. {
  762. const char *apps_dir = "apps/";
  763. const size_t apps_len = strlen(apps_dir);
  764. size_t offset;
  765. #ifdef TOPDIR
  766. /* TOPDIR macro contains the absolute path to the "nuttx"
  767. * root directory. It should have been defined via Makefile
  768. * and it is required to accurately evaluate the relative
  769. * path contained in the file header. Otherwise, skip this
  770. * verification.
  771. */
  772. char *basedir = strstr(g_file_name, TOPDIR);
  773. if (basedir != NULL)
  774. {
  775. /* Add 1 to the offset for the slash character */
  776. offset = strlen(TOPDIR) + 1;
  777. /* Duplicate the line from the beginning of the
  778. * relative file path, removing the '\n' at the end of
  779. * the string.
  780. */
  781. char *line_dup = strndup(&line[n + 2],
  782. strlen(&line[n + 2]) - 1);
  783. if (strcmp(line_dup, basedir + offset) != 0)
  784. {
  785. ERROR("Relative file path does not match actual file",
  786. lineno, n);
  787. }
  788. free(line_dup);
  789. }
  790. else if (strncmp(&line[n + 2], apps_dir, apps_len) != 0)
  791. {
  792. /* g_file_name neither belongs to "nuttx" repository
  793. * nor begins with the root dir of the other
  794. * repository (e.g. "apps/")
  795. */
  796. ERROR("Path relative to repository other than \"nuttx\" "
  797. "must begin with the root directory", lineno, n);
  798. }
  799. else
  800. {
  801. #endif
  802. offset = 0;
  803. if (strncmp(&line[n + 2], apps_dir, apps_len) == 0)
  804. {
  805. /* Input file belongs to the "apps" repository */
  806. /* Calculate the offset to the first directory
  807. * after the "apps/" folder.
  808. */
  809. offset += apps_len;
  810. }
  811. /* Duplicate the line from the beginning of the
  812. * relative file path, removing the '\n' at the end of
  813. * the string.
  814. */
  815. char *line_dup = strndup(&line[n + 2],
  816. strlen(&line[n + 2]) - 1);
  817. ssize_t base =
  818. strlen(g_file_name) - strlen(&line_dup[offset]);
  819. if (base < 0 ||
  820. (base != 0 && g_file_name[base - 1] != '/') ||
  821. strcmp(&g_file_name[base], &line_dup[offset]) != 0)
  822. {
  823. ERROR("Relative file path does not match actual file",
  824. lineno, n);
  825. }
  826. free(line_dup);
  827. #ifdef TOPDIR
  828. }
  829. #endif
  830. }
  831. }
  832. /* Check for a blank line following a right brace */
  833. if (bfunctions && lineno == rbrace_lineno + 1)
  834. {
  835. /* Check if this line contains a right brace. A right brace
  836. * must be followed by 'else', 'while', 'break', a blank line,
  837. * another right brace, or a pre-processor directive like #endif
  838. */
  839. if (dnest == 0 &&
  840. strchr(line, '}') == NULL && line[n] != '#' &&
  841. strncmp(&line[n], "else", 4) != 0 &&
  842. strncmp(&line[n], "while", 5) != 0 &&
  843. strncmp(&line[n], "break", 5) != 0)
  844. {
  845. ERROR("Right brace must be followed by a blank line",
  846. rbrace_lineno, n + 1);
  847. }
  848. /* If the right brace is followed by a pre-processor command
  849. * like #endif (but not #else or #elif), then set the right
  850. * brace line number to the line number of the pre-processor
  851. * command (it then must be followed by a blank line)
  852. */
  853. if (line[n] == '#')
  854. {
  855. int ii;
  856. for (ii = n + 1; line[ii] != '\0' && isspace(line[ii]); ii++)
  857. {
  858. }
  859. if (strncmp(&line[ii], "else", 4) != 0 &&
  860. strncmp(&line[ii], "elif", 4) != 0)
  861. {
  862. rbrace_lineno = lineno;
  863. }
  864. }
  865. }
  866. }
  867. /* STEP 1: Find the indentation level and the start of real stuff on
  868. * the line.
  869. */
  870. for (n = 0; line[n] != '\n' && isspace((int)line[n]); n++)
  871. {
  872. switch (line[n])
  873. {
  874. case ' ':
  875. {
  876. indent++;
  877. }
  878. break;
  879. case '\t':
  880. {
  881. if (!btabs)
  882. {
  883. ERROR("TABs found. First detected", lineno, n);
  884. btabs = true;
  885. }
  886. indent = (indent + 4) & ~3;
  887. }
  888. break;
  889. case '\r':
  890. {
  891. if (!bcrs)
  892. {
  893. ERROR("Carriage returns found. "
  894. "First detected", lineno, n);
  895. bcrs = true;
  896. }
  897. }
  898. break;
  899. default:
  900. {
  901. snprintf(buffer, sizeof(buffer),
  902. "Unexpected white space character %02x found",
  903. line[n]);
  904. ERROR(buffer, lineno, n);
  905. }
  906. break;
  907. }
  908. }
  909. /* STEP 2: Detect some certain start of line conditions */
  910. /* Skip over pre-processor lines (or continuations of pre-processor
  911. * lines as indicated by ppline)
  912. */
  913. if (line[indent] == '#' || ppline != PPLINE_NONE)
  914. {
  915. int len;
  916. int ii;
  917. /* Suppress error for comment following conditional compilation */
  918. noblank_lineno = lineno;
  919. /* Check pre-processor commands if this is not a continuation
  920. * line.
  921. */
  922. ii = indent + 1;
  923. if (ppline == PPLINE_NONE)
  924. {
  925. /* Skip to the pre-processor command following the '#' */
  926. while (line[ii] != '\0' && isspace(line[ii]))
  927. {
  928. ii++;
  929. }
  930. if (line[ii] != '\0')
  931. {
  932. /* Make sure that pre-processor definitions are all in
  933. * the pre-processor definitions section.
  934. */
  935. ppline = PPLINE_OTHER;
  936. if (strncmp(&line[ii], "define", 6) == 0)
  937. {
  938. ppline = PPLINE_DEFINE;
  939. if (g_section != PRE_PROCESSOR_DEFINITIONS)
  940. {
  941. /* A complication is the header files always have
  942. * the idempotence guard definitions before the
  943. * "Pre-processor Definitions section".
  944. */
  945. if (g_section == NO_SECTION &&
  946. g_file_type != C_HEADER)
  947. {
  948. /* Only a warning because there is some usage
  949. * of define outside the Pre-processor
  950. * Definitions section which is justifiable.
  951. * Should be manually checked.
  952. */
  953. WARN("#define outside of 'Pre-processor "
  954. "Definitions' section",
  955. lineno, ii);
  956. }
  957. }
  958. }
  959. /* Make sure that files are included only in the Included
  960. * Files section.
  961. */
  962. else if (strncmp(&line[ii], "include", 7) == 0)
  963. {
  964. if (g_section != INCLUDED_FILES)
  965. {
  966. /* Only a warning because there is some usage of
  967. * include outside the Included Files section
  968. * which may be is justifiable. Should be
  969. * manually checked.
  970. */
  971. WARN("#include outside of 'Included Files' "
  972. "section",
  973. lineno, ii);
  974. }
  975. }
  976. else if (strncmp(&line[ii], "if", 2) == 0)
  977. {
  978. ppifnest++;
  979. ppline = PPLINE_IF;
  980. ii += 2;
  981. }
  982. else if (strncmp(&line[ii], "elif", 4) == 0)
  983. {
  984. if (ppifnest == inasm)
  985. {
  986. inasm = 0;
  987. }
  988. ppline = PPLINE_ELIF;
  989. ii += 4;
  990. }
  991. else if (strncmp(&line[ii], "else", 4) == 0)
  992. {
  993. if (ppifnest == inasm)
  994. {
  995. inasm = 0;
  996. }
  997. ppline = PPLINE_ELSE;
  998. }
  999. else if (strncmp(&line[ii], "endif", 4) == 0)
  1000. {
  1001. if (ppifnest == inasm)
  1002. {
  1003. inasm = 0;
  1004. }
  1005. ppifnest--;
  1006. ppline = PPLINE_ENDIF;
  1007. }
  1008. }
  1009. }
  1010. if (ppline == PPLINE_IF || ppline == PPLINE_ELIF)
  1011. {
  1012. int bdef = 0;
  1013. if (strncmp(&line[ii], "def", 3) == 0)
  1014. {
  1015. bdef = 1;
  1016. ii += 3;
  1017. }
  1018. else
  1019. {
  1020. while (line[ii] != '\0' && isspace(line[ii]))
  1021. {
  1022. ii++;
  1023. }
  1024. if (strncmp(&line[ii], "defined", 7) == 0)
  1025. {
  1026. bdef = 1;
  1027. ii += 7;
  1028. }
  1029. }
  1030. if (bdef)
  1031. {
  1032. while (line[ii] != '\0' &&
  1033. (isspace(line[ii]) || line[ii] == '('))
  1034. {
  1035. ii++;
  1036. }
  1037. if (strncmp(&line[ii], "__ASSEMBLY__", 12) == 0)
  1038. {
  1039. inasm = ppifnest;
  1040. }
  1041. }
  1042. }
  1043. /* Check if the next line will be a continuation of the pre-
  1044. * processor command.
  1045. */
  1046. len = strlen(&line[indent]) + indent - 1;
  1047. if (line[len] == '\n')
  1048. {
  1049. len--;
  1050. }
  1051. /* Propagate rhcomment over preprocessor lines Issue #120 */
  1052. if (prevrhcmt != 0)
  1053. {
  1054. /* Don't check position */
  1055. rhcomment = -1;
  1056. }
  1057. lptr = strstr(line, "/*");
  1058. if (lptr != NULL)
  1059. {
  1060. n = lptr - &line[0];
  1061. if (line[n + 2] == '\n')
  1062. {
  1063. ERROR("C comment opening on separate line", lineno, n);
  1064. }
  1065. else if (!isspace((int)line[n + 2]) && line[n + 2] != '*')
  1066. {
  1067. ERROR("Missing space after opening C comment", lineno, n);
  1068. }
  1069. if (strstr(lptr, "*/") == NULL)
  1070. {
  1071. /* Increment the count of nested comments */
  1072. ncomment++;
  1073. }
  1074. if (ppline == PPLINE_DEFINE)
  1075. {
  1076. rhcomment = n;
  1077. if (prevrhcmt > 0 && n != prevrhcmt)
  1078. {
  1079. rhcomment = prevrhcmt;
  1080. WARN("Wrong column position of comment right of code",
  1081. lineno, n);
  1082. }
  1083. }
  1084. else
  1085. {
  1086. /* Signal rhcomment, but ignore position */
  1087. rhcomment = -1;
  1088. if (ncomment > 0 &&
  1089. (ppline == PPLINE_IF ||
  1090. ppline == PPLINE_ELSE ||
  1091. ppline == PPLINE_ELIF))
  1092. {
  1093. /* in #if... and #el... */
  1094. ERROR("No multiline comment right of code allowed here",
  1095. lineno, n);
  1096. }
  1097. }
  1098. }
  1099. if (line[len] != '\\' || ncomment > 0)
  1100. {
  1101. ppline = PPLINE_NONE;
  1102. }
  1103. continue;
  1104. }
  1105. /* Check for a single line comment */
  1106. linelen = strlen(line);
  1107. if (linelen >= 5) /* Minimum is slash, star, star, slash, newline */
  1108. {
  1109. lptr = strstr(line, "*/");
  1110. if (line[indent] == '/' && line[indent + 1] == '*' &&
  1111. lptr - line == linelen - 3)
  1112. {
  1113. /* If preceding comments were to the right of code, then we can
  1114. * assume that there is a columnar alignment of columns that do
  1115. * no follow the usual alignment. So the rhcomment flag
  1116. * should propagate.
  1117. */
  1118. rhcomment = prevrhcmt;
  1119. /* Check if there should be a blank line before the comment */
  1120. if (lineno > 1 &&
  1121. comment_lineno != lineno - 1 &&
  1122. blank_lineno != lineno - 1 &&
  1123. noblank_lineno != lineno - 1 &&
  1124. rhcomment == 0)
  1125. {
  1126. /* TODO: This generates a false alarm if preceded
  1127. * by a label.
  1128. */
  1129. ERROR("Missing blank line before comment found", lineno, 1);
  1130. }
  1131. /* 'comment_lineno 'holds the line number of the last closing
  1132. * comment. It is used only to verify that the comment is
  1133. * followed by a blank line.
  1134. */
  1135. comment_lineno = lineno;
  1136. }
  1137. }
  1138. /* Check for the comment block indicating the beginning of a new file
  1139. * section.
  1140. */
  1141. if (check_section_header(line, lineno))
  1142. {
  1143. if (g_section == PRIVATE_FUNCTIONS || g_section == PUBLIC_FUNCTIONS)
  1144. {
  1145. bfunctions = true; /* Latched */
  1146. }
  1147. }
  1148. /* Check for some kind of declaration.
  1149. * REVISIT: The following logic fails for any non-standard types.
  1150. * REVISIT: Terminator after keyword might not be a space. Might be
  1151. * a newline, for example. struct and unions are often unnamed, for
  1152. * example.
  1153. */
  1154. else if (inasm == 0)
  1155. {
  1156. if (strncmp(&line[indent], "auto ", 5) == 0 ||
  1157. strncmp(&line[indent], "bool ", 5) == 0 ||
  1158. strncmp(&line[indent], "char ", 5) == 0 ||
  1159. strncmp(&line[indent], "CODE ", 5) == 0 ||
  1160. strncmp(&line[indent], "const ", 6) == 0 ||
  1161. strncmp(&line[indent], "double ", 7) == 0 ||
  1162. strncmp(&line[indent], "struct ", 7) == 0 ||
  1163. strncmp(&line[indent], "struct\n", 7) == 0 || /* May be unnamed */
  1164. strncmp(&line[indent], "enum ", 5) == 0 ||
  1165. strncmp(&line[indent], "extern ", 7) == 0 ||
  1166. strncmp(&line[indent], "EXTERN ", 7) == 0 ||
  1167. strncmp(&line[indent], "FAR ", 4) == 0 ||
  1168. strncmp(&line[indent], "float ", 6) == 0 ||
  1169. strncmp(&line[indent], "int ", 4) == 0 ||
  1170. strncmp(&line[indent], "int16_t ", 8) == 0 ||
  1171. strncmp(&line[indent], "int32_t ", 8) == 0 ||
  1172. strncmp(&line[indent], "long ", 5) == 0 ||
  1173. strncmp(&line[indent], "off_t ", 6) == 0 ||
  1174. strncmp(&line[indent], "register ", 9) == 0 ||
  1175. strncmp(&line[indent], "short ", 6) == 0 ||
  1176. strncmp(&line[indent], "signed ", 7) == 0 ||
  1177. strncmp(&line[indent], "size_t ", 7) == 0 ||
  1178. strncmp(&line[indent], "ssize_t ", 8) == 0 ||
  1179. strncmp(&line[indent], "static ", 7) == 0 ||
  1180. strncmp(&line[indent], "time_t ", 7) == 0 ||
  1181. strncmp(&line[indent], "typedef ", 8) == 0 ||
  1182. strncmp(&line[indent], "uint8_t ", 8) == 0 ||
  1183. strncmp(&line[indent], "uint16_t ", 9) == 0 ||
  1184. strncmp(&line[indent], "uint32_t ", 9) == 0 ||
  1185. strncmp(&line[indent], "union ", 6) == 0 ||
  1186. strncmp(&line[indent], "union\n", 6) == 0 || /* May be unnamed */
  1187. strncmp(&line[indent], "unsigned ", 9) == 0 ||
  1188. strncmp(&line[indent], "void ", 5) == 0 ||
  1189. strncmp(&line[indent], "volatile ", 9) == 0)
  1190. {
  1191. /* Check if this is extern "C"; We don't typically indent
  1192. * following this.
  1193. */
  1194. if (strncmp(&line[indent], "extern \"C\"", 10) == 0)
  1195. {
  1196. externc_lineno = lineno;
  1197. }
  1198. /* bfunctions: True: Processing private or public functions.
  1199. * bnest: Brace nesting level on this line
  1200. * dnest: Data declaration nesting level on this line
  1201. */
  1202. /* REVISIT: Also picks up function return types */
  1203. /* REVISIT: Logic problem for nested data/function declarations */
  1204. if ((!bfunctions || bnest > 0) && dnest == 0)
  1205. {
  1206. dnest = 1;
  1207. }
  1208. /* Check for multiple definitions of variables on the line.
  1209. * Ignores declarations within parentheses which are probably
  1210. * formal parameters.
  1211. */
  1212. if (pnest == 0)
  1213. {
  1214. int tmppnest;
  1215. /* Note, we have not yet parsed each character on the line so
  1216. * a comma have have been be preceded by '(' on the same line.
  1217. * We will have parse up to any comma to see if that is the
  1218. * case.
  1219. */
  1220. for (i = indent, tmppnest = 0;
  1221. line[i] != '\n' && line[i] != '\0';
  1222. i++)
  1223. {
  1224. if (tmppnest == 0 && line[i] == ',')
  1225. {
  1226. ERROR("Multiple data definitions", lineno, i + 1);
  1227. break;
  1228. }
  1229. else if (line[i] == '(')
  1230. {
  1231. tmppnest++;
  1232. }
  1233. else if (line[i] == ')')
  1234. {
  1235. if (tmppnest < 1)
  1236. {
  1237. /* We should catch this later */
  1238. break;
  1239. }
  1240. tmppnest--;
  1241. }
  1242. else if (line[i] == ';')
  1243. {
  1244. /* Break out if the semicolon terminates the
  1245. * declaration is found. Avoids processing any
  1246. * righthand comments in most cases.
  1247. */
  1248. break;
  1249. }
  1250. }
  1251. }
  1252. }
  1253. /* Check for a keyword indicating the beginning of a statement.
  1254. * REVISIT: This, obviously, will not detect statements that do not
  1255. * begin with a C keyword (such as assignment statements).
  1256. */
  1257. else if (strncmp(&line[indent], "break ", 6) == 0 ||
  1258. strncmp(&line[indent], "case ", 5) == 0 ||
  1259. #if 0 /* Part of switch */
  1260. strncmp(&line[indent], "case ", 5) == 0 ||
  1261. #endif
  1262. strncmp(&line[indent], "continue ", 9) == 0 ||
  1263. #if 0 /* Part of switch */
  1264. strncmp(&line[indent], "default ", 8) == 0 ||
  1265. #endif
  1266. strncmp(&line[indent], "do ", 3) == 0 ||
  1267. strncmp(&line[indent], "else ", 5) == 0 ||
  1268. strncmp(&line[indent], "goto ", 5) == 0 ||
  1269. strncmp(&line[indent], "if ", 3) == 0 ||
  1270. strncmp(&line[indent], "return ", 7) == 0 ||
  1271. #if 0 /* Doesn't follow pattern */
  1272. strncmp(&line[indent], "switch ", 7) == 0 ||
  1273. #endif
  1274. strncmp(&line[indent], "while ", 6) == 0)
  1275. {
  1276. bstatm = true;
  1277. }
  1278. /* Spacing works a little differently for and switch statements */
  1279. else if (strncmp(&line[indent], "for ", 4) == 0)
  1280. {
  1281. bfor = true;
  1282. bstatm = true;
  1283. }
  1284. else if (strncmp(&line[indent], "switch ", 7) == 0)
  1285. {
  1286. bswitch = true;
  1287. }
  1288. /* Also check for C keywords with missing white space */
  1289. else if (strncmp(&line[indent], "do(", 3) == 0 ||
  1290. strncmp(&line[indent], "if(", 3) == 0 ||
  1291. strncmp(&line[indent], "while(", 6) == 0)
  1292. {
  1293. ERROR("Missing whitespace after keyword", lineno, n);
  1294. bstatm = true;
  1295. }
  1296. else if (strncmp(&line[indent], "for(", 4) == 0)
  1297. {
  1298. ERROR("Missing whitespace after keyword", lineno, n);
  1299. bfor = true;
  1300. bstatm = true;
  1301. }
  1302. else if (strncmp(&line[indent], "switch(", 7) == 0)
  1303. {
  1304. ERROR("Missing whitespace after keyword", lineno, n);
  1305. bswitch = true;
  1306. }
  1307. }
  1308. /* STEP 3: Parse each character on the line */
  1309. bquote = false; /* True: Backslash quoted character next */
  1310. bblank = true; /* Used to verify block comment terminator */
  1311. for (; line[n] != '\n' && line[n] != '\0'; n++)
  1312. {
  1313. /* Report any use of non-standard white space characters */
  1314. if (isspace(line[n]))
  1315. {
  1316. if (line[n] == '\t')
  1317. {
  1318. if (!btabs)
  1319. {
  1320. ERROR("TABs found. First detected", lineno, n);
  1321. btabs = true;
  1322. }
  1323. }
  1324. else if (line[n] == '\r')
  1325. {
  1326. if (!bcrs)
  1327. {
  1328. ERROR("Carriage returns found. "
  1329. "First detected", lineno, n);
  1330. bcrs = true;
  1331. }
  1332. }
  1333. else if (line[n] != ' ')
  1334. {
  1335. snprintf(buffer, sizeof(buffer),
  1336. "Unexpected white space character %02x found",
  1337. line[n]);
  1338. ERROR(buffer, lineno, n);
  1339. }
  1340. }
  1341. /* Skip over identifiers */
  1342. if (ncomment == 0 && !bstring && (line[n] == '_' || isalpha(line[n])))
  1343. {
  1344. bool have_upper = false;
  1345. bool have_lower = false;
  1346. int ident_index = n;
  1347. /* Parse over the identifier. Check if it contains mixed upper-
  1348. * and lower-case characters.
  1349. */
  1350. do
  1351. {
  1352. have_upper |= isupper(line[n]);
  1353. /* The coding standard provides for some exceptions of lower
  1354. * case characters in pre-processor strings:
  1355. *
  1356. * IPv[4|6] as an IP version number
  1357. * ICMPv6 as an ICMP version number
  1358. * IGMPv2 as an IGMP version number
  1359. * [0-9]p[0-9] as a decimal point
  1360. * d[0-9] as a divisor
  1361. * Hz for frequencies (including KHz, MHz, etc.)
  1362. */
  1363. if (!have_lower && islower(line[n]))
  1364. {
  1365. switch (line[n])
  1366. {
  1367. /* A sequence containing 'v' may occur at the
  1368. * beginning of the identifier.
  1369. */
  1370. case 'v':
  1371. if (n > 1 &&
  1372. line[n - 2] == 'I' &&
  1373. line[n - 1] == 'P' &&
  1374. (line[n + 1] == '4' ||
  1375. line[n + 1] == '6'))
  1376. {
  1377. }
  1378. else if (n > 3 &&
  1379. line[n - 4] == 'I' &&
  1380. line[n - 3] == 'C' &&
  1381. line[n - 2] == 'M' &&
  1382. line[n - 1] == 'P' &&
  1383. line[n + 1] == '6')
  1384. {
  1385. }
  1386. else if (n > 3 &&
  1387. line[n - 4] == 'I' &&
  1388. line[n - 3] == 'G' &&
  1389. line[n - 2] == 'M' &&
  1390. line[n - 1] == 'P' &&
  1391. line[n + 1] == '2')
  1392. {
  1393. }
  1394. else
  1395. {
  1396. have_lower = true;
  1397. }
  1398. break;
  1399. /* Sequences containing 'p', 'd', or 'z' must have
  1400. * been preceded by upper case characters.
  1401. */
  1402. case 'p':
  1403. if (!have_upper || n < 1 ||
  1404. !isdigit(line[n - 1]) ||
  1405. !isdigit(line[n + 1]))
  1406. {
  1407. have_lower = true;
  1408. }
  1409. break;
  1410. case 'd':
  1411. if (!have_upper || !isdigit(line[n + 1]))
  1412. {
  1413. have_lower = true;
  1414. }
  1415. break;
  1416. case 'z':
  1417. if (!have_upper || n < 1 ||
  1418. line[n - 1] != 'H')
  1419. {
  1420. have_lower = true;
  1421. }
  1422. break;
  1423. break;
  1424. default:
  1425. have_lower = true;
  1426. break;
  1427. }
  1428. }
  1429. n++;
  1430. }
  1431. while (line[n] == '_' || isalnum(line[n]));
  1432. /* Check for mixed upper and lower case */
  1433. if (have_upper && have_lower)
  1434. {
  1435. /* Ignore symbols that begin with white-listed prefixes */
  1436. if (white_list(&line[ident_index], lineno))
  1437. {
  1438. /* No error */
  1439. }
  1440. /* Special case hex constants. These will look like
  1441. * identifiers starting with 'x' or 'X' but preceded
  1442. * with '0'
  1443. */
  1444. else if (ident_index < 1 ||
  1445. (line[ident_index] != 'x' &&
  1446. line[ident_index] != 'X') ||
  1447. line[ident_index - 1] != '0')
  1448. {
  1449. ERROR("Mixed case identifier found",
  1450. lineno, ident_index);
  1451. }
  1452. else if (have_upper)
  1453. {
  1454. ERROR("Upper case hex constant found",
  1455. lineno, ident_index);
  1456. }
  1457. }
  1458. /* Check if the identifier is the last thing on the line */
  1459. if (line[n] == '\n' || line[n] == '\0')
  1460. {
  1461. break;
  1462. }
  1463. }
  1464. /* Handle comments */
  1465. if (line[n] == '/' && !bstring)
  1466. {
  1467. /* Check for start of a C comment */
  1468. if (line[n + 1] == '*')
  1469. {
  1470. if (line[n + 2] == '\n')
  1471. {
  1472. ERROR("C comment opening on separate line", lineno, n);
  1473. }
  1474. else if (!isspace((int)line[n + 2]) && line[n + 2] != '*')
  1475. {
  1476. ERROR("Missing space after opening C comment", lineno, n);
  1477. }
  1478. /* Increment the count of nested comments */
  1479. ncomment++;
  1480. /* If there is anything to the left of the left brace, then
  1481. * this must be a comment to the right of code.
  1482. * Also if preceding comments were to the right of code, then
  1483. * we can assume that there is a columnar alignment of columns
  1484. * that do no follow the usual alignment. So the rhcomment
  1485. * flag should propagate.
  1486. */
  1487. if (prevrhcmt == 0)
  1488. {
  1489. if (n != indent)
  1490. {
  1491. rhcomment = n;
  1492. }
  1493. }
  1494. else
  1495. {
  1496. rhcomment = n;
  1497. if (prevrhcmt > 0 && n != prevrhcmt)
  1498. {
  1499. rhcomment = prevrhcmt;
  1500. if (n != indent)
  1501. {
  1502. WARN("Wrong column position of "
  1503. "comment right of code", lineno, n);
  1504. }
  1505. else
  1506. {
  1507. ERROR("Wrong column position or missing "
  1508. "blank line before comment", lineno, n);
  1509. }
  1510. }
  1511. }
  1512. n++;
  1513. continue;
  1514. }
  1515. /* Check for end of a C comment */
  1516. else if (n > 0 && line[n - 1] == '*')
  1517. {
  1518. if (n < 2)
  1519. {
  1520. ERROR("Closing C comment not indented", lineno, n);
  1521. }
  1522. else if (!isspace((int)line[n - 2]) && line[n - 2] != '*')
  1523. {
  1524. ERROR("Missing space before closing C comment", lineno,
  1525. n);
  1526. }
  1527. /* Check for block comments that are not on a separate line.
  1528. * This would be the case if we are we are within a comment
  1529. * that did not start on this line and the current line is
  1530. * not blank up to the point where the comment was closed.
  1531. */
  1532. if (prevncomment > 0 && !bblank && rhcomment == 0)
  1533. {
  1534. ERROR("Block comment terminator must be on a "
  1535. "separate line", lineno, n);
  1536. }
  1537. #if 0
  1538. /* REVISIT: Generates false alarms when portions of an
  1539. * expression are commented out within the expression.
  1540. */
  1541. if (line[n + 1] != '\n')
  1542. {
  1543. ERROR("Garbage on line after C comment", lineno, n);
  1544. }
  1545. #endif
  1546. /* Handle nested comments */
  1547. if (ncomment > 0)
  1548. {
  1549. /* Remember the line number of the line containing the
  1550. * closing of the outermost comment.
  1551. */
  1552. if (--ncomment == 0)
  1553. {
  1554. /* 'comment_lineno 'holds the line number of the
  1555. * last closing comment. It is used only to
  1556. * verify that the comment is followed by a blank
  1557. * line.
  1558. */
  1559. comment_lineno = lineno;
  1560. /* Note that rhcomment must persist to support a
  1561. * later test for comment alignment. We will fix
  1562. * that at the top of the loop when ncomment == 0.
  1563. */
  1564. }
  1565. }
  1566. else
  1567. {
  1568. /* Note that rhcomment must persist to support a later
  1569. * test for comment alignment. We will will fix that
  1570. * at the top of the loop when ncomment == 0.
  1571. */
  1572. ncomment = 0;
  1573. ERROR("Closing without opening comment", lineno, n);
  1574. }
  1575. n++;
  1576. continue;
  1577. }
  1578. /* Check for C++ style comments */
  1579. else if (line[n + 1] == '/')
  1580. {
  1581. /* Check for URI schemes, e.g. "http://" or "https://" */
  1582. if (n == 0 || strncmp(&line[n - 1], "://", 3) != 0)
  1583. {
  1584. ERROR("C++ style comment", lineno, n);
  1585. n++;
  1586. continue;
  1587. }
  1588. }
  1589. }
  1590. /* Check if the line is blank so far. This is only used to
  1591. * to verify the the closing of a block comment is on a separate
  1592. * line. So we also need to treat '*' as a 'blank'.
  1593. */
  1594. if (!isblank(line[n]) && line[n] != '*')
  1595. {
  1596. bblank = false;
  1597. }
  1598. /* Check for a string... ignore if we are in the middle of a
  1599. * comment.
  1600. */
  1601. if (ncomment == 0)
  1602. {
  1603. /* Backslash quoted character */
  1604. if (line[n] == '\\')
  1605. {
  1606. bquote = true;
  1607. n++;
  1608. }
  1609. /* Check for quoted characters: \" in string */
  1610. if (line[n] == '"' && !bquote)
  1611. {
  1612. bstring = !bstring;
  1613. }
  1614. bquote = false;
  1615. }
  1616. /* The rest of the line is only examined of we are not in a comment,
  1617. * in a string or in assembly.
  1618. *
  1619. * REVISIT: Should still check for whitespace at the end of the
  1620. * line.
  1621. */
  1622. if (ncomment == 0 && !bstring && inasm == 0)
  1623. {
  1624. switch (line[n])
  1625. {
  1626. /* Handle logic nested with curly braces */
  1627. case '{':
  1628. {
  1629. if (n > indent)
  1630. {
  1631. /* REVISIT: dnest is always > 0 here if bfunctions ==
  1632. * false.
  1633. */
  1634. if (dnest == 0 || !bfunctions || lineno == rbrace_lineno)
  1635. {
  1636. ERROR("Left bracket not on separate line", lineno,
  1637. n);
  1638. }
  1639. }
  1640. else if (line[n + 1] != '\n')
  1641. {
  1642. if (dnest == 0)
  1643. {
  1644. ERROR("Garbage follows left bracket", lineno, n);
  1645. }
  1646. }
  1647. bnest++;
  1648. if (dnest > 0)
  1649. {
  1650. dnest++;
  1651. }
  1652. /* Check if we are within 'extern "C"', we don't
  1653. * normally indent in that case because the 'extern "C"'
  1654. * is conditioned on __cplusplus.
  1655. */
  1656. if (lineno == externc_lineno ||
  1657. lineno - 1 == externc_lineno)
  1658. {
  1659. bexternc = true;
  1660. }
  1661. /* Suppress error for comment following a left brace */
  1662. noblank_lineno = lineno;
  1663. lbrace_lineno = lineno;
  1664. }
  1665. break;
  1666. case '}':
  1667. {
  1668. /* Decrement the brace nesting level */
  1669. if (bnest < 1)
  1670. {
  1671. ERROR("Unmatched right brace", lineno, n);
  1672. }
  1673. else
  1674. {
  1675. bnest--;
  1676. if (bnest < 1)
  1677. {
  1678. bnest = 0;
  1679. bswitch = false;
  1680. }
  1681. }
  1682. /* Decrement the declaration nesting level */
  1683. if (dnest < 3)
  1684. {
  1685. dnest = 0;
  1686. bexternc = false;
  1687. }
  1688. else
  1689. {
  1690. dnest--;
  1691. }
  1692. /* The right brace should be on a separate line */
  1693. if (n > indent)
  1694. {
  1695. if (dnest == 0)
  1696. {
  1697. ERROR("Right bracket not on separate line",
  1698. lineno, n);
  1699. }
  1700. }
  1701. /* Check for garbage following the left brace */
  1702. if (line[n + 1] != '\n' &&
  1703. line[n + 1] != ',' &&
  1704. line[n + 1] != ';')
  1705. {
  1706. int sndx = n + 1;
  1707. bool whitespace = false;
  1708. /* Skip over spaces */
  1709. while (line[sndx] == ' ')
  1710. {
  1711. sndx++;
  1712. }
  1713. /* One possibility is that the right bracket is
  1714. * followed by an identifier then a semi-colon.
  1715. * Comma is possible to but would be a case of
  1716. * multiple declaration of multiple instances.
  1717. */
  1718. if (line[sndx] == '_' || isalpha(line[sndx]))
  1719. {
  1720. int endx = sndx;
  1721. /* Skip to the end of the identifier. Checking
  1722. * for mixed case identifiers will be done
  1723. * elsewhere.
  1724. */
  1725. while (line[endx] == '_' ||
  1726. isalnum(line[endx]))
  1727. {
  1728. endx++;
  1729. }
  1730. /* Skip over spaces */
  1731. while (line[endx] == ' ')
  1732. {
  1733. whitespace = true;
  1734. endx++;
  1735. }
  1736. /* Handle according to what comes after the
  1737. * identifier.
  1738. */
  1739. if (strncmp(&line[sndx], "while", 5) == 0)
  1740. {
  1741. ERROR("'while' must be on a separate line",
  1742. lineno, sndx);
  1743. }
  1744. else if (line[endx] == ',')
  1745. {
  1746. ERROR("Multiple data definitions on line",
  1747. lineno, endx);
  1748. }
  1749. else if (line[endx] == ';')
  1750. {
  1751. if (whitespace)
  1752. {
  1753. ERROR("Space precedes semi-colon",
  1754. lineno, endx);
  1755. }
  1756. }
  1757. else if (line[endx] == '=')
  1758. {
  1759. /* There's a struct initialization following */
  1760. check_spaces_leftright(line, lineno, endx, endx);
  1761. dnest = 1;
  1762. }
  1763. else
  1764. {
  1765. ERROR("Garbage follows right bracket",
  1766. lineno, n);
  1767. }
  1768. }
  1769. else
  1770. {
  1771. ERROR("Garbage follows right bracket", lineno, n);
  1772. }
  1773. }
  1774. /* The right brace should not be preceded with a a blank
  1775. * line.
  1776. */
  1777. if (lineno == blank_lineno + 1)
  1778. {
  1779. ERROR("Blank line precedes right brace at line",
  1780. lineno, 1);
  1781. }
  1782. rbrace_lineno = lineno;
  1783. }
  1784. break;
  1785. /* Handle logic with parentheses */
  1786. case '(':
  1787. {
  1788. /* Increase the parenthetical nesting level */
  1789. pnest++;
  1790. /* Check for inappropriate space around parentheses */
  1791. if (line[n + 1] == ' ') /* && !bfor */
  1792. {
  1793. ERROR("Space follows left parenthesis", lineno, n);
  1794. }
  1795. }
  1796. break;
  1797. case ')':
  1798. {
  1799. /* Decrease the parenthetical nesting level */
  1800. if (pnest < 1)
  1801. {
  1802. ERROR("Unmatched right parentheses", lineno, n);
  1803. pnest = 0;
  1804. }
  1805. else
  1806. {
  1807. pnest--;
  1808. }
  1809. /* Allow ')' as first thing on the line (n == indent)
  1810. * Allow "for (xx; xx; )" (bfor == true)
  1811. */
  1812. if (n > 0 && n != indent && line[n - 1] == ' ' && !bfor)
  1813. {
  1814. ERROR("Space precedes right parenthesis", lineno, n);
  1815. }
  1816. }
  1817. break;
  1818. /* Check for inappropriate space around square brackets */
  1819. case '[':
  1820. {
  1821. if (line[n + 1] == ' ')
  1822. {
  1823. ERROR("Space follows left bracket", lineno, n);
  1824. }
  1825. }
  1826. break;
  1827. case ']':
  1828. {
  1829. if (n > 0 && line[n - 1] == ' ')
  1830. {
  1831. ERROR("Space precedes right bracket", lineno, n);
  1832. }
  1833. }
  1834. break;
  1835. /* Semi-colon may terminate a declaration */
  1836. case ';':
  1837. {
  1838. if (!isspace((int)line[n + 1]))
  1839. {
  1840. ERROR("Missing whitespace after semicolon", lineno, n);
  1841. }
  1842. /* Semicolon terminates a declaration/definition if there
  1843. * was no left curly brace (i.e., dnest is only 1).
  1844. */
  1845. if (dnest == 1)
  1846. {
  1847. dnest = 0;
  1848. }
  1849. }
  1850. break;
  1851. /* Semi-colon may terminate a declaration */
  1852. case ',':
  1853. {
  1854. if (!isspace((int)line[n + 1]))
  1855. {
  1856. ERROR("Missing whitespace after comma", lineno, n);
  1857. }
  1858. }
  1859. break;
  1860. /* Skip over character constants */
  1861. case '\'':
  1862. {
  1863. int endndx = n + 2;
  1864. if (line[n + 1] != '\n' && line[n + 1] != '\0')
  1865. {
  1866. if (line[n + 1] == '\\')
  1867. {
  1868. for (;
  1869. line[endndx] != '\n' &&
  1870. line[endndx] != '\0' &&
  1871. line[endndx] != '\'';
  1872. endndx++);
  1873. }
  1874. n = endndx + 1;
  1875. }
  1876. }
  1877. break;
  1878. /* Check for space around various operators */
  1879. case '-':
  1880. /* ->, -- */
  1881. if (line[n + 1] == '>' || line[n + 1] == '-')
  1882. {
  1883. n++;
  1884. }
  1885. /* -= */
  1886. else if (line[n + 1] == '=')
  1887. {
  1888. check_spaces_leftright(line, lineno, n, n + 1);
  1889. n++;
  1890. }
  1891. /* Scientific notation with a negative exponent (eg. 10e-10)
  1892. * REVISIT: This fails for cases where the variable name
  1893. * ends with 'e' preceded by a digit:
  1894. * a = abc1e-10;
  1895. * a = ABC1E-10;
  1896. */
  1897. else if ((line[n - 1] == 'e' || line[n - 1] == 'E') &&
  1898. isdigit(line[n + 1]) && isdigit(line[n - 2]))
  1899. {
  1900. n++;
  1901. }
  1902. else
  1903. {
  1904. /* '-' may function as a unary operator and snuggle
  1905. * on the left.
  1906. */
  1907. check_spaces_left(line, lineno, n);
  1908. }
  1909. break;
  1910. case '+':
  1911. /* ++ */
  1912. if (line[n + 1] == '+')
  1913. {
  1914. n++;
  1915. }
  1916. /* += */
  1917. else if (line[n + 1] == '=')
  1918. {
  1919. check_spaces_leftright(line, lineno, n, n + 1);
  1920. n++;
  1921. }
  1922. else
  1923. {
  1924. /* '+' may function as a unary operator and snuggle
  1925. * on the left.
  1926. */
  1927. check_spaces_left(line, lineno, n);
  1928. }
  1929. break;
  1930. case '&':
  1931. /* &<variable> OR &(<expression>) */
  1932. if (isalpha((int)line[n + 1]) || line[n + 1] == '_' ||
  1933. line[n + 1] == '(')
  1934. {
  1935. }
  1936. /* &&, &= */
  1937. else if (line[n + 1] == '=' || line[n + 1] == '&')
  1938. {
  1939. check_spaces_leftright(line, lineno, n, n + 1);
  1940. n++;
  1941. }
  1942. else
  1943. {
  1944. check_spaces_leftright(line, lineno, n, n);
  1945. }
  1946. break;
  1947. case '/':
  1948. /* C comment terminator */
  1949. if (line[n - 1] == '*')
  1950. {
  1951. n++;
  1952. }
  1953. /* C++-style comment */
  1954. else if (line[n + 1] == '/')
  1955. {
  1956. /* Check for "http://" or "https://" */
  1957. if ((n < 5 || strncmp(&line[n - 5], "http://", 7) != 0) &&
  1958. (n < 6 || strncmp(&line[n - 6], "https://", 8) != 0))
  1959. {
  1960. ERROR("C++ style comment on at %d:%d\n",
  1961. lineno, n);
  1962. }
  1963. n++;
  1964. }
  1965. /* /= */
  1966. else if (line[n + 1] == '=')
  1967. {
  1968. check_spaces_leftright(line, lineno, n, n + 1);
  1969. n++;
  1970. }
  1971. /* Division operator */
  1972. else
  1973. {
  1974. check_spaces_leftright(line, lineno, n, n);
  1975. }
  1976. break;
  1977. case '*':
  1978. /* *\/, ** */
  1979. if (line[n] == '*' &&
  1980. (line[n + 1] == '/' ||
  1981. line[n + 1] == '*'))
  1982. {
  1983. n++;
  1984. break;
  1985. }
  1986. /* *<variable>, *(<expression>) */
  1987. else if (isalpha((int)line[n + 1]) ||
  1988. line[n + 1] == '_' ||
  1989. line[n + 1] == '(')
  1990. {
  1991. break;
  1992. }
  1993. /* (<type> *) */
  1994. else if (line[n + 1] == ')')
  1995. {
  1996. /* REVISIT: This gives false alarms on syntax like *--ptr */
  1997. if (line[n - 1] != ' ')
  1998. {
  1999. ERROR("Operator/assignment must be preceded "
  2000. "with whitespace", lineno, n);
  2001. }
  2002. break;
  2003. }
  2004. /* *= */
  2005. else if (line[n + 1] == '=')
  2006. {
  2007. check_spaces_leftright(line, lineno, n, n + 1);
  2008. n++;
  2009. }
  2010. else
  2011. {
  2012. /* A single '*' may be an binary operator, but
  2013. * it could also be a unary operator when used to deference
  2014. * a pointer.
  2015. */
  2016. check_spaces_left(line, lineno, n);
  2017. }
  2018. break;
  2019. case '%':
  2020. /* %= */
  2021. if (line[n + 1] == '=')
  2022. {
  2023. check_spaces_leftright(line, lineno, n, n + 1);
  2024. n++;
  2025. }
  2026. else
  2027. {
  2028. check_spaces_leftright(line, lineno, n, n);
  2029. }
  2030. break;
  2031. case '<':
  2032. /* <=, <<, <<= */
  2033. if (line[n + 1] == '=')
  2034. {
  2035. check_spaces_leftright(line, lineno, n, n + 1);
  2036. n++;
  2037. }
  2038. else if (line[n + 1] == '<')
  2039. {
  2040. if (line[n + 2] == '=')
  2041. {
  2042. check_spaces_leftright(line, lineno, n, n + 2);
  2043. n += 2;
  2044. }
  2045. else
  2046. {
  2047. check_spaces_leftright(line, lineno, n, n + 1);
  2048. n++;
  2049. }
  2050. }
  2051. else
  2052. {
  2053. check_spaces_leftright(line, lineno, n, n);
  2054. }
  2055. break;
  2056. case '>':
  2057. /* >=, >>, >>= */
  2058. if (line[n + 1] == '=')
  2059. {
  2060. check_spaces_leftright(line, lineno, n, n + 1);
  2061. n++;
  2062. }
  2063. else if (line[n + 1] == '>')
  2064. {
  2065. if (line[n + 2] == '=')
  2066. {
  2067. check_spaces_leftright(line, lineno, n, n + 2);
  2068. n += 2;
  2069. }
  2070. else
  2071. {
  2072. check_spaces_leftright(line, lineno, n, n + 1);
  2073. n++;
  2074. }
  2075. }
  2076. else
  2077. {
  2078. check_spaces_leftright(line, lineno, n, n);
  2079. }
  2080. break;
  2081. case '|':
  2082. /* |=, || */
  2083. if (line[n + 1] == '=')
  2084. {
  2085. check_spaces_leftright(line, lineno, n, n + 1);
  2086. n++;
  2087. }
  2088. else if (line[n + 1] == '|')
  2089. {
  2090. check_spaces_leftright(line, lineno, n, n + 1);
  2091. n++;
  2092. }
  2093. else
  2094. {
  2095. check_spaces_leftright(line, lineno, n, n);
  2096. }
  2097. break;
  2098. case '^':
  2099. /* ^= */
  2100. if (line[n + 1] == '=')
  2101. {
  2102. check_spaces_leftright(line, lineno, n, n + 1);
  2103. n++;
  2104. }
  2105. else
  2106. {
  2107. check_spaces_leftright(line, lineno, n, n);
  2108. }
  2109. break;
  2110. case '=':
  2111. /* == */
  2112. if (line[n + 1] == '=')
  2113. {
  2114. check_spaces_leftright(line, lineno, n, n + 1);
  2115. n++;
  2116. }
  2117. else
  2118. {
  2119. check_spaces_leftright(line, lineno, n, n);
  2120. }
  2121. break;
  2122. case '~':
  2123. check_spaces_left(line, lineno, n);
  2124. break;
  2125. case '!':
  2126. /* != */
  2127. if (line[n + 1] == '=')
  2128. {
  2129. check_spaces_leftright(line, lineno, n, n + 1);
  2130. n++;
  2131. }
  2132. /* !! */
  2133. else if (line[n + 1] == '!')
  2134. {
  2135. check_spaces_left(line, lineno, n);
  2136. n++;
  2137. }
  2138. else
  2139. {
  2140. check_spaces_left(line, lineno, n);
  2141. }
  2142. break;
  2143. default:
  2144. break;
  2145. }
  2146. }
  2147. }
  2148. /* Loop terminates when NUL or newline character found */
  2149. if (line[n] == '\n' || line[n] == '\0')
  2150. {
  2151. /* If the parse terminated on the NULL, then back up to the last
  2152. * character (which should be the newline).
  2153. */
  2154. int m = n;
  2155. if (line[m] == '\0' && m > 0)
  2156. {
  2157. m--;
  2158. }
  2159. /* Check for space at the end of the line. Except for carriage
  2160. * returns which we have already reported (one time) above.
  2161. */
  2162. if (m > 1 && isspace((int)line[m - 1]) &&
  2163. line[m - 1] != '\n' && line[m - 1] != '\r')
  2164. {
  2165. ERROR("Dangling whitespace at the end of line", lineno, m);
  2166. }
  2167. /* The line width is determined by the location of the final
  2168. * asterisk in block comments. The closing line of the block
  2169. * comment will exceed that by one one character, the '/'
  2170. * following the final asterisk.
  2171. */
  2172. else if (m > g_maxline)
  2173. {
  2174. bool bslash;
  2175. int a;
  2176. for (bslash = false, a = m;
  2177. a > 2 && strchr("\n\r/", line[a]) != NULL;
  2178. a--)
  2179. {
  2180. if (line[a] == '/')
  2181. {
  2182. bslash = true;
  2183. }
  2184. }
  2185. if (bslash && line[a] == '*')
  2186. {
  2187. m = a + 1;
  2188. }
  2189. }
  2190. /* Check for long lines
  2191. *
  2192. * REVISIT: Long line checks suppressed on right hand comments
  2193. * for now. This just prevents a large number of difficult-to-
  2194. * fix complaints that we would have otherwise.
  2195. */
  2196. if (m > g_maxline && !rhcomment)
  2197. {
  2198. ERROR("Long line found", lineno, m);
  2199. }
  2200. }
  2201. /* STEP 4: Check alignment */
  2202. /* Within a comment block, we need only check on the alignment of the
  2203. * comment.
  2204. */
  2205. if ((ncomment > 0 || prevncomment > 0) && !bstring)
  2206. {
  2207. /* Nothing should begin in comment zero */
  2208. if (indent == 0 && line[0] != '/' && !bexternc)
  2209. {
  2210. /* NOTE: if this line contains a comment to the right of the
  2211. * code, then ncomment will be misleading because it was
  2212. * already incremented above.
  2213. */
  2214. if (ncomment > 1 || rhcomment == 0)
  2215. {
  2216. ERROR("No indentation line", lineno, indent);
  2217. }
  2218. }
  2219. else if (indent == 1 && line[0] == ' ' && line[1] == '*')
  2220. {
  2221. /* Good indentation */
  2222. }
  2223. else if (indent > 0 && line[indent] == '\n')
  2224. {
  2225. ERROR("Whitespace on blank line", lineno, indent);
  2226. }
  2227. else if (indent > 0 && indent < 2)
  2228. {
  2229. if (bnest > 0)
  2230. {
  2231. ERROR("Insufficient indentation", lineno, indent);
  2232. }
  2233. else
  2234. {
  2235. ERROR("Expected indentation line", lineno, indent);
  2236. }
  2237. }
  2238. else if (indent > 0 && !bswitch)
  2239. {
  2240. if (line[indent] == '/')
  2241. {
  2242. /* Comments should like at offsets 2, 6, 10, ...
  2243. * This rule is not followed, however, if the comments are
  2244. * aligned to the right of the code.
  2245. */
  2246. if ((indent & 3) != 2 && rhcomment == 0)
  2247. {
  2248. ERROR("Bad comment alignment", lineno, indent);
  2249. }
  2250. /* REVISIT: This screws up in cases where there is C code,
  2251. * followed by a comment that continues on the next line.
  2252. */
  2253. else if (line[indent + 1] != '*')
  2254. {
  2255. ERROR("Missing asterisk in comment", lineno, indent);
  2256. }
  2257. }
  2258. else if (line[indent] == '*')
  2259. {
  2260. /* REVISIT: Generates false alarms on comments at the end of
  2261. * the line if there is nothing preceding (such as the aligned
  2262. * comments with a structure field definition). So disabled
  2263. * for comments before beginning of function definitions.
  2264. *
  2265. * Suppress this error if this is a comment to the right of
  2266. * code.
  2267. * Those may be unaligned.
  2268. */
  2269. if ((indent & 3) != 3 && bfunctions && dnest == 0 &&
  2270. rhcomment == 0)
  2271. {
  2272. ERROR("Bad comment block alignment", lineno, indent);
  2273. }
  2274. if (line[indent + 1] != ' ' &&
  2275. line[indent + 1] != '*' &&
  2276. line[indent + 1] != '\n' &&
  2277. line[indent + 1] != '/')
  2278. {
  2279. ERROR("Invalid character after asterisk "
  2280. "in comment block", lineno, indent);
  2281. }
  2282. }
  2283. /* If this is not the line containing the comment start, then this
  2284. * line should begin with '*'
  2285. */
  2286. else if (prevncomment > 0)
  2287. {
  2288. ERROR("Missing asterisk in comment block", lineno, indent);
  2289. }
  2290. }
  2291. }
  2292. /* Check for various alignment outside of the comment block */
  2293. else if ((ncomment == 0 && prevncomment == 0) && !bstring)
  2294. {
  2295. if (indent == 0 && strchr("\n#{}", line[0]) == NULL)
  2296. {
  2297. /* Ignore if we are at global scope */
  2298. if (prevbnest > 0)
  2299. {
  2300. bool blabel = false;
  2301. if (isalpha((int)line[indent]))
  2302. {
  2303. for (i = indent + 1; isalnum((int)line[i]) ||
  2304. line[i] == '_'; i++);
  2305. blabel = (line[i] == ':');
  2306. }
  2307. if (!blabel && !bexternc)
  2308. {
  2309. ERROR("No indentation line", lineno, indent);
  2310. }
  2311. }
  2312. }
  2313. else if (indent == 1 && line[0] == ' ' && line[1] == '*')
  2314. {
  2315. /* Good indentation */
  2316. }
  2317. else if (indent > 0 && line[indent] == '\n')
  2318. {
  2319. ERROR("Whitespace on blank line", lineno, indent);
  2320. }
  2321. else if (indent > 0 && indent < 2)
  2322. {
  2323. ERROR("Insufficient indentation line", lineno, indent);
  2324. }
  2325. else if (line[indent] == '{')
  2326. {
  2327. /* Check for left brace in first column, but preceded by a
  2328. * blank line. Should never happen (but could happen with
  2329. * internal compound statements).
  2330. */
  2331. if (indent == 0 && lineno == blank_lineno + 1)
  2332. {
  2333. ERROR("Blank line before opening left brace", lineno, indent);
  2334. }
  2335. /* REVISIT: Possible false alarms in compound statements
  2336. * without a preceding conditional. That usage often violates
  2337. * the coding standard.
  2338. */
  2339. else if (!bfunctions && (indent & 1) != 0)
  2340. {
  2341. ERROR("Bad left brace alignment", lineno, indent);
  2342. }
  2343. else if ((indent & 3) != 0 && !bswitch && dnest == 0)
  2344. {
  2345. ERROR("Bad left brace alignment", lineno, indent);
  2346. }
  2347. }
  2348. else if (line[indent] == '}')
  2349. {
  2350. /* REVISIT: Possible false alarms in compound statements
  2351. * without a preceding conditional. That usage often violates
  2352. * the coding standard.
  2353. */
  2354. if (!bfunctions && (indent & 1) != 0)
  2355. {
  2356. ERROR("Bad left brace alignment", lineno, indent);
  2357. }
  2358. else if ((indent & 3) != 0 && !bswitch && prevdnest == 0)
  2359. {
  2360. ERROR("Bad right brace alignment", lineno, indent);
  2361. }
  2362. }
  2363. else if (indent > 0)
  2364. {
  2365. /* REVISIT: Generates false alarms when a statement continues on
  2366. * the next line. The bstatm check limits to lines beginning
  2367. * with C keywords.
  2368. * REVISIT: The bstatm check will not detect statements that
  2369. * do not begin with a C keyword (such as assignment statements).
  2370. * REVISIT: Generates false alarms on comments at the end of
  2371. * the line if there is nothing preceding (such as the aligned
  2372. * comments with a structure field definition). So disabled for
  2373. * comments before beginning of function definitions.
  2374. */
  2375. if ((bstatm || /* Begins with C keyword */
  2376. (line[indent] == '/' && bfunctions)) && /* Comment in functions */
  2377. !bswitch && /* Not in a switch */
  2378. dnest == 0) /* Not a data definition */
  2379. {
  2380. if ((indent & 3) != 2)
  2381. {
  2382. ERROR("Bad alignment", lineno, indent);
  2383. }
  2384. }
  2385. /* Crazy cases. There should be no small odd alignments
  2386. * outside of comment/string. Odd alignments are possible
  2387. * on continued lines, but not if they are small.
  2388. */
  2389. else if (indent == 1 || indent == 3)
  2390. {
  2391. ERROR("Small odd alignment", lineno, indent);
  2392. }
  2393. }
  2394. }
  2395. }
  2396. if (!bfunctions && g_file_type == C_SOURCE)
  2397. {
  2398. ERROR("\"Private/Public Functions\" not found!"
  2399. " File will not be checked", lineno, 1);
  2400. }
  2401. if (ncomment > 0 || bstring)
  2402. {
  2403. ERROR("Comment or string found at end of file", lineno, 1);
  2404. }
  2405. fclose(instream);
  2406. if (g_verbose == 1)
  2407. {
  2408. fprintf(stderr, "%s: %s nxstyle check\n", g_file_name,
  2409. g_status == 0 ? "PASSED" : "FAILED");
  2410. }
  2411. return g_status;
  2412. }