/** * @short Helps to prepare each pair. */ static void onion_dict_json_preorder(onion_block *block, const char *key, const void *value, int flags){ if (!onion_block_size(block)) // Error somewhere. return; char *s; s=onion_c_quote_new(key); if (s==NULL){ onion_block_clear(block); return; } onion_block_add_str(block, s); free(s); onion_block_add_char(block, ':'); if (flags&OD_DICT){ onion_block *tmp; tmp=onion_dict_to_json((onion_dict*)value); if (!tmp){ onion_block_clear(block); return; } onion_block_add_block(block, tmp); onion_block_free(tmp); } else{ s=onion_c_quote_new(value); if (s==NULL){ onion_block_clear(block); return; } onion_block_add_str(block, s); free(s); } onion_block_add_data(block, ", ",2); }
void POST_a_lot(void) { sleep(1); onion_block *tosend = onion_block_new(); onion_block_add_str(tosend, "POST /configuration HTTP/1.1\nHost: example.com\nContent-Type: x-application/garbage\nContent-Length: 1000000\n\n"); { int i; onion_block *bl = onion_block_new(); for (i = 0; i < 1000; i++) { onion_block_add_char(bl, rand() & 255); } for (i = 0; i < 1000; i++) { onion_block_add_block(tosend, bl); } onion_block_free(bl); } onion_block *bl = connect_and_send("127.0.0.1", "8080", tosend, 1024 * 64); onion_block_free(tosend); ONION_DEBUG("%p", strstr(onion_block_data(bl), "\n1000000\n")); FAIL_IF_NOT(strstr(onion_block_data(bl), "\n1000000\n") != NULL); onion_block_free(bl); }
void t02_several_add_methods(){ INIT_TEST(); onion_block *block=onion_block_new(); FAIL_IF_EQUAL(block, NULL); int i; for (i=0;i<1024;i++){ onion_block_add_char(block, (char)i); } onion_block_clear(block); onion_block_add_str(block, "first "); for (i=0;i<1024;i++) onion_block_add_str(block, "test "); FAIL_IF_NOT_STRSTR(onion_block_data(block), "test"); for (i=0;i<1024;i++) onion_block_add_data(block, "world", 4); FAIL_IF_STRSTR(onion_block_data(block), "world"); FAIL_IF_NOT_STRSTR(onion_block_data(block), "worl"); int s=onion_block_size(block); onion_block_add_block(block, block); FAIL_IF_NOT_EQUAL(onion_block_size(block), s+s); onion_block_free(block); END_TEST(); }
/** * @short Returns the current data. * @memberof onion_block_t * * It will be finished with a \0 (if not already, to ensure is printable. */ const char *onion_block_data(const onion_block *b){ // It can really modify the size, as it ensures a \0 at the end, but its ok if (b->size==b->maxsize){ onion_block_add_char((onion_block*)b, 0); ((onion_block*)b)->size--; } else // Its within limits b->data[b->size]='\0'; return b->data; }
/** * @short Converts a dict to a json string * @memberof onion_dict_t * * Given a dictionary and a buffer (with size), it writes a json dictionary to it. * * @returns an onion_block with the json data, or NULL on error */ onion_block *onion_dict_to_json(onion_dict *dict){ onion_block *block=onion_block_new(); onion_block_add_char(block, '{'); if (dict && dict->root) onion_dict_node_preorder(dict->root, (void*)onion_dict_json_preorder, block); int s=onion_block_size(block); if (s==0){ // Error. onion_block_free(block); return NULL; } if (s!=1) // To remove a final ", " onion_block_rewind(block, 2); onion_block_add_char(block, '}'); return block; }
/** * @short Helps to prepare each pair. */ static void onion_dict_json_preorder(onion_block *block, const char *key, const void *value, int flags){ if (!onion_block_size(block)) // Error somewhere. return; onion_block_add_char(block,'\"'); onion_json_quote_add(block, key); onion_block_add_data(block,"\":",2); if (flags&OD_DICT){ onion_block *tmp; tmp=onion_dict_to_json((onion_dict*)value); if (!tmp){ onion_block_clear(block); return; } onion_block_add_block(block, tmp); onion_block_free(tmp); } else{ onion_block_add_char(block,'\"'); onion_json_quote_add(block, value); onion_block_add_char(block,'\"'); } onion_block_add_data(block, ", ",2); }
void t01_create_and_free(){ INIT_TEST(); onion_block *block=onion_block_new(); FAIL_IF_EQUAL(block, NULL); int i; for (i=0;i<16*1024;i++){ onion_block_add_char(block, (char)i); } onion_block_free(block); END_TEST(); }
/** * @short Adds some code to the top function */ void function_add_code(parser_status *st, const char *fmt, ...){ function_data *p=(function_data*)st->function_stack->tail->data; if (p->flags&F_NO_MORE_WRITE) return; char tmp[4096]; va_list ap; va_start(ap, fmt); vsnprintf(tmp, sizeof(tmp), fmt, ap); va_end(ap); if (use_orig_line_numbers){ char line[32]; int p=onion_block_size(st->current_code); if (p && onion_block_data(st->current_code)[p-1]!='\n') onion_block_add_char(st->current_code, '\n'); snprintf(line,sizeof(line),"#line %d\n", st->line); // I have to do it for every \n too. This is going to be slow. const char *orig=tmp; int lorig=strlen(orig); int i=0, li=0; for (i=0;i<lorig;i++){ if (orig[i]=='\n'){ onion_block_add_str(st->current_code, line); onion_block_add_data(st->current_code, &orig[li], i-li+1); li=i; } } if (i-1!=li){ onion_block_add_str(st->current_code, line); onion_block_add_str(st->current_code, &orig[li]); } } else{ //ONION_DEBUG("Add to level %d text %s",list_count(st->function_stack), tmp); onion_block_add_str(st->current_code, tmp); } }
onion_dict *onion_dict_from_json_(const char **_data){ const char *data=*_data; ONION_DEBUG("Parse %s", *_data); while (is_json_space(*data)) ++data; if (*data!='{') return NULL; ++data; while (is_json_space(*data)) ++data; ; onion_dict *ret=onion_dict_new(); onion_block *key=onion_block_new(); onion_block *value=onion_block_new(); while (*data!='}'){ // Get Key ssize_t read_bytes=onion_json_unquote_add(key, data); if (read_bytes<0) goto error; data+=read_bytes; while (is_json_space(*data)) ++data; /// Get : if (*data!=':'){ // Includes \0 ONION_DEBUG("Expected : got %c", *data); goto error; } ++data; while (is_json_space(*data)) ++data; /// Get Value if (*data=='{'){ // Includes \0 *_data=data; onion_dict *sub=onion_dict_from_json_(_data); if (!sub){ goto error; } onion_dict_add(ret, onion_block_data(key), sub, OD_DUP_KEY|OD_DICT|OD_FREE_VALUE); data=*_data; } else if (is_json_digit(*data)){ while(is_json_digit(*data)){ onion_block_add_char(value, *data); ++data; } onion_dict_add(ret, onion_block_data(key), onion_block_data(value), OD_DUP_ALL); } else if (*data=='"'){ // parse string ssize_t read_bytes=onion_json_unquote_add(value, data); if (read_bytes<0) goto error; data+=read_bytes; onion_dict_add(ret, onion_block_data(key), onion_block_data(value), OD_DUP_ALL); onion_block_clear(value); } else { // Includes \0 ONION_DEBUG("Expected \" got %c", *data); goto error; } onion_block_clear(key); while (is_json_space(*data)) ++data; if (*data=='}'){ ++data; *_data=data; onion_block_free(key); onion_block_free(value); return ret; } if (*data!=','){ ONION_DEBUG("Expected , got %c", *data); goto error; } ++data; while (is_json_space(*data)) ++data; } ++data; *_data=data; onion_block_free(key); onion_block_free(value); return ret; error: onion_block_free(key); onion_block_free(value); onion_dict_free(ret); return NULL; }
/** * @short Solves a variable into code. * * It uses the type to check it its a literal string, a dcit string or a dict. */ void variable_solve(parser_status *st, const char *data, const char *tmpname, vartype_e type){ if (type==LITERAL){ char *s=onion_c_quote_new(data); function_add_code(st, " %s=%s;\n", tmpname, s); free(s); return; } if (! (type==STRING || type==DICT) ){ ONION_ERROR("Invalid type for variable solve"); exit(1); } list *parts=list_new(onion_block_free); onion_block *lastblock; list_add(parts, lastblock=onion_block_new()); int i=0; int l=strlen(data); const char *d=data; for (i=0;i<l;i++){ if (d[i]=='.') list_add(parts, lastblock=onion_block_new()); else if (d[i]==' ') continue; else onion_block_add_char(lastblock, d[i]); } if (list_count(parts)==1){ char *s=onion_c_quote_new(onion_block_data(lastblock)); if (type==STRING) function_add_code(st, " %s=onion_dict_get(context, %s);\n", tmpname, s); else if (type==DICT) function_add_code(st, " %s=onion_dict_get_dict(context, %s);\n", tmpname, s); free(s); } else{ if (type==STRING) function_add_code(st," %s=onion_dict_rget(context", tmpname); else if (type==DICT) function_add_code(st," %s=onion_dict_rget_dict(context", tmpname); else{ ONION_ERROR("Invalid type for variable solve"); exit(1); } list_item *it=parts->head; while (it){ lastblock=it->data; char *s=onion_c_quote_new(onion_block_data(lastblock)); function_add_code(st,", %s", s); free(s); it=it->next; } function_add_code(st,", NULL);\n"); } list_free(parts); }
/// Read a char from the st->in- void add_char(parser_status *st, char c){ onion_block_add_char(st->rawblock, c); }
onion_dict *onion_dict_from_json_(const char **_data){ const char *data=*_data; ONION_DEBUG("Parse %s", *_data); while (isspace(SAFETY_CAST(*data))) ++data; if (*data!='{') return NULL; ++data; while (isspace(SAFETY_CAST(*data))) ++data; ; onion_dict *ret=onion_dict_new(); onion_block *key=onion_block_new(); onion_block *value=onion_block_new(); while (*data!='}'){ // Get Key if (*data!='"'){ // Includes \0 ONION_DEBUG("Expected \" got %c", *data); goto error; } ++data; while (*data!='"'){ if (!*data){ // \0 ONION_DEBUG("Expected \" got eof"); goto error; } onion_block_add_char(key, *data); ++data; } ++data; while (isspace(SAFETY_CAST(*data))) ++data; /// Get : if (*data!=':'){ // Includes \0 ONION_DEBUG("Expected : got %c", *data); goto error; } ++data; while (isspace(SAFETY_CAST(*data))) ++data; /// Get Value if (*data=='{'){ // Includes \0 *_data=data; onion_dict *sub=onion_dict_from_json_(_data); if (!sub){ goto error; } onion_dict_add(ret, onion_block_data(key), sub, OD_DUP_KEY|OD_DICT|OD_FREE_VALUE); data=*_data; } else if (isdigit(SAFETY_CAST(*data))){ while(isdigit(SAFETY_CAST(*data))){ onion_block_add_char(value, *data); ++data; } onion_dict_add(ret, onion_block_data(key), onion_block_data(value), OD_DUP_ALL); } else if (*data=='"'){ ++data; while (*data!='"'){ if (!*data){ // \0 ONION_DEBUG("Expected \" got eof"); goto error; } onion_block_add_char(value, *data); ++data; } ++data; onion_dict_add(ret, onion_block_data(key), onion_block_data(value), OD_DUP_ALL); onion_block_clear(value); } else { // Includes \0 ONION_DEBUG("Expected \" got %c", *data); goto error; } onion_block_clear(key); while (isspace(SAFETY_CAST(*data))) ++data; if (*data=='}'){ ++data; *_data=data; onion_block_free(key); onion_block_free(value); return ret; } if (*data!=','){ ONION_DEBUG("Expected , got %c", *data); goto error; } ++data; while (isspace(SAFETY_CAST(*data))) ++data; } ++data; *_data=data; onion_block_free(key); onion_block_free(value); return ret; error: onion_block_free(key); onion_block_free(value); onion_dict_free(ret); return NULL; }