[comp.sources.unix] v18i079: Absolutely-portable remote interchange library 1

rsalz@uunet.uu.net (Rich Salz) (04/01/89)

Submitted-by: Dave Taylor <taylor@hplabsz.hpl.hp.com>
Posting-number: Volume 18, Issue 79
Archive-name: april-fool

# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# This archive contains:
#	uuexpand.1	uuexpand.c	Makefile	
#
# Error checking via wc(1) will be performed.

LANG=""; export LANG

echo x - uuexpand.1
cat >uuexpand.1 <<'@EOF'
.TH UUEXPAND 1L "" ""
.ad b
.SH NAME
uuexpand, uuunexpand \- make file representation independent
.SH SYNOPSIS
.B uuexpand
[
.B \-87?hAEdeuv
] [
.B \-16
] [
.B \-w
.I width
]
.br
.B uuunexpand
[
.I uuexpand options
] 
.SH DESCRIPTION
.I Uuexpand
is a representation independent file archival and transportation
mechanism for any operating system that has a "C" compiler available,
including Unix, the Macintosh, MS-DOS, OS/2, VMS, and the like.
.I Uuexpand
also supports all international character sets, including 16-bit Asian,
and 8-bit non-English, as required by the application.
.PP
The program pair are intended to be used to aid in the easy
transportation of program and textual sources, data files, and
binaries via electronic media.
.PP
.SS Options
.PP
There are many options:
.TP 
.B  \-16
Specifies that 16-bit character sets are being used and to ensure 
portability. (Note on non-standard character sets: you must ensure
that when unexpanded the same parameter is specified to the 
program!)
.TP 
.B  \-8 
Specifies that 8-bit character sets are being used.  This is the
default character set assumed (255 character extended ASCII)
.TP 
.B  \-7 
Use a 7-bit ASCII representation for smaller output files.  This
is useful if you are sure that you've not strayed beyond the 
basic 128 ASCII characters.  (see the note under the '-16' option)
.TP 
.B  \-? 
Output a summary of the starting options available.
.TP
.B \-A
Use the ASCII character set for the output of the program.  This is
the default character set assumed.
.TP
.B \-E
Use the EBCDIC character set for the output of the program.  If you
use this option you must ensure that the other end also uses this
option when the file or software is unpacked.
.TP
.B \-d
Turn on debugging for more output and some ending statistics.
.TP
.B \-e
Expand the input -- act as if we'd invoked 
.I uuexpand
explicitly (for sites that choose to change the name).
.TP
.B \-h
Output a summary of starting options; identical to '-?'
.TP
.B \-u
Unexpand the input -- act as if we'd invoked
.I uuunexpand
explicitly (for sites that might not have the symbolic link
between the two names installed)
.TP
.B \-v
Enable verbose output including some ending statistics.
.TP
.B \-w N
Set the expanded line output width to 
.I N
representational independent output elements.  The default, with
the 8-bit characters, is 8 units per output line.
including indirect blocks, is printed.
.SH EXAMPLES
A very typical usage of the program would be for a person at a
site in, say, Hong Kong, to mail a Chinese (16-bit) data file to
a fellow Unix-ite with:
.PP
.ti +.5i
uuexpand -16 < data | mail -s "Data" user@farhost.com
.ti -.5i
.PP
The user at the other end could then simply save the message
int a file then invoke a command similar to:
.PP
.ti +.5i
uuunexpand -16 < data.mailed > data
.ti -.5i
.PP
And the data file would be intact regardless of transport
hosts along the way.
.SH AUTHOR 
Dave Taylor, Intuitive Systems, Los Altos, California
.SH SEE ALSO
uuencode(1L), crypt(1), mail(1), uumail(1), shar(1L)
.SH INTERNATIONAL SUPPORT
16-bit, 8-bit and 7-bit data.
.SH BUGS
The EBCDIC support is minimal and needs to be further developed
by someone on an IBM or other EBCDIC machine.
.PP
The portability of the C code has not been completely
verified; input from people on strange hardware, especially
386 Unix machines, would be a useful addition.
.PP
The program doesn't, but should, deal with machines that
have peculiar byte sex problems.
@EOF
if test "`wc -lwc <uuexpand.1`" != '    123    595   3485'
then
	echo ERROR: wc results of uuexpand.1 are `wc -lwc <uuexpand.1` should be     123    595   3485
fi

chmod 666 uuexpand.1

