home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / netsrcs / mailmrge < prev    next >
Encoding:
Internet Message Format  |  1987-04-01  |  8.7 KB

  1. From rs@mirror.TMC.COM Thu Apr  2 14:23:42 1987
  2. Path: seismo!rutgers!pyrnj!mirror!rs
  3. From: rs@mirror.TMC.COM (Rich Salz)
  4. Newsgroups: net.sources,comp.text
  5. Subject: Quicky "mail-merge" program
  6. Message-ID: <2763@mirror.TMC.COM>
  7. Date: 2 Apr 87 19:23:42 GMT
  8. Organization: Mirror Systems, Cambridge MA
  9. Lines: 373
  10.  
  11. We needed to generate a whole bunch of form letters, and it was quicker
  12. and easier to throw together his general solution, than for me to write
  13. a general-purpose troff .rd macro-caller.  Besides, sometimes we just
  14. quick something straight to the lineprinter.
  15.  
  16. You should be able to specify the number of lines per field on the command
  17. line, I suppose...
  18.     /r$
  19.  
  20. #! /bin/sh
  21. # This is a shell archive.  Remove anything before this line,
  22. # then unpack it by saving it in a file and typing "sh file".
  23. # If this archive is complete, you will see the message:
  24. #        "End of shell archive."
  25. # Contents:  mmerge.1 mmerge.l Makefile Test.list Test.template
  26. # Wrapped by rs@mirror on Thu Apr  2 14:19:28 1987
  27. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  28. echo shar: Extracting \"mmerge.1\" \(2456 characters\)
  29. if test -f mmerge.1 ; then 
  30.   echo shar: Will not over-write existing file \"mmerge.1\"
  31. else
  32. sed "s/^X//" >mmerge.1 <<'END_OF_mmerge.1'
  33. X.TH MMERGE 1 LOCAL
  34. X\" $Header:$
  35. X.SH NAME
  36. Xmmerge \- ``quick and dirty'' mail-merge program.
  37. X.SH SYNOPSIS
  38. X.B mmerge
  39. Xtemplate_file list_file
  40. X.SH DESCRIPTION
  41. X.I Mmerge
  42. Xis a short little program designed to help generate form letters and
  43. Xthe like.
  44. XIt should be given two arguments:  the name of the template file, and
  45. Xthe name of the list file.
  46. XIf either name is a dash,
  47. X.BR \- ,
  48. Xstandard input is used.
  49. XOutput is sent to standard output, presumably to be piped into
  50. X.IR lpr (1)
  51. Xor
  52. X.IR ptroff (1).
  53. X.PP
  54. XThe template file is a normal text file, that contains special ``markers''
  55. Xindicating where you want the input from the address list to appear.
  56. XFor example:
  57. X.RS
  58. X.nf
  59. X\&^L
  60. X$$1$
  61. X$$3$, $$4$
  62. XApril 1, 1986
  63. X
  64. XDear $$1$:
  65. X
  66. XYou may already be a winner!  That's right, $$2$, you could be
  67. Xthe first in the town of $$3$, $$4$, to win $1000.
  68. X    .
  69. X.sp -.5
  70. X    .
  71. X.sp -.5
  72. X    .
  73. X    Sincerely,
  74. X
  75. X    Ed McMahon
  76. X.fi
  77. X.RE
  78. X(You would probably want to start or end the template with a formfeed if
  79. Xyou are sending your output to a lineprinter, hence the ``^L'' as the
  80. Xfirst line.)
  81. X.PP
  82. XWithin the template, there can be any number of markers of the form
  83. X.BI $$ digits $
  84. Xmeaning that the contents of field number
  85. X.I digits
  86. Xfrom the list file should be inserted at that point.
  87. X.PP
  88. XContinuing this example, here is what a sample list file might look
  89. Xlike:
  90. X.RS
  91. X.nf
  92. XLINES: 4
  93. X
  94. XRichard Salz
  95. XRich
  96. XCambridge
  97. XMassachusetts
  98. X
  99. XJohnny Carson
  100. XJoohhhny!
  101. XBurbank
  102. XCalifornia
  103. X
  104. X.fi
  105. X.RE
  106. XThe first line of the file contains the word
  107. X.I LINES
  108. Xin all capitals, followed by a colon and space, then the number of fields
  109. Xin each entry.
  110. XThe second line is blank.
  111. XThen, each record appears, separated by a blank line.
  112. X(Note that the file
  113. X.I ends
  114. Xwith a blank line, too.)
  115. X.PP
  116. XFinally, if the template file (shown first) is called
  117. X.IR temp ,
  118. Xand the list file (shown second) is called
  119. X.IR list ,
  120. Xthen typing:
  121. X.RS
  122. Xmmerge temp list | lpr
  123. X.RE
  124. Xwould send the following to the lineprinter:
  125. X.RS
  126. X.nf
  127. X.I "(new page)"
  128. XRichard Salz
  129. XCambridge, Massachusetts
  130. XApril 1, 1986
  131. X
  132. XDear Richard Salz:
  133. X
  134. XYou may already be a winner!  That's right, Rich, you could be
  135. Xthe first in the town of Cambridge, Massachusetts, to win $1000.
  136. X    .
  137. X.sp -.5
  138. X    .
  139. X.sp -.5
  140. X    .
  141. X    Sincerely,
  142. X
  143. X    Ed McMahon
  144. X.I "(new page)"
  145. XJohnny Carson
  146. XBurbank, California
  147. XApril 1, 1986
  148. X
  149. XDear Johnny Carson:
  150. X
  151. XYou may already be a winner!  That's right, Joohhny!, you could be
  152. Xthe first in the town of Burbank, California, to win $1000.
  153. X    .
  154. X.sp -.5
  155. X    .
  156. X.sp -.5
  157. X    .
  158. X    Sincerely,
  159. X
  160. X    Ed McMahon
  161. X.fi
  162. X.RE
  163. END_OF_mmerge.1
  164. if test 2456 -ne `wc -c <mmerge.1`; then
  165.     echo shar: \"mmerge.1\" unpacked with wrong size!
  166. fi
  167. # end of overwriting check
  168. fi
  169. echo shar: Extracting \"mmerge.l\" \(2511 characters\)
  170. if test -f mmerge.l ; then 
  171.   echo shar: Will not over-write existing file \"mmerge.l\"
  172. else
  173. sed "s/^X//" >mmerge.l <<'END_OF_mmerge.l'
  174. X
  175. X%{
  176. X/*
  177. X**  MMERGE
  178. X**  A quick and dirty "mail merge" program.
  179. X**
  180. X**  Sloppy programming:  we let exit() close all open files for us.
  181. X*/
  182. X
  183. X#include <stdio.h>
  184. X
  185. X#ifndef    lint
  186. Xstatic char     RCS[] = "$Header: mmerge.c,v 1.1 87/04/02 10:35:34 rs REL $";
  187. X#endif    /* lint */
  188. X
  189. X#define LINESIZE    99
  190. X#define MARK        '$'
  191. X#define NIL        (char *)NULL
  192. X
  193. Xstatic int      Lines;
  194. Xstatic char      LINES[] = "LINES: ";
  195. Xstatic char    **Text;
  196. X
  197. Xextern int     errno;
  198. Xextern int     sys_nerr;
  199. Xextern char    *sys_errlist[];
  200. Xextern char    *calloc();
  201. Xextern char    *index();
  202. X
  203. X
  204. Xstatic void
  205. XYelp(a, b)
  206. X    char    *a;
  207. X    char    *b;
  208. X{
  209. X    int         e;
  210. X
  211. X    e = errno;
  212. X    fprintf(stderr, "mmerge:  ");
  213. X    fprintf(stderr, a, b);
  214. X    fprintf(stderr, " (errno = %d, %s).\n",
  215. X        e, e < 0 || e > sys_nerr ? "oops" : sys_errlist[errno]);
  216. X    exit(1);
  217. X}
  218. X
  219. X
  220. Xmain(ac, av)
  221. X    int              ac;
  222. X    char         *av[];
  223. X{
  224. X    register FILE     *Input;
  225. X    register char     *p;
  226. X    register int      i;
  227. X    char          buff[BUFSIZ];
  228. X
  229. X    /* Check usage. */
  230. X    if (ac != 3)
  231. X    Yelp("Bad usage", NIL);
  232. X
  233. X    /* Open files. */
  234. X    if ((yyin = strcmp(av[1], "-") ? fopen(av[1], "r") : stdin) == NULL)
  235. X    Yelp("Can't open %s as template file", av[1]);
  236. X    if ((Input = strcmp(av[2], "-") ? fopen(av[2], "r") : stdin) == NULL)
  237. X    Yelp("Can't open %s as input file", av[2]);
  238. X    if (yyin == stdin && Input == stdin)
  239. X    Yelp("Both files can't be from standard input", NIL);
  240. X
  241. X    /* First line of Input should be "LINES: #"; second should be blank. */
  242. X    if (fgets(buff, sizeof buff, Input) == NULL
  243. X     || strncmp(buff, LINES, sizeof LINES - 1) != 0
  244. X     || (Lines = atoi(buff + sizeof LINES - 1)) == 0
  245. X     || fgets(buff, sizeof buff, Input) == NULL
  246. X     || buff[0] != '\n')
  247. X    Yelp("Input file has bad format!", NIL);
  248. X
  249. X    /* Get space for each field. */
  250. X    if ((Text = (char **)calloc((unsigned int)Lines+1, sizeof(char *))) == NULL)
  251. X    Yelp("calloc failure #1", NIL);
  252. X    for (i = Lines + 1; --i >= 0; )
  253. X    if ((Text[i] = (char *)calloc(LINESIZE, 1)) == NULL)
  254. X        Yelp("calloc failure #2", NIL);
  255. X
  256. X    while (!feof(Input)) {
  257. X    /* Read a field array from the list file. */
  258. X    for (i = 0; i <= Lines; i++) {
  259. X        if (fgets(Text[i], LINESIZE, Input) == NULL) {
  260. X        if (i)
  261. X            Yelp("Premature end of input?", NIL);
  262. X        exit(0);
  263. X        }
  264. X        if (p = index(Text[i], '\n'))
  265. X        *p = '\0';
  266. X    }
  267. X
  268. X    /* Read the template file, doing fill-ins as directed. */
  269. X    (void)rewind(yyin);
  270. X    yylex();
  271. X    }
  272. X
  273. X    exit(0);
  274. X}
  275. X%}
  276. X
  277. X%%
  278. X
  279. X\$\$[0-9]+\$    {
  280. X            int     i;
  281. X
  282. X            i = atoi(&yytext[2]) - 1;
  283. X            printf("%s", i >= 0 && i < Lines ? Text[i] : yytext);
  284. X        }
  285. X.        ECHO;
  286. X
  287. X%%
  288. END_OF_mmerge.l
  289. if test 2511 -ne `wc -c <mmerge.l`; then
  290.     echo shar: \"mmerge.l\" unpacked with wrong size!
  291. fi
  292. # end of overwriting check
  293. fi
  294. echo shar: Extracting \"Makefile\" \(366 characters\)
  295. if test -f Makefile ; then 
  296.   echo shar: Will not over-write existing file \"Makefile\"
  297. else
  298. sed "s/^X//" >Makefile <<'END_OF_Makefile'
  299. X##
  300. X##  MMERGE MAKEFILE
  301. X##
  302. X
  303. X##  Edit appropriately.
  304. XCFLAGS    = -O
  305. XDESTPROG= /usr/local/bin/mmerge
  306. XDESTMAN    = /usr/man/man1/mmerge.1
  307. X
  308. Xall:    mmerge lint
  309. X
  310. Xinstall:    all
  311. X    cp mmerge $(DESTPROG)
  312. X    cp mmerge.1 $(DESTMAN)
  313. X
  314. Xmmerge:        mmerge.c
  315. X    $(CC) $(CFLAGS) -o mmerge mmerge.c -ll
  316. X
  317. Xlint:        mmerge
  318. X    lint -hba mmerge.c >lint
  319. X
  320. Xclean:
  321. X    rm -f mmerge a.out foo core tags lint mmerge.[oc]
  322. END_OF_Makefile
  323. if test 366 -ne `wc -c <Makefile`; then
  324.     echo shar: \"Makefile\" unpacked with wrong size!
  325. fi
  326. # end of overwriting check
  327. fi
  328. echo shar: Extracting \"Test.list\" \(97 characters\)
  329. if test -f Test.list ; then 
  330.   echo shar: Will not over-write existing file \"Test.list\"
  331. else
  332. sed "s/^X//" >Test.list <<'END_OF_Test.list'
  333. XLINES: 4
  334. X
  335. XRichard Salz
  336. XRich
  337. XCambridge
  338. XMassachusetts
  339. X
  340. XJohnny Carson
  341. XJoohhhny!
  342. XBurbank
  343. XCalifornia
  344. X
  345. END_OF_Test.list
  346. if test 97 -ne `wc -c <Test.list`; then
  347.     echo shar: \"Test.list\" unpacked with wrong size!
  348. fi
  349. # end of overwriting check
  350. fi
  351. echo shar: Extracting \"Test.template\" \(193 characters\)
  352. if test -f Test.template ; then 
  353.   echo shar: Will not over-write existing file \"Test.template\"
  354. else
  355. sed "s/^X//" >Test.template <<'END_OF_Test.template'
  356. X
  357. X$$1$
  358. X$$3$, $$4$
  359. XApril 1, 1986
  360. X
  361. XDear $$1$:
  362. X
  363. XYou may already be a winner!  That's right, $$2$, you could be
  364. Xthe first in the town of $$3$, $$4$, to win $1000.
  365. X    .
  366. X    .
  367. X    .
  368. X    Sincerely,
  369. X
  370. X    Ed McMahon
  371. END_OF_Test.template
  372. if test 193 -ne `wc -c <Test.template`; then
  373.     echo shar: \"Test.template\" unpacked with wrong size!
  374. fi
  375. # end of overwriting check
  376. fi
  377. echo shar: End of shell archive.
  378. exit 0
  379. -- 
  380. --
  381. Rich $alz                    "Drug tests p**s me off"
  382. Mirror Systems, Cambridge Massachusetts        rs@mirror.TMC.COM
  383. {adelie, mit-eddie, ihnp4, harvard!wjh12, cca, cbosgd, seismo}!mirror!rs
  384.  
  385.  
  386.