File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lrzsz / lib / ansi2knr.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Thu Oct 24 15:49:50 2019 UTC (4 years, 8 months ago) by misho
Branches: lrzsz, MAIN
CVS tags: v0_12_20p5, HEAD
lrzsz ver 0.12.20

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>