[alt.sources] genfiles - packs and unpacks files for transfer

darcy@druid.uucp (D'Arcy J.M. Cain) (07/19/90)

As I mentioned in alt.sources.d, here is my pack/unpack utility.  Before
everyone points out that it isn't the perfect solution for the problems
discussed in a.s.d let me hasten to beat you to it.  The utilities in
this distribution were originally written for different purposes and
have been hacked on in order to make a start on some sort of solution.
Some of the issues addressed (and hopefully solved) are:

    The lines can be split if desired and restored on the receiving end.

    Many troublesome characters are translated to less troublesome ones
    and restored on the receiving end.

    The files are transmitted in a form that can be read without any
    further processing.  This is ***NOT*** a uuencoding type program.

    By modifying the code, systems that need some characters converted
    to trigraphs can do so by simply commenting out the case statement
    that converts the troublesome character(s).

What it doesn't have yet is multi-part support other than splitting
up the resulting file and restoring it by hand.  I will try to do
something about this.

It also doesn't unpack itself like shar files do but the program is
fairly simple and can easily be written for systems that can't use
this one for some reason.

In order to use the program that creates the script file you either
have to pick up my getarg program which I recently posted or else
hack the source to use normal getopt.  If you can't get getarg from
a local archive site you can get it from my machine's mail server.
Send mail to unix-server@druid.UUCP with the following line in the
body of the message:

send getarg.c

Note if the mail to the server gets too heavy I will have to shut it
down for my neighbours sake so please use it as a last resort.  This
is just a lowly leaf node with a single 2400 baud modem.

The program to unpack the files is self contained.

#!/bin/sh
# This is a shell archive (shar 3.10)
# made 07/19/1990 05:37 UTC by darcy@druid
# Source directory /usr/darcy/work/misc/genfiles
#
# existing files will NOT be overwritten
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   4689 -rw-r--r-- genfiles.c
#   4100 -rw-r--r-- mkscript.c
#   1601 -rw-r--r-- Makefile
#
touch 2>&1 | fgrep '[-amc]' > /tmp/s3_touch$$
if [ -s /tmp/s3_touch$$ ]
then
	TOUCH=can
else
	TOUCH=cannot
fi
rm -f /tmp/s3_touch$$
# ============= genfiles.c ==============
if test -f genfiles.c; then echo "File genfiles.c exists"; else
echo "x - extracting genfiles.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > genfiles.c &&
X/*
Xgenfiles.c
X
XWritten by D'Arcy J.M. Cain
XD'Arcy Cain Consulting
X275 Manse Road, Unit # 24
XWest Hill, Ontario
XM1E 4X8
X416 281 6094
X
XUUCP: darcy@druid
X
XFile generation utility
X
XThis program may be freely distributed as long as credit is given to D'Arcy
XJ.M. Cain, the source is included and this notice remains intact.  There is
Xspecifically no restrictions on use of the program including personal or
Xcommercial.  You may even charge others for this program as long as the above
Xconditions are met.
X
XThis is not shareware and no registration fee is expected.  If you like the
Xprogram and want to support this method of distribution, write a program and
Xdistribute it the same way and I will feel I have been paid.
X
XOf course gifts of money, drinks and extravagant jewels are always welcome.
X
XAs for documentation, you're looking at it.
X
XThis program reads a specially prepared text file from standard input and
Xcreates a file or files based on the contents of the file.  Each line of
Xinput is examined to see if it is one of the following constructs.
X
X;text
X	This is a comment and is ignored
X
X!text
X	The line is accepted from the second character for processing without
X	further checking other than the % character described below.
X
X$text
X	The text is printed on the screen.
X
X=text
X	Text up to the first space or end of line is treated as a file name
X	which is opened as the current output.
X
Xtext
X	The line is put to the current output.
X
XWithin the text, the '%' character is handled differently.  "%%" is treated
Xas a single '%'.  "%0" is replaced by the path name which was current when
Xthe program was started.  '%' followed by a single digit is replaced by
Xthe corresponding argument from the command line.  A '%' followed by an end
Xof line joins the current line with the next one.  In addition, the following
Xcharacter translation is performed:
X	%=  -->  #
X	%/  -->  \
X	%'  -->  ^
X	%(  -->  [
X	%)  -->  ]
X	%!  -->  |
X	%<  -->  {
X	%>  -->  }
X	%-  -->  ~
XIf all of the above fails to match, the character is printed unchanged
Xpreceded by ??.  This allows you to comment out the case statements
Xwhich convert to characters not handled by your system and automagically
Xhave trigraphs.  (Now you know where you saw the above table eh? :-) )
X
X
X*/
X
X#include	<stdio.h>
X#include	<string.h>
X#include	<ctype.h>
X#include	<malloc.h>
X#include	<stdlib.h>
X
X#ifdef		__TURBOC__
X#include	<dir.h>
X#endif
X
Xchar		*str_args[10], entry[512];
Xextern int	errno;
X
Xstatic void		mk_dir_env(char *path)
X{
X	char	*p, c;
X
X	if ((p = strchr(path, '\\')) == NULL)
X		p = strchr(path, '/');
X
X	if (p == NULL)
X		return;
X
X	c = *p;
X	*p = 0;
X	mk_dir_env(path);
X
X#ifdef	__MSDOS__
X	mkdir(path);
X#else
X	mkdir(path, 0);		/* let umask determine permissions */
X#endif
X
X	*p = c;
X}
X
Xvoid	main(int argc, char **argv)
X{
X	FILE	*out_fp = NULL;
X	char	c, *ptr;
X	int	 k;
X
X	printf("GENFILES - File generation utility\n");
X	printf("Copyright 1990 by D'Arcy J.M. Cain\n\n");
X
X	*str_args = getcwd(NULL, 64);
X
X	for (k = 1; k < argc; k++)
X		str_args[k] = argv[k];
X
X	while (k < 10)
X		str_args[k++] = "";
X
X	while (gets(entry) != NULL)
X	{
X		switch (*entry)
X		{
X			case ';':							/* comment */
X				break;
X
X			case '$':							/* print */
X				printf("%s\n", entry + 1);
X				break;
X
X			case '=':							/* open new file */
X				if (out_fp != NULL)
X					fclose(out_fp);
X
X				mk_dir_env(entry + 1);
X
X				if ((out_fp = fopen(entry + 1, "wt")) == NULL)
X				{
X					fprintf(stderr, "\a\n%s: ", entry + 1);
X					perror("Can't open file");
X					exit(errno);
X				}
X				break;
X
X			default:					/* ordinary string */
X				if (out_fp == NULL)
X				{
X					fprintf(stderr, "\a\nNo file opened.\n");
X					exit(1);
X				}
X
X				ptr = entry;
X
X				if (*entry == '!')		/* escape */
X					ptr++;
X
X				while (*ptr)
X				{
X					if ((c = *ptr++) == '%')
X					{
X						c = *ptr++;
X
X						if (isdigit(c))
X							fprintf(out_fp, "%s", str_args[*ptr++ - '0']);
X						else
X						{
X							switch (c)
X							{
X								case 0:
X									if (gets(entry) == NULL)
X										*entry = 0;
X
X									ptr = entry;
X									break;
X
X								case '%': fputc('%',out_fp); break;
X								case '=': fputc('#',out_fp); break;
X								case '/': fputc('\\',out_fp); break;
X								case '\'': fputc('^',out_fp); break;
X								case '(': fputc('[',out_fp); break;
X								case ')': fputc(']',out_fp); break;
X								case '!': fputc('|',out_fp); break;
X								case '<': fputc('{',out_fp); break;
X								case '>': fputc('}',out_fp); break;
X								case '-': fputc('~',out_fp); break;
X
X								default:
X									fprintf(out_fp, "??%c", c);
X									break;
X							}
X						}
X					}
X					else
X						fputc(c, out_fp);
X				}
X
X				fputc('\n', out_fp);
X				break;
X		}
X	}
X
X	free(*str_args);
X	fclose(out_fp);
X	exit(0);
X}
SHAR_EOF
chmod 0644 genfiles.c || echo "restore of genfiles.c fails"
if [ $TOUCH = can ]
then
    touch -am 0719000390 genfiles.c
fi
fi
# ============= mkscript.c ==============
if test -f mkscript.c; then echo "File mkscript.c exists"; else
echo "x - extracting mkscript.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > mkscript.c &&
X/*
Xmkscript.c
X
XWritten by D'Arcy J.M. Cain
XD'Arcy Cain Consulting
X275 Manse Road, Unit # 24
XWest Hill, Ontario
XM1E 4X8
X416 281 6094
X
XUUCP: darcy@druid
X
Xcreates scripts for genfiles
X
XThis program may be freely distributed as long as credit is given to D'Arcy
XJ.M. Cain, the source is included and this notice remains intact.  There is
Xspecifically no restrictions on use of the program including personal or
Xcommercial.  You may even charge others for this program as long as the above
Xconditions are met.
X
XThis is not shareware and no registration fee is expected.  If you like the
Xprogram and want to support this method of distribution, write a program and
Xdistribute it the same way and I will feel I have been paid.
X
XOf course gifts of money, drinks and extravagant jewels are always welcome.
X
XAs for documentation, you're looking at it.
X
Xthis program accepts a list of filenames and outputs a script suitable
Xfor use by genfiles.
X
XSample usage: (Ignore underscores.  They keep ANSI compilers from bitching.)
X	"mkscript src/_*.c src/_*.h src/makefile man/_* readme > dist.txt"
X
XNote the forward slash used above can be replaced by a backslash if you
Xdo your DOS development on a DOS machine.  (Who would do this?) (:-))
X
XIf you didn't grab a copy of my getarg function, send mail to my machine
Xto address unix-serever@druid.UUCP with the line "send getarg.c" in the
Xbody of the message.  You will need this to compile mkscript.
X*/
X
X#include    <stdio.h>
X#include    <string.h>
X#include    <ctype.h>
X#include	<malloc.h>
X#include    <stdlib.h>
X
X#define		BUFFER_SIZE		1024
X
Xchar        entry[BUFFER_SIZE];
Xextern int  errno;
Xextern char	*optarg;
X
Xint		main(int argc, char **argv)
X{
X    FILE    *in_fp = NULL;
X    int     k, c, line_len = BUFFER_SIZE;
X	char	*p;
X
X    printf("$ MKSCRIPT - GENFILES script generation utility\n");
X    printf("$ Copyright 1990 by D'Arcy J.M. Cain\n; \n");
X
X	initarge(argc, argv);
X
X	while ((c = getarg("l;")) != 0)
X	{
X		switch (c)
X		{
X			case 'l':
X				if (optarg == NULL)
X					line_len = BUFFER_SIZE;
X				else
X					line_len = atoi(optarg);
X	
X				if (line_len <= 8)	/* the silly limit */
X				{
X					fprintf(stderr, "%s: Limit must be more than 8\n", argv[0]);
X					exit(1);
X				}
X				break;
X
X			case -1:
X				if ((in_fp = fopen(optarg, "rt")) == NULL)
X				{
X					fprintf(stderr, "%s: %s - ", argv[0], optarg);
X					perror("Can't open for input");
X					exit(errno);
X				}
X
X				printf("=%s\n", optarg);
X				printf("$Creating %s\n", optarg);
X				fprintf(stderr, "%s: Saving %s\n", argv[0], optarg);
X
X				while (fgets(entry, sizeof(entry), in_fp) != NULL)
X				{
X					if ((p = strchr(entry, '\n')) != NULL)
X						*p = 0;
X
X					k = 0;
X					putchar('!');
X
X					for (p = entry; *p; p++)
X					{
X						if (++k >= line_len)
X						{
X							printf("%\n");
X							k = 0;
X						}
X
X						switch (*p)
X						{
X							case '%': printf("%%%%"); break;
X							case '#': printf("%%="); break;
X							case '\\': printf("%%/"); break;
X							case '^': printf("%%'"); break;
X							case '[': printf("%%("); break;
X							case ']': printf("%%)"); break;
X							case '|': printf("%%!"); break;
X							case '{': printf("%%<"); break;
X							case '}': printf("%%>"); break;
X							case '~': printf("%%-"); break;
X							default:  putchar(*p); break;
X						}
X					}
X
X					putchar('\n');
X				}
X
X				fclose(in_fp);
X				break;
X
X			default:
X				fprintf(stderr, "Unknown option - %c\n", c);
X			case 'h':
X				fprintf(stderr, "Usage: %s [-h] [-l[nn]] file_list\n", argv[0]);
X
X				fprintf(stderr,
X	"The -h option prints this message.  The -l option sets the maximum\n"
X	"length that the program will output.  If no argument is given there\n"
X	"is no limit.  If an argument is given there should be no space between\n"
X	"the 'l' and the number.  The options can be placed anywhere in the\n"
X	"command line.\n");
X				break;
X
X/* Note - this is not strictly true.  If there is no argument to -l, it sets */
X/* the limit to the maximum buffer size.  However, if an input line is longer */
X/* than that it will fail anyway so the above description is close enough for */
X/* Rock and Roll. */
X		}
X	}
X
X    return(0);
X}
SHAR_EOF
chmod 0644 mkscript.c || echo "restore of mkscript.c fails"
if [ $TOUCH = can ]
then
    touch -am 0719005590 mkscript.c
fi
fi
# ============= Makefile ==============
if test -f Makefile; then echo "File Makefile exists"; else
echo "x - extracting Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X# Makefile for genfiles
X# Written by D'Arcy J.M. Cain
X#
X# Note:  You will probably have to modify this file for your own use.  Some
X# of the things you will have to consider:
X#    The CFLAGS variable is for GNU C.  Modify for your compiler.
X#    It is designed for a make that knows how to make both Unix and MSDOS
X#      executables.  (I have modified GNU Make to do this.)
X#    My programs are stored in /usr/lbin.  Modify BIN for your system.
X#
X# If you have a make that can't handle this file no matter what you do, you
X# can simply compile the two programs.  They are each single module programs.
X
XCFLAGS=-O -Wall -g
XALL_BINARIES = genfiles mkscript
XUNIX_BINARIES =	$(ALL_BINARIES)
XDOS_BINARIES = $(foreach i, $(ALL_BINARIES), $i.exe)
XSCRIPTS =
XDIST = genfiles.c mkscript.c $(SCRIPTS) Makefile
XBIN = /usr/lbin
XLBINS = $(foreach i, $(UNIX_BINARIES), $(BIN)/$i)
XLBINS1 = $(foreach i, $(UNIX_BINARIES) $(SCRIPTS), $(BIN)/$i)
X
Xall:	unix dos
X
Xunix:	$(UNIX_BINARIES)
X
Xdos:	$(DOS_BINARIES)
X
Xclean:
X	rm -f *.o *.obj core
X
Xclobber:	clean
X	rm -f $(UNIX_BINARIES) $(DOS_BINARIES) genfiles.gen genfiles.shar
X
X# I use the following after I have done a clean and I want to work on a
X# file without compiling everything.  It simply makes sure that the BIN
X# files are duplicated in the current directory.
Xlink:
X	ln $(LBINS) .
X
Xinstall:	unix
X	rm -f $(LBINS1)
X	chmod 711 $(UNIX_BINARIES)
X	ln $(UNIX_BINARIES) $(SCRIPTS) $(BIN)
X
Xdist:	script shar
X
Xscript:	genfiles.gen
X
Xgenfiles.gen:	mkscript $(DIST)
X	mkscript $(DIST) > genfiles.gen
X
Xshar:	genfiles.shar
X
Xgenfiles.shar:	$(DIST)
X	shar -vxf $(DIST) > genfiles.shar
SHAR_EOF
chmod 0644 Makefile || echo "restore of Makefile fails"
if [ $TOUCH = can ]
then
    touch -am 0719013790 Makefile
fi
fi
exit 0
-- 
D'Arcy J.M. Cain (darcy@druid)     |   Government:
D'Arcy Cain Consulting             |   Organized crime with an attitude
West Hill, Ontario, Canada         |
(416) 281-6094                     |