xref: /plan9/sys/src/cmd/upas/send/dest.c (revision 25f7656a92d4745f0ae4bb0ac3376f038ab1f088)
13e12c5d1SDavid du Colombier #include "common.h"
23e12c5d1SDavid du Colombier #include "send.h"
33e12c5d1SDavid du Colombier 
43e12c5d1SDavid du Colombier static String* s_parseq(String*, String*);
53e12c5d1SDavid du Colombier 
63e12c5d1SDavid du Colombier /* exports */
73e12c5d1SDavid du Colombier dest *dlist;
83e12c5d1SDavid du Colombier 
93e12c5d1SDavid du Colombier extern dest*
d_new(String * addr)103e12c5d1SDavid du Colombier d_new(String *addr)
113e12c5d1SDavid du Colombier {
123e12c5d1SDavid du Colombier 	dest *dp;
133e12c5d1SDavid du Colombier 
1468060204SDavid du Colombier 	dp = (dest *)mallocz(sizeof(dest), 1);
153e12c5d1SDavid du Colombier 	if (dp == 0) {
163e12c5d1SDavid du Colombier 		perror("d_new");
173e12c5d1SDavid du Colombier 		exit(1);
183e12c5d1SDavid du Colombier 	}
193e12c5d1SDavid du Colombier 	dp->same = dp;
203e12c5d1SDavid du Colombier 	dp->nsame = 1;
213e12c5d1SDavid du Colombier 	dp->nchar = 0;
223e12c5d1SDavid du Colombier 	dp->next = dp;
237dd7cddfSDavid du Colombier 	dp->addr = escapespecial(addr);
243e12c5d1SDavid du Colombier 	dp->parent = 0;
253e12c5d1SDavid du Colombier 	dp->repl1 = dp->repl2 = 0;
263e12c5d1SDavid du Colombier 	dp->status = d_undefined;
273e12c5d1SDavid du Colombier 	return dp;
283e12c5d1SDavid du Colombier }
293e12c5d1SDavid du Colombier 
303e12c5d1SDavid du Colombier extern void
d_free(dest * dp)313e12c5d1SDavid du Colombier d_free(dest *dp)
323e12c5d1SDavid du Colombier {
333e12c5d1SDavid du Colombier 	if (dp != 0) {
343e12c5d1SDavid du Colombier 		s_free(dp->addr);
353e12c5d1SDavid du Colombier 		s_free(dp->repl1);
363e12c5d1SDavid du Colombier 		s_free(dp->repl2);
373e12c5d1SDavid du Colombier 		free((char *)dp);
383e12c5d1SDavid du Colombier 	}
393e12c5d1SDavid du Colombier }
403e12c5d1SDavid du Colombier 
413e12c5d1SDavid du Colombier /* The following routines manipulate an ordered list of items.  Insertions
423e12c5d1SDavid du Colombier  * are always to the end of the list.  Deletions are from the beginning.
433e12c5d1SDavid du Colombier  *
443e12c5d1SDavid du Colombier  * The list are circular witht the `head' of the list being the last item
453e12c5d1SDavid du Colombier  * added.
463e12c5d1SDavid du Colombier  */
473e12c5d1SDavid du Colombier 
483e12c5d1SDavid du Colombier /*  Get first element from a circular list linked via 'next'. */
493e12c5d1SDavid du Colombier extern dest *
d_rm(dest ** listp)503e12c5d1SDavid du Colombier d_rm(dest **listp)
513e12c5d1SDavid du Colombier {
523e12c5d1SDavid du Colombier 	dest *dp;
533e12c5d1SDavid du Colombier 
543e12c5d1SDavid du Colombier 	if (*listp == 0)
553e12c5d1SDavid du Colombier 		return 0;
563e12c5d1SDavid du Colombier 	dp = (*listp)->next;
573e12c5d1SDavid du Colombier 	if (dp == *listp)
583e12c5d1SDavid du Colombier 		*listp = 0;
593e12c5d1SDavid du Colombier 	else
603e12c5d1SDavid du Colombier 		(*listp)->next = dp->next;
613e12c5d1SDavid du Colombier 	dp->next = dp;
623e12c5d1SDavid du Colombier 	return dp;
633e12c5d1SDavid du Colombier }
643e12c5d1SDavid du Colombier 
653e12c5d1SDavid du Colombier /*  Insert a new entry at the end of the list linked via 'next'. */
663e12c5d1SDavid du Colombier extern void
d_insert(dest ** listp,dest * new)673e12c5d1SDavid du Colombier d_insert(dest **listp, dest *new)
683e12c5d1SDavid du Colombier {
693e12c5d1SDavid du Colombier 	dest *head;
703e12c5d1SDavid du Colombier 
713e12c5d1SDavid du Colombier 	if (*listp == 0) {
723e12c5d1SDavid du Colombier 		*listp = new;
733e12c5d1SDavid du Colombier 		return;
743e12c5d1SDavid du Colombier 	}
753e12c5d1SDavid du Colombier 	if (new == 0)
763e12c5d1SDavid du Colombier 		return;
773e12c5d1SDavid du Colombier 	head = new->next;
783e12c5d1SDavid du Colombier 	new->next = (*listp)->next;
793e12c5d1SDavid du Colombier 	(*listp)->next = head;
807dd7cddfSDavid du Colombier 	*listp = new;
813e12c5d1SDavid du Colombier 	return;
823e12c5d1SDavid du Colombier }
833e12c5d1SDavid du Colombier 
843e12c5d1SDavid du Colombier /*  Get first element from a circular list linked via 'same'. */
853e12c5d1SDavid du Colombier extern dest *
d_rm_same(dest ** listp)863e12c5d1SDavid du Colombier d_rm_same(dest **listp)
873e12c5d1SDavid du Colombier {
883e12c5d1SDavid du Colombier 	dest *dp;
893e12c5d1SDavid du Colombier 
903e12c5d1SDavid du Colombier 	if (*listp == 0)
913e12c5d1SDavid du Colombier 		return 0;
923e12c5d1SDavid du Colombier 	dp = (*listp)->same;
933e12c5d1SDavid du Colombier 	if (dp == *listp)
943e12c5d1SDavid du Colombier 		*listp = 0;
953e12c5d1SDavid du Colombier 	else
963e12c5d1SDavid du Colombier 		(*listp)->same = dp->same;
973e12c5d1SDavid du Colombier 	dp->same = dp;
983e12c5d1SDavid du Colombier 	return dp;
993e12c5d1SDavid du Colombier }
1003e12c5d1SDavid du Colombier 
101219b2ee8SDavid du Colombier /* Look for a duplicate on the same list */
102219b2ee8SDavid du Colombier int
d_same_dup(dest * dp,dest * new)103219b2ee8SDavid du Colombier d_same_dup(dest *dp, dest *new)
104219b2ee8SDavid du Colombier {
105219b2ee8SDavid du Colombier 	dest *first = dp;
106219b2ee8SDavid du Colombier 
107219b2ee8SDavid du Colombier 	if(new->repl2 == 0)
108219b2ee8SDavid du Colombier 		return 1;
109219b2ee8SDavid du Colombier 	do {
110219b2ee8SDavid du Colombier 		if(strcmp(s_to_c(dp->repl2), s_to_c(new->repl2))==0)
111219b2ee8SDavid du Colombier 			return 1;
112219b2ee8SDavid du Colombier 		dp = dp->same;
113219b2ee8SDavid du Colombier 	} while(dp != first);
114219b2ee8SDavid du Colombier 	return 0;
115219b2ee8SDavid du Colombier }
116219b2ee8SDavid du Colombier 
1173e12c5d1SDavid du Colombier /* Insert an entry into the corresponding list linked by 'same'.  Note that
1183e12c5d1SDavid du Colombier  * the basic structure is a list of lists.
1193e12c5d1SDavid du Colombier  */
1203e12c5d1SDavid du Colombier extern void
d_same_insert(dest ** listp,dest * new)1213e12c5d1SDavid du Colombier d_same_insert(dest **listp, dest *new)
1223e12c5d1SDavid du Colombier {
1233e12c5d1SDavid du Colombier 	dest *dp;
1243e12c5d1SDavid du Colombier 	int len;
1253e12c5d1SDavid du Colombier 
126219b2ee8SDavid du Colombier 	if(new->status == d_pipe || new->status == d_cat) {
1273e12c5d1SDavid du Colombier 		len = new->repl2 ? strlen(s_to_c(new->repl2)) : 0;
1283e12c5d1SDavid du Colombier 		if(*listp != 0){
1293e12c5d1SDavid du Colombier 			dp = (*listp)->next;
1303e12c5d1SDavid du Colombier 			do {
1313e12c5d1SDavid du Colombier 				if(dp->status == new->status
1323e12c5d1SDavid du Colombier 				&& strcmp(s_to_c(dp->repl1), s_to_c(new->repl1))==0){
133219b2ee8SDavid du Colombier 					/* remove duplicates */
134219b2ee8SDavid du Colombier 					if(d_same_dup(dp, new))
135219b2ee8SDavid du Colombier 						return;
136219b2ee8SDavid du Colombier 					/* add to chain if chain small enough */
137219b2ee8SDavid du Colombier 					if(dp->nsame < MAXSAME
138219b2ee8SDavid du Colombier 					&& dp->nchar + len < MAXSAMECHAR){
1393e12c5d1SDavid du Colombier 						new->same = dp->same;
1403e12c5d1SDavid du Colombier 						dp->same = new;
1413e12c5d1SDavid du Colombier 						dp->nchar += len + 1;
1423e12c5d1SDavid du Colombier 						dp->nsame++;
1433e12c5d1SDavid du Colombier 						return;
1443e12c5d1SDavid du Colombier 					}
145219b2ee8SDavid du Colombier 				}
1463e12c5d1SDavid du Colombier 				dp = dp->next;
1473e12c5d1SDavid du Colombier 			} while (dp != (*listp)->next);
1483e12c5d1SDavid du Colombier 		}
1493e12c5d1SDavid du Colombier 		new->nchar = strlen(s_to_c(new->repl1)) + len + 1;
1503e12c5d1SDavid du Colombier 	}
1513e12c5d1SDavid du Colombier 	new->next = new;
1523e12c5d1SDavid du Colombier 	d_insert(listp, new);
1533e12c5d1SDavid du Colombier }
1543e12c5d1SDavid du Colombier 
1557dd7cddfSDavid du Colombier /*
1567dd7cddfSDavid du Colombier  *  Form a To: if multiple destinations.
1577dd7cddfSDavid du Colombier  *  The local! and !local! checks are artificial intelligence,
1587dd7cddfSDavid du Colombier  *  there should be a better way.
1597dd7cddfSDavid du Colombier  */
1607dd7cddfSDavid du Colombier extern String*
d_to(dest * list)1617dd7cddfSDavid du Colombier d_to(dest *list)
1627dd7cddfSDavid du Colombier {
1637dd7cddfSDavid du Colombier 	dest *np, *sp;
1647dd7cddfSDavid du Colombier 	String *s;
1657dd7cddfSDavid du Colombier 	int i, n;
1667dd7cddfSDavid du Colombier 	char *cp;
1677dd7cddfSDavid du Colombier 
1687dd7cddfSDavid du Colombier 	s = s_new();
1697dd7cddfSDavid du Colombier 	s_append(s, "To: ");
1707dd7cddfSDavid du Colombier 	np = list;
1717dd7cddfSDavid du Colombier 	i = n = 0;
1727dd7cddfSDavid du Colombier 	do {
1737dd7cddfSDavid du Colombier 		np = np->next;
1747dd7cddfSDavid du Colombier 		sp = np;
1757dd7cddfSDavid du Colombier 		do {
1767dd7cddfSDavid du Colombier 			sp = sp->same;
1777dd7cddfSDavid du Colombier 			cp = s_to_c(sp->addr);
1787dd7cddfSDavid du Colombier 
1797dd7cddfSDavid du Colombier 			/* hack to get local! out of the names */
1807dd7cddfSDavid du Colombier 			if(strncmp(cp, "local!", 6) == 0)
1817dd7cddfSDavid du Colombier 				cp += 6;
1827dd7cddfSDavid du Colombier 
183*25f7656aSDavid du Colombier 			if(n > 20){	/* 20 to appease mailers complaining about long lines */
1847dd7cddfSDavid du Colombier 				s_append(s, "\n\t");
1857dd7cddfSDavid du Colombier 				n = 0;
1867dd7cddfSDavid du Colombier 			}
1877dd7cddfSDavid du Colombier 			if(i != 0){
1887dd7cddfSDavid du Colombier 				s_append(s, ", ");
1897dd7cddfSDavid du Colombier 				n += 2;
1907dd7cddfSDavid du Colombier 			}
1917dd7cddfSDavid du Colombier 			s_append(s, cp);
1927dd7cddfSDavid du Colombier 			n += strlen(cp);
1937dd7cddfSDavid du Colombier 			i++;
1947dd7cddfSDavid du Colombier 		} while(sp != np);
1957dd7cddfSDavid du Colombier 	} while(np != list);
1967dd7cddfSDavid du Colombier 
1977dd7cddfSDavid du Colombier 	return unescapespecial(s);
1987dd7cddfSDavid du Colombier }
1997dd7cddfSDavid du Colombier 
2003e12c5d1SDavid du Colombier /* expand a String of destinations into a linked list of destiniations */
2013e12c5d1SDavid du Colombier extern dest *
s_to_dest(String * sp,dest * parent)2023e12c5d1SDavid du Colombier s_to_dest(String *sp, dest *parent)
2033e12c5d1SDavid du Colombier {
2043e12c5d1SDavid du Colombier 	String *addr;
2053e12c5d1SDavid du Colombier 	dest *list=0;
2063e12c5d1SDavid du Colombier 	dest *new;
2073e12c5d1SDavid du Colombier 
2083e12c5d1SDavid du Colombier 	if (sp == 0)
2093e12c5d1SDavid du Colombier 		return 0;
2103e12c5d1SDavid du Colombier 	addr = s_new();
2113e12c5d1SDavid du Colombier 	while (s_parseq(sp, addr)!=0) {
2127dd7cddfSDavid du Colombier 		addr = escapespecial(addr);
2133e12c5d1SDavid du Colombier 		if(shellchars(s_to_c(addr))){
2143e12c5d1SDavid du Colombier 			while(new = d_rm(&list))
2153e12c5d1SDavid du Colombier 				d_free(new);
2163e12c5d1SDavid du Colombier 			break;
2173e12c5d1SDavid du Colombier 		}
2183e12c5d1SDavid du Colombier 		new = d_new(addr);
2193e12c5d1SDavid du Colombier 		new->parent = parent;
2203e12c5d1SDavid du Colombier 		new->authorized = parent->authorized;
2213e12c5d1SDavid du Colombier 		d_insert(&list, new);
2223e12c5d1SDavid du Colombier 		addr = s_new();
2233e12c5d1SDavid du Colombier 	}
2243e12c5d1SDavid du Colombier 	s_free(addr);
2253e12c5d1SDavid du Colombier 	return list;
2263e12c5d1SDavid du Colombier }
2273e12c5d1SDavid du Colombier 
2283e12c5d1SDavid du Colombier #define isspace(c) ((c)==' ' || (c)=='\t' || (c)=='\n')
2293e12c5d1SDavid du Colombier 
2303e12c5d1SDavid du Colombier /*  Get the next field from a String.  The field is delimited by white space.
2313e12c5d1SDavid du Colombier  *  Anything delimited by double quotes is included in the string.
2323e12c5d1SDavid du Colombier  */
2333e12c5d1SDavid du Colombier static String*
s_parseq(String * from,String * to)2343e12c5d1SDavid du Colombier s_parseq(String *from, String *to)
2353e12c5d1SDavid du Colombier {
2363e12c5d1SDavid du Colombier 	int c;
2373e12c5d1SDavid du Colombier 
2383e12c5d1SDavid du Colombier 	if (*from->ptr == '\0')
2393e12c5d1SDavid du Colombier 		return 0;
2403e12c5d1SDavid du Colombier 	if (to == 0)
2413e12c5d1SDavid du Colombier 		to = s_new();
2423e12c5d1SDavid du Colombier 	for (c = *from->ptr;!isspace(c) && c != 0; c = *(++from->ptr)){
2433e12c5d1SDavid du Colombier 		s_putc(to, c);
2443e12c5d1SDavid du Colombier 		if(c == '"'){
2453e12c5d1SDavid du Colombier 			for (c = *(++from->ptr); c && c != '"'; c = *(++from->ptr))
2463e12c5d1SDavid du Colombier 				s_putc(to, *from->ptr);
2473e12c5d1SDavid du Colombier 			s_putc(to, '"');
2483e12c5d1SDavid du Colombier 			if(c == 0)
2493e12c5d1SDavid du Colombier 				break;
2503e12c5d1SDavid du Colombier 		}
2513e12c5d1SDavid du Colombier 	}
2523e12c5d1SDavid du Colombier 	s_terminate(to);
2533e12c5d1SDavid du Colombier 
2543e12c5d1SDavid du Colombier 	/* crunch trailing white */
2553e12c5d1SDavid du Colombier 	while(isspace(*from->ptr))
2563e12c5d1SDavid du Colombier 		from->ptr++;
2573e12c5d1SDavid du Colombier 
2583e12c5d1SDavid du Colombier 	return to;
2593e12c5d1SDavid du Colombier }
260