-/* ansi2knr.c */
+/* Copyright (C) 1989, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved. */
+
+/*$Id: ansi2knr.c 1002 2003-10-04 10:34:10Z hniksic $*/
/* Convert ANSI C function definitions to K&R ("traditional C") syntax */
/*
Everyone is granted permission to copy, modify and redistribute ansi2knr,
but only under the conditions described in the GPL. A copy of this license
is supposed to have been given to you along with ansi2knr so you can know
-your rights and responsibilities. It should be in a file named COPYLEFT.
-Among other things, the copyright notice and this notice must be preserved
-on all copies.
+your rights and responsibilities. It should be in a file named COPYLEFT,
+or, if there is no file named COPYLEFT, a file named COPYING. Among other
+things, the copyright notice and this notice must be preserved on all
+copies.
We explicitly state here what we believe is already implied by the GPL: if
the ansi2knr program is distributed as a separate set of sources and a
/*
* Usage:
- ansi2knr input_file [output_file]
+ ansi2knr [--filename FILENAME] [INPUT_FILE [OUTPUT_FILE]]
+ * --filename provides the file name for the #line directive in the output,
+ * overriding input_file (if present).
+ * If no input_file is supplied, input is read from stdin.
* If no output_file is supplied, output goes to stdout.
* There are no error messages.
*
* identifier at the left margin, followed by a left parenthesis,
* with a right parenthesis as the last character on the line,
* and with a left brace as the first token on the following line
- * (ignoring possible intervening comments).
- * It will recognize a multi-line header provided that no intervening
- * line ends with a left or right brace or a semicolon.
+ * (ignoring possible intervening comments), except that a line
+ * consisting of only
+ * identifier1(identifier2)
+ * will not be considered a function definition unless identifier2 is
+ * the word "void", and a line consisting of
+ * identifier1(identifier2, <<arbitrary>>)
+ * will not be considered a function definition.
+ * ansi2knr will recognize a multi-line header provided
+ * that no intervening line ends with a left or right brace or a semicolon.
* These algorithms ignore whitespace and comments, except that
* the function name must be the first thing on the line.
* The following constructs will confuse it:
* - Any other construct that starts at the left margin and
* follows the above syntax (such as a macro or function call).
- * - Some macros that tinker with the syntax of the function header.
+ * - Some macros that tinker with the syntax of function headers.
*/
/*
* The original and principal author of ansi2knr is L. Peter Deutsch
* <ghost@aladdin.com>. Other authors are noted in the change history
* that follows (in reverse chronological order):
- lpd 96-01-21 added code to cope with not HAVE_CONFIG_H and with
+ lpd 1999-04-12 added minor fixes from Pavel Roskin
+ <pavel_roskin@geocities.com> for clean compilation with
+ gcc -W -Wall
+ lpd 1999-03-22 added hack to recognize lines consisting of
+ identifier1(identifier2, xxx) as *not* being procedures
+ lpd 1999-02-03 made indentation of preprocessor commands consistent
+ lpd 1999-01-28 fixed two bugs: a '/' in an argument list caused an
+ endless loop; quoted strings within an argument list
+ confused the parser
+ lpd 1999-01-24 added a check for write errors on the output,
+ suggested by Jim Meyering <meyering@ascend.com>
+ lpd 1998-11-09 added further hack to recognize identifier(void)
+ as being a procedure
+ lpd 1998-10-23 added hack to recognize lines consisting of
+ identifier1(identifier2) as *not* being procedures
+ lpd 1997-12-08 made input_file optional; only closes input and/or
+ output file if not stdin or stdout respectively; prints
+ usage message on stderr rather than stdout; adds
+ --filename switch (changes suggested by
+ <ceder@lysator.liu.se>)
+ lpd 1996-01-21 added code to cope with not HAVE_CONFIG_H and with
compilers that don't understand void, as suggested by
Tom Lane
- lpd 96-01-15 changed to require that the first non-comment token
+ lpd 1996-01-15 changed to require that the first non-comment token
on the line following a function header be a left brace,
to reduce sensitivity to macros, as suggested by Tom Lane
<tgl@sss.pgh.pa.us>
- lpd 95-06-22 removed #ifndefs whose sole purpose was to define
+ lpd 1995-06-22 removed #ifndefs whose sole purpose was to define
undefined preprocessor symbols as 0; changed all #ifdefs
for configuration symbols to #ifs
- lpd 95-04-05 changed copyright notice to make it clear that
+ lpd 1995-04-05 changed copyright notice to make it clear that
including ansi2knr in a program does not bring the entire
program under the GPL
- lpd 94-12-18 added conditionals for systems where ctype macros
+ lpd 1994-12-18 added conditionals for systems where ctype macros
don't handle 8-bit characters properly, suggested by
Francois Pinard <pinard@iro.umontreal.ca>;
removed --varargs switch (this is now the default)
- lpd 94-10-10 removed CONFIG_BROKETS conditional
- lpd 94-07-16 added some conditionals to help GNU `configure',
+ lpd 1994-10-10 removed CONFIG_BROKETS conditional
+ lpd 1994-07-16 added some conditionals to help GNU `configure',
suggested by Francois Pinard <pinard@iro.umontreal.ca>;
properly erase prototype args in function parameters,
contributed by Jim Avera <jima@netcom.com>;
correct error in writeblanks (it shouldn't erase EOLs)
- lpd 89-xx-xx original version
+ lpd 1989-xx-xx original version
*/
/* Most of the conditionals here are to make ansi2knr work with */
#endif
+/* Define NULL (for *very* old compilers). */
+#ifndef NULL
+# define NULL (0)
+#endif
+
/*
* The ctype macros don't always handle 8-bit characters correctly.
* Compensate for this here.
*/
#ifdef isascii
-# undef HAVE_ISASCII /* just in case */
-# define HAVE_ISASCII 1
+# undef HAVE_ISASCII /* just in case */
+# define HAVE_ISASCII 1
#else
#endif
#if STDC_HEADERS || !HAVE_ISASCII
-# define is_ascii(c) 1
+# define is_ascii(c) 1
#else
-# define is_ascii(c) isascii(c)
+# define is_ascii(c) isascii(c)
#endif
#define is_space(c) (is_ascii(c) && isspace(c))
/* Forward references */
char *skipspace();
+char *scanstring();
int writeblanks();
int test1();
int convert1();
main(argc, argv)
int argc;
char *argv[];
-{ FILE *in, *out;
+{ FILE *in = stdin;
+ FILE *out = stdout;
+ char *filename = 0;
+ char *program_name = argv[0];
+ char *output_name = 0;
#define bufsize 5000 /* arbitrary size */
char *buf;
char *line;
char *more;
+ char *usage =
+ "Usage: ansi2knr [--filename FILENAME] [INPUT_FILE [OUTPUT_FILE]]\n";
/*
* In previous versions, ansi2knr recognized a --varargs switch.
* If this switch was supplied, ansi2knr would attempt to convert
* check for this switch for backward compatibility.
*/
int convert_varargs = 1;
+ int output_error;
- if ( argc > 1 && argv[1][0] == '-' )
- { if ( !strcmp(argv[1], "--varargs") )
- { convert_varargs = 1;
- argc--;
- argv++;
- }
- else
- { fprintf(stderr, "Unrecognized switch: %s\n", argv[1]);
- exit(1);
- }
+ while ( argc > 1 && argv[1][0] == '-' ) {
+ if ( !strcmp(argv[1], "--varargs") ) {
+ convert_varargs = 1;
+ argc--;
+ argv++;
+ continue;
}
- if (argc < 2 || argc > 3)
+ if ( !strcmp(argv[1], "--filename") && argc > 2 ) {
+ filename = argv[2];
+ argc -= 2;
+ argv += 2;
+ continue;
+ }
+ fprintf(stderr, "%s: Unrecognized switch: %s\n", program_name,
+ argv[1]);
+ fprintf(stderr, usage);
+ exit(1);
+ }
+ switch ( argc )
{
- printf("Usage: ansi2knr input_file [output_file]\n");
- exit(1);
- }
- in = fopen(argv[1], "r");
- if ( in == NULL )
- {
- fprintf(stderr, "Cannot open input file %s\n", argv[1]);
- exit(1);
+ default:
+ fprintf(stderr, usage);
+ exit(0);
+ case 3:
+ output_name = argv[2];
+ out = fopen(output_name, "w");
+ if ( out == NULL ) {
+ fprintf(stderr, "%s: Cannot open output file %s\n",
+ program_name, output_name);
+ exit(1);
+ }
+ /* falls through */
+ case 2:
+ in = fopen(argv[1], "r");
+ if ( in == NULL ) {
+ fprintf(stderr, "%s: Cannot open input file %s\n",
+ program_name, argv[1]);
+ exit(1);
+ }
+ if ( filename == 0 )
+ filename = argv[1];
+ /* falls through */
+ case 1:
+ break;
}
- if (argc == 3)
- {
- out = fopen(argv[2], "w");
- if ( out == NULL )
- {
- fprintf(stderr, "Cannot open output file %s\n", argv[2]);
- exit(1);
- }
- }
- else
- {
- out = stdout;
- }
- fprintf(out, "#line 1 \"%s\"\n", argv[1]);
+ if ( filename )
+ fprintf(out, "#line 1 \"%s\"\n", filename);
buf = malloc(bufsize);
+ if ( buf == NULL )
+ {
+ fprintf(stderr, "Unable to allocate read buffer!\n");
+ exit(1);
+ }
line = buf;
while ( fgets(line, (unsigned)(buf + bufsize - line), in) != NULL )
{
if ( line != buf )
fputs(buf, out);
free(buf);
- fclose(out);
- fclose(in);
+ if ( output_name ) {
+ output_error = ferror(out);
+ output_error |= fclose(out);
+ } else { /* out == stdout */
+ fflush(out);
+ output_error = ferror(out);
+ }
+ if ( output_error ) {
+ fprintf(stderr, "%s: error writing to %s\n", program_name,
+ (output_name ? output_name : "stdout"));
+ exit(1);
+ }
+ if ( in != stdin )
+ fclose(in);
return 0;
}
-/* Skip over space and comments, in either direction. */
+/* Skip over whitespace and comments, in either direction. */
char *
skipspace(p, dir)
register char *p;
return p;
}
+/* Scan over a quoted string, in either direction. */
+char *
+scanstring(p, dir)
+ register char *p;
+ register int dir;
+{
+ for (p += dir; ; p += dir)
+ if (*p == '"' && p[-dir] != '\\')
+ return p + dir;
+}
+
/*
* Write blanks over part of a string.
* Don't overwrite end-of-line characters.
};
char **key = words;
char *kp;
- int len = endfn - buf;
+ unsigned len = endfn - buf;
while ( (kp = *key) != 0 )
{ if ( strlen(kp) == len && !strncmp(kp, buf, len) )
key++;
}
}
+ {
+ char *id = p;
+ int len;
+ /*
+ * Check for identifier1(identifier2) and not
+ * identifier1(void), or identifier1(identifier2, xxxx).
+ */
+
+ while ( isidchar(*p) )
+ p++;
+ len = p - id;
+ p = skipspace(p, 1);
+ if (*p == ',' ||
+ (*p == ')' && (len != 4 || strncmp(id, "void", 4)))
+ )
+ return 0; /* not a function */
+ }
+ /*
+ * If the last significant character was a ), we need to count
+ * parentheses, because it might be part of a formal parameter
+ * that is a procedure.
+ */
+ if (contin > 0) {
+ int level = 0;
+
+ for (p = skipspace(buf, 1); *p; p = skipspace(p + 1, 1))
+ level += (*p == '(' ? 1 : *p == ')' ? -1 : 0);
+ if (level > 0)
+ contin = -1;
+ }
return contin;
}
;
top: p = endfn;
breaks = (char **)malloc(sizeof(char *) * num_breaks * 2);
- if ( breaks == 0 )
+ if ( breaks == NULL )
{ /* Couldn't allocate break table, give up */
fprintf(stderr, "Unable to allocate break table!\n");
fputs(buf, out);
do
{ int level = 0;
char *lp = NULL;
- char *rp;
+ char *rp = NULL;
char *end = NULL;
if ( bp >= btop )
else rp = p;
break;
case '/':
- p = skipspace(p, 1) - 1;
+ if (p[1] == '*')
+ p = skipspace(p, 1) - 1;
break;
+ case '"':
+ p = scanstring(p, 1) - 1;
+ break;
default:
;
}
}
/* Erase any embedded prototype parameters. */
- if ( lp )
+ if ( lp && rp )
writeblanks(lp + 1, rp);
p--; /* back up over terminator */
/* Find the name being declared. */
while ( level )
switch ( *--p )
{
- case ']': case ')': level++; break;
- case '[': case '(': level--; break;
- case '/': p = skipspace(p, -1) + 1; break;
+ case ']': case ')':
+ level++;
+ break;
+ case '[': case '(':
+ level--;
+ break;
+ case '/':
+ if (p > buf && p[-1] == '*')
+ p = skipspace(p, -1) + 1;
+ break;
+ case '"':
+ p = scanstring(p, -1) + 1;
+ break;
default: ;
}
}
/* vsnprintf() will not step over the limit given by available_size.
If it fails, it will return either -1 (POSIX?) or the number of
characters that *would have* been written, if there had been
- enough room. In the former case, we double the available_size
- and malloc() to get a larger buffer, and try again. In the
- latter case, we use the returned information to build a buffer of
- the correct size. */
+ enough room (C99). In the former case, we double the
+ available_size and malloc to get a larger buffer, and try again.
+ In the latter case, we use the returned information to build a
+ buffer of the correct size. */
if (numwritten == -1)
{
return old;
}
+/* Handle difference in va_start between pre-ANSI and ANSI C. Note
+ that we always use `...' in function definitions and let ansi2knr
+ convert it for us. */
+
#ifdef WGET_USE_STDARG
-# define VA_START_1(arg1_type, arg1, args) va_start(args, arg1)
-# define VA_START_2(arg1_type, arg1, arg2_type, arg2, args) va_start(args, arg2)
-#else /* not WGET_USE_STDARG */
-# define VA_START_1(arg1_type, arg1, args) do { \
- va_start (args); \
- arg1 = va_arg (args, arg1_type); \
-} while (0)
-# define VA_START_2(arg1_type, arg1, arg2_type, arg2, args) do { \
- va_start (args); \
- arg1 = va_arg (args, arg1_type); \
- arg2 = va_arg (args, arg2_type); \
-} while (0)
-#endif /* not WGET_USE_STDARG */
+# define VA_START(args, arg1) va_start (args, arg1)
+#else
+# define VA_START(args, ignored) va_start (args)
+#endif
-/* Portability with pre-ANSI compilers makes these two functions look
- like @#%#@$@#$. */
+/* Print a message to the screen or to the log. The first argument
+ defines the verbosity of the message, and the rest are as in
+ printf(3). */
-#ifdef WGET_USE_STDARG
void
logprintf (enum log_options o, const char *fmt, ...)
-#else /* not WGET_USE_STDARG */
-void
-logprintf (va_alist)
- va_dcl
-#endif /* not WGET_USE_STDARG */
{
va_list args;
struct logvprintf_state lpstate;
int done;
-#ifndef WGET_USE_STDARG
- enum log_options o;
- const char *fmt;
-
- /* Perform a "dry run" of VA_START_2 to get the value of O. */
- VA_START_2 (enum log_options, o, char *, fmt, args);
- va_end (args);
-#endif
-
check_redirect_output ();
if (inhibit_logging)
return;
memset (&lpstate, '\0', sizeof (lpstate));
do
{
- VA_START_2 (enum log_options, o, char *, fmt, args);
+ VA_START (args, fmt);
done = logvprintf (&lpstate, fmt, args);
va_end (args);
}
#ifdef DEBUG
/* The same as logprintf(), but does anything only if opt.debug is
non-zero. */
-#ifdef WGET_USE_STDARG
void
debug_logprintf (const char *fmt, ...)
-#else /* not WGET_USE_STDARG */
-void
-debug_logprintf (va_alist)
- va_dcl
-#endif /* not WGET_USE_STDARG */
{
if (opt.debug)
{
va_list args;
-#ifndef WGET_USE_STDARG
- const char *fmt;
-#endif
struct logvprintf_state lpstate;
int done;
memset (&lpstate, '\0', sizeof (lpstate));
do
{
- VA_START_1 (char *, fmt, args);
+ VA_START (args, fmt);
done = logvprintf (&lpstate, fmt, args);
va_end (args);
}
logfp = stderr;
/* If the output is a TTY, enable storing, which will make Wget
- remember all the printed messages, to be able to dump them to
- a log file in case SIGHUP or SIGUSR1 is received (or
- Ctrl+Break is pressed under Windows). */
+ remember the last several printed messages, to be able to
+ dump them to a log file in case SIGHUP or SIGUSR1 is received
+ (or Ctrl+Break is pressed under Windows). */
if (1
#ifdef HAVE_ISATTY
&& isatty (fileno (logfp))