nuttx/tools/convert-comments.c

395 lines
11 KiB
C

/****************************************************************************
* tools/convert-comments.c
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/****************************************************************************
* Preprocessor Definitions
****************************************************************************/
#define LINESIZE 1024 /* Big so that we don't have to bother with range checks */
/****************************************************************************
* Private Data
****************************************************************************/
static char g_lineA[LINESIZE + 3];
static char g_lineB[LINESIZE + 3];
static char g_iobuffer[LINESIZE];
/****************************************************************************
* Public Functions
****************************************************************************/
int main(int argc, char **argv)
{
char *g_line0;
char *g_line1;
char *ptr;
char *tmpptr;
FILE *instream;
FILE *outstream;
unsigned long lineno = 0;
unsigned int indent;
unsigned int lastindent;
unsigned int nextindent;
unsigned int tmpindent;
bool iscomment;
bool wascomment;
bool willbecomment;
bool isblank;
bool wasblank;
bool willbeblank;
bool willbevalid;
int ret = 1;
if (argc != 3)
{
fprintf(stderr, "ERROR: Two arguments expected\n");
return 1;
}
/* Open the source file read-only */
instream = fopen(argv[1], "r");
if (instream == NULL)
{
fprintf(stderr, "ERROR: Failed to open %s for reading\n", argv[1]);
return 1;
}
/* Open the destination file write-only */
outstream = fopen(argv[2], "w");
if (outstream == NULL)
{
fprintf(stderr, "ERROR: Failed to open %s for reading\n", argv[2]);
goto errout_with_instream;
}
/* Prime the pump */
g_line0 = g_lineA;
g_line1 = g_lineB;
wasblank = true;
wascomment = false;
lastindent = 0;
/* Read line n + 1 (for n = 0) */
if (fgets(g_line1, LINESIZE, instream) == NULL)
{
fprintf(stderr, "ERROR: File is empty\n");
goto errout_with_outstream;
}
/* Skip over leading spaces in line1 n + 1 */
for (ptr = g_line1, nextindent = 0;
*ptr != '\0' && *ptr != '\n' && isspace(*ptr);
ptr++, nextindent++)
{
}
/* Check for a blank line */
if (*ptr == '\0' || *ptr == '\n')
{
ptr = g_line1;
ptr[0] = '\n';
ptr[1] = '\0';
willbeblank = true;
willbecomment = false;
nextindent = 0;
}
else
{
/* Check for a C++ style comment at this indentation in line n + 1 */
willbeblank = false;
willbecomment = strncmp(ptr, "//", 2) == 0;
}
do
{
/* Swap line n and line n + 1 */
ptr = g_line0;
g_line0 = g_line1; /* New line n */
g_line1 = ptr; /* Will be new line n + 1 */
/* Read the new line n + 1 */
willbevalid = (fgets(g_line1, LINESIZE, instream) != NULL);
/* Update info for line 0 */
lineno++;
indent = nextindent;
isblank = willbeblank;
iscomment = willbecomment;
if (willbevalid)
{
/* Strip trailing spaces and carriage returns from line n + 1 */
tmpptr = strchr(g_line1, '\r');
if (tmpptr != NULL)
{
*tmpptr++ = '\n';
*tmpptr++ = '\0';
}
else
{
int len = strlen(ptr);
if (len > 0)
{
for (ptr += len - 1; isspace(*ptr); ptr--)
{
ptr[0] = '\n';
ptr[1] = '\0';
}
}
}
/* Skip over leading spaces in line n + 1 */
for (ptr = g_line1, nextindent = 0;
*ptr != '\0' && *ptr != '\n' && isspace(*ptr);
ptr++, nextindent++)
{
}
/* Check for a blank line */
if (*ptr == '\0' || *ptr == '\n')
{
ptr = g_line1;
ptr[0] = '\n';
ptr[1] = '\0';
willbeblank = true;
willbecomment = false;
nextindent = 0;
}
else
{
/* Check for a C++ style comment at this indentation in line n + 1 */
willbeblank = false;
willbecomment = strncmp(ptr, "//", 2) == 0;
}
/* Check for a C++ style comment at this indentation in line n + 1 */
willbecomment = strncmp(ptr, "//", 2) == 0;
}
else
{
willbeblank = true;
willbecomment = false;
nextindent = 0;
}
/* If current line is not a comment line, then check for a C++ style comment at the
* end of the line.
*/
if (!iscomment)
{
/* Skip over leading spaces in line n + 1 */
for (ptr = g_line0 + indent, tmpindent = indent;
*ptr != '\0' && *ptr != '\n';
ptr++, tmpindent++)
{
if (ptr[0] == '/' && ptr[1] == '/')
{
indent = tmpindent;
iscomment = true;
wascomment = false;
break;
}
}
}
printf("*****************************************************************************\n");
printf("* %5lu. %s\n", lineno, g_line0);
printf("* indent: last=%u curr=%u next=%u\n",
lastindent, indent, nextindent);
printf("* comment: last=%u curr=%u next=%u\n",
wascomment, iscomment, willbecomment);
printf("* blank: last=%u curr=%u next=%u\n",
wasblank, isblank, willbeblank);
printf("*****************************************************************************\n");
/* Does line n start with a comment */
ptr = g_line0 + indent;
if (iscomment)
{
/* Check for a comment only line that is was not preceded by a
* comment.
*/
if (ptr[2] == '\n' && !wascomment)
{
/* Output a blank line */
fputc('\n', outstream);
}
/* Did line n - 1 start with a comment? */
else if (wascomment)
{
/* Yes.. Change it to a C-style block comment continuation */
ptr[0] = ' ';
ptr[1] = '*';
/* Write the modified line to the output */
(void)fputs(g_line0, outstream);
}
else
{
/* No.. Change it to a C-style opening comment. */
ptr[1] = '*';
if (!willbecomment)
{
int len;
/* Remove final linefeed */
len = strlen(ptr);
if (len > 0 && ptr[len - 1] == '\n')
{
len--;
}
/* Close the single line C comment */
ptr += len;
*ptr++ = ' ';
*ptr++ = '*';
*ptr++ = '/';
*ptr++ = '\n';
*ptr++ = '\0';
iscomment = false;
/* Write the modified line to the output */
(void)fputs(g_line0, outstream);
/* Closing comment must be followed by a blank line */
if (!willbeblank)
{
/* Output a blank line */
fputc('\n', outstream);
}
}
else
{
/* Write the modified line to the output */
(void)fputs(g_line0, outstream);
}
}
}
else if (wascomment)
{
/* Line n is not a comment, but line n - 1 was. Output a closing on a
* newline at the same indentation.
*/
memset(g_iobuffer, ' ', LINESIZE);
ptr = g_iobuffer + lastindent + 1;
*ptr++ = '*';
*ptr++ = '/';
*ptr++ = '\n';
*ptr++ = '\0';
/* Write the closing line to the output */
(void)fputs(g_iobuffer, outstream);
/* Closing comment must be followed by a blank line */
if (!isblank)
{
/* Output a blank line */
fputc('\n', outstream);
}
/* Write the noncomment line to the output */
(void)fputs(g_line0, outstream);
}
else
{
/* Write the noncomment line to the output */
(void)fputs(g_line0, outstream);
}
wascomment = iscomment;
wasblank = isblank;
lastindent = indent;
}
while (willbevalid);
ret = 0;
errout_with_outstream:
fclose(outstream);
errout_with_instream:
fclose(instream);
return ret;
}