sx.c (3316B)
1 #include "a.h" 2 3 Sx *Brdsx1(Biobuf*); 4 5 Sx* 6 Brdsx(Biobuf *b) 7 { 8 Sx **sx, *x; 9 int nsx; 10 11 nsx = 0; 12 sx = nil; 13 while((x = Brdsx1(b)) != nil){ 14 sx = erealloc(sx, (nsx+1)*sizeof sx[0]); 15 sx[nsx++] = x; 16 } 17 x = emalloc(sizeof *x); 18 x->sx = sx; 19 x->nsx = nsx; 20 x->type = SxList; 21 return x; 22 } 23 24 int 25 sxwalk(Sx *sx) 26 { 27 int i, n; 28 29 if(sx == nil) 30 return 1; 31 switch(sx->type){ 32 default: 33 case SxAtom: 34 case SxString: 35 case SxNumber: 36 return 1; 37 case SxList: 38 n = 0; 39 for(i=0; i<sx->nsx; i++) 40 n += sxwalk(sx->sx[i]); 41 return n; 42 } 43 } 44 45 void 46 freesx(Sx *sx) 47 { 48 int i; 49 50 if(sx == nil) 51 return; 52 switch(sx->type){ 53 case SxAtom: 54 case SxString: 55 free(sx->data); 56 break; 57 case SxList: 58 for(i=0; i<sx->nsx; i++) 59 freesx(sx->sx[i]); 60 free(sx->sx); 61 break; 62 } 63 free(sx); 64 } 65 66 Sx* 67 Brdsx1(Biobuf *b) 68 { 69 int c, len, nbr; 70 char *s; 71 vlong n; 72 Sx *x; 73 74 c = Bgetc(b); 75 if(c == ' ') 76 c = Bgetc(b); 77 if(c < 0) 78 return nil; 79 if(c == '\r') 80 c = Bgetc(b); 81 if(c == '\n') 82 return nil; 83 if(c == ')'){ /* end of list */ 84 Bungetc(b); 85 return nil; 86 } 87 if(c == '('){ /* parenthesized list */ 88 x = Brdsx(b); 89 c = Bgetc(b); 90 if(c != ')') /* oops! not good */ 91 Bungetc(b); 92 return x; 93 } 94 if(c == '{'){ /* length-prefixed string */ 95 len = 0; 96 while((c = Bgetc(b)) >= 0 && isdigit(c)) 97 len = len*10 + c-'0'; 98 if(c != '}') /* oops! not good */ 99 Bungetc(b); 100 c = Bgetc(b); 101 if(c != '\r') /* oops! not good */ 102 ; 103 c = Bgetc(b); 104 if(c != '\n') /* oops! not good */ 105 ; 106 x = emalloc(sizeof *x); 107 x->data = emalloc(len+1); 108 if(Bread(b, x->data, len) != len) 109 ; /* oops! */ 110 x->data[len] = 0; 111 x->ndata = len; 112 x->type = SxString; 113 return x; 114 } 115 if(c == '"'){ /* quoted string */ 116 s = nil; 117 len = 0; 118 while((c = Bgetc(b)) >= 0 && c != '"'){ 119 if(c == '\\') 120 c = Bgetc(b); 121 s = erealloc(s, len+1); 122 s[len++] = c; 123 } 124 s = erealloc(s, len+1); 125 s[len] = 0; 126 x = emalloc(sizeof *x); 127 x->data = s; 128 x->ndata = len; 129 x->type = SxString; 130 return x; 131 } 132 if(isdigit(c)){ /* number */ 133 n = c-'0';; 134 while((c = Bgetc(b)) >= 0 && isdigit(c)) 135 n = n*10 + c-'0'; 136 Bungetc(b); 137 x = emalloc(sizeof *x); 138 x->number = n; 139 x->type = SxNumber; 140 return x; 141 } 142 /* atom */ 143 len = 1; 144 s = emalloc(1); 145 s[0] = c; 146 nbr = 0; 147 while((c = Bgetc(b)) >= 0 && c > ' ' && !strchr("(){}", c)){ 148 /* allow embedded brackets as in BODY[] */ 149 if(c == '['){ 150 if(s[0] == '[') 151 break; 152 else 153 nbr++; 154 } 155 if(c == ']'){ 156 if(nbr > 0) 157 nbr--; 158 else 159 break; 160 } 161 s = erealloc(s, len+1); 162 s[len++] = c; 163 } 164 if(c != ' ') 165 Bungetc(b); 166 s = erealloc(s, len+1); 167 s[len] = 0; 168 x = emalloc(sizeof *x); 169 x->type = SxAtom; 170 x->data = s; 171 x->ndata = len; 172 return x; 173 } 174 175 int 176 sxfmt(Fmt *fmt) 177 { 178 int i, paren; 179 Sx *sx; 180 181 sx = va_arg(fmt->args, Sx*); 182 if(sx == nil) 183 return 0; 184 185 switch(sx->type){ 186 case SxAtom: 187 case SxString: 188 return fmtprint(fmt, "%q", sx->data); 189 190 case SxNumber: 191 return fmtprint(fmt, "%lld", sx->number); 192 193 case SxList: 194 paren = !(fmt->flags&FmtSharp); 195 if(paren) 196 fmtrune(fmt, '('); 197 for(i=0; i<sx->nsx; i++){ 198 if(i) 199 fmtrune(fmt, ' '); 200 fmtprint(fmt, "%$", sx->sx[i]); 201 } 202 if(paren) 203 return fmtrune(fmt, ')'); 204 return 0; 205 206 default: 207 return fmtstrcpy(fmt, "?"); 208 } 209 } 210 211 int 212 oksx(Sx *sx) 213 { 214 return sx->nsx >= 2 215 && sx->sx[1]->type == SxAtom 216 && cistrcmp(sx->sx[1]->data, "OK") == 0; 217 }