[net.sources] label: format labels for photocopy master sheets

perlman@wanginst.UUCP (Gary Perlman) (11/08/85)

Enclosed is a label making program.  It is really useful if
you want to do mass mailings, or for making sheets of all
the same label, like for products.  There is a simpe program
included to zipsort labels. 

It is designed to adapt to any format label copying sheet. 
I have found it best to get some photocopier labels sheets
from an office supply store and then tailer a shell script
to fit that label.  Two local shell scripts, big_label and
small_label are examples of this.  The shell scripts make it
pretty easy for secretarial staff to use the program,
otherwise, you have to explain UNIX options. 

Here is a quick example.  The defaults print 3 labels across
a sheet, each with six lines, the first of which is blank. 
Everything is programmable.  The options in the exampple
change the label width and the number of copies of each
label requested. 

label -w 25 -n 2 << 'EOF'
John Doe:123 Maple Lane:Anytown, USA
Jane Doe:1600 Penn. Ave.:Washington, DC
EOF
------------output

  John Doe                 John Doe                 Jane Doe
  123 Maple Lane           123 Maple Lane           1600 Penn. Ave.
  Anytown, USA             Anytown, USA             Washington, DC



  Jane Doe
  1600 Penn. Ave.
  Washington, DC


------------end of output

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	label.1
#	intro
#	zipsort.1
#	makefile
#	label.c
#	number.c
#	filter.c
#	big_label
#	small_label
#	zipsort.c
# This archive created: Thu Nov  7 18:38:24 1985
# By:	Gary Perlman (Wang Institute, Tyngsboro, MA 01879 USA)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'label.1'" '(2121 characters)'
if test -f 'label.1'
then
	echo shar: "will not over-write existing file 'label.1'"
