Subject: s2func.pl (Convert structures to network data and back)
From: [email-masked] (Sam Lantinga)
Date: Sun, 17 Oct 1993 06:16:45 GMT
Newsgroups: alt.sources

Finally!!  I got a program to write routines that will convert 
binary structure definitions into a portable data representation and
re-convert them.. similar to htons() and ntohs() for structures!

	This perl script takes a skeleton structure definition and
writes routines to convert it in and out of "network data representation".
It hasn't been thoroughly tested, but it has (and will) help me
write cross-platform networking code much faster.

	Yay! :)

		-Sam.

s2func.pl ---------------------------------------------------------
#!/site/bin/perl
#
# Sam Lantinga                                            10/17/93
#
# This is a perl script to take a structure definition and create
# structure -> network buffer / network buffer -> structure 
# C functions.
#
# This script has not been completely tested, so use at your own risk.
#
# Each of the functions take the following form:
#
#		structname2buf(structptr, bufptr, buflen)
#		buf2structname(structptr, bufptr, buflen)
#
# and return the length of the filled buffer.  They return -1 if
# the buffer was to small to contain the named structure.
#
# The structure definitions given to this script must be fairly
# simple.  They must not contain any structures within them, must
# not contain pointers, and must take the form:
#
# struct structname {
#		data element;		/* Optional comment */
#		data element;		/* Optional comment */
#		};
#
# The only data types allowed are: arrays of chars, shorts, ints
# and longs.  All other data types are not recognized.
#
#################################################################
#
#	Example code showing how these routines might be used.
#
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#  Server Side:
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#  struct first_packet first;
#
#	if ( (len=read(network_fd, buf, 4096)) <= 0 )
#		return;
#
#	if ( (len=buf2first_packet(&first, buf, len)) < 0 )
#		return;
#
#	fprintf(stderr, "Name: %s\n", first.name);
#	fprintf(stderr, "Passwd: %s\n", first.passwd);
#	fprintf(stderr, "Request: %d\n", first.request);
#	fprintf(stderr, "Port: %d\n", first.lport);
#	fprintf(stderr, "Pathname: %s\n", first.path);
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#  Client Side:
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
#	struct first_packet first;
#
#	strcpy(first.name, "Myname");
#	strcpy(first.passwd, "Open Sesame");
#  first.request=1;
#	first.lport=0;
#	strcpy(first.path, "/tmp/tempfile");
#
#
#	if ( (len=first_packet2buf(&first, buf, 4096)) < 0 ) {
#		perror("first2buf() error");
#		exit(3);
#	}
#	if ( sendto(network_fd, buf, len, 0, &serv_addr, sizeof(serv_addr)) < 0 ) {
#		perror("sendto() error");
#		exit(2);
#	}
#
#################################################################

while (<STDIN>) {
	chop;
	if ( ! $_ ) {
		next;
	}
	if ( /struct/ ) {
		if ( $in_struct ) {
			print STDERR "Structures within structures are not allowed.\n";
			exit(1);
		} else {
			$in_struct=1;
			($struct, $structname, $brace)=split(' ');
			next;
		}
	} elsif ( ! $in_struct ) {
		next;
	}
	if ( /\}/ ) {		# Print out the conversion routines.
		print "
int ${structname}2buf(structure, buf, len)
struct $structname *structure;
char *buf;
int len;
{
	char ";
		foreach $name (split(' ', $varlist)) {
			$type=$variables{$name};
			if ( $type eq "short" || $type eq "int" || $type eq "long" ) {
				print "$name[12], ";
			}
		}
		print "*ptr;
	int i=0;
";
		foreach $name (split(' ', $varlist)) {
			$type=$variables{$name};
			if ( $type eq "short" || $type eq "int" ) {
				print "
	sprintf($name, \"%d\", structure->$name);\n";
			} elsif ( $type eq "long" ) {
				print "
	sprintf($name, \"%l\", structure->$name);\n";
			}
		}

		foreach $name (split(' ', $varlist)) {
			$type=$variables{$name};
			if (  $type eq "short" || $type eq "int" || $type eq "long" ) {
				$varname=$name;
			} else {
				$varname="structure->$name";
			}
			print "
	for ( ptr=$varname; (*ptr && i<len); ++i, *(buf++)=(*(ptr++)) );
	if ( *ptr == '\\0' ) {
		*(buf++)='\\0';
		++i;
	} else
		return(-1);
";
		}
		print "
	return(i);
}

int buf2$structname(structure, buf, len)
struct $structname *structure;
char *buf;
int len;
{
	int i=0;
	char *ptr=buf;
";
		foreach $name (split(' ', $varlist)) {
			print "
	for ( ; (*ptr && i<len); ++i, ++ptr );
	if ( *ptr == '\\0' ) {
";
			$type=$variables{$name};
			if ( $type eq "short" || $type eq "int" ) {
				print "		structure->$name=atoi(buf);";
			} elsif ( $type eq "long" ) {
				print "		structure->$name=atol(buf);";
			} else {
				print "		strcpy(structure->$name, buf);";
			}
			print "
		buf=(++ptr);
		++i;
	} else
		return(-1);
";
		}
		print "
	return(i);
}
";
		undef %variables;
		undef $varlist;
		$in_struct=0;
		next;
	}
	if ( ! /\;/ ) {
		print STDERR "Expecting a semicolon: $_\n";
		exit(1);
	} else {
		($_, $null)=split(/;/);
	}
	if ( /unsigned/ ) {
		($unsigned, $type, $name)=split(' ');
	} else {
		($type, $name)=split(' ');
	}
	if ( $name =~ /\[.*\]/ ) {
		($name, $array)=split(/\[/, $name);
		if ( $type ne "char" ) {
			print STDERR "$type is not an allowed array data type.\n";
			exit(1);
		}
	} else if ( $type eq "char" ) {
		print STDERR "You may not use the single char data type.\n";
		exit(1);
	}
	if ( $name =~ /\*/ ) {
		print STDERR "Structures containing pointers are not allowed.\n";
		exit(1);
	}
	$variables{$name}=$type;
	$varlist="$varlist $name";
}