echo x - uuexpand.c
cat >uuexpand.c <<'@EOF'
/**				uuexpand.c			**/

/** This is a representation independent file archival and transportation
    mechanism for any operating system that has a "C" compiler available,
    including Unix, the Macintosh, MS-DOS, OS/2, VMS, and the like.  This
    also supports all international character sets, including 16-bit Asian
    characters as required by the application.

    (C) Copyright 1989 Dave Taylor, Intuitive Systems, Los Altos California

    >  Permission is hereby granted for the free distribution of this  <
    >  software throughout the known world with the clause that it be  <
    >  free and this version of the source code is always available.   <

**/

#include <stdio.h>

#define SLEN			2048	/* max length of an input line  */

#define DEFAULT_CHAR_WIDTH	8	/* 8 bit ASCII by default	*/
#define DEFAULT_BYTES_ON_LINE	8	/* default byte units / line	*/

#define EXPAND			1
#define UNEXPAND		2

#define ASCII			425
#define EBCDIC			943

#define ON_CHAR			'1'
#define OFF_CHAR		'0'

#define plural(n)		(n == 1? "" : "s")

int  width_of_line,		/* width of output block/line		 */
     action,			/* what are we doing? expand or unexpand */
     lines = 0,			/* lines we've read in from stdin	 */
     chars = 0,			/* chars we've read in from stdin	 */
     lines_output = 0,		/* lines we've output to stdout		 */
     char_width;		/* are we using 7-bit, 8-bit, or 16-bit? */

extern char *optarg;

main(argc, argv)
int  argc;
char *argv[];
{
	register int i, bit;
	char buffer[SLEN], char_buffer;
	int  bytes_on_line, verbose, output_charset, c;

	/* first step: set up the defaults for the program */

	action = (strcmp(argv[0], "uuexpand") == 0? EXPAND: UNEXPAND);

	char_width     = DEFAULT_CHAR_WIDTH;
	bytes_on_line  = DEFAULT_BYTES_ON_LINE;
	output_charset = ASCII;			/* default */

	/* now let's parse the starting arguments */

	while ((c = getopt(argc, argv, "AEeu781:w:vdh?")) != EOF) {
	  switch (c) {
	   case 'A' : output_charset = ASCII;		break;
	   case 'E' : output_charset = EBCDIC;		break;
	   case '7' : char_width = 7;			break;
	   case '8' : char_width = 8;			break;
	   case '1' : char_width = 16;			break;
	   case 'w' : bytes_on_line = atoi(optarg);	break;
	   case 'v' : 
	   case 'd' : verbose++;			break;
	   case 'e' : action = EXPAND;			break;
	   case 'u' : action = UNEXPAND;		break;
	   case 'h' :
	   case '?' : help(0);				break;
	    default : usage("unknown starting option");
	  }
	}

	/** a quick reality check on the bytes per line argument */

	if (bytes_on_line < 1 || (bytes_on_line * char_width > SLEN/2))
	  usage("invalid specification for line width");

	/** and we recompute the line width for output **/

	width_of_line = (char_width * bytes_on_line) - 1;
	
	/** now we're ready to go. **/
	
	if (verbose) {
	  fprintf(stderr, "%sexpand: %s character set %s with %d-bit chars\n",
		  action == EXPAND ? "" : "un",
		  action == UNEXPAND ? "input" : "output",
		  output_charset == ASCII ? "ASCII" : "EBCDIC",
		  char_width);
	}

	/** Main switch here: expanding, or unexpanding? **/

	if (action == EXPAND) {
	  while (fgets(buffer, SLEN, stdin) != NULL) {
	    lines++; chars += strlen(buffer);
	    for (i=0; buffer[i] != '\0'; i++) {
	      char_buffer = buffer[i];		/* ease of use */
	      for (bit=0;bit < char_width; bit++, char_buffer >>= 1)
	        output( char_buffer & 01 );
	    }
	  }
	}
	else /* UNEXPAND */ {
	  while (gets(buffer) != NULL) {
	    lines++; chars += strlen(buffer);
	    for (i=0; i < strlen(buffer); i += char_width) {
	      char_buffer = 0;
	      for (bit=char_width;bit >= 0; bit--) {
	        char_buffer <<= 1;
		char_buffer += (buffer[i+bit] == ON_CHAR ? 1 : 0);
	      }
	      putchar(char_buffer);
	      if (char_buffer == '\n' || char_buffer == '\r')
	        lines_output++;
	    }
	  }
	}

	if (verbose) {
	  if (action == EXPAND) {
	    fprintf(stderr, "Read in %d character%s, %d line%s\n", 
		    chars, plural(chars), lines, plural(lines));
	    fprintf(stderr, 
	       "Output %d representation independent element%s in %d line%s.\n",
		chars * char_width, plural(chars * char_width),
		lines_output, plural(lines_output));
	  }
	  else {
	    fprintf(stderr, 
	     "Read in %d representation independent element%s in %d line%s\n",
		chars, plural(chars), lines, plural(lines));
	    fprintf(stderr, 
		"Output %d character%s in %d line%s.\n",
		(int) (chars / char_width),
		plural(chars / char_width),
		lines_output, plural(lines_output));
	  }
	}
}

