[net.sources] Mail Merging, revisited

mh@killer.UUCP (04/05/87)

[]

Speaking of mail merging, here's an older one.

#!/bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by mh on Sat Apr  4 19:16:26 CST 1987
# Contents:  letter list mmerge.c mmerge.doc
 
echo x - letter
sed 's/^XX//' > "letter" <<'@//E*O*F letter//'
XX3 August 1985

XX@1
XX@2
XX@3
XX@4
XX@5

XXDear @6,
XX  The current offer is rejected, please resubmit in 90 days.

XXSincerely,

XXJoe Blow Industries
XXNew York
@//E*O*F letter//
chmod u=rw,g=r,o=r letter
 
echo x - list
sed 's/^XX//' > "list" <<'@//E*O*F list//'
XX.XXX
XXMr. Corncob Bueller
XXFinancial Wizard
XX301 N. Pork Chop
XXDallas, TX  10101

XXMr. Bueller
XX.XXX
XXMrs. G. Ricardo
XXPlaintiff
XX1441 E. 3rd St.
XXDallas, TX 01010

XXMrs. Ricardo
@//E*O*F list//
chmod u=rw,g=r,o=r list
 
echo x - mmerge.c
sed 's/^XX//' > "mmerge.c" <<'@//E*O*F mmerge.c//'
XX/*
XX	mmerge.c

XX	Matthew Rapaport, July 1985
XX	Scaetrix Co, 222 Fifth St, Petaluma, CA, 94952
XX	Compuserve 70371,255

XX	This version works with C/80(tm) v3.0
XX	and UniFLEX(tm) v2.0

XX	This program merges a list of names to a letter
XX	Sends impersonal mail to prospective customers
XX*/

XX#ifdef CPM
XX#include "a:stdio.h"
XX#include "a:printf.h"
XX#else
XX#include <stdio.h>
XX#endif

XX#define	FALSE	0
XX#define	TRUE	~FALSE

XX#define	MAXLINE	40

XXstruct	record	{
XX	char	testln[MAXLINE];
XX	char	nameln[MAXLINE];
XX	char	titlln[MAXLINE];
XX	char	addrln[MAXLINE];
XX	char	cityln[MAXLINE];
XX	char	auxone[MAXLINE];
XX	char	auxtwo[MAXLINE];
XX} currec;


XXmain(argc,argv)
XXint	argc;
XXchar	*argv[];
XX{
XX#ifdef CPM
XX	FILE	list, letter;
XX#else
XX	FILE	*list, *letter;
XX#endif
XX	char	*fgets();

XX	if (argc != 3)  {
XX		fprintf(stderr,"\nusage: mmerge listfile letterfile\n");
XX		exit(0);
XX	}

XX	if ((list = fopen(argv[1],"r")) == 0)  {
XX		fprintf(stderr,"\nCan't open list file %s\n",argv[1]);
XX		exit(0);
XX	}

XX	if ((letter = fopen(argv[2],"r")) == 0)  {
XX		fprintf(stderr,"\nCan't open letter file %s\n",argv[2]);
XX		exit(0);
XX	}

XX	for(;;)  {
XX		if ((fgets(currec.testln,MAXLINE,list)) == 0)
XX			break;

XX		fgets(currec.nameln,MAXLINE,list);
XX		fgets(currec.titlln,MAXLINE,list);
XX		fgets(currec.addrln,MAXLINE,list);
XX		fgets(currec.cityln,MAXLINE,list);
XX		fgets(currec.auxone,MAXLINE,list);
XX		fgets(currec.auxtwo,MAXLINE,list);

XX		mergit(&currec,letter);
XX	}

XX	fclose(list);
XX	fclose(letter);
XX}


XXmergit(ptr,letter)
XXstruct	record	*ptr;
XX#ifdef CPM
XXFILE	letter;
XX#else
XXFILE	*letter;
XX#endif
XX{
XX	int	i, letchar;
XX	char	d, flag, string[MAXLINE];

XX	while ((letchar = getc(letter)) != EOF)  {
XX		if (letchar == '@')  {
XX			d = letchar;
XX			letchar = getc(letter);
XX			flag = FALSE;
XX			switch (letchar)  {
XX				case '1':
XX					strcpy(string,ptr->nameln);
XX					break;
XX				case '2':
XX					strcpy(string,ptr->titlln);
XX					break; 
XX				case '3':
XX					strcpy(string,ptr->addrln);
XX					break;
XX				case '4':
XX					strcpy(string,ptr->cityln);
XX					break;
XX				case '5':
XX					strcpy(string,ptr->auxone);
XX					break;
XX				case '6':
XX					strcpy(string,ptr->auxtwo);
XX					break;

XX/* if the next char was not a number 1 - 6, print the '@' and what ever */
XX/*               followed it on the standard output                     */

XX				default:
XX					flag = TRUE;
XX					putchar(d);
XX					putchar(letchar);
XX			}

XX			if (!flag)
XX				for(i = 0; string[i] != '\n'; i++)
XX					putchar(string[i]);
XX		}
XX		else		/* no '@' so just put the char to stdout */
XX			putchar(letchar);
XX	} 

XX	putchar('\f');		/* form feed the printer */
XX#ifdef CPM
XX	seek(letter,0,0);	/* rewind letter file to beginning */
XX#else
XX	rewind(letter);
XX#endif
XX}

