convert-comments.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /****************************************************************************
  2. * tools/convert-comments.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 <stdbool.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <ctype.h>
  27. /****************************************************************************
  28. * Preprocessor Definitions
  29. ****************************************************************************/
  30. #define LINESIZE 1024 /* Big so that we don't have to bother with range checks */
  31. /****************************************************************************
  32. * Private Data
  33. ****************************************************************************/
  34. static char g_linea[LINESIZE + 3];
  35. static char g_lineb[LINESIZE + 3];
  36. static char g_iobuffer[LINESIZE];
  37. /****************************************************************************
  38. * Public Functions
  39. ****************************************************************************/
  40. int main(int argc, char **argv)
  41. {
  42. char *g_line0;
  43. char *g_line1;
  44. char *ptr;
  45. char *tmpptr;
  46. FILE *instream;
  47. FILE *outstream;
  48. unsigned long lineno = 0;
  49. unsigned int indent;
  50. unsigned int lastindent;
  51. unsigned int nextindent;
  52. unsigned int tmpindent;
  53. bool iscomment;
  54. bool wascomment;
  55. bool willbecomment;
  56. bool isblank;
  57. bool wasblank;
  58. bool willbeblank;
  59. bool willbevalid;
  60. int ret = 1;
  61. if (argc != 3)
  62. {
  63. fprintf(stderr, "ERROR: Two arguments expected\n");
  64. return 1;
  65. }
  66. /* Open the source file read-only */
  67. instream = fopen(argv[1], "r");
  68. if (instream == NULL)
  69. {
  70. fprintf(stderr, "ERROR: Failed to open %s for reading\n", argv[1]);
  71. return 1;
  72. }
  73. /* Open the destination file write-only */
  74. outstream = fopen(argv[2], "w");
  75. if (outstream == NULL)
  76. {
  77. fprintf(stderr, "ERROR: Failed to open %s for reading\n", argv[2]);
  78. goto errout_with_instream;
  79. }
  80. /* Prime the pump */
  81. g_line0 = g_linea;
  82. g_line1 = g_lineb;
  83. wasblank = true;
  84. wascomment = false;
  85. lastindent = 0;
  86. /* Read line n + 1 (for n = 0) */
  87. if (fgets(g_line1, LINESIZE, instream) == NULL)
  88. {
  89. fprintf(stderr, "ERROR: File is empty\n");
  90. goto errout_with_outstream;
  91. }
  92. /* Skip over leading spaces in line n + 1 */
  93. for (ptr = g_line1, nextindent = 0;
  94. *ptr != '\0' && *ptr != '\n' && isspace(*ptr);
  95. ptr++, nextindent++)
  96. {
  97. }
  98. /* Check for a blank line */
  99. if (*ptr == '\0' || *ptr == '\n')
  100. {
  101. ptr = g_line1;
  102. ptr[0] = '\n';
  103. ptr[1] = '\0';
  104. willbeblank = true;
  105. willbecomment = false;
  106. nextindent = 0;
  107. }
  108. else
  109. {
  110. /* Check for a C++ style comment at this indentation in line n + 1 */
  111. willbeblank = false;
  112. willbecomment = strncmp(ptr, "//", 2) == 0;
  113. }
  114. /* Loop for each line in the file */
  115. do
  116. {
  117. /* Swap line n and line n + 1 */
  118. ptr = g_line0;
  119. g_line0 = g_line1; /* New line n */
  120. g_line1 = ptr; /* Will be new line n + 1 */
  121. /* Read the new line n + 1 */
  122. willbevalid = (fgets(g_line1, LINESIZE, instream) != NULL);
  123. /* Update info for line 0 */
  124. lineno++;
  125. indent = nextindent;
  126. isblank = willbeblank;
  127. iscomment = willbecomment;
  128. if (willbevalid)
  129. {
  130. /* Strip trailing spaces and carriage returns from line n + 1 */
  131. tmpptr = strchr(g_line1, '\r');
  132. if (tmpptr != NULL)
  133. {
  134. *tmpptr++ = '\n';
  135. *tmpptr++ = '\0';
  136. }
  137. else
  138. {
  139. int len = strlen(ptr);
  140. if (len > 0)
  141. {
  142. for (ptr += len - 1; isspace(*ptr); ptr--)
  143. {
  144. ptr[0] = '\n';
  145. ptr[1] = '\0';
  146. }
  147. }
  148. }
  149. /* Skip over leading spaces in line n + 1 */
  150. for (ptr = g_line1, nextindent = 0;
  151. *ptr != '\0' && *ptr != '\n' && isspace(*ptr);
  152. ptr++, nextindent++)
  153. {
  154. }
  155. /* Check for a blank line */
  156. if (*ptr == '\0' || *ptr == '\n')
  157. {
  158. ptr = g_line1;
  159. ptr[0] = '\n';
  160. ptr[1] = '\0';
  161. willbeblank = true;
  162. willbecomment = false;
  163. nextindent = 0;
  164. }
  165. else
  166. {
  167. /* Check for a C++ style comment
  168. * at this indentation in line n + 1
  169. */
  170. willbeblank = false;
  171. willbecomment = strncmp(ptr, "//", 2) == 0;
  172. }
  173. /* Check for a C++ style comment
  174. * at this indentation in line n + 1
  175. */
  176. willbecomment = strncmp(ptr, "//", 2) == 0;
  177. }
  178. else
  179. {
  180. willbeblank = true;
  181. willbecomment = false;
  182. nextindent = 0;
  183. }
  184. /* If current line is not a comment line, then check for a C++ style
  185. * comment at the end of the line.
  186. */
  187. if (!iscomment)
  188. {
  189. /* Skip over leading spaces in line n + 1 */
  190. for (ptr = g_line0 + indent, tmpindent = indent;
  191. *ptr != '\0' && *ptr != '\n';
  192. ptr++, tmpindent++)
  193. {
  194. if (ptr[0] == '/' && ptr[1] == '/')
  195. {
  196. indent = tmpindent;
  197. iscomment = true;
  198. wascomment = false;
  199. break;
  200. }
  201. }
  202. }
  203. printf("***************************************"
  204. "**************************************\n");
  205. printf("* %5lu. %s\n", lineno, g_line0);
  206. printf("* indent: last=%u curr=%u next=%u\n",
  207. lastindent, indent, nextindent);
  208. printf("* comment: last=%u curr=%u next=%u\n",
  209. wascomment, iscomment, willbecomment);
  210. printf("* blank: last=%u curr=%u next=%u\n",
  211. wasblank, isblank, willbeblank);
  212. printf("***************************************"
  213. "**************************************\n");
  214. /* Does line n start with a comment */
  215. ptr = g_line0 + indent;
  216. if (iscomment)
  217. {
  218. char *endptr;
  219. /* Get a pointer for the first non-blank character following the
  220. * comment.
  221. */
  222. for (endptr = &ptr[2];
  223. *endptr != '\0' && *endptr != '\n' && isspace(*endptr);
  224. endptr++)
  225. {
  226. }
  227. /* Check for a comment only line that is was not preceded by a
  228. * comment.
  229. */
  230. if ((*endptr == '\n' || *endptr == '\0') && !wascomment)
  231. {
  232. /* Avoid double spacing */
  233. if (!wasblank)
  234. {
  235. /* Output a blank line */
  236. fputc('\n', outstream);
  237. }
  238. /* Reset to indicate a blank line */
  239. indent = 0;
  240. iscomment = false;
  241. isblank = true;
  242. }
  243. /* Did line n - 1 start with a comment? */
  244. else if (wascomment)
  245. {
  246. /* Yes.. Change it to a C-style block comment continuation */
  247. ptr[0] = ' ';
  248. ptr[1] = '*';
  249. /* Write the modified line to the output */
  250. fputs(g_line0, outstream);
  251. }
  252. else
  253. {
  254. /* No.. Change it to a C-style opening comment. */
  255. ptr[1] = '*';
  256. if (!willbecomment)
  257. {
  258. int len;
  259. /* Remove final linefeed */
  260. len = strlen(ptr);
  261. if (len > 0 && ptr[len - 1] == '\n')
  262. {
  263. len--;
  264. }
  265. /* Close the single line C comment */
  266. ptr += len;
  267. *ptr++ = ' ';
  268. *ptr++ = '*';
  269. *ptr++ = '/';
  270. *ptr++ = '\n';
  271. *ptr++ = '\0';
  272. iscomment = false;
  273. /* Write the modified line to the output */
  274. fputs(g_line0, outstream);
  275. /* Closing comment must be followed by a blank line */
  276. if (!willbeblank)
  277. {
  278. /* Output a blank line */
  279. fputc('\n', outstream);
  280. }
  281. }
  282. else
  283. {
  284. /* Write the modified line to the output */
  285. fputs(g_line0, outstream);
  286. }
  287. }
  288. }
  289. else if (wascomment)
  290. {
  291. /* Line n is not a comment, but line n - 1 was.
  292. * Output a closing on a newline at the same indentation.
  293. */
  294. memset(g_iobuffer, ' ', LINESIZE);
  295. ptr = g_iobuffer + lastindent + 1;
  296. *ptr++ = '*';
  297. *ptr++ = '/';
  298. *ptr++ = '\n';
  299. *ptr++ = '\0';
  300. /* Write the closing line to the output */
  301. fputs(g_iobuffer, outstream);
  302. /* Closing comment must be followed by a blank line */
  303. if (!isblank)
  304. {
  305. /* Output a blank line */
  306. fputc('\n', outstream);
  307. }
  308. /* Write the noncomment line to the output */
  309. fputs(g_line0, outstream);
  310. }
  311. else
  312. {
  313. /* Write the noncomment line to the output */
  314. fputs(g_line0, outstream);
  315. }
  316. wascomment = iscomment;
  317. wasblank = isblank;
  318. lastindent = indent;
  319. }
  320. while (willbevalid);
  321. ret = 0;
  322. errout_with_outstream:
  323. fclose(outstream);
  324. errout_with_instream:
  325. fclose(instream);
  326. return ret;
  327. }