diff options
| author | rsc <devnull@localhost> | 2005-10-29 16:26:44 +0000 |
|---|---|---|
| committer | rsc <devnull@localhost> | 2005-10-29 16:26:44 +0000 |
| commit | 5cdb17983ae6e6367ad7a940cb219eab247a9304 (patch) | |
| tree | 8ca1ef49af2a96e7daebe624d91fdf679814a057 /src/cmd/upas/send/dest.c | |
| parent | cd3745196389579fb78b9b01ef1daefb5a57aa71 (diff) | |
| download | plan9port-5cdb17983ae6e6367ad7a940cb219eab247a9304.tar.gz plan9port-5cdb17983ae6e6367ad7a940cb219eab247a9304.zip | |
Thanks to John Cummings.
Diffstat (limited to 'src/cmd/upas/send/dest.c')
| -rw-r--r-- | src/cmd/upas/send/dest.c | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/src/cmd/upas/send/dest.c b/src/cmd/upas/send/dest.c new file mode 100644 index 00000000..fa538547 --- /dev/null +++ b/src/cmd/upas/send/dest.c @@ -0,0 +1,260 @@ +#include "common.h" +#include "send.h" + +static String* s_parseq(String*, String*); + +/* exports */ +dest *dlist; + +extern dest* +d_new(String *addr) +{ + dest *dp; + + dp = (dest *)mallocz(sizeof(dest), 1); + if (dp == 0) { + perror("d_new"); + exit(1); + } + dp->same = dp; + dp->nsame = 1; + dp->nchar = 0; + dp->next = dp; + dp->addr = escapespecial(addr); + dp->parent = 0; + dp->repl1 = dp->repl2 = 0; + dp->status = d_undefined; + return dp; +} + +extern void +d_free(dest *dp) +{ + if (dp != 0) { + s_free(dp->addr); + s_free(dp->repl1); + s_free(dp->repl2); + free((char *)dp); + } +} + +/* The following routines manipulate an ordered list of items. Insertions + * are always to the end of the list. Deletions are from the beginning. + * + * The list are circular witht the `head' of the list being the last item + * added. + */ + +/* Get first element from a circular list linked via 'next'. */ +extern dest * +d_rm(dest **listp) +{ + dest *dp; + + if (*listp == 0) + return 0; + dp = (*listp)->next; + if (dp == *listp) + *listp = 0; + else + (*listp)->next = dp->next; + dp->next = dp; + return dp; +} + +/* Insert a new entry at the end of the list linked via 'next'. */ +extern void +d_insert(dest **listp, dest *new) +{ + dest *head; + + if (*listp == 0) { + *listp = new; + return; + } + if (new == 0) + return; + head = new->next; + new->next = (*listp)->next; + (*listp)->next = head; + *listp = new; + return; +} + +/* Get first element from a circular list linked via 'same'. */ +extern dest * +d_rm_same(dest **listp) +{ + dest *dp; + + if (*listp == 0) + return 0; + dp = (*listp)->same; + if (dp == *listp) + *listp = 0; + else + (*listp)->same = dp->same; + dp->same = dp; + return dp; +} + +/* Look for a duplicate on the same list */ +int +d_same_dup(dest *dp, dest *new) +{ + dest *first = dp; + + if(new->repl2 == 0) + return 1; + do { + if(strcmp(s_to_c(dp->repl2), s_to_c(new->repl2))==0) + return 1; + dp = dp->same; + } while(dp != first); + return 0; +} + +/* Insert an entry into the corresponding list linked by 'same'. Note that + * the basic structure is a list of lists. + */ +extern void +d_same_insert(dest **listp, dest *new) +{ + dest *dp; + int len; + + if(new->status == d_pipe || new->status == d_cat) { + len = new->repl2 ? strlen(s_to_c(new->repl2)) : 0; + if(*listp != 0){ + dp = (*listp)->next; + do { + if(dp->status == new->status + && strcmp(s_to_c(dp->repl1), s_to_c(new->repl1))==0){ + /* remove duplicates */ + if(d_same_dup(dp, new)) + return; + /* add to chain if chain small enough */ + if(dp->nsame < MAXSAME + && dp->nchar + len < MAXSAMECHAR){ + new->same = dp->same; + dp->same = new; + dp->nchar += len + 1; + dp->nsame++; + return; + } + } + dp = dp->next; + } while (dp != (*listp)->next); + } + new->nchar = strlen(s_to_c(new->repl1)) + len + 1; + } + new->next = new; + d_insert(listp, new); +} + +/* + * Form a To: if multiple destinations. + * The local! and !local! checks are artificial intelligence, + * there should be a better way. + */ +extern String* +d_to(dest *list) +{ + dest *np, *sp; + String *s; + int i, n; + char *cp; + + s = s_new(); + s_append(s, "To: "); + np = list; + i = n = 0; + do { + np = np->next; + sp = np; + do { + sp = sp->same; + cp = s_to_c(sp->addr); + + /* hack to get local! out of the names */ + if(strncmp(cp, "local!", 6) == 0) + cp += 6; + + if(n > 20){ /* 20 to appease mailers complaining about long lines */ + s_append(s, "\n\t"); + n = 0; + } + if(i != 0){ + s_append(s, ", "); + n += 2; + } + s_append(s, cp); + n += strlen(cp); + i++; + } while(sp != np); + } while(np != list); + + return unescapespecial(s); +} + +/* expand a String of destinations into a linked list of destiniations */ +extern dest * +s_to_dest(String *sp, dest *parent) +{ + String *addr; + dest *list=0; + dest *new; + + if (sp == 0) + return 0; + addr = s_new(); + while (s_parseq(sp, addr)!=0) { + addr = escapespecial(addr); + if(shellchars(s_to_c(addr))){ + while(new = d_rm(&list)) + d_free(new); + break; + } + new = d_new(addr); + new->parent = parent; + new->authorized = parent->authorized; + d_insert(&list, new); + addr = s_new(); + } + s_free(addr); + return list; +} + +#undef isspace +#define isspace(c) ((c)==' ' || (c)=='\t' || (c)=='\n') + +/* Get the next field from a String. The field is delimited by white space. + * Anything delimited by double quotes is included in the string. + */ +static String* +s_parseq(String *from, String *to) +{ + int c; + + if (*from->ptr == '\0') + return 0; + if (to == 0) + to = s_new(); + for (c = *from->ptr;!isspace(c) && c != 0; c = *(++from->ptr)){ + s_putc(to, c); + if(c == '"'){ + for (c = *(++from->ptr); c && c != '"'; c = *(++from->ptr)) + s_putc(to, *from->ptr); + s_putc(to, '"'); + if(c == 0) + break; + } + } + s_terminate(to); + + /* crunch trailing white */ + while(isspace(*from->ptr)) + from->ptr++; + + return to; +} |