XX#ifdef CPM
XXchar	*
XXfgets(buf,size,fp)	/* missing in c/80 library */
XXFILE	fp;
XXint	size;
XXchar	*buf;
XX{
XX	int	c;
XX	char	*cs;

XX	cs = buf;
XX	while (--size > 0 && (c = getc(fp)) != EOF)
XX		if ((*cs++ = c) == '\n')
XX			break;
XX	*cs = '\0';
XX	return((c == EOF && cs == buf) ? NULL : buf);
XX}
XX#endif
@//E*O*F mmerge.c//
chmod u=rw,g=r,o=r mmerge.c
 
echo x - mmerge.doc
sed 's/^XX//' > "mmerge.doc" <<'@//E*O*F mmerge.doc//'
XXAugust 3, 1985

XXMailmerge anyone?   Here is a short program that merges a list of 
XXnames, titles, addresses, etc. with documents specially formatted 
XXto  receive  the list.   The program takes the data to be  merged 
XXfrom  a  list file consisting of individual  lines  seperated  by 
XXnewlines.   There   must be seven such  lines  in   each  record, 
XXwith the first being a record separator line.   I use .XXX as  my  
XXseparator   line (I'm going to build  a  sorting  function around 
XXthis),   but anything will do.   The list thus has room for name,  
XXtitle,   address,   city-state-zip,  and two auxiliary lines that 
XXmight hold some other information. The list file looks like this:

XXSEPARATOR LINE
XXname
XXtitle
XXaddress
XXcity, state zipcode
XXaux 1
XXaux 2
XXSEPARATOR LINE
XXname
XXetc...

XXNote  that  even if aux 1 and aux 2 are not used,  there must  at 
XXleast be blank lines in their place.   The document to be  merged 
XXcan  be  any  kind  of text.   The function  mergit()  reads  the 
XXdocument  character  by  character until  it  encounters  an  '@' 
XXsymbol.   It  then  saves  that  character  and  reads  the  next 
XXcharacter.   If  this next character is a number in the range 1 - 
XX6,  the appropriate line from the list record will be substituted 
XXfor the '@1' or '@2' etc.  If the character immediately following 
XXthe '@' is not a number in the expected range,  the '@',  and the 
XXfollowing  character  are simply printed  to  the  stdout.   Thus 
XXnormal use can be made of the '@' symbol in the document.

XXA typical letter might look like:

XXDate here

XX@1
XX@2
XX@3
XX@4
XX@5

XXdear @6


XXIf lines one thru five of the list record contain the usual name, 
XXtitle, address, city-state-zip, aux 1 and the sixth line or aux 2 
XXis the first name, then the program would substitute these values 
XXappropriately in their respective places.  The merged document is 
XXsent (character by character) to the standard output.

XXThus  the merged documents can be sent anywhere the user  desires 
XXby redirecting in the command line.  A typical use would be:

XX(cpm)	mmerge listfile letterfile >lst:
XX(unix)	mmerge listfile letterfile | lpr

XXIf  six lines are not enough for some needs,  one can always  add 
XXmore  descriptions  to the structure  'record',  and  extend  the 
XXswitch-case  in mergit() appropriately.  Also remember to include 
XXthe new structure elements in the forever loop in main().

XXHope  you like it,  if there are any questions,  please drop me a 
XXnote via CIS or my business address:

XXMatthew Rapaport
XXSCAETRIX Co.
XX222 Fifth St.
XXPetaluma, CA 94952
XX(707) 778-7758
XXCIS [70371,255]
@//E*O*F mmerge.doc//
chmod u=rw,g=r,o=r mmerge.doc
 
echo Inspecting for damage in transit...
temp=/tmp/sharin$$; dtemp=/tmp/sharout$$
trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
cat > $temp <<\!!!
     15     26    143 letter
     14     29    168 list
    161    361   2885 mmerge.c
     75    427   2574 mmerge.doc
    265    843   5770 total
!!!
wc  letter list mmerge.c mmerge.doc | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
if test -s $dtemp
then echo "Ouch [diff of wc output]:" ; cat $dtemp
else echo "No problems found."
fi
exit 0