/** * @brief Get the fully expanded name of a folder. * @note The folder hierarchy will be delimited with a "." character. * @param folders the inx object holding all of a user's magma folders. * @param target a pointer to the magma folder object to have its name expanded. * @return NULL on failure or a pointer to a managed string with the fully expanded name of the specified folder. */ stringer_t * magma_folder_name(inx_t *folders, magma_folder_t *target) { stringer_t *result; int_t recursion = 0; if (!folders || !target || !target->foldernum || st_empty(target->name)) { log_pedantic("Invalid folder context. Unable to construct the name."); return NULL; } else if (!(result = st_dupe_opts(MANAGED_T | JOINTED | HEAP, target->name))) { log_pedantic("We were unable to duplicate the folder name."); return NULL; } while (target && target->parent != 0 && recursion++ < FOLDER_RECURSION_LIMIT) { // Get the parent target. if ((target = magma_folder_find_number(folders, target->parent)) == NULL) { log_pedantic("There appears to be a folder with an invalid parent."); return result; } // Append the seperator and then the parent name. result = st_append(result, PLACER(".", 1)); result = st_append(result, target->name); } return result; }
/** * @brief Encode a data buffer as a valid URL component. * @param s a managed string containing the data to be encoded. * @return NULL on failure, or a freshly allocated managed string containing the fully-escaped string suitable for use in a URL. */ stringer_t *url_encode(stringer_t *s) { chr_t hex[4]; uchr_t *p; stringer_t *output, *r; size_t len, expected = 0, written = 0; if (st_empty_out(s, &p, &len)) { log_pedantic("An empty string was passed in for encoding."); return NULL; } // Increment through the stringer and count the characters that need to be encoded. for (size_t i = 0; i < len; i++) { if (url_valid_chr(*p)) { expected++; } else { expected += 3; } p++; } // Allocate one byte for printable characters and three bytes for non-printable characters. if (!(output = st_alloc_opts(MANAGED_T | JOINTED | HEAP, expected))) { log_pedantic("Could not allocate a buffer large enough to hold encoded result. {requested = %zu}", expected); return NULL; } // Get setup. p = st_data_get(s); // Increment through the stringer and copy the data into the new stringer. for (size_t i = 0; i < len; i++) { // Escape the invalid characters. if (url_valid_chr(*p)) { if ((r = st_append(output, PLACER(p, 1)))) { output = r; written++; } } else if (snprintf(hex, 4, "%%%02X", *p) == 3 && (r = st_append(output, PLACER(&hex[0], 3)))) { output = r; written += 3; } // We always advance the input pointer. p++; } st_length_set(output, written); return output; }
/** * @brief Perform QP (quoted-printable) encoding of a string. * @param s a pointer to a managed string containing data to be encoded. * @return a pointer to a managed string containing the QP encoded data, or NULL on failure. */ stringer_t * qp_encode(stringer_t *s) { chr_t hex[4]; uchr_t *p;//, *o; stringer_t *output, *r; size_t len, expected = 0, line = 0; if (st_empty_out(s, &p, &len)) { log_pedantic("An empty string was passed in for encoding."); return NULL; } // Increment through the stringer and count the characters that need to be encoded. for (size_t i = 0; i < len; i++) { if (*p < '!' || *p > '~' || *p == '=' || *p == ' ' || *p == '\r' || *p == '\n' || *p == '\t') { expected += 3; } else { expected++; } p++; } // Include room for the soft line break sequence every seventy six characters. expected += ((expected + QP_LINE_WRAP_LENGTH) / QP_LINE_WRAP_LENGTH) * 3; // Allocate one byte for printable characters and three bytes for non-printable characters. if (!(output = st_alloc_opts(MANAGED_T | JOINTED | HEAP, expected))) { log_pedantic("Could not allocate a buffer large enough to hold encoded result. {requested = %zu}", expected); return NULL; } // Get setup. p = st_data_get(s); //o = st_data_get(output); // Increment through the stringer and copy the data into the new stringer. for (size_t i = 0; i < len; i++) { // Escape the characters matching this boolean while simply copying any other characters we encounter. if (*p < '!' || *p > '~' || *p == '=' || *p == ' ' || *p == '\r' || *p == '\n' || *p == '\t') { // If were within three characters of the limit append a soft line break to the buffer. if (line > (QP_LINE_WRAP_LENGTH - 3) && snprintf(hex, 4, "=\r\n") == 3 && (r = st_append(output, PLACER(&hex[0], 3)))) { output = r; line = 0; } if (snprintf(hex, 4, "=%02X", *p) == 3 && (r = st_append(output, PLACER(&hex[0], 3)))) { output = r; line += 3; } } else { // If were near the line length limit this will append a soft line break before appending the next character. if (line > (QP_LINE_WRAP_LENGTH - 1) && snprintf(hex, 4, "=\r\n") == 3 && (r = st_append(output, PLACER(&hex[0], 3)))) { output = r; line = 0; } if ((r = st_append(output, PLACER(p, 1)))) { output = r; line++; } } // We always advance the input pointer. p++; } return output; }
static void _rt_run(struct _rt_invocation* inv) { struct _rt_stack* sp = inv->top->sp; while(1) { int tmp; switch(*inv->top->pc++) { case OP_NOOP: break; case OP_DEBUG: break; case OP_POP: sp++; break; case OP_ADD: if(_rt_num(inv,sp) || _rt_num(inv,sp + 1)) break; sp[1].num += sp[0].num; sp++; break; case OP_SUB: if(_rt_num(inv,sp) || _rt_num(inv,sp + 1)) break; sp[1].num -= sp[0].num; sp++; break; case OP_MUL: if(_rt_num(inv,sp) || _rt_num(inv,sp + 1)) break; sp[1].num *= sp[0].num; sp++; break; case OP_DIV: if(_rt_num(inv,sp) || _rt_num(inv,sp + 1) || sp->num == 0) break; sp[1].num /= sp[0].num; sp++; break; case OP_NOT: sp->num = _rt_test(sp) == 0; sp->type = STACK_NUM; break; case OP_NEG: if(_rt_num(inv,sp)) break; sp->num *= -1; break; case OP_EQ: sp[1].num = _rt_equal(inv,sp,sp + 1); sp[1].type = STACK_NUM; sp++; break; case OP_NE: sp[1].num = _rt_equal(inv,sp,sp + 1) == 0; sp[1].type = STACK_NUM; sp++; break; case OP_GE: sp[1].num = _rt_compare(inv,sp,sp + 1) >= 0; sp++; break; case OP_GT: sp[1].num = _rt_compare(inv,sp,sp + 1) > 0; sp++; break; case OP_LE: sp[1].num = _rt_compare(inv,sp,sp + 1) <= 0; sp++; break; case OP_LT: sp[1].num = _rt_compare(inv,sp,sp + 1) < 0; sp++; break; case OP_BNZ: // emit Is (branch forward conditional) tmp = *((ushort*)inv->top->pc); inv->top->pc += sizeof(ushort); if(_rt_test(sp)) inv->top->pc += tmp; sp++; case OP_BZ: // emit Is (branch forward conditional) tmp = *((ushort*)inv->top->pc); inv->top->pc += sizeof(ushort); if(_rt_test(sp) == 0) inv->top->pc += tmp; sp++; break; case OP_BR: // emit Is (branch forward) tmp = *((ushort*)inv->top->pc); inv->top->pc += tmp + sizeof(ushort); break; case OP_LOOP: // JIT-HOOK // emit Is (branch back) tmp = *((ushort*)inv->top->pc); inv->top->pc -= tmp - sizeof(ushort); break; case OP_ZLOOP: tmp = *((ushort*)inv->top->pc); inv->top->pc += sizeof(ushort); if(_rt_test(sp) == 0) inv->top->pc -= tmp; sp++; break; case OP_NZLOOP: tmp = *((ushort*)inv->top->pc); inv->top->pc += sizeof(ushort); if(_rt_test(sp)) inv->top->pc -= tmp; sp++; break; case OP_FREE: // emit Ic2 (byte,byte) tmp = *inv->top->pc++; while(tmp-- > 0) _rt_free(inv,&inv->top->vars[tmp + *inv->top->pc]); inv->top->pc++; break; case OP_NULL: // remove sp--; sp->type = STACK_NULL; break; case OP_IMM: // emit II (imm short) sp--; sp->type = STACK_NUM; sp->num = *((short*)inv->top->pc); inv->top->pc += sizeof(short); break; case OP_STR: // emit Is sp--; sp->type = STACK_RO_PTR; sp->single_ptr = inv->top->code->strings; st_move(inv->t,&sp->single_ptr,inv->top->pc,sizeof(ushort)); inv->top->pc += sizeof(ushort); break; case OP_OBJ: sp--; sp->type = STACK_OBJ; sp->ptr = sp->obj = inv->top->object; cle_skip_header(inv->hdl->inst,&sp->ptr); break; case OP_NEW: tmp = *((ushort*)inv->top->pc); inv->top->pc += sizeof(ushort); sp--; // if(cle_goto_object_cdat(inv->hdl->inst,inv->top->pc,tmp,&sp->obj)) if (1) _rt_error(inv,__LINE__); else { inv->top->pc += tmp; if(_rt_new_obj(inv,sp)) _rt_error(inv,__LINE__); } break; case OP_CLONE: if(sp->type != STACK_OBJ) _rt_error(inv,__LINE__); else if(_rt_new_obj(inv,sp)) _rt_error(inv,__LINE__); break; case OP_ID: sp--; sp->type = STACK_OBJ; sp->obj = inv->top->object; _rt_type_id(inv,sp); break; case OP_IDO: _rt_type_id(inv,sp); break; case OP_FIND: inv->top->pc++; if(sp->type == STACK_PTR || sp->type == STACK_RO_PTR) { if(cle_goto_object(inv->hdl->inst,sp->single_ptr,&sp->obj)) sp->type = STACK_NULL; else { sp->ptr = sp->obj; cle_skip_header(inv->hdl->inst,&sp->ptr); sp->type = STACK_OBJ; } } else _rt_error(inv,__LINE__); break; case OP_IT: inv->top->pc++; sp--; switch(sp[1].type) { case STACK_PROP: // try to start iterator on value break; case STACK_COLLECTION: it_create(inv->t,&sp->it,&sp[1].ptr); sp->type = STACK_ITERATOR_COL; break; case STACK_PTR: case STACK_RO_PTR: it_create(inv->t,&sp->it,&sp[1].single_ptr); sp->type = STACK_ITERATOR; break; default: _rt_error(inv,__LINE__); } break; case OP_INEXT: tmp = *inv->top->pc++; switch(sp->type) { case STACK_ITERATOR: sp->num = it_next(inv->t,0,&sp->it,0); break; case STACK_ITERATOR_COL: sp->num = it_next(inv->t,0,&sp->it,sizeof(oid)); break; default: _rt_error(inv,__LINE__); } sp->type = STACK_NUM; break; case OP_IPREV: tmp = *inv->top->pc++; switch(sp->type) { case STACK_ITERATOR: sp->num = it_prev(inv->t,0,&sp->it,0); break; case STACK_ITERATOR_COL: sp->num = it_prev(inv->t,0,&sp->it,sizeof(oid)); break; default: _rt_error(inv,__LINE__); } sp->type = STACK_NUM; break; case OP_IKEY: inv->top->pc++; if(sp->type != STACK_ITERATOR && sp->type != STACK_ITERATOR_COL) _rt_error(inv,__LINE__); else { st_ptr pt; st_empty(inv->t,&pt); st_append(inv->t,&pt,sp->it.kdata,sp->it.kused); sp->single_ptr = sp->single_ptr_w = pt; sp->type = STACK_PTR; } break; case OP_IVAL: inv->top->pc++; if(sp->type == STACK_ITERATOR) { st_ptr pt; if(it_current(inv->t,&sp->it,&pt) == 0) { sp->single_ptr = sp->single_ptr_w = pt; sp->type = STACK_PTR; } else sp->type = STACK_NULL; } else if(sp->type == STACK_ITERATOR_COL) { if(sp->it.kused == sizeof(oid)) { // TODO: move to object.c st_ptr pt = inv->hdl->inst.root; st_move(inv->t,&pt,sp->it.kdata,sizeof(oid)); sp->ptr = sp->obj = pt; cle_skip_header(inv->hdl->inst,&sp->ptr); sp->type = STACK_OBJ; } else sp->type = STACK_NULL; } else _rt_error(inv,__LINE__); break; case OP_OMV: tmp = *((ushort*)inv->top->pc); inv->top->pc += sizeof(ushort); sp--; sp->obj = inv->top->object; if(cle_get_property_host(inv->hdl->inst,&sp->ptr,inv->top->pc,tmp) < 0) { sp->type = STACK_NULL; inv->top->pc += tmp; } else { inv->top->pc += tmp; sp->ptr = sp->obj; cle_skip_header(inv->hdl->inst,&sp->ptr); _rt_get(inv,&sp); } break; case OP_MV: tmp = *((ushort*)inv->top->pc); inv->top->pc += sizeof(ushort); if(_rt_move(inv,&sp,inv->top->pc,tmp)) sp->type = STACK_NULL; inv->top->pc += tmp; break; case OP_RIDX: if(sp->type == STACK_NUM) { char buffer[sizeof(rt_number) + HEAD_SIZE]; buffer[0] = 0; buffer[1] = 'N'; memcpy(buffer + 2,&sp->num,sizeof(rt_number)); sp++; if(_rt_move(inv,&sp,buffer,sizeof(buffer))) sp->type = STACK_NULL; } else if(sp->type == STACK_PTR || sp->type == STACK_RO_PTR) { st_ptr mv = sp->single_ptr; sp++; if(_rt_move_st(inv,&sp,&mv)) sp->type = STACK_NULL; } break; case OP_LVAR: sp--; *sp = inv->top->vars[*inv->top->pc++]; break; // writer case OP_POPW: if(sp->type == STACK_OUTPUT) sp->out->pop(sp->outdata); else sp++; break; case OP_DMVW: tmp = *((ushort*)inv->top->pc); inv->top->pc += sizeof(ushort); switch(sp->type) { case STACK_REF: if(sp->var->type == STACK_NULL) { st_empty(inv->t,&sp->var->single_ptr_w); sp->var->single_ptr = sp->var->single_ptr_w; } else if(sp->var->type != STACK_PTR) { _rt_error(inv,__LINE__); return; } sp->single_ptr_w = sp->var->single_ptr; sp->single_ptr = sp->single_ptr_w; sp->type = STACK_PTR; case STACK_PTR: sp--; sp[0] = sp[1]; st_insert(inv->t,&sp->single_ptr_w,inv->top->pc,tmp); break; case STACK_OUTPUT: if(inv->response_started == 0) { sp->out->start(sp->outdata); inv->response_started = 1; } else inv->response_started = 2; sp->out->push(sp->outdata); sp->out->data(sp->outdata,inv->top->pc,tmp); } inv->top->pc += tmp; break; case OP_MVW: tmp = *((ushort*)inv->top->pc); inv->top->pc += sizeof(ushort); switch(sp->type) { case STACK_PTR: st_insert(inv->t,&sp->single_ptr_w,inv->top->pc,tmp); break; case STACK_OUTPUT: if(inv->response_started == 0) { sp->out->start(sp->outdata); inv->response_started = 1; } else inv->response_started = 2; sp->out->data(sp->outdata,inv->top->pc,tmp); } inv->top->pc += tmp; break; case OP_WIDX: // replace by OP_OUT ? _rt_out(inv,&sp,sp,sp + 1); sp++; break; case OP_OPEN: _rt_do_open(inv,&sp); break; case OP_OPEN_POP: // unfinished output if(inv->response_started == 2) sp->out->next(sp->outdata); sp->out->end(sp->outdata,0,0); inv->response_started = 1; tk_commit_task(sp->outtask); // well, what if something went wrong?? sp++; break; // receive input case OP_RECV: sp += *inv->top->pc++; inv->top->sp = sp; return; case OP_SET: if(inv->top->is_expr != 0) _rt_error(inv,__LINE__); else if(sp[1].type != STACK_PROP) _rt_error(inv,__LINE__); else { switch(sp->type) { case STACK_PROP: if(cle_identity_value(inv->hdl->inst,sp->prop_id,sp->prop_obj,&sp->ptr)) _rt_error(inv,__LINE__); if(cle_set_property_ptr(inv->hdl->inst,sp[1].prop_obj,sp[1].prop_id,&sp[1].ptr)) _rt_error(inv,__LINE__); // might not be a good idea if prop-val is a mem-ref st_copy_st(inv->t,&sp[1].ptr,&sp->ptr); break; case STACK_RO_PTR: // link if(cle_set_property_ptr(inv->hdl->inst,sp[1].prop_obj,sp[1].prop_id,&sp[1].ptr)) _rt_error(inv,__LINE__); st_link(inv->t,&sp[1].ptr,&sp->single_ptr); break; case STACK_PTR: // copy if(cle_set_property_ptr(inv->hdl->inst,sp[1].prop_obj,sp[1].prop_id,&sp[1].ptr)) _rt_error(inv,__LINE__); st_copy_st(inv->t,&sp[1].ptr,&sp->single_ptr); break; case STACK_NUM: // bin-num if(cle_set_property_num(inv->hdl->inst,sp[1].prop_obj,sp[1].prop_id,sp->num)) _rt_error(inv,__LINE__); break; case STACK_OBJ: // obj-ref if(cle_set_property_ref(inv->hdl->inst,sp[1].prop_obj,sp[1].prop_id,sp->obj)) _rt_error(inv,__LINE__); break; case STACK_CODE: // write out path/event to method/handler if(st_move(inv->t,&sp->single_ptr,"p",1) == 0) { if(cle_set_property_ptr(inv->hdl->inst,sp[1].prop_obj,sp[1].prop_id,&sp[1].ptr)) _rt_error(inv,__LINE__); st_copy_st(inv->t,&sp[1].ptr,&sp->single_ptr); break; } // or null default: // empty / null if(cle_set_property_ptr(inv->hdl->inst,sp[1].prop_obj,sp[1].prop_id,&sp[1].ptr)) _rt_error(inv,__LINE__); } } sp += 2; break; case OP_MERGE: switch(sp->type) { case STACK_PROP: if(inv->top->is_expr != 0) _rt_error(inv,__LINE__); else if(cle_set_property_ptr(inv->hdl->inst,sp->prop_obj,sp->prop_id,&sp->single_ptr)) _rt_error(inv,__LINE__); else { sp->single_ptr_w = sp->single_ptr; sp->type = STACK_PTR; } break; case STACK_REF: if(sp->var->type == STACK_NULL) { st_empty(inv->t,&sp->var->single_ptr); sp->var->single_ptr_w = sp->var->single_ptr; sp->var->type = STACK_PTR; } else if(sp->var->type != STACK_PTR) _rt_error(inv,__LINE__); case STACK_PTR: case STACK_OUTPUT: break; default: _rt_error(inv,__LINE__); } break; case OP_2STR: tmp = *inv->top->pc++; // vars if(tmp != 1) { _rt_error(inv,__LINE__); break; } // fall throu case OP_CAT: { struct _rt_stack to; st_empty(inv->t,&to.single_ptr); to.single_ptr_w = to.single_ptr; to.type = STACK_PTR; _rt_out(inv,&sp,&to,sp); *sp = to; } break; case OP_NEXT: // non-string (concat) out-ing [OUT Last Tree] if(sp[1].type == STACK_REF) { if(sp[1].var->type == STACK_NULL) *sp[1].var = *sp; else _rt_ref_out(inv,&sp,sp + 1); } else { if(_rt_out(inv,&sp,sp + 1,sp) == 0) { sp++; if(inv->response_started == 2 && sp->type == STACK_OUTPUT) { inv->response_started = 1; sp->out->next(sp->outdata); } } } break; case OP_OUTL: // TODO: stream out structures case OP_OUT: // stream out string if(sp[1].type == STACK_REF) _rt_ref_out(inv,&sp,sp + 1); else _rt_out(inv,&sp,sp + 1,sp); sp++; break; case OP_AVAR: inv->top->vars[*inv->top->pc++] = *sp; sp++; break; case OP_DEFP: // emit Is2 (branch forward) tmp = *inv->top->pc++; // var if(inv->top->vars[tmp].type == STACK_NULL) { sp--; inv->top->vars[tmp].var = sp; inv->top->vars[tmp].type = STACK_REF; inv->top->pc += sizeof(ushort); } else { tmp = *((ushort*)inv->top->pc); inv->top->pc += tmp + sizeof(ushort); } break; case OP_END: tmp = inv->top->code->body.maxparams; while(tmp-- > 0) _rt_free(inv,&inv->top->vars[tmp]); if(inv->top->parent == 0) { // unfinished output? -> next if(inv->response_started == 2) inv->hdl->response->next(inv->hdl->respdata); cle_stream_end(inv->hdl); return; } else { struct _rt_callframe* cf = inv->top; inv->top = inv->top->parent; sp = inv->top->sp; // unref page of origin tk_unref(inv->t,cf->pg); } break; case OP_DOCALL: tmp = *inv->top->pc++; // params if(_rt_call(inv,sp,tmp) == 0) { inv->top->parent->sp = sp + 1 + tmp; // return-stack *(--inv->top->sp) = *(sp + 1 + tmp); // copy output-target sp = inv->top->sp; // set new stack } break; case OP_DOCALL_N: tmp = *inv->top->pc++; // params if(_rt_call(inv,sp,tmp) == 0) { inv->top->parent->sp = sp + tmp; // return-stack inv->top->sp--; inv->top->sp->type = STACK_REF; // ref to sp-top inv->top->sp->var = sp + tmp; inv->top->sp->var->type = STACK_NULL; sp = inv->top->sp; // set new stack } break; case OP_ERROR: // system exception return; default: _rt_error(inv,__LINE__); } } }