|
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); }