(file) Return to ansi2knr.c CVS log (file) (dir) Up to [RizwankCVS] / testProject / src

  1 rizwank 1.1 /* Copyright (C) 1989, 1997 Aladdin Enterprises.  All rights reserved. */
  2             
  3             /*$Id: ansi2knr.c,v 1.9 1998/04/03 21:56:52 tromey Exp $*/
  4             /* Convert ANSI C function definitions to K&R ("traditional C") syntax */
  5             
  6             /*
  7             ansi2knr is distributed in the hope that it will be useful, but WITHOUT ANY
  8             WARRANTY.  No author or distributor accepts responsibility to anyone for the
  9             consequences of using it or for whether it serves any particular purpose or
 10             works at all, unless he says so in writing.  Refer to the GNU General Public
 11             License (the "GPL") for full details.
 12             
 13             Everyone is granted permission to copy, modify and redistribute ansi2knr,
 14             but only under the conditions described in the GPL.  A copy of this license
 15             is supposed to have been given to you along with ansi2knr so you can know
 16             your rights and responsibilities.  It should be in a file named COPYLEFT,
 17             or, if there is no file named COPYLEFT, a file named COPYING.  Among other
 18             things, the copyright notice and this notice must be preserved on all
 19             copies.
 20             
 21             We explicitly state here what we believe is already implied by the GPL: if
 22 rizwank 1.1 the ansi2knr program is distributed as a separate set of sources and a
 23             separate executable file which are aggregated on a storage medium together
 24             with another program, this in itself does not bring the other program under
 25             the GPL, nor does the mere fact that such a program or the procedures for
 26             constructing it invoke the ansi2knr executable bring any other part of the
 27             program under the GPL.
 28             */
 29             
 30             /*
 31              * Usage:
 32             	ansi2knr [--filename FILENAME] [INPUT_FILE [OUTPUT_FILE]]
 33              * --filename provides the file name for the #line directive in the output,
 34              * overriding input_file (if present).
 35              * If no input_file is supplied, input is read from stdin.
 36              * If no output_file is supplied, output goes to stdout.
 37              * There are no error messages.
 38              *
 39              * ansi2knr recognizes function definitions by seeing a non-keyword
 40              * identifier at the left margin, followed by a left parenthesis,
 41              * with a right parenthesis as the last character on the line,
 42              * and with a left brace as the first token on the following line
 43 rizwank 1.1  * (ignoring possible intervening comments).
 44              * It will recognize a multi-line header provided that no intervening
 45              * line ends with a left or right brace or a semicolon.
 46              * These algorithms ignore whitespace and comments, except that
 47              * the function name must be the first thing on the line.
 48              * The following constructs will confuse it:
 49              *	- Any other construct that starts at the left margin and
 50              *	    follows the above syntax (such as a macro or function call).
 51              *	- Some macros that tinker with the syntax of the function header.
 52              */
 53             
 54             /*
 55              * The original and principal author of ansi2knr is L. Peter Deutsch
 56              * <ghost@aladdin.com>.  Other authors are noted in the change history
 57              * that follows (in reverse chronological order):
 58             	lpd 97-12-08 made input_file optional; only closes input and/or
 59             		output file if not stdin or stdout respectively; prints
 60             		usage message on stderr rather than stdout; adds
 61             		--filename switch (changes suggested by
 62             		<ceder@lysator.liu.se>)
 63             	lpd 96-01-21 added code to cope with not HAVE_CONFIG_H and with
 64 rizwank 1.1 		compilers that don't understand void, as suggested by
 65             		Tom Lane
 66             	lpd 96-01-15 changed to require that the first non-comment token
 67             		on the line following a function header be a left brace,
 68             		to reduce sensitivity to macros, as suggested by Tom Lane
 69             		<tgl@sss.pgh.pa.us>
 70             	lpd 95-06-22 removed #ifndefs whose sole purpose was to define
 71             		undefined preprocessor symbols as 0; changed all #ifdefs
 72             		for configuration symbols to #ifs
 73             	lpd 95-04-05 changed copyright notice to make it clear that
 74             		including ansi2knr in a program does not bring the entire
 75             		program under the GPL
 76             	lpd 94-12-18 added conditionals for systems where ctype macros
 77             		don't handle 8-bit characters properly, suggested by
 78             		Francois Pinard <pinard@iro.umontreal.ca>;
 79             		removed --varargs switch (this is now the default)
 80             	lpd 94-10-10 removed CONFIG_BROKETS conditional
 81             	lpd 94-07-16 added some conditionals to help GNU `configure',
 82             		suggested by Francois Pinard <pinard@iro.umontreal.ca>;
 83             		properly erase prototype args in function parameters,
 84             		contributed by Jim Avera <jima@netcom.com>;
 85 rizwank 1.1 		correct error in writeblanks (it shouldn't erase EOLs)
 86             	lpd 89-xx-xx original version
 87              */
 88             
 89             /* Most of the conditionals here are to make ansi2knr work with */
 90             /* or without the GNU configure machinery. */
 91             
 92             #if HAVE_CONFIG_H
 93             # include <config.h>
 94             #endif
 95             
 96             #include <stdio.h>
 97             #include <ctype.h>
 98             
 99             #if HAVE_CONFIG_H
