#include "a.h" Sx *Brdsx1(Biobuf*); Sx* Brdsx(Biobuf *b) { Sx **sx, *x; int nsx; nsx = 0; sx = nil; while((x = Brdsx1(b)) != nil){ sx = erealloc(sx, (nsx+1)*sizeof sx[0]); sx[nsx++] = x; } x = emalloc(sizeof *x); x->sx = sx; x->nsx = nsx; x->type = SxList; return x; } int sxwalk(Sx *sx) { int i, n; if(sx == nil) return 1; switch(sx->type){ default: case SxAtom: case SxString: case SxNumber: return 1; case SxList: n = 0; for(i=0; insx; i++) n += sxwalk(sx->sx[i]); return n; } } void freesx(Sx *sx) { int i; if(sx == nil) return; switch(sx->type){ case SxAtom: case SxString: free(sx->data); break; case SxList: for(i=0; insx; i++) freesx(sx->sx[i]); free(sx->sx); break; } free(sx); } Sx* Brdsx1(Biobuf *b) { int c, len, nbr; char *s; vlong n; Sx *x; c = Bgetc(b); if(c == ' ') c = Bgetc(b); if(c < 0) return nil; if(c == '\r') c = Bgetc(b); if(c == '\n') return nil; if(c == ')'){ /* end of list */ Bungetc(b); return nil; } if(c == '('){ /* parenthesized list */ x = Brdsx(b); c = Bgetc(b); if(c != ')') /* oops! not good */ Bungetc(b); return x; } if(c == '{'){ /* length-prefixed string */ len = 0; while((c = Bgetc(b)) >= 0 && isdigit(c)) len = len*10 + c-'0'; if(c != '}') /* oops! not good */ Bungetc(b); c = Bgetc(b); if(c != '\r') /* oops! not good */ ; c = Bgetc(b); if(c != '\n') /* oops! not good */ ; x = emalloc(sizeof *x); x->data = emalloc(len+1); if(Bread(b, x->data, len) != len) ; /* oops! */ x->data[len] = 0; x->ndata = len; x->type = SxString; return x; } if(c == '"'){ /* quoted string */ s = nil; len = 0; while((c = Bgetc(b)) >= 0 && c != '"'){ if(c == '\\') c = Bgetc(b); s = erealloc(s, len+1); s[len++] = c; } s = erealloc(s, len+1); s[len] = 0; x = emalloc(sizeof *x); x->data = s; x->ndata = len; x->type = SxString; return x; } if(isdigit(c)){ /* number */ n = c-'0';; while((c = Bgetc(b)) >= 0 && isdigit(c)) n = n*10 + c-'0'; Bungetc(b); x = emalloc(sizeof *x); x->number = n; x->type = SxNumber; return x; } /* atom */ len = 1; s = emalloc(1); s[0] = c; nbr = 0; while((c = Bgetc(b)) >= 0 && c > ' ' && !strchr("(){}", c)){ /* allow embedded brackets as in BODY[] */ if(c == '['){ if(s[0] == '[') break; else nbr++; } if(c == ']'){ if(nbr > 0) nbr--; else break; } s = erealloc(s, len+1); s[len++] = c; } if(c != ' ') Bungetc(b); s = erealloc(s, len+1); s[len] = 0; x = emalloc(sizeof *x); x->type = SxAtom; x->data = s; x->ndata = len; return x; } int sxfmt(Fmt *fmt) { int i, paren; Sx *sx; sx = va_arg(fmt->args, Sx*); if(sx == nil) return 0; switch(sx->type){ case SxAtom: case SxString: return fmtprint(fmt, "%q", sx->data); case SxNumber: return fmtprint(fmt, "%lld", sx->number); case SxList: paren = !(fmt->flags&FmtSharp); if(paren) fmtrune(fmt, '('); for(i=0; insx; i++){ if(i) fmtrune(fmt, ' '); fmtprint(fmt, "%$", sx->sx[i]); } if(paren) return fmtrune(fmt, ')'); return 0; default: return fmtstrcpy(fmt, "?"); } } int oksx(Sx *sx) { return sx->nsx >= 2 && sx->sx[1]->type == SxAtom && cistrcmp(sx->sx[1]->data, "OK") == 0; }