v08i054: Ease, a language for writing sendmail.cf files, Part02/04
sources-request at mirror.UUCP
sources-request at mirror.UUCP
Thu Feb 12 06:29:50 AEST 1987
Submitted by: ksb at j.cc.purdue.edu
Mod.sources: Volume 8, Issue 54
Archive-name: ease/Part02
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# src
if test ! -d src
then
mkdir src
echo "shar: part 01 is missing?"
fi
chdir src
cat << \SHAR_EOF > emitcf.c
/* $Header: /usr/src/local/etc/ease/RCS/emitcf.c,v 1.3 85/11/22 20:14:11 jss Exp $ */
/*
* emitcf.c -- This file contains routines associated with the writing
* and formatting of a translated sendmail configuration file.
*
* author -- James S. Schoner, Purdue University Computing Center,
* West Lafayette, Indiana 47907
*
* date -- July 9, 1985
*
* Copyright (c) 1985 by Purdue Research Foundation
*
* All rights reserved.
*
*/
#include <stdio.h>
#include "symtab.h"
#define REGLINE 60 /* length of output lines which may be continued */
#define MAXLINE 256 /* liberal maximum line length */
extern short Rformat; /* read-format flag for a class */
extern char *MacScan ();
extern char MakeMac ();
extern void PrintError (),
FatalError (),
PrintWarning (),
ErrorReport ();
void PrintDef ();
static char ClassCH; /* printable class macro char */
/*
* EmitDef () -- Emit a definition line (Ease block definition) in cf
* format.
*
*/
void
EmitDef (blockdef, targ, defstr1, defstr2)
register enum bdefs blockdef; /* type of definition */
register struct he *targ; /* target to be defined */
char *defstr1, *defstr2; /* one or two definition strings */
{
/*
* This routine is about as pretty as a translated ease file...
* Each type of line (Ease block) is handled case by case below.
*
*/
switch (blockdef) {
case def_macro: printf ("D%c", MakeMac (targ, ID_MACRO));
PrintDef (def_macro, MacScan (defstr1));
if (ISMACRO(targ->idd))
PrintWarning ("Redefining macro %s.\n", targ->psb);
targ->idd |= ID_MACRO; /* signal definition */
break;
case def_class: if (Rformat) /* read format */
printf ("F");
else
printf ("C");
printf ("%c", ClassCH = MakeMac (targ, ID_CLASS));
if (Rformat) { /* read format */
printf ("%s\n", defstr1);
Rformat = FALSE;
} else
PrintDef (def_class, defstr1);
if (ISCLASS(targ->idd))
PrintWarning ("Redefining class %s.\n", targ->psb);
targ->idd |= ID_CLASS; /* signal definition */
break;
case def_option: printf ("O%c", *defstr1);
PrintDef (def_option, defstr2);
break;
case def_prec: printf ("P%s=%d\n", targ->psb, targ->idval.prec);
break;
case def_trusted: printf ("T");
PrintDef (def_trusted, defstr1);
break;
case def_header: printf ("H");
if (defstr1 != NULL)
printf ("?%s?", defstr1);
PrintDef (def_header, defstr2);
break;
case def_mailer: if (ISMAILER(targ->idtype)) {
if (ISMAILER(targ->idd))
PrintWarning ("Redefining mailer %s.\n", targ->psb);
} else if (ISTYPED(targ->idtype)) {
PrintError ("Redeclaration of identifier as mailer:", targ->psb);
return;
}
targ->idd |= ID_MAILER; /* signal definition */
printf ("M%s, ", targ->psb);
PrintDef (def_mailer, defstr1);
break;
case def_ruleset: printf ("R");
PrintDef (def_ruleset, defstr1);
break;
default: FatalError ("Bad case in EmitDef ()", (char *) NULL);
}
}
/*
* PrintContinued () -- Print a line definition (buf) by splitting it over
* more than one line. The two definition types
* accepted for this method of continuation are class
* and trusted user lists, indicated in the argument
* btype
*
*/
void
PrintContinued (btype, buf)
enum bdefs btype; /* block (line) type for definition */
register char *buf; /* buffer containing the definition */
{
register char *tmp; /* breakpoint search pointer */
register char tc; /* temporary swap byte */
int buflen; /* length of definition buffer */
buflen = strlen (buf);
tmp = buf + REGLINE;
while ((*--tmp != ' ') && (tmp != buf)) /* look for suitable break */
/* null */ ;
if (tmp == buf) {
for (tmp = buf + REGLINE; (*tmp != ' ') && (tmp - buf != buflen); tmp++)
/* null */ ;
if ((tmp - buf) >= MAXLINE)
PrintWarning ("Member name may be too long.\n", (char *) NULL);
}
tc = *tmp; /* swap break char with null char */
*tmp = '\0';
printf ("%s\n", buf);
if ((*tmp = tc) == '\0')
return;
else
tmp++;
if (btype == def_class) /* start next line */
printf ("C%c", ClassCH);
else
printf ("T");
if (strlen (tmp) < REGLINE) /* continue the line */
printf ("%s\n", tmp);
else
PrintContinued (btype, tmp);
}
/*
* PrintDef () -- Handles special cases (like line continuation) when
* printing definitions.
*
*/
void
PrintDef (btype, dstr)
register enum bdefs btype; /* block type (output line type) */
register char *dstr; /* definition string */
{
register char *tmp;
for (tmp = dstr; *tmp != '\0'; tmp++) /* search for line continuations */
if ((*tmp == '\\') && (*++tmp == '\n'))
if (btype != def_header) {
ErrorReport ("Non-header string contains line continuation\n");
return;
} else
break;
/*
* Perform case by case handling of definition printing.
*
*/
switch (btype) {
case def_header : if (*tmp-- == '\n') {
*tmp = '\0';
if (tmp - dstr >= MAXLINE)
PrintWarning ("Header may be too long.\n",
(char *) NULL);
printf ("%s\n\t", dstr);
tmp += 2;
PrintDef (def_header, tmp);
} else {
if (strlen (dstr) >= MAXLINE)
PrintWarning ("Header may be too long.\n",
(char *) NULL);
printf ("%s\n", dstr);
}
break;
case def_mailer : if (strlen (dstr) >= MAXLINE)
PrintWarning ("Mailer definition may be too long.\n",
(char *) NULL);
printf ("%s\n", dstr);
break;
case def_ruleset: if (strlen (dstr) >= MAXLINE)
PrintWarning ("Rewriting rule may be too long.\n",
(char *) NULL);
printf ("%s\n", dstr);
break;
case def_option : if (strlen (dstr) >= MAXLINE)
PrintWarning ("Option assignment may be too long.\n",
(char *) NULL);
printf ("%s\n", dstr);
break;
case def_macro : if (strlen (dstr) >= MAXLINE)
PrintWarning ("Macro assignment may be too long.\n",
(char *) NULL);
printf ("%s\n", dstr);
break;
case def_prec : if (strlen (dstr) >= MAXLINE)
PrintWarning ("Precedence relation may be too long.\n",
(char *) NULL);
printf ("%s\n", dstr);
break;
case def_trusted:
case def_class : if (strlen (dstr) < REGLINE)
printf ("%s\n", dstr);
else /* use line continuation feature */
PrintContinued (btype, dstr);
break;
default : FatalError ("Invalid case in PrintDef ()", (char *) NULL);
}
}
/*
* StartRuleset () -- Prints a ruleset heading for the ruleset identifier
* contained in the argument rsid.
*
*/
void
StartRuleset (rsid)
register struct he *rsid; /* ruleset identifier */
{
if (!ISRULESET(rsid->idtype))
if (ISTYPED(rsid->idtype))
PrintError ("Identifier not of ruleset type:", rsid->psb);
else
PrintError ("Ruleset identifier not bound to a number:", rsid->psb);
else {
if (ISRULESET(rsid->idd))
PrintWarning ("Redefining ruleset %s.\n", rsid->psb);
rsid->idd |= ID_RULESET;
printf ("S%s\n", rsid->idval.rsn);
}
}
SHAR_EOF
if test 7227 -ne "`wc -c emitcf.c`"
then
echo shar: error transmitting emitcf.c '(should have been 7227 characters)'
fi
cat << \SHAR_EOF > errors.c
/* $Header: /usr/src/local/etc/ease/RCS/errors.c,v 1.2 85/10/29 23:40:20 jss Exp $ */
/*
* errors.c -- Contains error initialization and reporting routines.
*
* author -- James S. Schoner, Purdue University Computing Center,
* West Lafayette, Indiana 47907
*
* date -- July 9, 1985
*
* Copyright (c) 1985 by Purdue Research Foundation
*
* All rights reserved.
*
*/
#include <stdio.h>
extern int ErrorCount; /* error count */
extern char FNbuf[]; /* input file name */
extern int Lcount; /* line count */
FILE *DIAGf = {stderr}; /* file for diagnostic output */
/*
* ErrorReport () -- Prints source file name (FNbuf), line number (Lcount),
* and error message (sbErr) for each invokation.
*
*/
void
ErrorReport (sbErr)
char *sbErr;
{
fprintf (DIAGf, "%s, line %d: %s", FNbuf, Lcount, sbErr);
ErrorCount++;
}
/*
* FatalError () -- Translator fatal error routine which prints
* error message (sbErr) and an argument (sbArg).
*
*/
void
FatalError (sbErr, sbArg)
char *sbErr,
*sbArg;
{
fprintf (DIAGf, "%s, line %d: Fatal Error In Translator: %s %s\n",
FNbuf, Lcount, sbErr, sbArg);
exit (1);
}
/*
* yyerror () -- Prints source file name (FNbuf), line number (Lcount),
* and error message (sbErr) for each invokation.
*
*/
void
yyerror (sbErr)
char *sbErr;
{
fprintf (DIAGf, "%s, line %d: %s\n", FNbuf, Lcount, sbErr);
ErrorCount++;
}
/*
* PrintError () -- Prints source file name (FNbuf), line number
* (cline), error message (sbErr), and argument
* (sbArg) for each invokation.
*
*/
void
PrintError (sbErr, sbArg)
char *sbErr;
char *sbArg;
{
fprintf (DIAGf, "%s, line %d: %s %s.\n", FNbuf, Lcount, sbErr, sbArg);
ErrorCount++;
}
/*
* PrintWarning () -- Prints a warning message with source file
* name (FNbuf), line number (Lcount), warning
* (sbWarn), and a possible identifier (sbID).
*
*/
void
PrintWarning (sbWarn, sbID)
char *sbWarn;
char *sbID;
{
fprintf (DIAGf, "%s, line %d: Warning: ", FNbuf, Lcount);
if (sbID != NULL)
fprintf (DIAGf, sbWarn, sbID);
else
fprintf (DIAGf, sbWarn);
}
/*
* InitError () -- Initialize line count (Lcount) to one and error count
* (ErrorCount) to zero.
*
*/
void
InitError ()
{
Lcount = 1;
ErrorCount = 0;
}
SHAR_EOF
if test 2340 -ne "`wc -c errors.c`"
then
echo shar: error transmitting errors.c '(should have been 2340 characters)'
fi
cat << \SHAR_EOF > idman.c
/* $Header: /usr/src/local/etc/ease/RCS/idman.c,v 1.2 85/10/29 23:41:38 jss Exp $ */
/*
* idman.c -- Contains routines for manipulating identifiers and their
* symbolic associations.
*
* author -- James S. Schoner, Purdue University Computing Center,
* West Lafayette, Indiana 47907
*
* date -- July 9, 1985
*
* Copyright (c) 1985 by Purdue Research Foundation
*
* All rights reserved.
*
*/
#include <stdio.h>
#include "symtab.h"
extern struct he *LookupSymbol ();
extern void FatalError (),
ErrorReport (),
PrintWarning (),
PrintError ();
short Uchar = 'A'; /* for unique macro names */
/*
* UniqMac () -- Assigns and returns a unique one-character macro
* name (upper-case) for an Ease macro name.
*
*/
char
UniqMac (phe)
struct he *phe; /* symbol table entry for Ease macro */
{
if ((phe->idval.idc = Uchar++) > 'Z')
FatalError ("Too many macro names (26 max)", (char *) NULL);
return (phe->idval.idc);
}
/*
* BindID () -- Binds either a ruleset or precedence identifier (phe) to
* an integer (vid). The id type distinction is passed in
* the parameter idt.
*
*/
void
BindID (phe, vid, idt)
register struct he *phe; /* symbol table entry for an identifier */
int vid; /* value of the identifier */
unsigned idt; /* identifier type (ruleset or precedence) */
{
if (ISTYPED(phe->idtype)) { /* should be undefined */
PrintWarning ("Redeclaration of %s.\n", phe->psb);
phe->idtype = ID_UNTYPED;
}
phe->idtype |= idt; /* make defined */
if (ISRULESET(phe->idtype)) {
if (vid > VALRSNMAX) {
ErrorReport ("Ruleset number too large.\n");
return;
} else if (vid < 0) {
ErrorReport ("Ruleset number must be non-negative.\n");
return;
}
sprintf (phe->idval.rsn, "%d", vid);
} else
phe->idval.prec = vid;
}
/*
* CheckRS () -- Checks validity of a ruleset identifier (phe) and
* returns the ruleset string to which the identifier
* is bound. If the ruleset identifier is invalid, the
* null string is returned.
*
*/
char *
CheckRS (phe)
struct he *phe; /* symbol table entry for ruleset identifier */
{
if (!ISRULESET(phe->idtype)) {
if (!ISTYPED(phe->idtype))
PrintError ("Ruleset identifier not bound to a number:", phe->psb);
else
PrintError ("Identifier not of ruleset type:", phe->psb);
return (NULL);
} else
return (phe->idval.rsn);
}
/*
* MakeMac () -- Declare a macro name (pmac) as a class and/or macro type
* (targtype) and return the unique cf character assigned
* to it.
*
*/
char
MakeMac (pmac, targtype)
register struct he *pmac; /* symbol table entry for macro identifier */
unsigned targtype; /* target declaration type for the macro */
{
/*
* An Ease macro may be declared as both a singular macro and
* a class macro.
*
*/
if (ISMACRO(pmac->idtype) || ISCLASS(pmac->idtype)) {
pmac->idtype |= targtype;
return (pmac->idval.idc);
}
if (ISTYPED(pmac->idtype)) { /* not a macro or class id */
PrintError ("Redeclaring or using as macro or class:", pmac->psb);
return ('\0');
}
pmac->idtype |= targtype; /* previously untyped; declare here */
return (UniqMac (pmac));
}
/*
* GetField () -- Returns a field type string given a field
* identifier (fid).
*
*/
char *
GetField (fid)
register struct he *fid; /* field identifier */
{
if (!ISFIELD(fid->idtype)) {
PrintError ("Field type not defined for", fid->psb);
return (NULL);
} else
return (fid->idval.fstring);
}
/*
* CheckMailer () -- Declares a mailer identifier (mid) as type mailer,
* checking that the identifier was not previously
* declared a different type.
*
*/
char *
CheckMailer (mid)
register struct he *mid;
{
if (ISTYPED (mid->idtype) && !ISMAILER (mid->idtype)) {
PrintError ("Redeclaration as mailer:", mid->psb);
return (NULL);
}
mid->idtype |= ID_MAILER;
return (mid->psb);
}
/*
* AssignType () -- Assigns to each field identifier in fidlist the
* type (in string form) fidtype. This is accomplished
* by making each field identifier symbol table entry
* "point" to the type found in fidtype.
*
*/
void
AssignType (fidlist, fidtype)
register char *fidlist; /* field identifier list, blank separated */
char *fidtype; /* field identifier type string */
{
register struct he *fid; /* pointer to a field identifier */
char *fres; /* field type result string */
register char *srch; /* fidlist search pointer */
char sep; /* fidlist separator character */
fres = (char *) malloc (strlen (fidtype) + 1);
if (fres == NULL)
FatalError ("System out of string space in AssignType ()", (char *) NULL);
strcpy (fres, fidtype); /* make clean copy of string type */
/*
* Search for all field identifiers and make the type assignment.
*
*/
srch = fidlist;
while (*srch != '\0') {
while ((*++srch != ' ') && (*srch != '\0'))
/* null */ ;
if (*fidlist != '\0') { /* found a field id */
sep = *srch;
*srch = '\0';
fid = LookupSymbol (fidlist); /* get symbol table entry */
if (ISFIELD(fid->idtype)) {
if (strcmp (fid->idval.fstring, fres))
PrintWarning ("Redefinition of field type for %s.\n", fid->psb);
} else if (ISTYPED(fid->idtype)) {
PrintError ("Redeclaration of identifier as a field:", fid->psb);
return;
}
fid->idtype |= ID_FIELD; /* type the identifier */
fid->idval.fstring = fres; /* type the field */
if ((*srch = sep) != '\0')
fidlist = ++srch;
}
}
}
SHAR_EOF
if test 5550 -ne "`wc -c idman.c`"
then
echo shar: error transmitting idman.c '(should have been 5550 characters)'
fi
cat << \SHAR_EOF > main.c
/* $Header: /usr/src/local/etc/ease/RCS/main.c,v 1.2 85/10/29 23:43:38 jss Exp $ */
/*
* main.c -- Main procedure for Ease Translator.
*
* author -- James S. Schoner, Purdue University Computing Center
* West Lafayette, Indiana 47907
*
* date -- July 9, 1985
*
* Copyright (c) 1985 by Purdue Research Foundation
*
* All rights reserved.
*
*/
#include <stdio.h>
extern FILE *DIAGf; /* diagnostic file */
extern void InitError (),
InitSymbolTable (),
DefScan (),
FatalError (),
PreLoad ();
int ErrorCount; /* translation error count */
void GetArgs (); /* gets arguments to "et" */
/*
* main () -- Main procedure for the Ease Translator et. If no files are
* given as arguments to et, stdin is translated and written to
* stdout. If one file is given, it is translated and written
* to stdout. If two files are given, the first is translated
* and written to the second. If the first filename is "-",
* standard input is assumed. A translation is performed on
* valid Ease input only, producing a regular sendmail
* configuration file.
*
*/
void
main (argc, argv)
int argc; /* argument count for "et" */
char *argv[]; /* argument vector for "et" */
{
InitError (); /* initialize error conditions */
InitSymbolTable (); /* initialize the symbol table */
PreLoad (); /* preload special identifiers */
GetArgs (argc, argv); /* set up argument files */
(void) yyparse (); /* perform translation */
if (fflush (stdout) == EOF)
FatalError ("Cannot flush output stream/file", (char *) NULL);
DefScan (); /* warn about undefined idents */
if (ErrorCount)
fprintf (DIAGf, "\n\n*** %d error(s) detected.\n", ErrorCount);
exit (ErrorCount);
}
/*
* GetArgs () -- Processes arguments to the Ease translator "et". The
* arguments are files (margv) which may replace either/both
* of the files standard input and standard output. The
* following cases are possible:
*
* -- et f.e f.cf
* Translate Ease file f.e and write result
* to f.cf.
*
* -- et f.e
* Translate Ease file f.e and write result to
* standard output.
*
* -- et - f.cf
* Translate standard input and write result to
* f.cf.
*
* -- et
* Translate standard input and write result to
* standard output.
*
* Finally, a message indicating the volatility of the
* Ease output is written.
*
*/
void
GetArgs (margc, margv)
register int margc; /* argument count */
register char *margv[]; /* argument vector */
{
switch (margc) {
case 1 : break;
case 2 :
case 3 : if (strcmp (margv[1], "-") && (freopen (margv[1], "r", stdin) == NULL))
FatalError ("Cannot open input stream/file:", margv[1]);
if ((margc == 3) && (freopen (margv[2], "w", stdout) == NULL))
FatalError ("Cannot open output file:", margv[2]);
break;
default: FatalError ("Usage: et [infile [outfile]]", (char *) NULL);
break;
}
printf ("###################################################\n");
printf ("## ##\n");
printf ("## WARNING: THIS FILE IS TO BE MODIFIED BY ##\n");
printf ("## THE EASE TRANSLATOR (ET) ONLY. ##\n");
printf ("## ##\n");
printf ("## ALL OTHER MODIFICATIONS WILL ##\n");
printf ("## DISAPPEAR THE NEXT TIME ET IS RUN. ##\n");
printf ("## ##\n");
printf ("## MAKE MODIFICATIONS TO THE EASE ##\n");
printf ("## SOURCE ONLY. ##\n");
printf ("## ##\n");
printf ("###################################################\n");
}
SHAR_EOF
if test 3915 -ne "`wc -c main.c`"
then
echo shar: error transmitting main.c '(should have been 3915 characters)'
fi
cat << \SHAR_EOF > strops.c
/* $Header: /usr/src/local/etc/ease/RCS/strops.c,v 1.2 85/10/29 23:45:39 jss Exp $ */
/*
* strops.c -- Contains string operation routines used for constructing
* definitions in cf format.
*
* author -- James S. Schoner, Purdue University Computing Center,
* West Lafayette, Indiana 47907
*
* date -- July 9, 1985
*
* Copyright (c) 1985 by Purdue Research Foundation
*
* All rights reserved.
*
*/
#include <stdio.h>
#include <strings.h>
#include "symtab.h"
#define MAXTOKPOS 99 /* maximum number of token positions */
#define MAXNAME 1024 /* maximum length of an identifier */
extern struct he *LookupSymbol ();
extern char MakeMac ();
extern void FatalError (),
PrintError (),
ErrorReport ();
short Rformat = FALSE; /* class read format flag */
static char *Ptok = "$ "; /* positional token structure */
static char *Cfield = "$= "; /* class reference structure */
static char *Ofield = "$-"; /* one token match structure */
static char *Zfield = "$*"; /* zero or more tokens structure */
static char *Pfield = "$+"; /* one or more tokens structure */
static char *Mtest = "$? "; /* conditional macro test string */
/*
* ConvOpt () -- Convert an Ease option identifier (optid) by returning a
* string representation of the cf format.
*
*/
char *
ConvOpt (optid)
register enum opts optid;
{
switch (optid) {
case opt_A : return ("A");
case opt_a : return ("a");
case opt_B : return ("B");
case d_opt_b: return ("b");
case opt_c : return ("c");
case opt_D : return ("D");
case opt_d : return ("d");
case opt_e :
case e_opt_e: return ("e");
case opt_F : return ("F");
case opt_f : return ("f");
case opt_g : return ("g");
case opt_H : return ("H");
case opt_i :
case d_opt_i: return ("i");
case opt_L : return ("L");
case opt_m :
case e_opt_m: return ("m");
case opt_N : return ("N");
case opt_o : return ("o");
case e_opt_p: return ("p");
case opt_Q : return ("Q");
case d_opt_q: return ("q");
case opt_r : return ("r");
case opt_S : return ("S");
case opt_s : return ("s");
case opt_T : return ("T");
case opt_t : return ("t");
case opt_u : return ("u");
case opt_v : return ("v");
case opt_W : return ("W");
case e_opt_w: return ("w");
case opt_x : return ("x");
case opt_X : return ("X");
case e_opt_z: return ("z");
default : FatalError ("Bad case in ConvOpt ()", (char *) NULL);
}
/*NOTREACHED*/
}
/*
* ConvFlg () -- Convert an Ease mailer flag identifier (flgid) by
* string representation of the cf format.
*
*/
char *
ConvFlg (flgid)
register enum flgs flgid; /* flag identifier */
{
switch (flgid) {
case flg_f: return ("f");
case flg_r: return ("r");
case flg_S: return ("S");
case flg_n: return ("n");
case flg_l: return ("l");
case flg_s: return ("s");
case flg_m: return ("m");
case flg_F: return ("F");
case flg_D: return ("D");
case flg_M: return ("M");
case flg_x: return ("x");
case flg_P: return ("P");
case flg_u: return ("u");
case flg_h: return ("h");
case flg_A: return ("A");
case flg_U: return ("U");
case flg_e: return ("e");
case flg_X: return ("X");
case flg_L: return ("L");
case flg_p: return ("p");
case flg_I: return ("I");
case flg_C: return ("C");
default : FatalError ("Bad case in ConvFlg ()", (char *) NULL);
}
/*NOTREACHED*/
}
/*
* ConvMat () -- Convert an Ease mailer attribute (mat) by returning a
* string representation of the cf format.
*
*/
char *
ConvMat (mat)
register enum mats mat; /* mailer attribute flag */
{
switch (mat) {
case mat_path : return ("P");
case mat_flags : return ("F");
case mat_sender : return ("S");
case mat_recipient : return ("R");
case mat_argv : return ("A");
case mat_eol : return ("E");
case mat_maxsize : return ("M");
default : FatalError ("Bad case in ConvMat ()", (char *) NULL);
}
/*NOTREACHED*/
}
/*
* MacScan () -- Scan a string (pstring) for macros, replacing the Ease
* form with the one-character form required by cf format.
*
*/
char *
MacScan (pstring)
char *pstring; /* macro expandable string */
{
register char *searchptr; /* string search pointer */
register char *bptr, *eptr; /* macro begin and end pointers */
char macname [MAXNAME]; /* macro name buffer */
if ((searchptr = pstring) == NULL)
return ((char *) NULL);
while (*searchptr != '\0') /* find and rewrite all macros */
if (*searchptr == '\\') {
searchptr = searchptr + 2;
continue;
} else if (*searchptr++ == '$' && *searchptr == '{') {
if (sscanf (searchptr + 1, "%[^}]", macname) != 1) {
PrintError ("Invalid macro format:", searchptr + 1);
return ((char *) NULL);
}
*searchptr++ = MakeMac (LookupSymbol (macname), ID_MACRO);
bptr = eptr = searchptr;
while (*eptr++ != '}') /* delete old macro chars */
/* empty */ ;
do
*bptr++ = *eptr;
while (*eptr++ != '\0');
}
return (pstring);
}
/*
* MakeRStr () -- Construct and return a pointer to a class read string
* using the filename fname and read format rformat.
*
*/
char *
MakeRStr (fname, rformat)
char *fname, /* file name for class read */
*rformat; /* format for class read */
{
register char *res; /* resultant read string */
Rformat = TRUE; /* set read format flag */
if (rformat == NULL)
return (fname);
res = (char *) realloc (fname, strlen (fname) + strlen (rformat) + 2);
if (res == NULL)
FatalError ("System out of string space in MakeRStr ()", (char *) NULL);
res = strcat (res, " "); /* construct read string */
res = strcat (res, rformat);
free (rformat);
return (res);
}
/*
* ListAppend () -- Append string list2 to string list1 using the
* separator sep. A pointer to the newly constructed
* string is returned.
*
*/
char *
ListAppend (list1, list2, sep)
char *list1, /* first string */
*list2, /* second string */
*sep; /* string separator */
{
register char *res; /* resultant string */
res = (char *) malloc (strlen (list1) + strlen (list2) + strlen (sep) + 1);
if (res == NULL)
FatalError ("System out of string space in ListAppend ()", (char *) NULL);
res = strcpy (res, list1);
if (list1 != NULL) /* use separator if first string not null */
res = strcat (res, sep);
res = strcat (res, list2);
return (res);
}
/*
* MakeCond () -- Construct a macro conditional string in cf format. The
* conditional is based on the macro testmac, with an "if
* set" result ifstring, which may contain an optional
* "if not set" result string appended to it.
*
*/
char *
MakeCond (testmac, ifstring)
struct he *testmac; /* macro for conditional testing */
char *ifstring; /* "if macro set" result string(s) */
{
register char *res; /* resultant conditional string */
Mtest[2] = MakeMac (testmac, ID_MACRO); /* get one-char macro rep */
res = (char *) malloc (strlen (ifstring) + 6);
if (res == NULL)
FatalError ("System out of string space in MakeCond ()", (char *) NULL);
res = strcpy (res, Mtest);
res = strcat (res, ifstring); /* build result part */
res = strcat (res, "$."); /* end of conditional */
free (ifstring);
return (res);
}
/*
* MakePosTok () -- Construct and return a positional token string
* representation from the parameter num.
*
*/
char *
MakePosTok (num)
register int num; /* numerical value of positional token */
{
if (num > MAXTOKPOS) {
ErrorReport ("Positional token too large.\n");
return ((char *) NULL);
} else {
if (num > 9) { /* two-digit positional token */
Ptok[1] = '0' + (num / 10);
Ptok[2] = '0' + (num % 10);
Ptok[3] = '\0';
} else {
Ptok[1] = '0' + num;
Ptok[2] = '\0';
}
return (Ptok);
}
}
/*
* Bracket () -- Construct and return a cf string form of the
* canonicalization of the string identifier passed in
* the string parameter psb if dflag is true, else
* simply bracket the identifier without dollar signs
* for numeric hostname specifications.
*
*/
char *
Bracket (psb, dflag)
char *psb; /* identifier to be canonicalized */
short dflag; /* dollar flag */
{
register char *res; /* resultant cf form */
register short extra; /* extra space needed for malloc */
extra = dflag ? 5 : 3;
res = (char *) malloc (strlen (psb) + extra);
if (res == NULL)
FatalError ("System out of string space in Bracket ()", (char *) NULL);
if (dflag)
res = strcpy (res, "$[");
else
res = strcpy (res, "[");
res = strcat (res, psb);
if (dflag)
res = strcat (res, "$");
res = strcat (res, "]");
return (res);
}
/*
* MakeRSCall () -- Construct and return a cf string form of a call
* to a ruleset (cid), which would pass to it the
* remainder of a rewriting address (rwaddr).
*
*/
char *
MakeRSCall (cid, rwaddr)
register struct he *cid; /* called ruleset identifier */
register char *rwaddr; /* remainder of rewriting address */
{
register char *res; /* resultant cf string for the call */
if (!ISRULESET(cid->idtype)) { /* check validity of ruleset */
PrintError ("Undefined ruleset identifier:", cid->psb);
return ((char *) NULL);
}
res = (char *) malloc (strlen (cid->idval.rsn) + strlen (rwaddr) + 3);
if (res == NULL)
FatalError ("System out of string space in MakeRSCall ()", (char *) NULL);
res = strcpy (res, "$>"); /* construct the call string */
res = strcat (res, cid->idval.rsn);
res = strcat (res, rwaddr);
return (res);
}
/*
* MakeField () -- Construct and return the cf string format for a
* field variable. The match count (count), an optional
* class (class), and a match repetition flag (fstar)
* are used to determine what type of field string to
* construct.
*
*/
char *
MakeField (count, class, fstar)
register int count; /* match count (0 or 1) */
register struct he *class; /* optional class type */
register short fstar; /* repetition flag */
{
switch (count) {
case 0: if (class == NULL) /* any token is valid */
if (fstar)
return (Zfield);
else {
ErrorReport ("Invalid field type.\n");
return ((char *) NULL);
}
else { /* match 0 from class */
Cfield[1] = '~';
Cfield[2] = MakeMac (class, ID_CLASS);
return (Cfield);
}
case 1: if (class == NULL) /* any token is valid */
if (fstar)
return (Pfield);
else
return (Ofield);
else { /* match 1 from class */
Cfield[1] = '=';
Cfield[2] = MakeMac (class, ID_CLASS);
return (Cfield);
}
default: ErrorReport ("Invalid field type.\n");
}
/*NOTREACHED*/
}
SHAR_EOF
if test 10730 -ne "`wc -c strops.c`"
then
echo shar: error transmitting strops.c '(should have been 10730 characters)'
fi
cat << \SHAR_EOF > symtab.c
/* $Header: /usr/src/local/etc/ease/RCS/symtab.c,v 1.2 85/10/29 23:46:48 jss Exp $ */
/*
* symtab.c -- Contains Ease Translator symbol table routines.
*
* author -- James S. Schoner, Purdue University Computing Center,
* West Lafayette, Indiana 47907
*
* date -- July 9, 1985
*
* Copyright (c) 1985 by Purdue Research Foundation
*
* All rights reserved.
*
*/
#include <stdio.h>
#include <ctype.h>
#include "symtab.h"
#define ERRORMAILER "error" /* predefined error mailer name */
extern void FatalError (),
PrintWarning ();
struct he *LookupSymbol ();
struct Defmac { /* predefined macro struct def */
char *macname;
char macrep;
};
struct he *SymTab[SST]; /* hash table base array */
static struct Defmac MacDefs[] = { /* predefined macros */
{"m_smtp", 'e'},
{"m_oname", 'j'},
{"m_ufrom", 'l'},
{"m_daemon", 'n'},
{"m_addrops", 'o'},
{"m_defaddr", 'q'},
{"m_sitename", 'w'},
{"m_odate", 'a'},
{"m_adate", 'b'},
{"m_hops", 'c'},
{"m_udate", 'd'},
{"m_saddr", 'f'},
{"m_sreladdr", 'g'},
{"m_rhost", 'h'},
{"m_qid", 'i'},
{"m_pid", 'p'},
{"m_protocol", 'r'},
{"m_shostname", 's'},
{"m_ctime", 't'},
{"m_ruser", 'u'},
{"m_version", 'v'},
{"m_sname", 'x'},
{"m_stty", 'y'},
{"m_rhdir", 'z'},
{"sentinel", '\0'}
};
/*
* DefScan () -- Scan symbol table to find macros, classes, mailers,
* and rulesets which have been referenced or declared, but
* not defined. A warning is printed for each such
* occurence. This routine is usually called at the end
* of a successful Ease translation.
*
*/
void
DefScan ()
{
register int stindex; /* symbol table hash index */
register struct he *hcsearch; /* hash chain search pointer */
for (stindex = 0; stindex < SST; stindex++) {
if ((hcsearch = SymTab[stindex]) != NULL)
while (hcsearch != NULL) {
if ((ISMACRO(hcsearch->idtype) &&
isupper(hcsearch->idval.idc)) &&
!ISMACRO(hcsearch->idd))
PrintWarning ("Macro not defined: %s\n", hcsearch->psb);
if (ISCLASS(hcsearch->idtype) && !ISCLASS(hcsearch->idd))
PrintWarning ("Class not defined: %s\n", hcsearch->psb);
if (ISMAILER(hcsearch->idtype) && !ISMAILER(hcsearch->idd))
PrintWarning ("Mailer not defined: %s\n", hcsearch->psb);
if (ISRULESET(hcsearch->idtype) && !ISRULESET(hcsearch->idd))
PrintWarning ("Ruleset not defined: %s\n", hcsearch->psb);
hcsearch = hcsearch->phe;
}
}
}
/*
* InitSymbolTable () -- Invoked by main () to initialize the symbol table.
*
*/
void
InitSymbolTable ()
{
int i;
for (i = 0; i < SST; i++) /* initialize base array */
SymTab[i] = NULL;
}
/*
* PreLoad () -- Invoked by main () to preload special macro names
* and mailer declarations.
*
*/
void
PreLoad ()
{
struct Defmac *macptr;
struct he *symptr;
/* preload special (lower-case) macros */
for (macptr = &MacDefs[0]; (*macptr).macrep != '\0'; macptr++) {
symptr = LookupSymbol ((*macptr).macname);
symptr->idtype |= ID_MACRO;
symptr->idval.idc = (*macptr).macrep;
}
/* preload error mailer declaration */
symptr = LookupSymbol (ERRORMAILER);
symptr->idtype |= ID_MAILER;
symptr->idd |= ID_MAILER;
}
/*
* LookupSymbol () -- Returns a pointer to the hash entry already
* existing, or newly created, which corresponds
* to string sb.
*
*/
struct he *
LookupSymbol (sb)
char sb[]; /* string buffer containing identifier */
{
struct he *phe; /* hash entry search pointer */
int hc; /* hash code of sb identifier */
phe = SymTab[hc = HashCode (sb)];
while (phe != NULL) /* find hash entry for sb */
if (!strcmp (phe->psb, sb))
return (phe);
else
phe = phe->phe;
/* make new symbol table entry */
if ((phe = (struct he *) malloc (sizeof (struct he))) == NULL)
FatalError ("System out of space in LookupSymbol ()", (char *) NULL);
if ((phe->psb = (char *) malloc (strlen (sb) + 1)) == NULL)
FatalError ("System out of space in LookupSymbol ()", (char *) NULL);
strcpy (phe->psb, sb);
phe->idval.idc = '\0';
phe->idtype = ID_UNTYPED;
phe->idd = ID_UNTYPED;
phe->phe = SymTab[hc];
return (SymTab[hc] = phe);
}
/*
* RemoveSymbol () -- Removes the symbol table entry phe from the
* symbol table.
*
*/
void
RemoveSymbol (phe)
struct he *phe; /* pointer to hash entry to be removed from symbol table */
{
int hc; /* hash code of entry phe */
struct he *sphe; /* search pointer for entry phe */
if (phe == NULL)
return;
else { /* search and remove entry phe */
sphe = SymTab[hc = HashCode (phe->psb)];
free (phe->psb);
if (sphe == phe)
SymTab[hc] = phe->phe;
else
while (sphe != NULL)
if (sphe->phe == phe) {
sphe->phe = phe->phe;
return;
} else
sphe = sphe->phe;
}
}
/*
* HashCode () -- Returns the hash code of the string in sb by adding
* the character values and applying mod by the hash
* table size.
*
*/
int
HashCode (sb)
char sb[];
{
int ccSum = 0; /* sum of char values in string sb */
int i;
for (i = 0; sb[i]; i++) /* add char codes for sb chars */
ccSum += sb[i];
return (ccSum % SST); /* return sum mod table size */
}
SHAR_EOF
if test 5288 -ne "`wc -c symtab.c`"
then
echo shar: error transmitting symtab.c '(should have been 5288 characters)'
fi
cat << \SHAR_EOF > lexan.l
%{
/* $Header: /usr/src/local/etc/ease/RCS/lexan.l,v 1.2 85/10/29 23:42:40 jss Exp $ */
/*
* lexan.l -- Lexical Analyzer for EASE.
*
* Contains code for lex(1) which generates a lexical
* analyzer (lex.yy.c) for Ease, a high-level specification
* format for sendmail configuration files.
*
* author -- James S. Schoner, Purdue University Computing Center,
* West Lafayette, Indiana 47907
*
* date -- July 1, 1985
*
* Copyright (c) 1985 by Purdue Research Foundation
*
* All rights reserved.
*
*/
#include "symtab.h"
#include "lexdefs.h"
#define LEXnewline '\n'
#define LEXeof '\0'
#define MaxFN 200 /* maximum file name length */
extern struct he *LookupSymbol ();
extern void ErrorReport ();
int Lcount; /* line counter */
char FNbuf[MaxFN]; /* file name buffer */
short RMatch = FALSE; /* ruleset match flag */
%}
/* lex-specific extensions */
%e 1100
%p 3700
%n 500
%%
int INch; /* any input character */
[ \t\f]+ ; /* discard whitepsace */
[\n] Lcount++;
^\#[ \t]*[0-9]+[ \t]*\".*\"[ \t]*$ {
sscanf (yytext, "%*c%d%s", &Lcount, FNbuf);
INch = input ();
}
match return (MATCH);
in return (IN);
bind return (BIND);
define return (DEFINE);
macro return (MACRO);
class return (CLASS);
options return (OPTIONS);
precedence return (PRECEDENCE);
trusted return (TRUSTED);
header return (HEADER);
ruleset return (RULESET);
mailer return (MAILER);
host return (HOST);
user return (USER);
hostnum return (HOSTNUM);
if return (IF);
retry return (RETRY);
next return (NEXT);
return return (RETURN);
resolve return (RESOLVE);
for return (FOR);
field return (FIELD);
concat return (CONCAT);
ifset return (IFSET);
canon return (CANON);
readclass return (READCLASS);
Path return (MPATH);
Flags return (MFLAGS);
Sender return (MSENDER);
Recipient return (MRECIPIENT);
Argv return (MARGV);
Eol return (MEOL);
Maxsize return (MMAXSIZE);
o_alias return (AAOPT);
o_ewait return (AOPT);
o_bsub return (BBOPT);
o_qwait return (COPT);
o_delivery return (DOPT);
d_interactive return (DOPTI);
d_background return (DOPTB);
d_queue return (DOPTQ);
o_rebuild return (DDOPT);
o_handling return (EOPT);
h_print return (EOPTP);
h_exit return (EOPTE);
h_mail return (EOPTM);
h_write return (EOPTW);
h_mailz return (EOPTZ);
o_tmode return (FFOPT);
o_usave return (FOPT);
o_gid return (GOPT);
o_fsmtp return (HHOPT);
o_skipd return (IOPT);
o_slog return (LLOPT);
o_rsend return (MOPT);
o_dnet return (NNOPT);
o_hformat return (OOPT);
o_qdir return (QQOPT);
o_tread return (ROPT);
o_flog return (SSOPT);
o_safe return (SOPT);
o_qtimeout return (TTOPT);
o_timezone return (TOPT);
o_dmuid return (UOPT);
o_verbose return (VOPT);
o_wizpass return (WWOPT);
o_loadq return (XOPT);
o_loadnc return (XXOPT);
f_ffrom return (FFLAG);
f_rfrom return (RFLAG);
f_noreset return (SSFLAG);
f_noufrom return (NFLAG);
f_locm return (LFLAG);
f_strip return (SFLAG);
f_mult return (MFLAG);
f_from return (FFFLAG);
f_date return (DDFLAG);
f_mesg return (MMFLAG);
f_full return (XFLAG);
f_return return (PPFLAG);
f_upperu return (UFLAG);
f_upperh return (HFLAG);
f_arpa return (AAFLAG);
f_ufrom return (UUFLAG);
f_expensive return (EFLAG);
f_dot return (XXFLAG);
f_llimit return (LLFLAG);
f_retsmtp return (PFLAG);
f_smtp return (IIFLAG);
f_addrw return (CCFLAG);
[A-Za-z][A-Za-z0-9_-]* {
/* store identifiers in symbol table */
yylval.phe = LookupSymbol (yytext);
return (IDENT);
}
["]((\\\n)|(\\\")|[^"\n])* {
if ((INch = input()) == LEXnewline) {
ErrorReport ("End of line in string.\n");
unput (INch);
}
yylval.psb = (char *) malloc (strlen (yytext) + 1);
strcpy (yylval.psb, yytext + 1);
return (SCONST);
}
[0][0-7]* {
sscanf (yytext, "%o", &yylval.ival); /* octal constant */
return (ICONST);
}
[-]?[1-9][0-9]* {
yylval.ival = atoi (yytext);
return (ICONST);
}
"=" return (ASGN);
"," return (COMMA);
"{" return (LBRACE);
"}" return (RBRACE);
"(" return (LPAREN);
")" return (RPAREN);
";" return (SEMI);
"$" return (DOLLAR);
":" return (COLON);
"*" return (STAR);
"/*" {
/* eat C comments */
INch = input ();
while ((INch != '*') ||
((INch = input ()) != '/')) {
if (INch == LEXnewline)
Lcount++;
else
if (INch == LEXeof) {
ErrorReport ("End of file in comment.\n");
break;
}
if (INch != '*')
INch = input ();
}
}
[\\]?. {
if (RMatch) { /* in rulesets, return literal character */
yylval.ival = (yytext[0] == '\\') ? yytext[1] : yytext[0];
return (SEPCHAR);
} else {
ErrorReport ("Illegal delimiter character");
printf (": (octal code) \\%03o\n", *yytext);
}
}
%%
SHAR_EOF
if test 5031 -ne "`wc -c lexan.l`"
then
echo shar: error transmitting lexan.l '(should have been 5031 characters)'
fi
cat << \SHAR_EOF > symtab.h
/* $Header: /usr/src/local/etc/ease/RCS/symtab.h,v 1.2 85/10/29 23:47:47 jss Exp $ */
/*
* symtab.h -- Definitions related to the "et" symbol table.
*
* author -- James S. Schoner, Purdue University Computing Center,
* West Lafayette, Indiana 47907
*
* date -- July 1, 1985
*
* Copyright (c) 1985 by Purdue Research Foundation
*
* All rights reserved.
*
*/
#define TRUE 1
#define FALSE 0
#define SST 101 /* size of hash table (symbol table) */
#define RSNMAX 5 /* size of a ruleset number character buffer */
#define VALRSNMAX 9999 /* max value of ruleset number */
/* identifier types */
#define ID_UNTYPED 0
#define ID_MACRO 01
#define ID_CLASS 02
#define ID_RULESET 04
#define ID_FIELD 010
#define ID_PREC 020
#define ID_MAILER 040
/* identifier type macros */
#define ISTYPED(x) (x|ID_UNTYPED)
#define ISMACRO(x) (x&ID_MACRO)
#define ISCLASS(x) (x&ID_CLASS)
#define ISRULESET(x) (x&ID_RULESET)
#define ISFIELD(x) (x&ID_FIELD)
#define ISPREC(x) (x&ID_PREC)
#define ISMAILER(x) (x&ID_MAILER)
/* block definition types */
enum bdefs {def_macro, def_class, def_option, def_prec, def_trusted,
def_header, def_mailer, def_ruleset};
/* option types */
enum opts {opt_A, opt_a, opt_B, opt_c, opt_D, opt_d, opt_e, opt_F, opt_f,
opt_g, opt_H, opt_i, opt_L, opt_m, opt_N, opt_o, opt_Q, opt_r,
opt_S, opt_s, opt_T, opt_t, opt_u, opt_v, opt_W, opt_x, opt_X,
d_opt_i, d_opt_b, d_opt_q,
e_opt_p, e_opt_e, e_opt_m, e_opt_w, e_opt_z};
/* flag types */
enum flgs {flg_f, flg_r, flg_S, flg_n, flg_l, flg_s, flg_m, flg_F, flg_D,
flg_M, flg_x, flg_P, flg_u, flg_h, flg_A, flg_U, flg_e, flg_X,
flg_L, flg_p, flg_I, flg_C};
/* mailer parameters */
enum mats {mat_path, mat_flags, mat_sender, mat_recipient, mat_argv,
mat_eol, mat_maxsize};
struct he { /* hash entry structure for symbol table node */
unsigned idtype; /* identifier type */
unsigned idd; /* identifier definition flag */
char *psb; /* identifier string buffer */
union {
char rsn[RSNMAX]; /* ruleset number */
int prec; /* precedence value */
char idc; /* one char id representation */
char *fstring; /* field string */
} idval;
struct he *phe; /* next hash entry */
};
SHAR_EOF
if test 2309 -ne "`wc -c symtab.h`"
then
echo shar: error transmitting symtab.h '(should have been 2309 characters)'
fi
cat << \SHAR_EOF > Makefile
# Makefile for Ease Translator (et).
#
# $Header: /usr/src/local/etc/ease/RCS/Makefile,v 1.4 85/10/29 22:57:06 jss Exp $
#
# James S. Schoner, Purdue University Computing Center,
# West Lafayette, Indiana 47907
#
# Copyright (c) 1985 by Purdue Research Foundation
#
# All rights reserved.
#
INCLUDE =
DEST = /usr/local/etc
OWNER = binary
GROUP = system
MODE = 751
DEFS =
CFLAGS = -O ${DEFS} ${INCLUDE}
LP = lpr
LPFLAGS = -J"Ease Source"
HDR = symtab.h
SRC = main.c emitcf.c errors.c idman.c strops.c symtab.c
LST = Makefile lexan.l parser.y ${HDR} ${SRC}
DEP = y.tab.c lex.yy.c ${SRC}
OBJ = y.tab.o lex.yy.o main.o emitcf.o errors.o idman.o strops.o symtab.o
all: et
et: ${OBJ}
cc ${CFLAGS} -o et ${OBJ} -ll
clean: FRC
rm -f et *.o lex.yy.c y.tab.c y.output yacc.acts yacc.tmp \
lexdefs.h y.tab.h errs Makefile.bak
depend: ${DEP} ${HDR}
maketd -a ${DEP}
install: et FRC
install -c -m ${MODE} -o ${OWNER} -g ${GROUP} -s et ${DEST}
lint: ${DEP} symtab.h FRC
lint -hxn ${DEP}
print: ${LST} FRC
@pr -f ${LST} | ${LP} ${LPFLAGS}
spotless: clean FRC
rcsclean ${LST}
lexdefs.h y.tab.c: parser.y
yacc -d parser.y
-(cmp -s y.tab.h lexdefs.h || cp y.tab.h lexdefs.h)
lex.yy.c: lexan.l
lex lexan.l
${HDR} ${SRC} lexan.l parser.y:
co $@
FRC:
# DO NOT DELETE THIS LINE - maketd DEPENDS ON IT
# Dependencies generated at: Thu Oct 17 14:55:17 EST 1985
emitcf.o: symtab.h
emitcf.o: /usr/include/stdio.h
emitcf.o: emitcf.c
errors.o: /usr/include/stdio.h
errors.o: errors.c
idman.o: symtab.h
idman.o: /usr/include/stdio.h
idman.o: idman.c
lex.yy.o: lexdefs.h
lex.yy.o: symtab.h
lex.yy.o: /usr/include/stdio.h
lex.yy.o: lex.yy.c
main.o: /usr/include/stdio.h
main.o: main.c
strops.o: symtab.h
strops.o: /usr/include/stdio.h
strops.o: /usr/include/strings.h
strops.o: strops.c
symtab.o: symtab.h
symtab.o: /usr/include/ctype.h
symtab.o: /usr/include/stdio.h
symtab.o: symtab.c
y.tab.o: symtab.h
y.tab.o: /usr/include/stdio.h
y.tab.o: y.tab.c
# DO NOT ADD ANYTHING HERE - it will go away.
SHAR_EOF
if test 2016 -ne "`wc -c Makefile`"
then
echo shar: error transmitting Makefile '(should have been 2016 characters)'
fi
chdir ..
# End of shell archive
exit 0
More information about the Mod.sources
mailing list