rs@mirror.UUCP (04/02/87)
We needed to generate a whole bunch of form letters, and it was quicker and easier to throw together his general solution, than for me to write a general-purpose troff .rd macro-caller. Besides, sometimes we just quick something straight to the lineprinter. You should be able to specify the number of lines per field on the command line, I suppose... /r$ #! /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". # If this archive is complete, you will see the message: # "End of shell archive." # Contents: mmerge.1 mmerge.l Makefile Test.list Test.template # Wrapped by rs@mirror on Thu Apr 2 14:19:28 1987 PATH=/bin:/usr/bin:/usr/ucb ; export PATH echo shar: Extracting \"mmerge.1\" \(2456 characters\) if test -f mmerge.1 ; then echo shar: Will not over-write existing file \"mmerge.1\" else sed "s/^X//" >mmerge.1 <<'END_OF_mmerge.1' X.TH MMERGE 1 LOCAL X\" $Header:$ X.SH NAME Xmmerge \- ``quick and dirty'' mail-merge program. X.SH SYNOPSIS X.B mmerge Xtemplate_file list_file X.SH DESCRIPTION X.I Mmerge Xis a short little program designed to help generate form letters and Xthe like. XIt should be given two arguments: the name of the template file, and Xthe name of the list file. XIf either name is a dash, X.BR \- , Xstandard input is used. XOutput is sent to standard output, presumably to be piped into X.IR lpr (1) Xor X.IR ptroff (1). X.PP XThe template file is a normal text file, that contains special ``markers'' Xindicating where you want the input from the address list to appear. XFor example: X.RS X.nf X\&^L X$$1$ X$$3$, $$4$ XApril 1, 1986 X XDear $$1$: X XYou may already be a winner! That's right, $$2$, you could be Xthe first in the town of $$3$, $$4$, to win $1000. X . X.sp -.5 X . X.sp -.5 X . X Sincerely, X X Ed McMahon X.fi X.RE X(You would probably want to start or end the template with a formfeed if Xyou are sending your output to a lineprinter, hence the ``^L'' as the Xfirst line.) X.PP XWithin the template, there can be any number of markers of the form X.BI $$ digits $ Xmeaning that the contents of field number X.I digits Xfrom the list file should be inserted at that point. X.PP XContinuing this example, here is what a sample list file might look Xlike: X.RS X.nf XLINES: 4 X XRichard Salz XRich XCambridge XMassachusetts X XJohnny Carson XJoohhhny! XBurbank XCalifornia X X.fi X.RE XThe first line of the file contains the word X.I LINES Xin all capitals, followed by a colon and space, then the number of fields Xin each entry. XThe second line is blank. XThen, each record appears, separated by a blank line. X(Note that the file X.I ends Xwith a blank line, too.) X.PP XFinally, if the template file (shown first) is called X.IR temp , Xand the list file (shown second) is called X.IR list , Xthen typing: X.RS Xmmerge temp list | lpr X.RE Xwould send the following to the lineprinter: X.RS X.nf X.I "(new page)" XRichard Salz XCambridge, Massachusetts XApril 1, 1986 X XDear Richard Salz: X XYou may already be a winner! That's right, Rich, you could be Xthe first in the town of Cambridge, Massachusetts, to win $1000. X . X.sp -.5 X . X.sp -.5 X . X Sincerely, X X Ed McMahon X.I "(new page)" XJohnny Carson XBurbank, California XApril 1, 1986 X XDear Johnny Carson: X XYou may already be a winner! That's right, Joohhny!, you could be Xthe first in the town of Burbank, California, to win $1000. X . X.sp -.5 X . X.sp -.5 X . X Sincerely, X X Ed McMahon X.fi X.RE END_OF_mmerge.1 if test 2456 -ne `wc -c <mmerge.1`; then echo shar: \"mmerge.1\" unpacked with wrong size! fi # end of overwriting check fi echo shar: Extracting \"mmerge.l\" \(2511 characters\) if test -f mmerge.l ; then echo shar: Will not over-write existing file \"mmerge.l\" else sed "s/^X//" >mmerge.l <<'END_OF_mmerge.l' X X%{ X/* X** MMERGE X** A quick and dirty "mail merge" program. X** X** Sloppy programming: we let exit() close all open files for us. X*/ X X#include <stdio.h> X X#ifndef lint Xstatic char RCS[] = "$Header: mmerge.c,v 1.1 87/04/02 10:35:34 rs REL $"; X#endif /* lint */ X X#define LINESIZE 99 X#define MARK '$' X#define NIL (char *)NULL X Xstatic int Lines; Xstatic char LINES[] = "LINES: "; Xstatic char **Text; X Xextern int errno; Xextern int sys_nerr; Xextern char *sys_errlist[]; Xextern char *calloc(); Xextern char *index(); X X Xstatic void XYelp(a, b) X char *a; X char *b; X{ X int e; X X e = errno; X fprintf(stderr, "mmerge: "); X fprintf(stderr, a, b); X fprintf(stderr, " (errno = %d, %s).\n", X e, e < 0 || e > sys_nerr ? "oops" : sys_errlist[errno]); X exit(1); X} X X Xmain(ac, av) X int ac; X char *av[]; X{ X register FILE *Input; X register char *p; X register int i; X char buff[BUFSIZ]; X X /* Check usage. */ X if (ac != 3) X Yelp("Bad usage", NIL); X X /* Open files. */ X if ((yyin = strcmp(av[1], "-") ? fopen(av[1], "r") : stdin) == NULL) X Yelp("Can't open %s as template file", av[1]); X if ((Input = strcmp(av[2], "-") ? fopen(av[2], "r") : stdin) == NULL) X Yelp("Can't open %s as input file", av[2]); X if (yyin == stdin && Input == stdin) X Yelp("Both files can't be from standard input", NIL); X X /* First line of Input should be "LINES: #"; second should be blank. */ X if (fgets(buff, sizeof buff, Input) == NULL X || strncmp(buff, LINES, sizeof LINES - 1) != 0 X || (Lines = atoi(buff + sizeof LINES - 1)) == 0 X || fgets(buff, sizeof buff, Input) == NULL X || buff[0] != '\n') X Yelp("Input file has bad format!", NIL); X X /* Get space for each field. */ X if ((Text = (char **)calloc((unsigned int)Lines+1, sizeof(char *))) == NULL) X Yelp("calloc failure #1", NIL); X for (i = Lines + 1; --i >= 0; ) X if ((Text[i] = (char *)calloc(LINESIZE, 1)) == NULL) X Yelp("calloc failure #2", NIL); X X while (!feof(Input)) { X /* Read a field array from the list file. */ X for (i = 0; i <= Lines; i++) { X if (fgets(Text[i], LINESIZE, Input) == NULL) { X if (i) X Yelp("Premature end of input?", NIL); X exit(0); X } X if (p = index(Text[i], '\n')) X *p = '\0'; X } X X /* Read the template file, doing fill-ins as directed. */ X (void)rewind(yyin); X yylex(); X } X X exit(0); X} X%} X X%% X X\$\$[0-9]+\$ { X int i; X X i = atoi(&yytext[2]) - 1; X printf("%s", i >= 0 && i < Lines ? Text[i] : yytext); X } X. ECHO; X X%% END_OF_mmerge.l if test 2511 -ne `wc -c <mmerge.l`; then echo shar: \"mmerge.l\" unpacked with wrong size! fi # end of overwriting check fi echo shar: Extracting \"Makefile\" \(366 characters\) if test -f Makefile ; then echo shar: Will not over-write existing file \"Makefile\" else sed "s/^X//" >Makefile <<'END_OF_Makefile' X## X## MMERGE MAKEFILE X## X X## Edit appropriately. XCFLAGS = -O XDESTPROG= /usr/local/bin/mmerge XDESTMAN = /usr/man/man1/mmerge.1 X Xall: mmerge lint X Xinstall: all X cp mmerge $(DESTPROG) X cp mmerge.1 $(DESTMAN) X Xmmerge: mmerge.c X $(CC) $(CFLAGS) -o mmerge mmerge.c -ll X Xlint: mmerge X lint -hba mmerge.c >lint X Xclean: X rm -f mmerge a.out foo core tags lint mmerge.[oc] END_OF_Makefile if test 366 -ne `wc -c <Makefile`; then echo shar: \"Makefile\" unpacked with wrong size! fi # end of overwriting check fi echo shar: Extracting \"Test.list\" \(97 characters\) if test -f Test.list ; then echo shar: Will not over-write existing file \"Test.list\" else sed "s/^X//" >Test.list <<'END_OF_Test.list' XLINES: 4 X XRichard Salz XRich XCambridge XMassachusetts X XJohnny Carson XJoohhhny! XBurbank XCalifornia X END_OF_Test.list if test 97 -ne `wc -c <Test.list`; then echo shar: \"Test.list\" unpacked with wrong size! fi # end of overwriting check fi echo shar: Extracting \"Test.template\" \(193 characters\) if test -f Test.template ; then echo shar: Will not over-write existing file \"Test.template\" else sed "s/^X//" >Test.template <<'END_OF_Test.template' X X$$1$ X$$3$, $$4$ XApril 1, 1986 X XDear $$1$: X XYou may already be a winner! That's right, $$2$, you could be Xthe first in the town of $$3$, $$4$, to win $1000. X . X . X . X Sincerely, X X Ed McMahon END_OF_Test.template if test 193 -ne `wc -c <Test.template`; then echo shar: \"Test.template\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of shell archive. exit 0 -- -- Rich $alz "Drug tests p**s me off" Mirror Systems, Cambridge Massachusetts rs@mirror.TMC.COM {adelie, mit-eddie, ihnp4, harvard!wjh12, cca, cbosgd, seismo}!mirror!rs