tdest.c - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
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 }