blob: c9379307c7d79b807ec2985b9d3966968729492b [file] [log] [blame]
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include "plumb.h"
static char attrbuf[4096];
char *home;
static int
Strlen(char *s)
{
if(s == nil)
return 0;
return strlen(s);
}
static char*
Strcpy(char *s, char *t)
{
if(t == nil)
return s;
return strcpy(s, t) + strlen(t);
}
/* quote attribute value, if necessary */
static char*
quote(char *s)
{
char *t;
int c;
if(s == nil){
attrbuf[0] = '\0';
return attrbuf;
}
if(strpbrk(s, " '=\t") == nil)
return s;
t = attrbuf;
*t++ = '\'';
while(t < attrbuf+sizeof attrbuf-2){
c = *s++;
if(c == '\0')
break;
*t++ = c;
if(c == '\'')
*t++ = c;
}
*t++ = '\'';
*t = '\0';
return attrbuf;
}
char*
plumbpackattr(Plumbattr *attr)
{
int n;
Plumbattr *a;
char *s, *t;
if(attr == nil)
return nil;
n = 0;
for(a=attr; a!=nil; a=a->next)
n += Strlen(a->name) + 1 + Strlen(quote(a->value)) + 1;
s = malloc(n);
if(s == nil)
return nil;
t = s;
*t = '\0';
for(a=attr; a!=nil; a=a->next){
if(t != s)
*t++ = ' ';
strcpy(t, a->name);
strcat(t, "=");
strcat(t, quote(a->value));
t += strlen(t);
}
if(t > s+n)
abort();
return s;
}
char*
plumblookup(Plumbattr *attr, char *name)
{
while(attr){
if(strcmp(attr->name, name) == 0)
return attr->value;
attr = attr->next;
}
return nil;
}
char*
plumbpack(Plumbmsg *m, int *np)
{
int n, ndata;
char *buf, *p, *attr;
ndata = m->ndata;
if(ndata < 0)
ndata = Strlen(m->data);
attr = plumbpackattr(m->attr);
n = Strlen(m->src)+1 + Strlen(m->dst)+1 + Strlen(m->wdir)+1 +
Strlen(m->type)+1 + Strlen(attr)+1 + 16 + ndata;
buf = malloc(n+1); /* +1 for '\0' */
if(buf == nil){
free(attr);
return nil;
}
p = Strcpy(buf, m->src);
*p++ = '\n';
p = Strcpy(p, m->dst);
*p++ = '\n';
p = Strcpy(p, m->wdir);
*p++ = '\n';
p = Strcpy(p, m->type);
*p++ = '\n';
p = Strcpy(p, attr);
*p++ = '\n';
p += sprint(p, "%d\n", ndata);
memmove(p, m->data, ndata);
*np = (p-buf)+ndata;
buf[*np] = '\0'; /* null terminate just in case */
if(*np >= n+1)
abort();
free(attr);
return buf;
}
static int
plumbline(char **linep, char *buf, int i, int n, int *bad)
{
int starti;
char *p;
if(*bad)
return i;
starti = i;
while(i<n && buf[i]!='\n')
i++;
if(i == n)
*bad = 1;
else{
p = malloc((i-starti) + 1);
if(p == nil)
*bad = 1;
else{
memmove(p, buf+starti, i-starti);
p[i-starti] = '\0';
}
*linep = p;
i++;
}
return i;
}
void
plumbfree(Plumbmsg *m)
{
Plumbattr *a, *next;
free(m->src);
free(m->dst);
free(m->wdir);
free(m->type);
for(a=m->attr; a!=nil; a=next){
next = a->next;
free(a->name);
free(a->value);
free(a);
}
free(m->data);
free(m);
}
Plumbattr*
plumbunpackattr(char *p)
{
Plumbattr *attr, *prev, *a;
char *q, *v;
int c, quoting;
attr = prev = nil;
while(*p!='\0' && *p!='\n'){
while(*p==' ' || *p=='\t')
p++;
if(*p == '\0')
break;
for(q=p; *q!='\0' && *q!='\n' && *q!=' ' && *q!='\t'; q++)
if(*q == '=')
break;
if(*q != '=')
break; /* malformed attribute */
a = malloc(sizeof(Plumbattr));
if(a == nil)
break;
a->name = malloc(q-p+1);
if(a->name == nil){
free(a);
break;
}
memmove(a->name, p, q-p);
a->name[q-p] = '\0';
/* process quotes in value */
q++; /* skip '=' */
v = attrbuf;
quoting = 0;
while(*q!='\0' && *q!='\n'){
if(v >= attrbuf+sizeof attrbuf)
break;
c = *q++;
if(quoting){
if(c == '\''){
if(*q == '\'')
q++;
else{
quoting = 0;
continue;
}
}
}else{
if(c==' ' || c=='\t')
break;
if(c == '\''){
quoting = 1;
continue;
}
}
*v++ = c;
}
a->value = malloc(v-attrbuf+1);
if(a->value == nil){
free(a->name);
free(a);
break;
}
memmove(a->value, attrbuf, v-attrbuf);
a->value[v-attrbuf] = '\0';
a->next = nil;
if(prev == nil)
attr = a;
else
prev->next = a;
prev = a;
p = q;
}
return attr;
}
Plumbattr*
plumbaddattr(Plumbattr *attr, Plumbattr *new)
{
Plumbattr *l;
l = attr;
if(l == nil)
return new;
while(l->next != nil)
l = l->next;
l->next = new;
return attr;
}
Plumbattr*
plumbdelattr(Plumbattr *attr, char *name)
{
Plumbattr *l, *prev;
prev = nil;
for(l=attr; l!=nil; l=l->next){
if(strcmp(name, l->name) == 0)
break;
prev = l;
}
if(l == nil)
return nil;
if(prev)
prev->next = l->next;
else
attr = l->next;
free(l->name);
free(l->value);
free(l);
return attr;
}
Plumbmsg*
plumbunpackpartial(char *buf, int n, int *morep)
{
Plumbmsg *m;
int i, bad;
char *ntext, *attr;
m = malloc(sizeof(Plumbmsg));
if(m == nil)
return nil;
memset(m, 0, sizeof(Plumbmsg));
if(morep != nil)
*morep = 0;
bad = 0;
i = plumbline(&m->src, buf, 0, n, &bad);
i = plumbline(&m->dst, buf, i, n, &bad);
i = plumbline(&m->wdir, buf, i, n, &bad);
i = plumbline(&m->type, buf, i, n, &bad);
i = plumbline(&attr, buf, i, n, &bad);
m->attr = plumbunpackattr(attr);
free(attr);
i = plumbline(&ntext, buf, i, n, &bad);
m->ndata = atoi(ntext);
if(m->ndata != n-i){
bad = 1;
if(morep!=nil && m->ndata>n-i)
*morep = m->ndata - (n-i);
}
free(ntext);
if(!bad){
m->data = malloc(n-i+1); /* +1 for '\0' */
if(m->data == nil)
bad = 1;
else{
memmove(m->data, buf+i, m->ndata);
m->ndata = n-i;
/* null-terminate in case it's text */
m->data[m->ndata] = '\0';
}
}
if(bad){
plumbfree(m);
m = nil;
}
return m;
}
Plumbmsg*
plumbunpack(char *buf, int n)
{
return plumbunpackpartial(buf, n, nil);
}