|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T m
Length: 11118 (0x2b6e)
Types: TextFile
Names: »make-lists.c«
└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
└─⟦dc59850a2⟧ »EurOpenD22/pp5.0/pp-5.tar.Z«
└─⟦e5a54fb17⟧
└─⟦this⟧ »pp-5.0/Tools/make-lists/make-lists.c«
/* make-lists.c: */
# ifndef lint
static char Rcsid[] = "@(#)$Header: /cs/research/pp/hubris/pp-beta/Tools/make-lists/RCS/make-lists.c,v 5.0 90/09/20 16:26:39 pp Exp Locker: pp $";
# endif
/*
* $Header: /cs/research/pp/hubris/pp-beta/Tools/make-lists/RCS/make-lists.c,v 5.0 90/09/20 16:26:39 pp Exp Locker: pp $
*
* $Log: make-lists.c,v $
* Revision 5.0 90/09/20 16:26:39 pp
* rcsforce : 5.0 public release
*
*/
/*
*
* Reads usernames aliases file, and creates quipu distribution list
* channel files.
*
* Usage:
*
* make-lists input channel-file list-directory
*
* A line starting with '#' is a comment. Else, a line containg both
* ':' and ',' is assumed to be the first line of a list; it continues
* while succeeding lines start with whitespace.
*
* Note that the list directory must be in a form suitable for
* prefixing directly a filename (ie ends in / on unix, or is like
* [zxc] or thing: on VMS), this name is placed into the channel-file.
*
* (nb vms/unix compatible, mainly so I can debug with a *decent* debugger.
* It'll only be run 'in anger' on un*x) (M.A.Scott)
*
*
* Modified, fairly extensively A.Macpherson.
*
*/
static char sccsid[] = { "%W%\t-\t%E%\tSTL\n" };
#include <stdio.h>
extern char *malloc();
extern char *realloc();
extern char *strchr(), *strrchr();
extern char *strcpy();
static int readline ();
static int addusers ();
static void panic ();
#define MAXMODERATOR 6
struct list {
struct list *next; /* link pointer */
struct list *left; /* other link */
char *list_name; /* name of the list (eg "200") */
char *users; /* points to '\n' separated record of users */
int users_alloc; /* currently allocated space INCLUDING the
* '\0' */
int users_used; /* currently used space including the null */
char *moderator[MAXMODERATOR]; /* list-request person(s) */
};
#define USERS_INCR 512 /* increment for 'users' area */
static struct list *list_pointer;
#ifndef BUFSIZ
# define BUFSIZ 255 /* input line length allowed */
#endif
#ifdef VMS
# define ERROR (USER_FATAL|USER_INHIBIT)
# define OK USER_SUCCESS
# include <misc.h>
#else
# define ERROR 1
# define OK 0
# define EOS '\0'
#endif
#define FIRST 0
#define CONTIN 1
static struct list *get_list();
static void write_tables();
static int trim();
static int analyse_first();
static int analyse_contin();
static int analyse_request();
static char *
mymalloc(n)
int n;
{
char *p = malloc((unsigned) n);
if (p == 0) {
perror("mymalloc");
exit(ERROR);
}
return p;
}
main(argc, argv)
int argc;
char *argv[];
{
FILE *input;
static char buffer[BUFSIZ + 1];
int state;
struct list *current = 0;
if (argc != 4) {
(void) printf("usage: %s input-file channel-table dislist-directory\n",
argv[0]);
exit(ERROR);
}
input = fopen(argv[1], "r");
if (input == 0) {
perror("cannot read input");
exit(ERROR);
}
/* read entire input file.... */
state = FIRST;
while (readline(buffer, BUFSIZ, input) != EOF) {
if (buffer[0] == '#' || buffer[0] == '\0')
continue; /* comment line */
switch (state) {
case FIRST:
if (buffer[0] == ' ') {
(void) printf("unexpected continuation line - ignored!\n%s\n", buffer);
continue;
}
trim(buffer);
/*
* it's not an error if it's not a list, but we need to check for a
* request line
*/
if (analyse_request(buffer, current))
break;
if (analyse_first(buffer, ¤t))
state = CONTIN;
break;
case CONTIN:
if (!analyse_contin(buffer, current))
state = FIRST;
break;
default:
panic();
break;
}
}
(void) fclose(input);
write_tables(argv[2], argv[3]);
}
/* returns 1 if user list end in ',' else 0 */
static int analyse_first(buffer, current_pointer)
char *buffer;
struct list **current_pointer;
{
struct list *p;
char *rest;
int i;
/* get dis list name */
rest = strchr(buffer, ':');
if (rest == 0)
panic();
*rest++ = EOS;
p = get_list(buffer);
*current_pointer = p;
return addusers(rest, p); /* and user list */
}
/* returns 1 if user list end in ',' else 0 */
static int
analyse_contin(buffer, current_pointer)
char *buffer;
struct list *current_pointer;
{
if ((strchr(buffer, ':') != 0) || (buffer[0] != ' ')) {
(void) printf("continuation line of list expected - ignored!\n%s\n",
buffer);
return 0;
}
trim(buffer);
return addusers(buffer, current_pointer);
}
/*
* check for a -request, ie moderator, line. This is assumed to occur after
* the list is defined. Duplicate moderators are appended, up to a maximum.
*/
static
analyse_request(buffer, current_pointer)
char *buffer;
struct list *current_pointer;
{
char *moderator = strchr(buffer, ':');
char *dash;
char *at;
struct list *p = current_pointer;
int i;
if (moderator == 0)
return(0);
*moderator++ = EOS;
dash = strrchr(buffer, '-');
if (dash == 0 || strncmp(dash + 1, "request", 7) != 0) {
*--moderator = ':';
return(0);
}
*dash = EOS; /* buffer now points to list name */
/*
* good chance current list is the one! If not, scan whole list.
*/
if ((p == 0) || strcmp(p->list_name, buffer) != 0)
p = get_list(buffer);
for (i = 0; i < MAXMODERATOR; ++i) {
if (dash = strchr(moderator, ','))
*dash++ = EOS;
if (p->moderator[i] == 0)
p->moderator[i] = mymalloc(strlen(moderator) + 1);
at = strchr(moderator, '@');
if (at != 0)
*at = EOS;
(void) strcpy(p->moderator[i], moderator);
if (dash)
moderator = dash;
else
break;
}
if (i >= MAXMODERATOR)
(void) printf("too many moderators for list %s: %s ignored!\n",
buffer, moderator);
return(1);
}
static void
write_tables(channel_file, table_dir)
char *channel_file, *table_dir;
{
struct list *p;
FILE *fch;
void inorder_lists();
fch = fopen(channel_file, "w");
if (fch == 0) {
(void) printf("channel file open error\n");
perror(channel_file);
exit(ERROR);
}
if (chdir(table_dir) != 0) {
(void) printf("list directory error\n");
perror(table_dir);
unlink(channel_file);
exit(ERROR);
}
inorder_lists(list_pointer, fch, table_dir);
if (ferror(fch) != 0 || (fclose(fch) != 0)) {
(void) printf("channel file write error\n");
perror(channel_file);
exit(ERROR);
};
}
char modbuff[BUFSIZ];
void
inorder_lists(p, fch, table_dir)
struct list *p;
FILE *fch;
char *table_dir;
{
FILE *flist;
int i;
if (!p)
return;
inorder_lists(p->next, fch, table_dir);
if (p->moderator[0] || strchr(p->users, '\n') != (char *)0) {
flist = fopen(p->list_name, "w");
if (flist == 0) {
(void) printf("list file open error\n");
perror(p->list_name);
exit(ERROR);
}
/*
* there's a bug in printf in VMS C, at least for old versions, for >512
* chars output at once, so...
*/
#ifdef VMS
{
char *c;
for (c = p->users; *c != EOS; ++c)
fputc(*c, flist);
fputc('\n', flist);
}
#else
(void) fputs(p->users, flist);
(void) fputc('\n', flist);
#endif
if (ferror(flist) != 0 || (fclose(flist) != 0)) {
(void) printf("list file write error\n");
perror(p->list_name);
exit(ERROR);
}
(void) fprintf(fch, "%s:%s", /* listname */
p->list_name,
p->moderator[0] != 0 ? p->moderator[0]: "postmaster");
for (i = 1; i < MAXMODERATOR && p->moderator[i] != 0; ++i)
(void) fprintf(fch, "|%s", p->moderator[i]);
(void) fprintf(fch, ",file=%s%s,%s\n",
table_dir, p->list_name,
p->list_name); /* filename, description */
strcpy(modbuff, p->list_name);
strcat(modbuff, "-request");
if ( p->moderator[0] == 0 || strcmp(modbuff, p->moderator[0])) {
(void) fprintf(fch, "%s-request:postmaster,%s", p->list_name,
p->moderator[0] != 0 ? p->moderator[0]: "postmaster");
for (i = 1; i < MAXMODERATOR && p->moderator[i] != 0; ++i)
(void) fprintf(fch, "|%s", p->moderator[i]);
(void) fprintf(fch, ",Moderators for list %s\n",
p->list_name); /* filename, description */
}
}
inorder_lists(p->left, fch, table_dir);
}
/* remove blanks from string in place */
static int
trim(s)
char *s;
{
char *t;
for (t = s; *s != EOS; ++s)
if (*s != ' ' && *s != '\t')
*t++ = *s;
*t++ = EOS;
return;
}
/* add users to list, converting ',' to '\n',and increasing space as needed */
/* returns 1 if a trailing comma found, else 0 */
static int
addusers(users, p)
char *users;
struct list *p;
{
int l = strlen(users);
char *s;
int comma;
/* get enough space and some more */
if (p->users_used + l > p->users_alloc) {
p->users = realloc(p->users, (unsigned) (p->users_alloc + l + USERS_INCR));
if (p->users == 0) {
(void) printf("out of memory!\n");
exit(ERROR);
}
p->users_alloc += (l + USERS_INCR);
}
/* copy across list */
comma = 0;
for (s = p->users + p->users_used - 1; *users != EOS; ++s, ++users)
if (comma = (*users == ','))
*s = '\n';
else
*s = *users;
p->users_used += l;
return comma;
}
static int
readline(buffer, len, input)
char *buffer;
int len;
FILE *input;
{
int i;
if (fgets(buffer, len, input) == 0) {
if (!feof(input)) {
perror("read error");
exit(ERROR);
} else
return EOF;
}
i = strlen(buffer);
if (buffer[i - 1] != '\n')
(void) printf("line too long (data may be lost):\n%s\n", buffer);
else
buffer[i - 1] = EOS;
return 0;
}
static void panic()
{
(void) printf("internal error!!\n");
exit(ERROR);
}
static struct list *
get_list(name)
char *name;
{
register struct list **p;
int lr;
/* Double de-reference so only one pointer needed, and
the empty tree is not a special case */
for (p = &list_pointer; *p != 0; ) {
if ((lr = strcmp((*p)->list_name, name)) == 0){
return(*p);
}
p = (lr > 0) ? &(*p)->next : &(*p)->left;
}
/* grab some store and init it... */
*p = (struct list *) mymalloc(sizeof(struct list));
(*p)->users = mymalloc(USERS_INCR + 1);
(*p)->users[0] = EOS;
(*p)->users_alloc = USERS_INCR + 1;
(*p)->users_used = 1; /* the EOS */
for (lr = 0; lr < MAXMODERATOR; ++lr)
(*p)->moderator[lr] = 0;
(*p)->next = (struct list *) 0;
(*p)->left = (struct list *) 0;
(*p)->list_name = mymalloc(strlen(name) + 1);
(void) strcpy((*p)->list_name, name); /* copy list name */
return (*p);
}