100             
101             /*
102                For properly autoconfiguring ansi2knr, use AC_CONFIG_HEADER(config.h).
103                This will define HAVE_CONFIG_H and so, activate the following lines.
104              */
105             
106 rizwank 1.1 # if STDC_HEADERS || HAVE_STRING_H
107             #  include <string.h>
108             # else
109             #  include <strings.h>
110             # endif
111             
112             #else /* not HAVE_CONFIG_H */
113             
114             /* Otherwise do it the hard way */
115             
116             # ifdef BSD
117             #  include <strings.h>
118             # else
119             #  ifdef VMS
120                 extern int strlen(), strncmp();
121             #  else
122             #   include <string.h>
123             #  endif
124             # endif
125             
126             #endif /* not HAVE_CONFIG_H */
127 rizwank 1.1 
128             #if STDC_HEADERS
129             # include <stdlib.h>
130             #else
131             /*
132                malloc and free should be declared in stdlib.h,
133                but if you've got a K&R compiler, they probably aren't.
134              */
135             # ifdef MSDOS
136             #  include <malloc.h>
137             # else
138             #  ifdef VMS
139                  extern char *malloc();
140                  extern void free();
141             #  else
142                  extern char *malloc();
143                  extern int free();
144             #  endif
145             # endif
146             
147             #endif
148 rizwank 1.1 
149             /*
150              * The ctype macros don't always handle 8-bit characters correctly.
151              * Compensate for this here.
152              */
153             #ifdef isascii
154             #  undef HAVE_ISASCII		/* just in case */
155             #  define HAVE_ISASCII 1
156             #else
157             #endif
158             #if STDC_HEADERS || !HAVE_ISASCII
159             #  define is_ascii(c) 1
160             #else
161             #  define is_ascii(c) isascii(c)
162             #endif
163             
164             #define is_space(c) (is_ascii(c) && isspace(c))
165             #define is_alpha(c) (is_ascii(c) && isalpha(c))
166             #define is_alnum(c) (is_ascii(c) && isalnum(c))
167             
168             /* Scanning macros */
169 rizwank 1.1 #define isidchar(ch) (is_alnum(ch) || (ch) == '_')
170             #define isidfirstchar(ch) (is_alpha(ch) || (ch) == '_')
171             
172             /* Forward references */
173             char *skipspace();
174             int writeblanks();
175             int test1();
176             int convert1();
177             
178             /* The main program */
179             int
180             main(argc, argv)
181                 int argc;
182                 char *argv[];
183             {	FILE *in = stdin;
184             	FILE *out = stdout;
185             	char *filename = 0;
186             #define bufsize 5000			/* arbitrary size */
187             	char *buf;
188             	char *line;
189             	char *more;
190 rizwank 1.1 	char *usage =
191             	  "Usage: ansi2knr [--filename FILENAME] [INPUT_FILE [OUTPUT_FILE]]\n";
192             	/*
193             	 * In previous versions, ansi2knr recognized a --varargs switch.
194             	 * If this switch was supplied, ansi2knr would attempt to convert
195             	 * a ... argument to va_alist and va_dcl; if this switch was not
196             	 * supplied, ansi2knr would simply drop any such arguments.
197             	 * Now, ansi2knr always does this conversion, and we only
198             	 * check for this switch for backward compatibility.
199             	 */
200             	int convert_varargs = 1;
201             
202             	while ( argc > 1 && argv[1][0] == '-' ) {
203             	  if ( !strcmp(argv[1], "--varargs") ) {
204             	    convert_varargs = 1;
205             	    argc--;
206             	    argv++;
207             	    continue;
208             	  }
209             	  if ( !strcmp(argv[1], "--filename") && argc > 2 ) {
210             	    filename = argv[2];
211 rizwank 1.1 	    argc -= 2;
212             	    argv += 2;
213             	    continue;
214             	  }
215             	  fprintf(stderr, "Unrecognized switch: %s\n", argv[1]);
216             	  fprintf(stderr, usage);
217             	  exit(1);
218             	}
219             	switch ( argc )
220             	   {
221             	default:
222             		fprintf(stderr, usage);
223             		exit(0);
224             	case 3:
225             		out = fopen(argv[2], "w");
226             		if ( out == NULL ) {
227             		  fprintf(stderr, "Cannot open output file %s\n", argv[2]);
228             		  exit(1);
229             		}
230             		/* falls through */
231             	case 2:
232 rizwank 1.1 		in = fopen(argv[1], "r");
233             		if ( in == NULL ) {
234             		  fprintf(stderr, "Cannot open input file %s\n", argv[1]);
235             		  exit(1);
236             		}
237             		if ( filename == 0 )
238             		  filename = argv[1];
239             		/* falls through */
240             	case 1:
241             		break;
242             	   }
243             	if ( filename )
244             	  fprintf(out, "#line 1 \"%s\"\n", filename);
245             	buf = malloc(bufsize);
246             	line = buf;
247             	while ( fgets(line, (unsigned)(buf + bufsize - line), in) != NULL )
248             	   {
249             test:		line += strlen(line);
250             		switch ( test1(buf) )
251             		   {
252             		case 2:			/* a function header */
253 rizwank 1.1 			convert1(buf, out, 1, convert_varargs);
254             			break;
255             		case 1:			/* a function */
256             			/* Check for a { at the start of the next line. */
257             			more = ++line;
258             f:			if ( line >= buf + (bufsize - 1) ) /* overflow check */
259             			  goto wl;
260             			if ( fgets(line, (unsigned)(buf + bufsize - line), in) == NULL )
261             			  goto wl;
262             			switch ( *skipspace(more, 1) )
263             			  {
264             			  case '{':
265             			    /* Definitely a function header. */
266             			    convert1(buf, out, 0, convert_varargs);
267             			    fputs(more, out);
268             			    break;
269             			  case 0:
270             			    /* The next line was blank or a comment: */
271             			    /* keep scanning for a non-comment. */
272             			    line += strlen(line);
273             			    goto f;
274 rizwank 1.1 			  default:
275             			    /* buf isn't a function header, but */
276             			    /* more might be. */
277             			    fputs(buf, out);
278             			    strcpy(buf, more);
279             			    line = buf;
280             			    goto test;
281             			  }
282             			break;
283             		case -1:		/* maybe the start of a function */
284             			if ( line != buf + (bufsize - 1) ) /* overflow check */
285             			  continue;
286             			/* falls through */
287             		default:		/* not a function */
288             wl:			fputs(buf, out);
289             			break;
290             		   }
291             		line = buf;
292             	   }
293             	if ( line != buf )
294             	  fputs(buf, out);
295 rizwank 1.1 	free(buf);
296             	if ( out != stdout )
297             	  fclose(out);
298             	if ( in != stdin )
299             	  fclose(in);
300             	return 0;
301             }
302             
303             /* Skip over space and comments, in either direction. */
304             char *
305             skipspace(p, dir)
306                 register char *p;
307                 register int dir;			/* 1 for forward, -1 for backward */
308             {	for ( ; ; )
309             	   {	while ( is_space(*p) )
310             		  p += dir;
311             		if ( !(*p == '/' && p[dir] == '*') )
312             		  break;
313             		p += dir;  p += dir;
314             		while ( !(*p == '*' && p[dir] == '/') )
315             		   {	if ( *p == 0 )
316 rizwank 1.1 			  return p;	/* multi-line comment?? */
317             			p += dir;
318             		   }
319             		p += dir;  p += dir;
320             	   }
321             	return p;
322             }
323             
324             /*
325              * Write blanks over part of a string.
326              * Don't overwrite end-of-line characters.
327              */
328             int
329             writeblanks(start, end)
330                 char *start;
331                 char *end;
332             {	char *p;
333             	for ( p = start; p < end; p++ )
334             	  if ( *p != '\r' && *p != '\n' )
335             	    *p = ' ';
336             	return 0;
337 rizwank 1.1 }
338             
339             /*
340              * Test whether the string in buf is a function definition.
341              * The string may contain and/or end with a newline.
342              * Return as follows:
343              *	0 - definitely not a function definition;
344              *	1 - definitely a function definition;
345              *	2 - definitely a function prototype (NOT USED);
346              *	-1 - may be the beginning of a function definition,
347              *		append another line and look again.
348              * The reason we don't attempt to convert function prototypes is that
349              * Ghostscript's declaration-generating macros look too much like
350              * prototypes, and confuse the algorithms.
351              */
352             int
353             test1(buf)
354                 char *buf;
355             {	register char *p = buf;
356             	char *bend;
357             	char *endfn;
358 rizwank 1.1 	int contin;
359             
360             	if ( !isidfirstchar(*p) )
361             	  return 0;		/* no name at left margin */
362             	bend = skipspace(buf + strlen(buf) - 1, -1);
363             	switch ( *bend )
364             	   {
365             	   case ';': contin = 0 /*2*/; break;
366             	   case ')': contin = 1; break;
367             	   case '{': return 0;		/* not a function */
368             	   case '}': return 0;		/* not a function */
369             	   default: contin = -1;
370             	   }
371             	while ( isidchar(*p) )
372             	  p++;
373             	endfn = p;
374             	p = skipspace(p, 1);
375             	if ( *p++ != '(' )
376             	  return 0;		/* not a function */
377             	p = skipspace(p, 1);
378             	if ( *p == ')' )
379 rizwank 1.1 	  return 0;		/* no parameters */
380             	/* Check that the apparent function name isn't a keyword. */
381             	/* We only need to check for keywords that could be followed */
382             	/* by a left parenthesis (which, unfortunately, is most of them). */
383             	   {	static char *words[] =
384             		   {	"asm", "auto", "case", "char", "const", "double",
385             			"extern", "float", "for", "if", "int", "long",
386             			"register", "return", "short", "signed", "sizeof",
387             			"static", "switch", "typedef", "unsigned",
388             			"void", "volatile", "while", 0
389             		   };
390             		char **key = words;
391             		char *kp;
392             		int len = endfn - buf;
393             
394             		while ( (kp = *key) != 0 )
395             		   {	if ( strlen(kp) == len && !strncmp(kp, buf, len) )
396             			  return 0;	/* name is a keyword */
397             			key++;
398             		   }
399             	   }
400 rizwank 1.1 	return contin;
401             }
402             
403             /* Convert a recognized function definition or header to K&R syntax. */
404             int
405             convert1(buf, out, header, convert_varargs)
406                 char *buf;
407                 FILE *out;
408                 int header;			/* Boolean */
409                 int convert_varargs;	/* Boolean */
410             {	char *endfn;
411             	register char *p;
412             	/*
413             	 * The breaks table contains pointers to the beginning and end
414             	 * of each argument.
415             	 */
416             	char **breaks;
417             	unsigned num_breaks = 2;	/* for testing */
418             	char **btop;
419             	char **bp;
420             	char **ap;
421 rizwank 1.1 	char *vararg = 0;
422             
423             	/* Pre-ANSI implementations don't agree on whether strchr */
424             	/* is called strchr or index, so we open-code it here. */
425             	for ( endfn = buf; *(endfn++) != '('; )
426             	  ;
427             top:	p = endfn;
428             	breaks = (char **)malloc(sizeof(char *) * num_breaks * 2);
429             	if ( breaks == 0 )
430             	   {	/* Couldn't allocate break table, give up */
431             		fprintf(stderr, "Unable to allocate break table!\n");
432             		fputs(buf, out);
433             		return -1;
434             	   }
435             	btop = breaks + num_breaks * 2 - 2;
436             	bp = breaks;
437             	/* Parse the argument list */
438             	do
439             	   {	int level = 0;
440             		char *lp = NULL;
441             		char *rp;
442 rizwank 1.1 		char *end = NULL;
443             
444             		if ( bp >= btop )
445             		   {	/* Filled up break table. */
446             			/* Allocate a bigger one and start over. */
447             			free((char *)breaks);
448             			num_breaks <<= 1;
449             			goto top;
450             		   }
451             		*bp++ = p;
452             		/* Find the end of the argument */
453             		for ( ; end == NULL; p++ )
454             		   {	switch(*p)
455             			   {
456             			   case ',':
457             				if ( !level ) end = p;
458             				break;
459             			   case '(':
460             				if ( !level ) lp = p;
461             				level++;
462             				break;
463 rizwank 1.1 			   case ')':
464             				if ( --level < 0 ) end = p;
465             				else rp = p;
466             				break;
467             			   case '/':
468             				p = skipspace(p, 1) - 1;
469             				break;
470             			   default:
471             				;
472             			   }
473             		   }
474             		/* Erase any embedded prototype parameters. */
475             		if ( lp )
476             		  writeblanks(lp + 1, rp);
477             		p--;			/* back up over terminator */
478             		/* Find the name being declared. */
479             		/* This is complicated because of procedure and */
480             		/* array modifiers. */
481             		for ( ; ; )
482             		   {	p = skipspace(p - 1, -1);
483             			switch ( *p )
484 rizwank 1.1 			   {
485             			   case ']':	/* skip array dimension(s) */
486             			   case ')':	/* skip procedure args OR name */
487             			   {	int level = 1;
488             				while ( level )
489             				 switch ( *--p )
490             				   {
491             				   case ']': case ')': level++; break;
492             				   case '[': case '(': level--; break;
493             				   case '/': p = skipspace(p, -1) + 1; break;
494             				   default: ;
495             				   }
496             			   }
497             				if ( *p == '(' && *skipspace(p + 1, 1) == '*' )
498             				   {	/* We found the name being declared */
499             					while ( !isidfirstchar(*p) )
500             					  p = skipspace(p, 1) + 1;
501             					goto found;
502             				   }
503             				break;
504             			   default:
505 rizwank 1.1 				goto found;
506             			   }
507             		   }
508             found:		if ( *p == '.' && p[-1] == '.' && p[-2] == '.' )
509             		  {	if ( convert_varargs )
510             			  {	*bp++ = "va_alist";
511             				vararg = p-2;
512             			  }
513             			else
514             			  {	p++;
515             				if ( bp == breaks + 1 )	/* sole argument */
516             				  writeblanks(breaks[0], p);
517             				else
518             				  writeblanks(bp[-1] - 1, p);
519             				bp--;
520             			  }
521             		   }
522             		else
523             		   {	while ( isidchar(*p) ) p--;
524             			*bp++ = p+1;
525             		   }
526 rizwank 1.1 		p = end;
527             	   }
528             	while ( *p++ == ',' );
529             	*bp = p;
530             	/* Make a special check for 'void' arglist */
531             	if ( bp == breaks+2 )
532             	   {	p = skipspace(breaks[0], 1);
533             		if ( !strncmp(p, "void", 4) )
534             		   {	p = skipspace(p+4, 1);
535             			if ( p == breaks[2] - 1 )
536             			   {	bp = breaks;	/* yup, pretend arglist is empty */
537             				writeblanks(breaks[0], p + 1);
538             			   }
539             		   }
540             	   }
541             	/* Put out the function name and left parenthesis. */
542             	p = buf;
543             	while ( p != endfn ) putc(*p, out), p++;
544             	/* Put out the declaration. */
545             	if ( header )
546             	  {	fputs(");", out);
547 rizwank 1.1 		for ( p = breaks[0]; *p; p++ )
548             		  if ( *p == '\r' || *p == '\n' )
549             		    putc(*p, out);
550             	  }
551             	else
552             	  {	for ( ap = breaks+1; ap < bp; ap += 2 )
553             		  {	p = *ap;
554             			while ( isidchar(*p) )
555             			  putc(*p, out), p++;
556             			if ( ap < bp - 1 )
557             			  fputs(", ", out);
558             		  }
559             		fputs(")  ", out);
560             		/* Put out the argument declarations */
561             		for ( ap = breaks+2; ap <= bp; ap += 2 )
562             		  (*ap)[-1] = ';';
563             		if ( vararg != 0 )
564             		  {	*vararg = 0;
565             			fputs(breaks[0], out);		/* any prior args */
566             			fputs("va_dcl", out);		/* the final arg */
567             			fputs(bp[0], out);
568 rizwank 1.1 		  }
569             		else
570             		  fputs(breaks[0], out);
571             	  }
572             	free((char *)breaks);
573             	return 0;
574             }

Rizwan Kassim
Powered by
ViewCVS 0.9.2