URI:
       tdest.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tdest.c (4804B)
       ---
            1 #include "common.h"
            2 #include "send.h"
            3 
            4 static String* s_parseq(String*, String*);
            5 
            6 /* exports */
            7 dest *dlist;
            8 
            9 extern dest*
           10 d_new(String *addr)
           11 {
           12         dest *dp;
           13 
           14         dp = (dest *)mallocz(sizeof(dest), 1);
           15         if (dp == 0) {
           16                 perror("d_new");
           17                 exit(1);
           18         }
           19         dp->same = dp;
           20         dp->nsame = 1;
           21         dp->nchar = 0;
           22         dp->next = dp;
           23         dp->addr = escapespecial(addr);
           24         dp->parent = 0;
           25         dp->repl1 = dp->repl2 = 0;
           26         dp->status = d_undefined;
           27         return dp;
           28 }
           29 
           30 extern void
           31 d_free(dest *dp)
           32 {
           33         if (dp != 0) {
           34                 s_free(dp->addr);
           35                 s_free(dp->repl1);
           36                 s_free(dp->repl2);
           37                 free((char *)dp);
           38         }
           39 }
           40 
           41 /* The following routines manipulate an ordered list of items.  Insertions
           42  * are always to the end of the list.  Deletions are from the beginning.
           43  *
           44  * The list are circular witht the `head' of the list being the last item
           45  * added.
           46  */
           47 
           48 /*  Get first element from a circular list linked via 'next'. */
           49 extern dest *
           50 d_rm(dest **listp)
           51 {
           52         dest *dp;
           53 
           54         if (*listp == 0)
           55                 return 0;
           56         dp = (*listp)->next;
           57         if (dp == *listp)
           58                 *listp = 0;
           59         else
           60                 (*listp)->next = dp->next;
           61         dp->next = dp;
           62         return dp;
           63 }
           64 
           65 /*  Insert a new entry at the end of the list linked via 'next'. */
           66 extern void
           67 d_insert(dest **listp, dest *new)
           68 {
           69         dest *head;
           70 
           71         if (*listp == 0) {
           72                 *listp = new;
           73                 return;
           74         }
           75         if (new == 0)
           76                 return;
           77         head = new->next;
           78         new->next = (*listp)->next;
           79         (*listp)->next = head;
           80         *listp = new;
           81         return;
           82 }
           83 
           84 /*  Get first element from a circular list linked via 'same'. */
           85 extern dest *
           86 d_rm_same(dest **listp)
           87 {
           88         dest *dp;
           89 
           90         if (*listp == 0)
           91                 return 0;
           92         dp = (*listp)->same;
           93         if (dp == *listp)
           94                 *listp = 0;
           95         else
           96                 (*listp)->same = dp->same;
           97         dp->same = dp;
           98         return dp;
           99 }
          100 
          101 /* Look for a duplicate on the same list */
          102 int
          103 d_same_dup(dest *dp, dest *new)
          104 {
          105         dest *first = dp;
          106 
          107         if(new->repl2 == 0)
          108                 return 1;
          109         do {
          110                 if(strcmp(s_to_c(dp->repl2), s_to_c(new->repl2))==0)
          111                         return 1;
          112                 dp = dp->same;
          113         } while(dp != first);
          114         return 0;
          115 }
          116 
          117 /* Insert an entry into the corresponding list linked by 'same'.  Note that
          118  * the basic structure is a list of lists.
          119  */
          120 extern void
          121 d_same_insert(dest **listp, dest *new)
          122 {
          123         dest *dp;
          124         int len;
          125 
          126         if(new->status == d_pipe || new->status == d_cat) {
          127                 len = new->repl2 ? strlen(s_to_c(new->repl2)) : 0;
          128                 if(*listp != 0){
          129                         dp = (*listp)->next;
          130                         do {
          131                                 if(dp->status == new->status
          132                                 && strcmp(s_to_c(dp->repl1), s_to_c(new->repl1))==0){
          133                                         /* remove duplicates */
          134                                         if(d_same_dup(dp, new))
          135                                                 return;
          136                                         /* add to chain if chain small enough */
          137                                         if(dp->nsame < MAXSAME
          138                                         && dp->nchar + len < MAXSAMECHAR){
          139                                                 new->same = dp->same;
          140                                                 dp->same = new;
          141                                                 dp->nchar += len + 1;
          142                                                 dp->nsame++;
          143                                                 return;
          144                                         }
          145                                 }
          146                                 dp = dp->next;
          147                         } while (dp != (*listp)->next);
          148                 }
          149                 new->nchar = strlen(s_to_c(new->repl1)) + len + 1;
          150         }
          151         new->next = new;
          152         d_insert(listp, new);
          153 }
          154 
          155 /*
          156  *  Form a To: if multiple destinations.
          157  *  The local! and !local! checks are artificial intelligence,
          158  *  there should be a better way.
          159  */
          160 extern String*
          161 d_to(dest *list)
          162 {
          163         dest *np, *sp;
          164         String *s;
          165         int i, n;
          166         char *cp;
          167 
          168         s = s_new();
          169         s_append(s, "To: ");
          170         np = list;
          171         i = n = 0;
          172         do {
          173                 np = np->next;
          174                 sp = np;
          175                 do {
          176                         sp = sp->same;
          177                         cp = s_to_c(sp->addr);
          178 
          179                         /* hack to get local! out of the names */
          180                         if(strncmp(cp, "local!", 6) == 0)
          181                                 cp += 6;
          182 
          183                         if(n > 20){        /* 20 to appease mailers complaining about long lines */
          184                                 s_append(s, "\n\t");
          185                                 n = 0;
          186                         }
          187                         if(i != 0){
          188                                 s_append(s, ", ");
          189                                 n += 2;
          190                         }
          191                         s_append(s, cp);
          192                         n += strlen(cp);
          193                         i++;
          194                 } while(sp != np);
          195         } while(np != list);
          196 
          197         return unescapespecial(s);
          198 }
          199 
          200 /* expand a String of destinations into a linked list of destiniations */
          201 extern dest *
          202 s_to_dest(String *sp, dest *parent)
          203 {
          204         String *addr;
          205         dest *list=0;
          206         dest *new;
          207 
          208         if (sp == 0)
          209                 return 0;
          210         addr = s_new();
          211         while (s_parseq(sp, addr)!=0) {
          212                 addr = escapespecial(addr);
          213                 if(shellchars(s_to_c(addr))){
          214                         while(new = d_rm(&list))
          215                                 d_free(new);
          216                         break;
          217                 }
          218                 new = d_new(addr);
          219                 new->parent = parent;
          220                 new->authorized = parent->authorized;
          221                 d_insert(&list, new);
          222                 addr = s_new();
          223         }
          224         s_free(addr);
          225         return list;
          226 }
          227 
          228 #undef isspace
          229 #define isspace(c) ((c)==' ' || (c)=='\t' || (c)=='\n')
          230 
          231 /*  Get the next field from a String.  The field is delimited by white space.
          232  *  Anything delimited by double quotes is included in the string.
          233  */
          234 static String*
          235 s_parseq(String *from, String *to)
          236 {
          237         int c;
          238 
          239         if (*from->ptr == '\0')
          240                 return 0;
          241         if (to == 0)
          242                 to = s_new();
          243         for (c = *from->ptr;!isspace(c) && c != 0; c = *(++from->ptr)){
          244                 s_putc(to, c);
          245                 if(c == '"'){
          246                         for (c = *(++from->ptr); c && c != '"'; c = *(++from->ptr))
          247                                 s_putc(to, *from->ptr);
          248                         s_putc(to, '"');
          249                         if(c == 0)
          250                                 break;
          251                 }
          252         }
          253         s_terminate(to);
          254 
          255         /* crunch trailing white */
          256         while(isspace(*from->ptr))
          257                 from->ptr++;
          258 
          259         return to;
          260 }