#define MAX_VALID_NUMBER 1048575 #include #include #include #include "linereader.h" struct linereader { char *b; int a; int l; int o; void (*got)(char *, int, void *); void *arg; } ; static void new_line(LINEREADER *l) { l->l = 0; l->o = -1; } LINEREADER *linereader_open(LINEREADER_GOTFN got, void *arg) { LINEREADER *l; l = malloc(sizeof(LINEREADER)); l->b = 0; l->a = 0; l->got = got; l->arg = arg; new_line(l); return(l); } int linereader_input(LINEREADER *l, const void *data, int len) { const unsigned char *dp; int dv; for (dp=data;len>0;len--,dp++) { if (l->o < 0) { switch (*dp) { case 0x30: dv = 0; if (0) { case 0x31: dv = 1; } if (0) { case 0x32: dv = 2; } if (0) { case 0x33: dv = 3; } if (0) { case 0x34: dv = 4; } if (0) { case 0x35: dv = 5; } if (0) { case 0x36: dv = 6; } if (0) { case 0x37: dv = 7; } if (0) { case 0x38: dv = 8; } if (0) { case 0x39: dv = 9; } if (!dv && !l->l) return(1); l->l = (l->l * 10) + dv; if (l->l > 65536) return(1); break; case 0x7e: if (l->l > l->a) { free(l->b); l->b = malloc(l->a=l->l); } if (l->l == 0) { (*l->got)(0,0,l->arg); new_line(l); } else { l->o = 0; } break; default: return(1); break; } } else { l->b[l->o++] = *dp; if (l->o >= l->l) { (*l->got)(l->b,l->l,l->arg); new_line(l); } } } return(0); } void linereader_close(LINEREADER *l) { free(l->b); free(l); } int recv_line(const void *data, int len, ...) { __label__ ret_fail; __label__ ret_succeed; typedef enum { CSS_MUST_TRUE = 1, CSS_MUST_FALSE, CSS_NOTYET, CSS_TRUE, CSS_NOMORE } CSSTATE; typedef enum { CST_ONEOF = 1, CST_IF } CSTYPE; typedef struct cstack CSTACK; struct cstack { CSTACK *link; CSTYPE type; CSSTATE state; } ; typedef struct tofree TOFREE; struct tofree { TOFREE *link; void *ptr; } ; va_list ap; const unsigned char *dp; int l; int key; CSTACK *cstack; CSTACK *c; int in_true; TOFREE *tofree; static void adv(int n) { if (n > l) abort(); dp += n; l -= n; } static int valid_number(void) { unsigned int n; int dv; if (*dp == '0') return(-1); n = 0; while (l > 0) { switch (*dp) { case '0': dv = 0; if (0) { case '1': dv = 1; } if (0) { case '2': dv = 2; } if (0) { case '3': dv = 3; } if (0) { case '4': dv = 4; } if (0) { case '5': dv = 5; } if (0) { case '6': dv = 6; } if (0) { case '7': dv = 7; } if (0) { case '8': dv = 8; } if (0) { case '9': dv = 9; } n = (10 * n) + dv; if (n > MAX_VALID_NUMBER) return(-1); adv(1); break; default: return(n); break; } } return(n); } static void record_free(void *data) { TOFREE *f; f = malloc(sizeof(TOFREE)); f->ptr = data; f->link = tofree; tofree = f; } static void flush_frees(int freethem) { TOFREE *f; while (tofree) { f = tofree; tofree = f->link; if (freethem) free(f->ptr); free(f); } } static void fail(void) { flush_frees(1); goto ret_fail; } static void succeed(void) { flush_frees(0); goto ret_succeed; } if (0) { ret_fail:; return(-1); ret_succeed:; return(0); } dp = data; l = len; cstack = 0; tofree = 0; va_start(ap,len); while (1) { key = va_arg(ap,int); in_true = !cstack || (cstack->state == CSS_TRUE); if ( cstack && ( (cstack->state == CSS_MUST_TRUE) || (cstack->state == CSS_MUST_FALSE) ) && (key != RL__OPTION) ) abort(); switch (key) { case RL__END: if (cstack) abort(); if (l) fail(); else succeed(); break; case RL__ONEOF: c = malloc(sizeof(CSTACK)); c->type = CST_ONEOF; c->state = in_true ? CSS_MUST_TRUE : CSS_MUST_FALSE; c->link = cstack; cstack = c; break; case RL__ENDOF: if (!cstack || (cstack->type != CST_ONEOF)) abort(); c = cstack; cstack = c->link; free(c); break; case RL__OPTION: { const char *s; int sl; int match; if (!cstack || (cstack->type != CST_ONEOF)) abort(); s = va_arg(ap,const char *); sl = strlen(s); match = (l >= sl) && !bcmp(dp,s,sl); switch (cstack->state) { default: abort(); break; case CSS_MUST_TRUE: if (match) { cstack->state = CSS_TRUE; adv(sl); } else { cstack->state = CSS_NOTYET; } break; case CSS_MUST_FALSE: cstack->state = CSS_NOMORE; break; case CSS_NOTYET: if (match) { cstack->state = CSS_TRUE; adv(sl); } break; case CSS_TRUE: cstack->state = CSS_NOMORE; break; case CSS_NOMORE: break; } } break; case RL__STRING: { unsigned char **datap; int *lenp; int len; unsigned char *b; datap = va_arg(ap,unsigned char **); lenp = va_arg(ap,int *); if (in_true) { len = valid_number(); if (len < 0) fail(); if ((l < 1) || (*dp != '"')) fail(); adv(1); if (len > l) fail(); b = malloc(len); bcopy(dp,b,len); *datap = b; *lenp = len; record_free(b); adv(len); } } break; case RL__OCTET: { unsigned char *op; op = va_arg(ap,unsigned char *); if (in_true) { if (l < 1) fail(); *op = *dp; adv(1); } } break; case RL__NUMBER: { unsigned int *vp; vp = va_arg(ap,unsigned int *); if (in_true) { int v; v = valid_number(); if (v < 0) fail(); if ((l < 1) || (*dp != '#')) fail(); *vp = v; adv(1); } } break; case RL__SET_FN: { void (**fp)(void); void (*fv)(void); fp = va_arg(ap,__typeof__(fp)); fv = va_arg(ap,__typeof__(fv)); if (in_true) *fp = fv; } break; case RL__REST: { const unsigned char **datap; int *lenp; datap = va_arg(ap,const unsigned char **); lenp = va_arg(ap,int *); if (in_true) { *datap = dp; *lenp = l; adv(l); } } break; case RL__IF: { int (*fn)(void); fn = va_arg(ap,__typeof__(fn)); c = malloc(sizeof(CSTACK)); c->type = CST_IF; c->link = cstack; cstack = c; if (in_true) { c->state = (*fn)() ? CSS_TRUE : CSS_NOTYET; } else { c->state = CSS_NOMORE; } } break; case RL__ENDIF: if (!cstack || (cstack->type != CST_IF)) abort(); c = cstack; cstack = c->link; free(c); break; default: abort(); break; } } } int rl__int(int arg) { return(arg); } const char *rl__const_char_p(const char *arg) { return(arg); } unsigned char *rl__unsigned_char_p(unsigned char *arg) { return(arg); } unsigned char **rl__unsigned_char_pp(unsigned char **arg) { return(arg); } const unsigned char **rl__const_unsigned_char_pp(const unsigned char **arg) { return(arg); } int *rl__int_p(int *arg) { return(arg); } unsigned int *rl__unsigned_int_p(unsigned int *arg) { return(arg); } void (**rl__void__pp__void(void (**arg)(void)))(void) { return(arg); } void (*rl__void__p__void(void (*arg)(void)))(void) { return(arg); } int (*rl__int__p__void(int (*arg)(void)))(void) { return(arg); }