rsc | 3d7e909 | 2003-10-14 02:35:00 +0000 | [diff] [blame] | 1 | #include <u.h> |
| 2 | #include <libc.h> |
rsc | 32f69c3 | 2003-12-11 17:48:38 +0000 | [diff] [blame] | 3 | #include <fcall.h> |
rsc | 3d7e909 | 2003-10-14 02:35:00 +0000 | [diff] [blame] | 4 | #include "plumb.h" |
| 5 | |
| 6 | static char attrbuf[4096]; |
| 7 | |
rsc | b7e6f41 | 2003-11-23 18:16:51 +0000 | [diff] [blame] | 8 | char *home; |
rsc | 49588d5 | 2003-12-17 04:34:52 +0000 | [diff] [blame] | 9 | |
rsc | 3d7e909 | 2003-10-14 02:35:00 +0000 | [diff] [blame] | 10 | static int |
| 11 | Strlen(char *s) |
| 12 | { |
| 13 | if(s == nil) |
| 14 | return 0; |
| 15 | return strlen(s); |
| 16 | } |
| 17 | |
| 18 | static char* |
| 19 | Strcpy(char *s, char *t) |
| 20 | { |
| 21 | if(t == nil) |
| 22 | return s; |
| 23 | return strcpy(s, t) + strlen(t); |
| 24 | } |
| 25 | |
| 26 | /* quote attribute value, if necessary */ |
| 27 | static char* |
| 28 | quote(char *s) |
| 29 | { |
| 30 | char *t; |
| 31 | int c; |
| 32 | |
| 33 | if(s == nil){ |
| 34 | attrbuf[0] = '\0'; |
| 35 | return attrbuf; |
| 36 | } |
| 37 | if(strpbrk(s, " '=\t") == nil) |
| 38 | return s; |
| 39 | t = attrbuf; |
| 40 | *t++ = '\''; |
| 41 | while(t < attrbuf+sizeof attrbuf-2){ |
| 42 | c = *s++; |
| 43 | if(c == '\0') |
| 44 | break; |
| 45 | *t++ = c; |
| 46 | if(c == '\'') |
| 47 | *t++ = c; |
| 48 | } |
| 49 | *t++ = '\''; |
| 50 | *t = '\0'; |
| 51 | return attrbuf; |
| 52 | } |
| 53 | |
| 54 | char* |
| 55 | plumbpackattr(Plumbattr *attr) |
| 56 | { |
| 57 | int n; |
| 58 | Plumbattr *a; |
| 59 | char *s, *t; |
| 60 | |
| 61 | if(attr == nil) |
| 62 | return nil; |
| 63 | n = 0; |
| 64 | for(a=attr; a!=nil; a=a->next) |
| 65 | n += Strlen(a->name) + 1 + Strlen(quote(a->value)) + 1; |
| 66 | s = malloc(n); |
| 67 | if(s == nil) |
| 68 | return nil; |
| 69 | t = s; |
| 70 | *t = '\0'; |
| 71 | for(a=attr; a!=nil; a=a->next){ |
| 72 | if(t != s) |
| 73 | *t++ = ' '; |
| 74 | strcpy(t, a->name); |
| 75 | strcat(t, "="); |
| 76 | strcat(t, quote(a->value)); |
| 77 | t += strlen(t); |
| 78 | } |
| 79 | if(t > s+n) |
| 80 | abort(); |
| 81 | return s; |
| 82 | } |
| 83 | |
| 84 | char* |
| 85 | plumblookup(Plumbattr *attr, char *name) |
| 86 | { |
| 87 | while(attr){ |
| 88 | if(strcmp(attr->name, name) == 0) |
| 89 | return attr->value; |
| 90 | attr = attr->next; |
| 91 | } |
| 92 | return nil; |
| 93 | } |
| 94 | |
| 95 | char* |
| 96 | plumbpack(Plumbmsg *m, int *np) |
| 97 | { |
| 98 | int n, ndata; |
| 99 | char *buf, *p, *attr; |
| 100 | |
| 101 | ndata = m->ndata; |
| 102 | if(ndata < 0) |
| 103 | ndata = Strlen(m->data); |
| 104 | attr = plumbpackattr(m->attr); |
| 105 | n = Strlen(m->src)+1 + Strlen(m->dst)+1 + Strlen(m->wdir)+1 + |
| 106 | Strlen(m->type)+1 + Strlen(attr)+1 + 16 + ndata; |
| 107 | buf = malloc(n+1); /* +1 for '\0' */ |
| 108 | if(buf == nil){ |
| 109 | free(attr); |
| 110 | return nil; |
| 111 | } |
| 112 | p = Strcpy(buf, m->src); |
| 113 | *p++ = '\n'; |
| 114 | p = Strcpy(p, m->dst); |
| 115 | *p++ = '\n'; |
| 116 | p = Strcpy(p, m->wdir); |
| 117 | *p++ = '\n'; |
| 118 | p = Strcpy(p, m->type); |
| 119 | *p++ = '\n'; |
| 120 | p = Strcpy(p, attr); |
| 121 | *p++ = '\n'; |
| 122 | p += sprint(p, "%d\n", ndata); |
| 123 | memmove(p, m->data, ndata); |
| 124 | *np = (p-buf)+ndata; |
| 125 | buf[*np] = '\0'; /* null terminate just in case */ |
| 126 | if(*np >= n+1) |
| 127 | abort(); |
| 128 | free(attr); |
| 129 | return buf; |
| 130 | } |
| 131 | |
rsc | 3d7e909 | 2003-10-14 02:35:00 +0000 | [diff] [blame] | 132 | static int |
| 133 | plumbline(char **linep, char *buf, int i, int n, int *bad) |
| 134 | { |
| 135 | int starti; |
| 136 | char *p; |
| 137 | |
| 138 | if(*bad) |
| 139 | return i; |
| 140 | starti = i; |
| 141 | while(i<n && buf[i]!='\n') |
| 142 | i++; |
| 143 | if(i == n) |
| 144 | *bad = 1; |
| 145 | else{ |
| 146 | p = malloc((i-starti) + 1); |
| 147 | if(p == nil) |
| 148 | *bad = 1; |
| 149 | else{ |
| 150 | memmove(p, buf+starti, i-starti); |
| 151 | p[i-starti] = '\0'; |
| 152 | } |
| 153 | *linep = p; |
| 154 | i++; |
| 155 | } |
| 156 | return i; |
| 157 | } |
| 158 | |
| 159 | void |
| 160 | plumbfree(Plumbmsg *m) |
| 161 | { |
| 162 | Plumbattr *a, *next; |
| 163 | |
| 164 | free(m->src); |
| 165 | free(m->dst); |
| 166 | free(m->wdir); |
| 167 | free(m->type); |
| 168 | for(a=m->attr; a!=nil; a=next){ |
| 169 | next = a->next; |
| 170 | free(a->name); |
| 171 | free(a->value); |
| 172 | free(a); |
| 173 | } |
| 174 | free(m->data); |
| 175 | free(m); |
| 176 | } |
| 177 | |
| 178 | Plumbattr* |
| 179 | plumbunpackattr(char *p) |
| 180 | { |
| 181 | Plumbattr *attr, *prev, *a; |
| 182 | char *q, *v; |
| 183 | int c, quoting; |
| 184 | |
| 185 | attr = prev = nil; |
| 186 | while(*p!='\0' && *p!='\n'){ |
| 187 | while(*p==' ' || *p=='\t') |
| 188 | p++; |
| 189 | if(*p == '\0') |
| 190 | break; |
| 191 | for(q=p; *q!='\0' && *q!='\n' && *q!=' ' && *q!='\t'; q++) |
| 192 | if(*q == '=') |
| 193 | break; |
| 194 | if(*q != '=') |
| 195 | break; /* malformed attribute */ |
| 196 | a = malloc(sizeof(Plumbattr)); |
| 197 | if(a == nil) |
| 198 | break; |
| 199 | a->name = malloc(q-p+1); |
| 200 | if(a->name == nil){ |
| 201 | free(a); |
| 202 | break; |
| 203 | } |
| 204 | memmove(a->name, p, q-p); |
| 205 | a->name[q-p] = '\0'; |
| 206 | /* process quotes in value */ |
| 207 | q++; /* skip '=' */ |
| 208 | v = attrbuf; |
| 209 | quoting = 0; |
| 210 | while(*q!='\0' && *q!='\n'){ |
| 211 | if(v >= attrbuf+sizeof attrbuf) |
| 212 | break; |
| 213 | c = *q++; |
| 214 | if(quoting){ |
| 215 | if(c == '\''){ |
| 216 | if(*q == '\'') |
| 217 | q++; |
| 218 | else{ |
| 219 | quoting = 0; |
| 220 | continue; |
| 221 | } |
| 222 | } |
| 223 | }else{ |
| 224 | if(c==' ' || c=='\t') |
| 225 | break; |
| 226 | if(c == '\''){ |
| 227 | quoting = 1; |
| 228 | continue; |
| 229 | } |
| 230 | } |
| 231 | *v++ = c; |
| 232 | } |
| 233 | a->value = malloc(v-attrbuf+1); |
| 234 | if(a->value == nil){ |
| 235 | free(a->name); |
| 236 | free(a); |
| 237 | break; |
| 238 | } |
| 239 | memmove(a->value, attrbuf, v-attrbuf); |
| 240 | a->value[v-attrbuf] = '\0'; |
| 241 | a->next = nil; |
| 242 | if(prev == nil) |
| 243 | attr = a; |
| 244 | else |
| 245 | prev->next = a; |
| 246 | prev = a; |
| 247 | p = q; |
| 248 | } |
| 249 | return attr; |
| 250 | } |
| 251 | |
| 252 | Plumbattr* |
| 253 | plumbaddattr(Plumbattr *attr, Plumbattr *new) |
| 254 | { |
| 255 | Plumbattr *l; |
| 256 | |
| 257 | l = attr; |
| 258 | if(l == nil) |
| 259 | return new; |
| 260 | while(l->next != nil) |
| 261 | l = l->next; |
| 262 | l->next = new; |
| 263 | return attr; |
| 264 | } |
| 265 | |
| 266 | Plumbattr* |
| 267 | plumbdelattr(Plumbattr *attr, char *name) |
| 268 | { |
| 269 | Plumbattr *l, *prev; |
| 270 | |
| 271 | prev = nil; |
| 272 | for(l=attr; l!=nil; l=l->next){ |
| 273 | if(strcmp(name, l->name) == 0) |
| 274 | break; |
| 275 | prev = l; |
| 276 | } |
| 277 | if(l == nil) |
| 278 | return nil; |
| 279 | if(prev) |
| 280 | prev->next = l->next; |
| 281 | else |
| 282 | attr = l->next; |
| 283 | free(l->name); |
| 284 | free(l->value); |
| 285 | free(l); |
| 286 | return attr; |
| 287 | } |
| 288 | |
| 289 | Plumbmsg* |
| 290 | plumbunpackpartial(char *buf, int n, int *morep) |
| 291 | { |
| 292 | Plumbmsg *m; |
| 293 | int i, bad; |
| 294 | char *ntext, *attr; |
| 295 | |
| 296 | m = malloc(sizeof(Plumbmsg)); |
| 297 | if(m == nil) |
| 298 | return nil; |
| 299 | memset(m, 0, sizeof(Plumbmsg)); |
| 300 | if(morep != nil) |
| 301 | *morep = 0; |
| 302 | bad = 0; |
| 303 | i = plumbline(&m->src, buf, 0, n, &bad); |
| 304 | i = plumbline(&m->dst, buf, i, n, &bad); |
| 305 | i = plumbline(&m->wdir, buf, i, n, &bad); |
| 306 | i = plumbline(&m->type, buf, i, n, &bad); |
| 307 | i = plumbline(&attr, buf, i, n, &bad); |
| 308 | m->attr = plumbunpackattr(attr); |
| 309 | free(attr); |
| 310 | i = plumbline(&ntext, buf, i, n, &bad); |
| 311 | m->ndata = atoi(ntext); |
| 312 | if(m->ndata != n-i){ |
| 313 | bad = 1; |
| 314 | if(morep!=nil && m->ndata>n-i) |
| 315 | *morep = m->ndata - (n-i); |
| 316 | } |
| 317 | free(ntext); |
| 318 | if(!bad){ |
| 319 | m->data = malloc(n-i+1); /* +1 for '\0' */ |
| 320 | if(m->data == nil) |
| 321 | bad = 1; |
| 322 | else{ |
| 323 | memmove(m->data, buf+i, m->ndata); |
| 324 | m->ndata = n-i; |
| 325 | /* null-terminate in case it's text */ |
| 326 | m->data[m->ndata] = '\0'; |
| 327 | } |
| 328 | } |
| 329 | if(bad){ |
| 330 | plumbfree(m); |
| 331 | m = nil; |
| 332 | } |
| 333 | return m; |
| 334 | } |
| 335 | |
| 336 | Plumbmsg* |
| 337 | plumbunpack(char *buf, int n) |
| 338 | { |
| 339 | return plumbunpackpartial(buf, n, nil); |
| 340 | } |
| 341 | |