else
sed 's/^	X//' << \SHAR_EOF > 'label.1'
	X.TH LABEL "1WI" "November 1985" "Wang Institute" "UNIX User's Manual"
	X.SH NAME
	Xlabel \- print label sheet
	X.SH USAGE
	X.I label
	X[-cU] [-d\ delim] [-h\ height] [-i\ indent] [-l\ count] [-n\ repeat]
	X.ti +.5i
	X[-s\ skip] [-w\ width] [-] [files]
	X.SH OPTIONS
	X.I label
	Xoptions adjust to different label page formats by
	Xcontrolling the number of labels across a page,
	Xthe label height and width, and so on..
	X.de OP\" option-letter [optional value]
	X.TP
	X.B -\\$1 \\$2
	X..
	X.OP c
	XCenter text on each line in the label.
	XThis option resets the label indent to 0.
	X.OP d delim
	XThe label line field delimiter (default: `:' the colon) tells
	X.I label
	Xhow to separate fields in a line.
	XThis character should not appear in the fields you want to print.
	XSeveral field delimiters in a row (blank fields) are skipped.
	XIf you really want a blank line inside a label, use a space.
	X.OP h height
	XThe height of a label (default: 6 lines).
	X.OP i indent
	XThe number of spaces to indent before each label (default: 2).
	X.OP l labels
	XThe number of labels to fit across a page (default: 3).
	X.OP n number
	XThe number of times to repeat each label (default: 1).
	X.OP s skip
	XThe number of lines to skip at the top of each label (default: 1).
	X.OP U
	XPrint a usage summary and exit.
	X.OP w width
	XThe label width in spaces (default 33).
	X.SH DESCRIPTION
	X.PP
	X.I label
	Xprints a series of labels in a matrix on a page
	Xthat is then suitable to use as a copy master for a page of stick on labels.
	XIf the labels are read in order: 1 2 3 4 5 6,
	Xand printed three across a page,
	Xthen the output is arranged like:
	X.nf
	X	1	2	3
	X	4	5	6
	X.fi
	X.SS Input
	X.I label
	Xreads non-blank lines that contain a series of delimited fields.
	XThe delimiter is a single character that separates the fields.
	XEach field is used as one line in a label.
	XExample labels:
	X.ce 2
	XGary Perlman:Wang Institute:Tyng Road:Tyngsboro, MA 01879
	XCopyright (c) 1985:Wang Institute:All Rights Reserved
	X.SS Output
	X.I label
	Xreads label lines until it has enough to print a row of labels.
	X.SH EXAMPLE
	X.nf
	XPrint six-high labels, four across, for 12 pitch print (100 wide):
	X	label  -h 6  -l 4  -w 25
	X.fi
	X.SH AUTHOR
	XGary Perlman
SHAR_EOF
if test 2121 -ne "`wc -c < 'label.1'`"
then
	echo shar: "error transmitting 'label.1'" '(should have been 2121 characters)'
fi
fi
echo shar: "extracting 'intro'" '(7110 characters)'
if test -f 'intro'
then
	echo shar: "will not over-write existing file 'intro'"
else
sed 's/^	X//' << \SHAR_EOF > 'intro'
	X                       Making Labels
	X                        Gary Perlman
	X
	XI am  pleased to  announce public  release of  my new  label
	Xprogram.  This program takes  label-lines and lays them  out
	Xfor transfer onto  label master  sheets.   Although hard  to
	Xbelieve, there  is a  lot  of technical  information  behind
	Xprinting labels, and this document will help you.
	X
	X                        Definitions
	X
	XLabel Master Sheets:  These are  8.5 X 11  inch sheets  with
	Xself-adhesive labels.  The sheets are designed for  jam-free
	Xphotocopy transfer  from printed  sheets.   There  are  many
	Xsizes of  label master  sheet  layouts.   Here at  the  Wang
	XInstitute, we have two:
	X
	X                Across Sheet           Top-to-Bottom
	X            #labels  #characters     #labels    #lines
	X    small      3         33             11        6
	X    big        2         50              5       12
	X
	XThe  number   of  available   characters  assumes   12-pitch
	Xprinting, or  100 characters  per  line.   This is  how  our
	XDiablo printer is  set up.   For  small labels,  there is  a
	Xcharacter not accounted for (3 labels times 33 characters is
	X99, not 100 characters).  This missing character is  cleaned
	Xup in a shell script, small_label, that sets all the options
	Xneeded for small-label master sheets.  For big labels, there
	Xare three lines at the top  of the page, and three lines  at
	Xthe bottom (5 labels  times 12 lines is  60, not 66  lines).
	XThese  extra  lines  are  cleaned  up  in  a  shell  script,
	Xbig_label, that sets  all the options  needed for  big-label
	Xmaster sheets.
	X
	XLabel Layout: A label  master sheet is  a matrix of  labels,
	Xwhile  a   set  of   label   description  lines   comes   in
	Xline-by-line.  The goal of  the label program is to  arrange
	Xthe labels so  that they  fit on  the labels  on the  master
	Xsheet.  For labels numbered 1  to 9 to fit on a  small-label
	Xmaster sheet, that means the labels should be arranged  like
	Xthis:
	X	1	2	3	
	X	4	5	6
	X	7	8	9
	X
	XLabel-Lines: The input to the  label program is a series  of
	Xlines, each with one label per line.  But because each label
	Xis several lines, a special character, the field  delimiter,
	Xmust be used  to separate  different lines  within a  label,
	Xcalled fields.  By default, this character is the colon (:),
	Xbut it can be changed to  another character if a colon  must
	Xappear in a label line.  An example label-line is:
	X
	X  G. Perlman:Wang Institute:Tyng Road:Tyngsboro, MA 01879
	X
	XThere are four fields  in this label.   Two copies of  this
	Xlabel, spanning this page width, would look like this:
	X
	X  G. Perlman                    G. Perlman
	X  Wang Institute                Wang Institute
	X  Tyng Road                     Tyng Road
	X  Tyngsboro, MA 01879           Tyngsboro, MA 01879
	X
	XNote that there is  a blank line at  the top of the  labels,
	Xand that each label is indented two spaces.
	X
	X                         Aesthetics
	X
	XAlthough small labels  have 6 lines  and 33 characters,  and
	Xbig labels  have 12  lines and  50 characters,  not all  the
	Xlabel is usable.  It is  common practice to leave the  first
	X(few) and last (few) lines of  a label clear, and to  indent
	Xthe text on labels at least  one or two spaces.  This  looks
	Xbetter, and it  makes the  alignment of text  on the  labels
	Xless critical.  The big_label and small_label shell  scripts
	Xassume that upper and left margins are wanted on all labels.
	X
	X                         Pragmatics
	X
	XTo make some labels, here is what you do, step by step.
	X
	XFirst, you must type  in your labels, one  per line, in  the
	Xformat described above.  Let's  assume your labels are in  a
	XUNIX file called "mylabels".
	X
	XSecond, you must decide what sort of labels you want, big or
	Xsmall.  For most  address labels, the  small labels are  too
	Xsmall, so the big ones should be used.  For labels like name
	Xtags, the small labels are okay.
	X
	XThird, you put  your labels through  the label program,  or,
	Xmore likely, through  one of the  convenient shell  scripts:
	Xsmall_label or big_label.   Let's  assume you  will use  the
	Xbig-label master sheets.  The call to big_label (that is  an
	Xunderscore between big and label) would look like this:
	X                     big_label mylabels
	X
	XBut that would  just print  the labels out  on your  screen,
	Xwhich is not very useful.   So you can save the output  from
	Xthe label program in  a file, which  we'll assume is  called
	X"mysheet":
	X                big_label mylabels > mysheet
	X
	XFourth, print the formatted label  sheet on a printer,  like
	Xthe Diablo printer.   The printer should be  set up so  that
	Xprinting will start in the extreme upper left hand corner of
	Xthe page.  The print command would look like this:
	X                    lpr -Pdiablo mysheet
	X
	XNote that the steps to make the labels and print them can be
	Xcombined using UNIX  pipes.  This  also avoids creating  the
	Xfile "mysheet" which serves no useful purpose.  The combined
	Xcommand would be:
	X             big_label mylabels | lpr -Pdiablo
	X
	XFifth, take the printed label  sheet and transfer it onto  a
	Xsheet of self-adhesive labels.  These  can be hand fed in  a
	Xphotocopy machine, or stacked into the paper feed bin.   The
	Xsheets are specially made  to not jam  up the copy  machine.
	XBecause the Diablo printer often has alignment problems, the
	Xprinted sheet may have to be adjusted a bit to match up with
	Xthe self-adhesive label master sheet.
	X
	X                           Frills
	X
	XThe label program  has several  options, many  of which  are
	Xused in the  shell scripts  big_label and  small_label.   In
	Xthis section, I will  discuss the options  you may are  most
	Xlikely to use.  All these options can be used with the shell
	Xscripts, or with the label  program directly.  First,  there
	Xis a -U option,  that will give you  a usage summary of  the
	Xprogram (with the current options) so that:
	X                       small_label -U
	Xwill print:
	X	label: format label sheet
	X	-c      center fields on each label line
	X	-d C    field delimiter character (:)
	X	-h N    height in lines of labels (6 lines)
	X	-i N    indent before each label (2 spaces)
	X	-l N    number of label across page (3)
	X	-n N    repeat each label N times (1 times)
	X	-s N    skip lines at label top (1 lines)
	X	-U      print this usage message
	X	-w N    label width (33 spaces)
	X
	XThe center option (-c)  will center all  the fields on  each
	Xline of the printed labels.  This is pretty on labels  other
	Xthan address labels.  The  -n option tells label the  number
	Xof times to print each label.  By default, label prints  one
	Xcopy, but sometimes more  than one is  wanted, such as  when
	Xyou want to  fill a sheet  with one label  to have a  stock.
	XHere is an example using the -c and the -n options:
	X
	X               small_label -c -n 33 copyright
	X
	Xwhere the file "copyright" contains one label:
	X
	X   Copyright (c) 1985:Wang Institute:All Rights Reserved
	X
	XA two-column two copy version of this label to fit this page
	Xwould look like this:
	X                  label -l 2 -w 30 -c -n 2
	X
	X       Copyright (c) 1985            Copyright (c) 1985
	X         Wang Institute                Wang Institute
	X      All Rights Reserved           All Rights Reserved
SHAR_EOF
if test 7110 -ne "`wc -c < 'intro'`"
then
	echo shar: "error transmitting 'intro'" '(should have been 7110 characters)'
fi
fi
echo shar: "extracting 'zipsort.1'" '(538 characters)'
if test -f 'zipsort.1'
then
	echo shar: "will not over-write existing file 'zipsort.1'"
else
sed 's/^	X//' << \SHAR_EOF > 'zipsort.1'
	X.TH ZIPSORT "1WI" "November 1985" "Wang Institute" "UNIX User's Manual"
	X.SH NAME
	Xzipsort \- sort lines by zipcode
	X.SH USAGE
	X.I zipsort
	X[-] [files]
	X.SH DESCRIPTION
	X.I zipsort
	Xreads a series of lines from the named files or the standard input
	Xand sorts them by zipcode (a five long series of digits).
	XIf there are more than one number on a line that looks like
	Xa zipcode, the last is used.
	X.SH "SEE ALSO"
	Xlabel(1W)
	X.SH AUTHOR(S)
	XGary Perlman
	X.SH WARNING
	X.I zipsort
	Xassumes that the
	X.I sort
	Xand
	X.I sed
	Xutilities are available on the system.
SHAR_EOF
if test 538 -ne "`wc -c < 'zipsort.1'`"
then
	echo shar: "error transmitting 'zipsort.1'" '(should have been 538 characters)'
fi
fi
echo shar: "extracting 'makefile'" '(768 characters)'
if test -f 'makefile'
then
	echo shar: "will not over-write existing file 'makefile'"
else
sed 's/^	X//' << \SHAR_EOF > 'makefile'
	XMAIN=label
	XHDRS=
	XSRCS=number.c filter.c
	XOBJS=number.o filter.o
	XDOCS=label.1 intro zipsort.1
	XLIBS=
	XDESTDIR=.
	XCFLAGS=-O
	XTEXT=$(HDRS) $(MAIN).c $(SRCS)
	X
	XLINT  =/usr/bin/lint -hp
	XPR    =@cpr
	XSPELL =sp
	XSHAR  =shar -a
	XRCS   =ci -l
	XCC    =/bin/cc
	X
	X$(MAIN): $(MAIN).o $(OBJS)
	X	$(CC) $(CFLAGS) -o $(MAIN) $(MAIN).o $(OBJS)
	X
	Xzipsort: zipsort.o
	X	$(CC) *(CFLAGS) -o zipsort zipsort.o
	X
	Xinstall: $(MAIN) zipsort
	X	cp -i $(MAIN) zipsort $(DESTDIR)/$(MAIN)
	X
	Xprint:
	X	$(PR) $(MAIN).c
	X
	Xlint:
	X	$(LINT) $(TEXT)
	X
	Xspell:
	X	seec -cqe $(TEXT) | $(SPELL)
	X
	Xarchive:
	X	$(SHAR) $(DOCS) [Mm]akefile $(TEXT) *_label zipsort.c > archive
	X
	Xclean:
	X	rm -f *.o core a.out mon.out gmon.out scmon.out
	X
	X$(MAIN).1: $(MAIN).c
	X	@seec -t MANUAL $(MAIN).c > $(MAIN).1
	X
	X.PRECIOUS: $(TEXT) $(DOCS) zipsort.c zipsort.1
SHAR_EOF
if test 768 -ne "`wc -c < 'makefile'`"
then
	echo shar: "error transmitting 'makefile'" '(should have been 768 characters)'
fi
fi
echo shar: "extracting 'label.c'" '(9423 characters)'
if test -f 'label.c'
then
	echo shar: "will not over-write existing file 'label.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'label.c'
	X/*MANUAL.TH LABEL "1WI" "November 1985" "Wang Institute" "UNIX User's Manual"
	X*/
	X
	X/*MANUAL.SH NAME
	Xlabel \- print label sheet
	X*/
	X
	X/*MANUAL.SH USAGE
	X.I label
	X[-cU] [-d\ delim] [-h\ height] [-i\ indent] [-l\ count] [-n\ repeat]
	X.ti +.5i
	X[-s\ skip] [-w\ width] [-] [files]
	X*/
	X
	X#include <stdio.h>
	X#include <ctype.h>
	X
	X#define	MAXFIELDS    30        /* max number of labels across */
	X
	Xtypedef	int       Status;      /* return/exit status of functions */
	X#define	SUCCESS   ((Status) 0)
	X#define	FAILURE   ((Status) 1)
	Xtypedef	int       Boole;       /* no Boolean type in C */
	X#define	TRUE      ((Boole) 1)
	X#define	FALSE     ((Boole) 0)
	X#define	EOS       '\0'
	X
	Xchar	*Argv0;            /* program name */
	Xchar	*File;             /* current file name */
	Xint 	Labelcount;        /* current label number in File */
	Xint 	Linecount;         /* current line number in File */
	X
	X/*MANUAL.SH OPTIONS
	X.I label
	Xoptions adjust to different label page formats by
	Xcontrolling the number of labels across a page,
	Xthe label height and width, and so on..
	X.de OP\" option-letter [optional value]
	X.TP
	X.B -\\$1 \\$2
	X..
	X*/
	X
	XBoole	Center = FALSE;    /*MANUAL.OP c
	XCenter text on each line in the label.
	XThis option resets the label indent to 0.
	X*/
	X
	Xchar	Delim = ':';       /*MANUAL.OP d delim
	XThe label line field delimiter (default: `:' the colon) tells
	X.I label
	Xhow to separate fields in a line.
	XThis character should not appear in the fields you want to print.
	XSeveral field delimiters in a row (blank fields) are skipped.
	XIf you really want a blank line inside a label, use a space.
	X*/
	X
	Xint 	Realheight;        /* Labheight - Labskip */
	Xint 	Labheight = 6;     /*MANUAL.OP h height
	XThe height of a label (default: 6 lines).
	X*/
	X
	Xint 	Labindent = 2;     /*MANUAL.OP i indent
	XThe number of spaces to indent before each label (default: 2).
	X*/
	X
	Xint 	Nlabels = 3;       /*MANUAL.OP l labels
	XThe number of labels to fit across a page (default: 3).
	X*/
	X
	Xint 	Repeat = 1;        /*MANUAL.OP n number
	XThe number of times to repeat each label (default: 1).
	X*/
	X
	Xint 	Labskip = 1;       /*MANUAL.OP s skip
	XThe number of lines to skip at the top of each label (default: 1).
	X*/
	X
	X/*MANUAL.OP U
	XPrint a usage summary and exit.
	X*/
	X
	Xint 	Realwidth;         /* usable width of label (Labwidth - Labindent) */
	Xint 	Labwidth = 33;     /*MANUAL.OP w width
	XThe label width in spaces (default 33).
	X*/
	X
	X/*FUNCTION printusage: on-line help */
	Xvoid
	Xprintusage ()
	X	{
	X	fprintf (stderr, "%s: format label sheet\n", Argv0);
	X	fprintf (stderr, "-c	center fields on each label line\n");
	X	fprintf (stderr, "-d C	field delimiter character (%c)\n", Delim);
	X	fprintf (stderr, "-h N	height in lines of labels (%d lines)\n", Labheight);
	X	fprintf (stderr, "-i N	indent before each label (%d spaces)\n", Labindent);
	X	fprintf (stderr, "-l N	number of label across page (%d)\n", Nlabels);
	X	fprintf (stderr, "-n N	repeat each label N times (%d times)\n", Repeat);
	X	fprintf (stderr, "-s N	skip lines at label top (%d lines)\n", Labskip);
	X	fprintf (stderr, "-U	print this usage message\n");
	X	fprintf (stderr, "-v	verbose information printed\n");
	X	fprintf (stderr, "-w N	label width (%d spaces)\n", Labwidth);
	X	}
	X
	X/*FUNCTION getint: set integer, checking type and range */
	XStatus
	Xgetint (flag, string, varptr, min, max)
	Xint 	flag;
	Xchar	*string;
	Xint 	*varptr;
	Xint 	min;
	Xint 	max;
	X	{
	X	int 	retval = FAILURE;
	X	if (number (string) == 1) /* an integer */
	X		{
	X		int 	value = atoi (string);
	X		if (value >= min && value <= max)
	X			{
	X			*varptr = value;
	X			retval = SUCCESS;
	X			}
	X		else
	X			{
	X			fprintf (stderr, "\007%s: -%c value (%s) must be between %d and %d\n",
	X				Argv0, flag, string, min, max);
	X			}
	X		}
	X	else
	X		fprintf (stderr, "\007%s: -%c value (%s) must be an integer\n",
	X			Argv0, flag, string);
	X	return (retval);
	X	}
	X
	Xvoid
	Xnputchar (c, n)
	X	{
	X	while (n-- > 0)
	X		putchar (c);
	X	}
	X
	X/*FUNCTION initial: returns local version of optind, index to first operand */
	Xint
	Xinitial (argc, argv) char **argv;
	X	{
	X	extern	char *optarg;    /* option value accessed through this by getopt */
	X	extern	int  optind;     /* will be index to first operand */
	X	int 	opterr = 0;      /* count of number of errors */
	X	int 	flag;            /* option flag characters read in here */
	X	char	*optstring =     /* getopt string */
	X		"cd:h:i:l:n:s:Uw:";
	X	char	*usage =         /* variable part of usage summary */
	X		"[-cU] [-d delim] [-h height] [-i indent] [-l count] [-n repeat]\n\t[-s skip] [-w width] [-] [files]";
	X
	X	Argv0 = argv[0];
	X
	X	while ((flag = getopt (argc, argv, optstring)) != EOF)
	X		switch (flag) /* put option cases here */
	X			{
	X			default:
	X				opterr++;
	X				break;
	X			case 'U':
	X				printusage ();
	X				exit (0);
	X			case 'c':
	X				Center = TRUE;
	X				Labindent = 0;
	X				break;
	X			case 'd':
	X				Delim = *optarg;
	X				break;
	X			case 'h':
	X				if (getint (flag, optarg, &Labheight, 0, 100) == FAILURE)
	X					opterr++;
	X				break;
	X			case 'i':
	X				if (getint (flag, optarg, &Labindent, 0, 100) == FAILURE)
	X					opterr++;
	X				break;
	X			case 'l':
	X				if (getint (flag, optarg, &Nlabels, 1, MAXFIELDS) == FAILURE)
	X					opterr++;
	X				break;
	X			case 'n':
	X				if (getint (flag, optarg, &Repeat, 1, 100) == FAILURE)
	X					opterr++;
	X				break;
	X			case 's':
	X				if (getint (flag, optarg, &Labskip, 0, 100) == FAILURE)
	X					opterr++;
	X				break;
	X			case 'w':
	X				if (getint (flag, optarg, &Labwidth, 10, 150) == FAILURE)
	X					opterr++;
	X				break;
	X			}
	X
	X	if (opterr)
	X		{
	X		fprintf (stderr, "\007Usage: %s %s\n", argv[0], usage);
	X		exit (1);
	X		}
	X
	X	Realwidth = Labwidth - Labindent;
	X	Realheight = Labheight - Labskip;
	X
	X	return (optind);
	X	}
	X
	X/*FUNCTION main: loop through files in classic UNIX filter style */
	Xvoid
	Xmain (argc, argv)
	Xint 	argc;     /* argument count */
	Xchar	**argv;   /* argument vector */
	X	{
	X	Status 	label ();   /* label (file, ioptr) will filter files */
	X	Status	status;     /* return status of filter () */
	X	int 	firstfile;  /* first file name index returned by initial */
	X	firstfile = initial (argc, argv);
	X	status = filter (argc, argv, firstfile, label);
	X	exit (status);
	X	}
	X
	X/*FUNCTION geline: get non-blank input line and duplicate as needed */
	Xchar *
	Xgetline (line, size, ioptr)
	Xchar	*line;
	XFILE	*ioptr;
	X	{
	X	static	char	buf[BUFSIZ];
	X	static	int 	nrepeat = 0;
	X	char	*ptr = buf;
	X
	X	if (nrepeat == 0)
	X		{
	X		do
	X			{
	X			if (fgets (ptr = buf, size, ioptr) == NULL)
	X				return (NULL);
	X			Linecount++;
	X			while (isspace (*ptr))
	X				ptr++;
	X		} while (*ptr == '\0');
	X		Labelcount++;
	X		checklabel (buf);
	X		}
	X	strncpy (line, buf, size);
	X	if (++nrepeat == Repeat)
	X		nrepeat = 0;
	X	return (line);
	X	}
	X
	X/*FUNCTION fieldprint: print a field in a label */
	Xchar *
	Xfieldprint (lptr)
	Xchar	*lptr;
	X	{
	X	char	*eptr = lptr;
	X	int 	len;           /* field length */
	X	int 	pad;           /* pad needed for field */
	X
	X	while (*eptr && *eptr != Delim && *eptr != '\n') eptr++;
	X	while (*eptr == Delim)
	X		*eptr++ = EOS;
	X	if (*eptr == '\n')
	X		*eptr = EOS;
	X
	X	nputchar (' ', Labindent);
	X	len = strlen (lptr);
	X	if (len > Realwidth)
	X		{
	X		lptr[Realwidth] = '\0';
	X		pad = 0;
	X		}
	X	else
	X		pad = Realwidth - len;
	X
	X	if (Center)
	X		{
	X		nputchar (' ', pad / 2);
	X		pad -= pad / 2;
	X		}
	X	printf (lptr);
	X	nputchar (' ', pad);
	X
	X	return (eptr);
	X	}
	X
	X/*MANUAL.SH DESCRIPTION
	X.PP
	X.I label
	Xprints a series of labels in a matrix on a page
	Xthat is then suitable to use as a copy master for a page of stick on labels.
	XIf the labels are read in order: 1 2 3 4 5 6,
	Xand printed three across a page,
	Xthen the output is arranged like:
	X.nf
	X	1	2	3
	X	4	5	6
	X.fi
	X.SS Input
	X.I label
	Xreads non-blank lines that contain a series of delimited fields.
	XThe delimiter is a single character that separates the fields.
	XEach field is used as one line in a label.
	XExample labels:
	X.ce 2
	XGary Perlman:Wang Institute:Tyng Road:Tyngsboro, MA 01879
	XCopyright (c) 1985:Wang Institute:All Rights Reserved
	X.SS Output
	X.I label
	Xreads label lines until it has enough to print a row of labels.
	X*/
	X
	X/*MANUAL.SH EXAMPLE
	X.nf
	XPrint six-high labels, four across, for 12 pitch print (100 wide):
	X	label  -h 6  -l 4  -w 25
	X.fi
	X*/
	X
	X/*MANUAL.SH AUTHOR
	XGary Perlman
	X*/
	X
	X/*FUNCTION checklabel: print warnings about problems with label */
	Xchecklabel (line)
	Xchar	*line;
	X	{
	X	char	*ptr;
	X	int 	nfields = 0;        /* number of fields in label */
	X	Boole	truncate = FALSE;   /* are fields truncated? */
	X
	X	for (;;)
	X		{
	X		for (ptr = line; *ptr && *ptr != '\n' && *ptr != Delim; ptr++);
	X		if (ptr - line > Realwidth)
	X			truncate = TRUE;
	X		while (*ptr == Delim)
	X			ptr++;
	X		nfields++;
	X		if (*ptr == EOS || *ptr == '\n')
	X			break;
	X		line = ptr;
	X		}
	X
	X	if (nfields > Realheight)
	X		fprintf (stderr, "\007%s: Field ignored in label %d on line %d in %s\n",
	X			Argv0, Labelcount, Linecount, File);
	X
	X	if (truncate == TRUE)
	X		fprintf (stderr, "\007%s: Field truncated in label %d on line %d in %s\n",
	X			Argv0, Labelcount, Linecount, File);
	X	}
	X
	X/*FUNCTION label: main routine */
	XStatus
	Xlabel (file, ioptr)
	Xchar	*file;
	XFILE	*ioptr;
	X	{
	X	char	labbuf[MAXFIELDS][BUFSIZ], *lptr[MAXFIELDS];
	X	int 	line, col;
	X
	X	File = file;
	X	Labelcount = 0;
	X
	X	for (;;)
	X		{
	X		for (col = 0; col < Nlabels; col++)
	X			{
	X			if (getline (labbuf[col], BUFSIZ, ioptr) == NULL)
	X				if (col == 0) /* no labels read in, just quit */
	X					return (SUCCESS);
	X				else /* at least one label read in, use blanks to pad */
	X					labbuf[col][0] = EOS;
	X			lptr[col] = labbuf[col];
	X			}
	X		nputchar ('\n', Labskip);
	X		for (line = 0; line < Labheight-Labskip; line++)
	X			{
	X			for (col = 0; col < Nlabels; col++)
	X				lptr[col] = fieldprint (lptr[col]);
	X			putchar ('\n');
	X			}
	X		}
	X	}
SHAR_EOF
if test 9423 -ne "`wc -c < 'label.c'`"
then
	echo shar: "error transmitting 'label.c'" '(should have been 9423 characters)'
fi
fi
echo shar: "extracting 'number.c'" '(4039 characters)'
if test -f 'number.c'
then
	echo shar: "will not over-write existing file 'number.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'number.c'
	X/* Copyright (c) 1982, 1985 Gary Perlman */
	X/* Copies can be made if not for material gain */
	X
	X/*
	X	number: report if a string is a UNIX formatted number
	X
	X	notes:
	X		a number in UNIX is one that can be converted from
	X		a string to an integer or real with no loss of information
	X			due to bad format
	X		all numbers can be surrounded by whitespace
	X		an integer has an optional minus sign, followed by digits
	X		a real number has an optional minus sign followed by digits
	X		if a string has a decimal point, followed by zeros, it is real, not int
	X
	X	value:
	X		1 is string is an integer [-] 0-9+
	X		2 is string is a real number (as seen by atof)
	X		0 for non-numbers
	X
	X	compilation flags:
	X		-DSTANDALONE	includes test main program
	X		$Compile: cc -DSTANDALONE -O -o %F %f
	X	
	X	deficiencies:
	X		does not check to see if significant digits will be ignored
	X	
	X	author:
	X		Gary Perlman
	X
	X	date:
	X		Wed May 22 13:30:40 EDT 1985
	X		Sun Sep  1 14:53:51 EDT 1985 (modified test module)
	X		
	X*/
	X#include <ctype.h>
	X
	X#ifndef lint
	Xstatic char sccsfid[] = "@(#) number.c 5.2 (unix|stat) 9/1/85";
	X#endif
	X
	X#define	IS_NOT      0            /* not a number */
	X#define	IS_INT      1            /* an integer */
	X#define	IS_REAL     2            /* a real number */
	X
	X#define	EOS         '\0'
	X
	X/*LINTLIBRARY*/
	X
	Xnumber (string)
	Xchar	*string;                 /* the string to be tested */
	X	{
	X	int 	answer = IS_INT;     /* start by assuming it is an integer */
	X	int 	before = 0;          /* anything before the decimal? */
	X	int 	after = 0;           /* anything after the decimal? */
	X	while (isspace (*string))    /* skip over blank space */
	X		string++;
	X	if (*string == EOS)          /* empty string not allowed */
	X		return (IS_NOT);
	X	if (*string == '+' || *string == '-') /* old atoi didn't allow '+' */
	X		{
	X		string++;
	X		if (!isdigit (*string) && *string != '.')
	X			return (IS_NOT);
	X		}
	X	if (isdigit (*string))       /* note that there was a digit before . */
	X		{
	X		before = 1;
	X		while (isdigit (*string))
	X			string++;
	X		}
	X	if (*string == '.')          /* found a decimal point, parse for real */
	X		{
	X		answer = IS_REAL;
	X		string++;
	X		if (isdigit (*string))   /* note that there was a digit after . */
	X			{
	X			after = 1;
	X			while (isdigit (*string))
	X				string++;
	X			}
	X		}
	X	if (!before && !after)       /* must be digit somewhere */
	X		return (IS_NOT);
	X	if (*string == 'E' || *string == 'e') /* exponent */
	X		{
	X		answer = IS_REAL;
	X		string++;
	X		if (*string == '+' || *string == '-') /* optional sign */
	X			string++;
	X		if (!isdigit (*string))  /* missing exponent */
	X			return (IS_NOT);
	X		while (isdigit (*string))
	X			string++;
	X		}
	X	while (isspace (*string))    /* skip optional spaces */
	X		string++;
	X	/* should now have exhausted the input string */
	X	return (*string == EOS ? answer : IS_NOT);
	X	}
	X
	X#ifdef STANDALONE
	X
	X#include <stdio.h>
	X/*
	X	exits with status = the number of args not numerical
	X	Shell Example:
	X		if number -i $*
	X		then
	X			echo processing $*
	X		else
	X			echo $0: arguments must be integers 
	X		fi
	X	Options:
	X		-i  arguments must be integer
	X		-n  arguments must be non-negative
	X*/
	Xint 	NoNegative;   /* do the values have to be non-negative? */
	Xint 	Integer;      /* do the values have to be integers? */
	X
	Xstatic
	Xint
	Xinitial (argc, argv) char **argv;
	X	{
	X	extern	char	*optarg;
	X	extern	int 	optind;
	X	int 	errflg = 0;
	X	int 	C;
	X	char	*optstring = "in";
	X	char	*usage = "[-in] string ...";
	X	while ((C = getopt (argc, argv, optstring)) != EOF)
	X		switch (C)
	X			{
	X			case 'i': Integer = 1; break;
	X			case 'n': NoNegative = 1; break;
	X			default: errflg++; break;
	X			}
	X	if (errflg)
	X		{
	X		fprintf (stderr, "Usage: %s %s\n", argv[0], usage);
	X		exit (1);
	X		}
	X	return (optind);
	X	}
	X
	Xmain (argc, argv) char **argv;
	X	{
	X	int 	status = 0;
	X	int 	arg = initial (argc, argv);
	X	char	*string;
	X	while (arg < argc)
	X		{
	X		string = argv[arg++];
	X		if (NoNegative && *string == '-') status++;
	X		else switch (number (string))
	X			{
	X			case IS_NOT:  status++; break;
	X			case IS_REAL: if (Integer) status++; break;
	X			case IS_INT:  break;
	X			default: /* CAN'T HAPPEN */ break;
	X			}
	X		}
	X	exit (status);
	X	}
	X
	X#endif
SHAR_EOF
if test 4039 -ne "`wc -c < 'number.c'`"
then
	echo shar: "error transmitting 'number.c'" '(should have been 4039 characters)'
fi
fi
echo shar: "extracting 'filter.c'" '(4306 characters)'
if test -f 'filter.c'
then
	echo shar: "will not over-write existing file 'filter.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'filter.c'
	X/*
	X	Function:    filter "Filter Command Line Files In Classic UNIX Style"
	X	Created:     Sat Aug 10 21:57:12 EDT 1985
	X	By:          Gary Perlman (Wang Institute, Tyngsboro, MA 01879 USA)
	X	Compilation: nothing unusual
	X	Tester:      $Compile: cc -DSTANDALONE -o filter %f
	X	Preconditions:
	X		The index of the first file operand has been determined.
	X	Postconditions:
	X		All files have been opened, processed, and closed.
	X	Returns:
	X		The return status (non-zero is bad) depends on the accessibility
	X		of files, the ability to open them, and the return statuses of
	X		the called function.
	X	Exceptions:
	X		If any file cannot be accessed, then none will be processed.
	X		During processing, if something goes wrong (a file that could
	X		be accessed cannot be opened, or the file processor returns a
	X		non-zero status), processing continues.
	X	Notes:
	X		"-" is the conventional name for the standard input.
	X			It can only be read once.
	X		Fputs and putc are used to print error messages to avoid
	X			loading fat fprintf just because filter used it.
	X*/
	X
	X
	X#include <stdio.h>
	X
	X#ifdef STANDALONE
	X
	Xint
	Xcat (file, ioptr)
	Xchar	*file;
	Xregister	FILE	*ioptr;
	X	{
	X	register	int 	C;
	X	while ((C = getc (ioptr)) != EOF)
	X		putchar (C);
	X	return (0);
	X	}
	X
	Xmain (argc, argv) char **argv;
	X	{
	X	int 	cat ();
	X
	X	if (filter (argc, argv, 1, cat))
	X		{
	X		putc ('\007', stderr); /* UNIX friendly error message */
	X		exit (1);
	X		}
	X	exit (0);
	X	}
	X
	X#endif STANDALONE
	X
	X
	X/* LINTLIBRARY */
	Xstatic
	Xvoid
	Xerrmsg (pgm, file, errorno, dflt)
	Xchar	*pgm;       /* name of the program running */
	Xchar	*file;      /* file operand to be mentioned (if any) */
	Xint 	errorno;    /* system errno or some bad value */
	Xchar	*dflt;      /* default message for bad error numbers */
	X	{
	X	extern	char *sys_errlist[];  /* list of error messages */
	X	extern	int sys_nerr;         /* number of error messages */
	X
	X	fputs (pgm, stderr);
	X	putc (':', stderr);
	X	putc (' ', stderr);
	X	if (errorno > 0 && errorno < sys_nerr)
	X		fputs (sys_errlist[errorno], stderr);
	X	else
	X		fputs (dflt, stderr);
	X	if (file)
	X		{
	X		putc (' ', stderr);
	X		putc ('\'', stderr);
	X		fputs (file, stderr);
	X		putc ('\'', stderr);
	X		}
	X	putc ('\n', stderr);
	X	}
	X
	X
	X#define	isstdin(file) (file[0] == '-' && file[1] == '\0')
	X
	Xint
	Xfilter (argc, argv, curarg, process)
	Xint 	argc;          /* real number of command line args */
	Xchar	**argv;        /* command line argument pointer */
	Xint 	curarg;        /* first argv to filter */
	Xint 	(*process) (); /* status process (char *name, FILE *ioptr) */
	X	{
	X	int 	status = 0;         /* return status of this function */
	X	int 	arg;                /* loop index variable */
	X	char	*file;              /* name of the current file */
	X	char	*pgm = argv[0];     /* name of the program */
	X	FILE	*ioptr;             /* file pointer for opening */
	X	int 	countstdin = 0;     /* number of times stdin is processed */
	X	extern	int errno;          /* system error number */
	X
	X	if (curarg == argc)
	X		status += ((*process) ("-", stdin));
	X	else
	X		{
	X		/* first check to make sure all files can be opened to read */
	X		for (arg = curarg; arg < argc; arg++)
	X			{
	X			file = argv[arg];
	X			if (isstdin (file))
	X				countstdin++;
	X			else if (access (file, 4))
	X				{
	X				errmsg (pgm, file, errno, "Can't access file");
	X				status++;
	X				}
	X			}
	X		if (countstdin > 1)
	X			{
	X			errmsg (pgm, NULL, -1, "Can only read standard input once");
	X			status++;
	X			}
	X		if (status == 0)
	X			for (arg = curarg; arg < argc; arg++)
	X				{
	X				file = argv[arg];
	X				if (isstdin (file))
	X					status += ((*process) (file, stdin) != 0);
	X				else if (ioptr = fopen (file, "r"))
	X					{
	X					status += ((*process) (file, ioptr) != 0);
	X					(void) fclose (ioptr);
	X					}
	X				else
	X					{
	X					errmsg (pgm, file, errno, "Can't open file");
	X					status++;
	X					}
	X				}
	X		}
	X	return (status);
	X	}
	X
	X/*NOTES
	X	Some modifications might be useful but unpopular:
	X		If there is piped input (!isatty (fileno (stdin))),
	X		and the standard input is not read,
	X		then some information may be ignored,
	X		so a warning should be printed.
	X		Unfortunately, this would break things like vi filters.
	X
	X		If there is not piped input,
	X		and the standard input is being read from the keyboard,
	X		then prompt the user for input with something like:
	X			pgm: reading input from terminal
	X		This would avoid the problem of people forgetting to supply
	X		an input redirection.
	X*/
SHAR_EOF
if test 4306 -ne "`wc -c < 'filter.c'`"
then
	echo shar: "error transmitting 'filter.c'" '(should have been 4306 characters)'
fi
fi
echo shar: "extracting 'big_label'" '(294 characters)'
if test -f 'big_label'
then
	echo shar: "will not over-write existing file 'big_label'"
else
sed 's/^	X//' << \SHAR_EOF > 'big_label'
	X#!/bin/sh
	X
	XPATH=$PATH:/usr/ebin
	Xexport PATH
	X
	X# make label pages for big labels 4.25 (50 spaces) x 2 (12 lines) inches
	X
	Xlabel -h 12 -s 2 -l 2 -w 50 -i 3 $* |
	X	ff -b -h "" -f "" -H 3 -F 3 |        # put on a three line header/footer
	X	sed "s/ *$//"                        # remove trailing spaces
SHAR_EOF
if test 294 -ne "`wc -c < 'big_label'`"
then
	echo shar: "error transmitting 'big_label'" '(should have been 294 characters)'
fi
chmod +x 'big_label'
fi
echo shar: "extracting 'small_label'" '(343 characters)'
if test -f 'small_label'
then
	echo shar: "will not over-write existing file 'small_label'"
else
sed 's/^	X//' << \SHAR_EOF > 'small_label'
	X#!/bin/sh
	X
	XPATH=$PATH:/usr/ebin
	Xexport PATH
	X
	X# make label pages for small labels 2.75 (33 spaces) x 1 (6 lines) inch
	X
	Xlabel -h 6 -l 3 -w 33 -i 2 $* |
	X	ff -b -i 1 |                         # indent the lines one space
	X	sed "s/ *$//"                        # remove trailing spaces
	X
	X# you could use 
	X#	sed "s/^/ /" instead of the faster ff call
SHAR_EOF
if test 343 -ne "`wc -c < 'small_label'`"
then
	echo shar: "error transmitting 'small_label'" '(should have been 343 characters)'
fi
chmod +x 'small_label'
fi
echo shar: "extracting 'zipsort.c'" '(3999 characters)'
if test -f 'zipsort.c'
then
	echo shar: "will not over-write existing file 'zipsort.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'zipsort.c'
	X/*
	X	$Compile: cc -O -o %F %f
	X*/
	X#include <stdio.h>
	X#include <ctype.h>
	X#include <strings.h>
	X
	Xint 	Special = '\001';   /* magic char after sorting key */
	X
	Xtypedef	int       Status;      /* return/exit status of functions */
	X#define	SUCCESS   ((Status) 0)
	X#define	FAILURE   ((Status) 1)
	Xtypedef	int       Boole;       /* no Boolean type in C */
	X#define	TRUE      ((Boole) 1)
	X#define	FALSE     ((Boole) 0)
	X
	XFILE	*Pioptr;   /* will pipe to sort and sed */
	X
	X/*FUNCTION main: loop through files in classic UNIX filter style */
	Xmain (argc, argv)
	Xint 	argc;     /* argument count */
	Xchar	**argv;   /* argument vector */
	X	{
	X	Status 	process (); /* process (file, ioptr) will filter files */
	X	Status	status;     /* return status of filter () */
	X	int 	firstfile;  /* first file name index returned by initial */
	X	FILE	*popen ();
	X	char	command[BUFSIZ];
	X
	X	firstfile = 1;
	X
	X	sprintf (command, "sort | sed 's/^.*%c//'", Special);
	X
	X	if (Pioptr = popen (command, "w"))
	X		{
	X		status = filter (argc, argv, firstfile, process);
	X		pclose (Pioptr);
	X		}
	X	else
	X		{
	X		fprintf (stderr, "%s: Can't run sorting pipeline\n", argv[0]);
	X		status = (-1);
	X		}
	X	exit (status);
	X	}
	X
	X#define	iszipcode(s) \
	X	(!isdigit (s[-1]) \
	X	&& isdigit (s[0]) \
	X	&& isdigit (s[1]) \
	X	&& isdigit (s[2]) \
	X	&& isdigit (s[3]) \
	X	&& isdigit (s[4]) \
	X	&& !isdigit (s[5]))
	X
	Xprocess (file, ioptr)
	Xchar	*file;
	XFILE	*ioptr;
	X	{
	X	char	line[BUFSIZ];
	X	char	*ptr;
	X	int 	zipcode;
	X
	X	while (fgets (ptr = line, BUFSIZ, ioptr))
	X		{
	X		zipcode = 0;
	X		for (ptr = line; *ptr; ptr++);
	X		while (ptr > line)
	X			if (iszipcode (ptr))
	X				{
	X				zipcode = atoi (ptr);
	X				break;
	X				}
	X			else ptr--;
	X		fprintf (Pioptr, "%05d%c%s", zipcode, Special, line);
	X		}
	X	}
	X
	Xstatic
	Xvoid
	Xerrmsg (pgm, file, errorno, dflt)
	Xchar	*pgm;       /* name of the program running */
	Xchar	*file;      /* file operand to be mentioned (if any) */
	Xint 	errorno;    /* system errno or some bad value */
	Xchar	*dflt;      /* default message for bad error numbers */
	X	{
	X	extern	char *sys_errlist[];  /* list of error messages */
	X	extern	int sys_nerr;         /* number of error messages */
	X
	X	fputs (pgm, stderr);
	X	putc (':', stderr);
	X	putc (' ', stderr);
	X	if (errorno > 0 && errorno < sys_nerr)
	X		fputs (sys_errlist[errorno], stderr);
	X	else
	X		fputs (dflt, stderr);
	X	if (file)
	X		{
	X		putc (' ', stderr);
	X		putc ('\'', stderr);
	X		fputs (file, stderr);
	X		putc ('\'', stderr);
	X		}
	X	putc ('\n', stderr);
	X	}
	X
	X#define	isstdin(file) (file[0] == '-' && file[1] == '\0')
	X
	Xint
	Xfilter (argc, argv, curarg, process)
	Xint 	argc;          /* real number of command line args */
	Xchar	**argv;        /* command line argument pointer */
	Xint 	curarg;        /* first argv to filter */
	Xint 	(*process) (); /* status process (char *name, FILE *ioptr) */
	X	{
	X	int 	status = 0;         /* return status of this function */
	X	int 	arg;                /* loop index variable */
	X	char	*file;              /* name of the current file */
	X	char	*pgm = argv[0];     /* name of the program */
	X	FILE	*ioptr;             /* file pointer for opening */
	X	int 	countstdin = 0;     /* number of times stdin is processed */
	X	extern	int errno;          /* system error number */
	X
	X	if (curarg == argc)
	X		status += ((*process) ("-", stdin));
	X	else
	X		{
	X		/* first check to make sure all files can be opened to read */
	X		for (arg = curarg; arg < argc; arg++)
	X			{
	X			file = argv[arg];
	X			if (isstdin (file))
	X				countstdin++;
	X			else if (access (file, 4))
	X				{
	X				errmsg (pgm, file, errno, "Can't access file");
	X				status++;
	X				}
	X			}
	X		if (countstdin > 1)
	X			{
	X			errmsg (pgm, NULL, -1, "Can only read standard input once");
	X			status++;
	X			}
	X		if (status == 0)
	X			for (arg = curarg; arg < argc; arg++)
	X				{
	X				file = argv[arg];
	X				if (isstdin (file))
	X					status += ((*process) (file, stdin) != 0);
	X				else if (ioptr = fopen (file, "r"))
	X					{
	X					status += ((*process) (file, ioptr) != 0);
	X					(void) fclose (ioptr);
	X					}
	X				else
	X					{
	X					errmsg (pgm, file, errno, "Can't open file");
	X					status++;
	X					}
	X				}
	X		}
	X	return (status);
	X	}
SHAR_EOF
if test 3999 -ne "`wc -c < 'zipsort.c'`"
then
	echo shar: "error transmitting 'zipsort.c'" '(should have been 3999 characters)'
fi
fi
exit 0
#	End of shell archive
-- 
Gary Perlman  Wang Institute  Tyngsboro, MA 01879  (617) 649-9731
UUCP: decvax!wanginst!perlman             CSNET: perlman@wanginst