output(bitvalue)
int bitvalue;
{
	/** Outputs the ON or OFF value based on what we've
	    been handed.  No return value.
	**/

	static int location_on_line = 0;

	if (location_on_line > width_of_line) {
	  putchar('\n');
	  lines_output++;
	  location_on_line = 0;
	}

	putchar(bitvalue ? ON_CHAR : OFF_CHAR);

	location_on_line++;
}

usage(errmsg)
char *errmsg;
{
	/** Output the error message and call help() for a usage **/

	fprintf(stderr, "\n**** Error: %s ****\n", errmsg);

	help(1);
}

help(exitcode)
int exitcode;
{
	/** output some starting parameter help and exit with
	    the code specified by the calling routine.
	**/

	fprintf(stderr,"\nUsage: uuexpand [opts]\n");
	fprintf(stderr,"   or: uuunexpand [opts]\n\n");
	fprintf(stderr,"Where [opts] can be:\n\n");
	fprintf(stderr,
"\t-16  \tEnsure 16-bit portability\n\
\t-8   \tEnsure 8-bit portability (the default)\n\
\t-7   \tEnsure 7-bit portability\n");
	fprintf(stderr,
"\t-?     \tList the starting options (this information)\n\
\t-h     \tIdentical in functionality to '-?'\n");
	fprintf(stderr,
"\t-A   \tUse the ASCII character set for expanded output\n\
\t-E     \tUse the EBCDIC character set for expanded output\n");
	fprintf(stderr,
"\t-d   \tEnable debugging output (to stderr)\n");
	fprintf(stderr,
"\t-e   \tExpand output (same as invoking 'uuexpand')\n\
\t-u     \tUnExpand output (same as invoking 'uuunexpand')\n");
	fprintf(stderr,
"\t-v   \tEnable verbose output (to stderr)\n");
	fprintf(stderr,
"\t-w N   \tSet expanded line output width to 'N' representational elements\n\
\t     \tper line (default is 8 per 8-bit represented line)\n\n");

	exit(exitcode);
}
@EOF
if test "`wc -lwc <uuexpand.c`" != '    211    842   6118'
then
	echo ERROR: wc results of uuexpand.c are `wc -lwc <uuexpand.c` should be     211    842   6118
fi

chmod 666 uuexpand.c

echo x - Makefile
cat >Makefile <<'@EOF'

#
# Makefile for the uuexpand program
#
# (C) 1989 Dave Taylor
#

SRC 	   = uuexpand.c
EXECUTABLE = uuexpand
OTHERNAME  = uuunexpand
MANPAGE	   = uuexpand.1

INSTALLDIR = /usr/local/bin
MANDIR	   = /usr/man/man1

CC	   = cc
CFLAGS	   = -O
DEFINES	   = 


$(EXECUTABLE) : $(SRC)
	$(CC) $(CFLAGS) $(DEFINES) $(SRC) -o $(EXECUTABLE)

install: $(EXECUTABLE)
	strip $(EXECUTABLE)
	cp $(EXECUTABLE) $(INSTALLDIR)/$(EXECUTABLE)
	ln -s $(EXECUTABLE) $(OTHERNAME)
	cp $(MANPAGE) $(MANDIR)/$(MANPAGE)
	ln -s $(MANDIR)/$(MANPAGE) $(MANDIR)/$(OTHERNAME).1

lint:	$(SRC)
	lint $(DEFINES) $(SRC) > LINT.OUT

clean:	
	rm -f a.out core
@EOF
if test "`wc -lwc <Makefile`" != '     35     79    621'
then
	echo ERROR: wc results of Makefile are `wc -lwc <Makefile` should be      35     79    621
fi

chmod 666 Makefile

exit 0

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.