5 #include "gen_allocdefs.h"
7 static struct token822 comma = { TOKEN822_COMMA };
9 void token822_reverse(ta)
17 for (i = 0;i + i < n;++i)
20 ta->t[i] = ta->t[n - i];
25 GEN_ALLOC_ready(token822_alloc,struct token822,t,len,a,i,n,x,30,token822_ready)
26 GEN_ALLOC_readyplus(token822_alloc,struct token822,t,len,a,i,n,x,30,token822_readyplus)
27 GEN_ALLOC_append(token822_alloc,struct token822,t,len,a,i,n,x,30,token822_readyplus,token822_append)
29 static int needspace(t1,t2)
34 if (t1 == TOKEN822_COLON) return 1;
35 if (t1 == TOKEN822_COMMA) return 1;
36 if (t2 == TOKEN822_LEFT) return 1;
39 case TOKEN822_ATOM: case TOKEN822_LITERAL:
40 case TOKEN822_QUOTE: case TOKEN822_COMMENT:
43 case TOKEN822_ATOM: case TOKEN822_LITERAL:
44 case TOKEN822_QUOTE: case TOKEN822_COMMENT:
56 case ' ': case '\t': case '\r': case '\n':
57 case '(': case '[': case '"':
58 case '<': case '>': case ';': case ':':
59 case '@': case ',': case '.':
65 static void atomcheck(t)
70 for (i = 0;i < t->slen;++i)
73 if ((ch < 32) || (ch > 126) || (ch == ')') || (ch == ']') || (ch == '\\'))
75 t->type = TOKEN822_QUOTE;
81 int token822_unparse(sa,ta,linelen)
99 for (i = 0;i < ta->len;++i)
103 if (needspace(lasttype,newtype))
110 case TOKEN822_AT: case TOKEN822_DOT: case TOKEN822_LEFT: case TOKEN822_RIGHT:
111 case TOKEN822_SEMI: case TOKEN822_COLON:
113 case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL: case TOKEN822_COMMENT:
114 if (t->type != TOKEN822_ATOM) len += 2;
115 for (j = 0;j < t->slen;++j)
118 case '"': case '[': case ']': case '(': case ')':
119 case '\\': case '\r': case '\n': ++len;
127 if (!stralloc_ready(sa,len))
135 for (i = 0;i < ta->len;++i)
139 if (needspace(lasttype,newtype))
147 s[0] = '\n'; s[1] = ' '; \
148 if (linee && (!linelen || (s - lineb <= linelen))) \
149 { while (linee < s) { linee[0] = linee[2]; ++linee; } linee -= 2; } \
150 else { if (linee) lineb = linee + 1; linee = s; s += 2; }
153 case TOKEN822_AT: *s++ = '@'; break;
154 case TOKEN822_DOT: *s++ = '.'; break;
155 case TOKEN822_LEFT: *s++ = '<'; break;
156 case TOKEN822_RIGHT: *s++ = '>'; break;
157 case TOKEN822_SEMI: *s++ = ';'; break;
158 case TOKEN822_COLON: *s++ = ':'; break;
159 case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL: case TOKEN822_COMMENT:
160 if (t->type == TOKEN822_QUOTE) *s++ = '"';
161 if (t->type == TOKEN822_LITERAL) *s++ = '[';
162 if (t->type == TOKEN822_COMMENT) *s++ = '(';
163 for (j = 0;j < t->slen;++j)
166 case '"': case '[': case ']': case '(': case ')':
167 case '\\': case '\r': case '\n': *s++ = '\\';
170 if (t->type == TOKEN822_QUOTE) *s++ = '"';
171 if (t->type == TOKEN822_LITERAL) *s++ = ']';
172 if (t->type == TOKEN822_COMMENT) *s++ = ')';
182 int token822_unquote(sa,ta)
193 for (i = 0;i < ta->len;++i)
198 case TOKEN822_COMMA: case TOKEN822_AT: case TOKEN822_DOT: case TOKEN822_LEFT:
199 case TOKEN822_RIGHT: case TOKEN822_SEMI: case TOKEN822_COLON:
201 case TOKEN822_LITERAL:
203 case TOKEN822_ATOM: case TOKEN822_QUOTE:
208 if (!stralloc_ready(sa,len))
213 for (i = 0;i < ta->len;++i)
218 case TOKEN822_COMMA: *s++ = ','; break;
219 case TOKEN822_AT: *s++ = '@'; break;
220 case TOKEN822_DOT: *s++ = '.'; break;
221 case TOKEN822_LEFT: *s++ = '<'; break;
222 case TOKEN822_RIGHT: *s++ = '>'; break;
223 case TOKEN822_SEMI: *s++ = ';'; break;
224 case TOKEN822_COLON: *s++ = ':'; break;
225 case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL:
226 if (t->type == TOKEN822_LITERAL) *s++ = '[';
227 for (j = 0;j < t->slen;++j)
229 if (t->type == TOKEN822_LITERAL) *s++ = ']';
231 case TOKEN822_COMMENT: break;
238 int token822_parse(ta,sa,buf)
255 for (i = 0;i < salen;++i)
258 case '.': case ',': case '@': case '<': case '>': case ':': case ';':
260 case ' ': case '\t': case '\r': case '\n': break;
261 case ')': case ']': return 0;
262 /* other control chars and non-ASCII chars are also bad, in theory */
267 if (++i >= salen) return 0;
270 case '(': ++level; break;
271 case ')': --level; break;
272 case '\\': if (++i >= salen) return 0;
282 if (++i >= salen) return 0;
285 case '"': --level; break;
286 case '\\': if (++i >= salen) return 0;
296 if (++i >= salen) return 0;
299 case ']': --level; break;
300 case '\\': if (++i >= salen) return 0;
313 while (atomok(sa->s[i]));
318 if (!token822_ready(ta,numtoks))
320 if (!stralloc_ready(buf,numchars))
326 for (i = 0;i < salen;++i)
329 case '.': t->type = TOKEN822_DOT; ++t; break;
330 case ',': t->type = TOKEN822_COMMA; ++t; break;
331 case '@': t->type = TOKEN822_AT; ++t; break;
332 case '<': t->type = TOKEN822_LEFT; ++t; break;
333 case '>': t->type = TOKEN822_RIGHT; ++t; break;
334 case ':': t->type = TOKEN822_COLON; ++t; break;
335 case ';': t->type = TOKEN822_SEMI; ++t; break;
336 case ' ': case '\t': case '\r': case '\n': break;
338 t->type = TOKEN822_COMMENT; t->s = cbuf; t->slen = 0;
342 ++i; /* assert: < salen */
345 case '(': ++level; break;
346 case ')': --level; break;
347 case '\\': ++i; /* assert: < salen */
348 default: *cbuf++ = sa->s[i]; ++t->slen;
354 t->type = TOKEN822_QUOTE; t->s = cbuf; t->slen = 0;
358 ++i; /* assert: < salen */
361 case '"': --level; break;
362 case '\\': ++i; /* assert: < salen */
363 default: *cbuf++ = sa->s[i]; ++t->slen;
369 t->type = TOKEN822_LITERAL; t->s = cbuf; t->slen = 0;
373 ++i; /* assert: < salen */
376 case ']': --level; break;
377 case '\\': ++i; /* assert: < salen */
378 default: *cbuf++ = sa->s[i]; ++t->slen;
384 t->type = TOKEN822_ATOM; t->s = cbuf; t->slen = 0;
387 *cbuf++ = sa->s[i]; ++t->slen;
391 while (atomok(sa->s[i]));
399 static int gotaddr(taout,taaddr,callback)
400 token822_alloc *taout;
401 token822_alloc *taaddr;
406 if (callback(taaddr) != 1)
409 if (!token822_readyplus(taout,taaddr->len))
412 for (i = 0;i < taaddr->len;++i)
413 taout->t[taout->len++] = taaddr->t[i];
419 int token822_addrlist(taout,taaddr,ta,callback)
420 token822_alloc *taout;
421 token822_alloc *taaddr;
426 struct token822 *beginning;
433 if (!token822_readyplus(taout,1)) return -1;
434 if (!token822_readyplus(taaddr,1)) return -1;
439 beginning = ta->t + 2;
440 t = ta->t + ta->len - 1;
442 /* rfc 822 address lists are easy to parse from right to left */
444 #define FLUSH if (taaddr->len) if (!gotaddr(taout,taaddr,callback)) return -1;
445 #define FLUSHCOMMA if (taaddr->len) { \
446 if (!gotaddr(taout,taaddr,callback)) return -1; \
447 if (!token822_append(taout,&comma)) return -1; }
448 #define ADDRLEFT if (!token822_append(taaddr,t--)) return -1;
449 #define OUTLEFT if (!token822_append(taout,t--)) return -1;
451 while (t >= beginning)
457 if (ingroup) return 0;
463 if (!ingroup) return 0;
465 while ((t >= beginning) && (t->type != TOKEN822_COMMA))
474 while ((t >= beginning) && (t->type != TOKEN822_LEFT))
476 /* important to use address here even if it's empty: <> */
477 if (!gotaddr(taout,taaddr,callback)) return -1;
478 if (t < beginning) return 0;
480 while ((t >= beginning) && ((t->type == TOKEN822_COMMENT) || (t->type == TOKEN822_ATOM) || (t->type == TOKEN822_QUOTE) || (t->type == TOKEN822_AT) || (t->type == TOKEN822_DOT)))
484 case TOKEN822_ATOM: case TOKEN822_QUOTE: case TOKEN822_LITERAL:
490 case TOKEN822_COMMENT:
491 /* comment is lexically a space; shouldn't affect wordok */
507 if (!token822_append(taout,--t)) return -1;
509 token822_reverse(taout);