/*--------------------------------------------------------------------*/ static INLINE size_t strbuf_grow (strbuf_t *buf, size_t len) /* Extend the stringbuffer <buf> to hold at least <len> more * bytes (ie. enough for a string of length <len>-1). * * Return <len> if all memory could be allocated, or a lower number * of only part of the required memory is available. * * N.B.: be careful with overflows when doing the checks. */ { size_t new_len; /* Catch some simple situations. */ if (buf->alloc_len >= MAX_STRBUF_LEN) return 0; /* Truncated */ if (buf->alloc_len - buf->length > len) return len; /* Allocate more than we need in anticipation of further adds, * but not more than we can manage */ if (MAX_STRBUF_LEN - buf->length < len * 3) { new_len = MAX_STRBUF_LEN; if (new_len - buf->length < len) len = new_len - buf->length; } else new_len = buf->length + len * 3; /* Is this the first allocation? */ if (!buf->buf) { memsafe(buf->buf = xalloc(new_len), new_len, "new strbuf"); buf->alloc_len = (u_long)new_len; buf->length = 0; *(buf->buf) = '\0'; return len; } /* Extension of the existing buffer */ memsafe(buf->buf = rexalloc(buf->buf, new_len), new_len, "larger strbuf"); buf->alloc_len = (u_long)new_len; return len; } /* strbuf_grow() */
/*-------------------------------------------------------------------------*/ svalue_t * f_tls_error(svalue_t *sp) /* EFUN tls_error() * * string tls_error(int errorno) * * tls_error() returns a string describing the error behind the * error number <errorno>. */ { string_t *s; const char *text; int err = sp->u.number; text = tls_error(err); if (text) { memsafe(s = new_mstring(text), strlen(text), "tls_error()"); free_svalue(sp); put_string(sp, s); } else { free_svalue(sp); put_number(sp, 0); } return sp; } /* f_tls_error() */
/*-------------------------------------------------------------------------*/ svalue_t * enhance_arraylist (svalue_t * list) /* Add an element to the arraylist to <list>. * It is the responsibility of the caller to ensure * that <list> is in fact an arraylist. */ { arraylist_t * data = (arraylist_t *) list->u.lvalue; arraylist_element_t * element; memsafe(element = xalloc(sizeof(*element)), sizeof(*element), "arraylist element"); element->next = NULL; put_number(&(element->value), 0); if (data->last == NULL) { data->first = element; data->last = element; } else { data->last->next = element; data->last = element; } data->num++; return &(element->value); } /* enhance_arraylist() */
/*-------------------------------------------------------------------------*/ string_t * trim_all_spaces (const string_t * txt) /* Trim the input string <txt> by removing all leading and trailing * space, and by folding embedded space runs into just one each. * Return the new string with one ref; the refcount of <txt> is not changed. * * Throw an error when out of memory. */ { char * dest; const char * src; size_t dest_ix, src_ix, srclen; string_t * rc; dest = alloca(mstrsize(txt)); if (dest == NULL) errorf("Stack overflow (%zu bytes)\n", mstrsize(txt)); src = get_txt((string_t *const)txt); srclen = mstrsize(txt); src_ix = 0; dest_ix = 0; /* Blank out trailing spaces */ while (srclen > 0 && src[srclen-1] == ' ') srclen--; /* Skip leading spaces */ while (src_ix < srclen && *src == ' ') src_ix++, src++; /* Copy characters, but fold embedded spaces. */ for ( ; src_ix < srclen; src_ix++, src++, dest_ix++) { dest[dest_ix] = *src; /* If this and the next character is a space, forward * src until the last space in this run. */ if (' ' == *src) { while (src_ix+1 < srclen && ' ' == src[1]) src_ix++, src++; } } memsafe(rc = new_n_mstring(dest, dest_ix), dest_ix, "trimmed result"); return rc; } /* trim_all_spaces() */
/*-------------------------------------------------------------------------*/ void put_arraylist (svalue_t * list) /* Create an arraylist and put it into <list>. */ { arraylist_t * data; memsafe(data = xalloc(sizeof(*data)), sizeof(*data), "arraylist"); data->head.fun = cleanup_arraylist; data->num = 0; data->first = NULL; data->last = NULL; list->type = T_ERROR_HANDLER; list->u.error_handler = &(data->head); } /* put_arraylist() */
/*-------------------------------------------------------------------------*/ svalue_t * v_tls_init_connection (svalue_t *sp, int num_arg) /* EFUN tls_init_connection() * * int tls_init_connection(object ob) * int tls_init_connection(object ob, string fun, string|object fob, mixed extra...) * int tls_init_connection(object ob, closure fun, mixed extra...) * * tls_init_connection() tries to start a TLS secured connection to the * interactive object <ob> (or this_object() if <ob> is not given). * Result: * errorcode < 0: unsuccessful, use tls_error() to get an useful * description of the error * number > 0: the secure connection is still being set up in the * background * number == 0: the secure connection is active. * * If the callback <fun>/<fun>:<fob> is specified, it will be called once * the fate of the secure connection has been determined. The first argument * will be the return code from the handshake (errorcode < 0 on failure, * or 0 on success), followed by the interactive object <ob> and any <extra> * arguments. */ { svalue_t * argp = sp - num_arg + 1; long ret; object_t * obj; interactive_t *ip; if (!tls_available()) errorf("tls_init_connection(): TLS layer hasn't been initialized.\n"); if (num_arg > 0) { obj = argp->u.ob; put_number(argp, 0); /* remove obj reference from the stack */ } else { obj = ref_object(current_object, "tls_init_connection"); } if (!O_SET_INTERACTIVE(ip, obj)) { free_object(obj, "tls_init_connection"); errorf("Bad arg 1 to tls_init_connection(): " "object not interactive.\n"); } free_object(obj, "tls_init_connection"); /* ip has another reference to obj, so this is safe to do */ if (ip->tls_status != TLS_INACTIVE) errorf("tls_init_connection(): Interactive already has a secure " "connection.\n"); /* Extract the callback information from the stack */ if (num_arg > 1) { /* Extract the callback information from the stack */ int error_index; callback_t * cb; inter_sp = sp; memsafe(cb = xalloc(sizeof *cb) , sizeof *cb , "callback structure"); assign_eval_cost(); error_index = setup_efun_callback(cb, argp+1, num_arg-1); if (error_index >= 0) { /* The callback values have already been removed. */ xfree(cb); inter_sp = sp = argp; vefun_bad_arg(error_index+2, argp); /* NOTREACHED */ return argp; } /* Callback creation successful */ ip->tls_cb = cb; } inter_sp = sp = argp - 1; /* Flush the connection */ { object_t * save_c_g = command_giver; command_giver = obj; add_message(message_flush); command_giver = save_c_g; } ret = tls_init_connection(ip); if (ret >= 0) { ip->tls_status = TLS_HANDSHAKING; ret = tls_continue_handshake(ip); /* Adjust the return value of tls_continue_handshake() */ if (ret >= 0) ret = !ret; } push_number(sp, ret); return sp; } /* f_tls_init_connection() */
/*--------------------------------------------------------------------*/ string_t * intersect_strings (const string_t * p_left, const string_t * p_right, Bool bSubtract) /* !bSubtract: Intersect string <left> with string <right> and return * a newly allocated string with all those characters which are in * both strings. * bSubtract: Subtract string <right> from string <left> and return * a newly allocated string with all those characters which are in * <left> but not in <right>. * The order of the characters returned is their order of appearance * in <left>. */ { size_t len_left, len_right, len_out; size_t ix_left, ix_right; long * pos; CBool * matches; const char * left_txt; char * left, * right, * result_txt; string_t *result; len_left = mstrsize(p_left); len_right = mstrsize(p_right); xallocate(matches, len_left+1, "intersection matches"); /* +1 so that smalloc won't complain when given an empty left string */ for (ix_left = 0; ix_left < len_left; ix_left++) matches[ix_left] = bSubtract ? MY_TRUE : MY_FALSE; /* Sort the two strings */ left = sort_string(p_left, len_left, &pos); right = sort_string(p_right, len_right, NULL); /* Intersect the two strings by mutual comparison. * Each non-matched character in left gets is pos[] set to -1. */ len_out = bSubtract ? len_left : 0; for ( ix_left = 0, ix_right = 0 ; ix_left < len_left && ix_right < len_right ; ) { if (left[ix_left] < right[ix_right]) ix_left++; else if (left[ix_left] > right[ix_right]) ix_right++; else /* left[ix_left] == right[ix_right]) */ { if (!bSubtract) { matches[pos[ix_left]] = MY_TRUE; len_out++; } else { matches[pos[ix_left]] = MY_FALSE; len_out--; } ix_left++; } } /* Create the result: copy all flagged characters */ memsafe(result = alloc_mstring(len_out), len_out, "intersection result"); left_txt = get_txt((string_t *const)p_left); result_txt = get_txt(result); for (ix_left = 0, ix_right = 0; ix_left < len_left; ix_left++) if (matches[ix_left]) result_txt[ix_right++] = left_txt[ix_left]; /* Free intermediate results */ xfree(pos); xfree(matches); xfree(left); xfree(right); return result; } /* intersect_strings() */
svalue_t * f_psyc_render(svalue_t *sp) { uint8_t i; vector_t *v; string_t *out; char *meth, *body; size_t mlen, blen; mapping_t *map; psycPacket packet; psycHeader headers[2]; // unless (sp->type == T_POINTER) return sp; v = sp->u.vec; if (VEC_SIZE(v) == PACKET_BODY + 1) { for (i = PACKET_ROUTING; i <= PACKET_ENTITY; i++) { headers[i].lines = 0; if (v->item[i].type == T_MAPPING) { map = v->item[i].u.map; if (!MAP_SIZE(map)) continue; headers[i].modifiers = malloc(sizeof(psycModifier) * MAP_SIZE(v->item[i].u.map)); if (!headers[i].modifiers) { errorf("Out of memory in psyc_render for modifier table.\n"); return sp; // not reached } walk_mapping(map, &fill_header_from_mapping, &(psyc_modifier_t) { &headers[i], map->num_values, i == PACKET_ROUTING ? PSYC_MODIFIER_ROUTING : PSYC_MODIFIER_CHECK_LENGTH }); } // else ... ignoring possibly invalid args } } else { errorf("Wrong number of elements (%" PRIdMPINT ") " "in array argument to psyc_render()\n", VEC_SIZE(v)); return sp; // not reached } if (v->item[PACKET_METHOD].type == T_STRING) { meth = get_txt(v->item[PACKET_METHOD].u.str); mlen = mstrsize(v->item[PACKET_METHOD].u.str); } else { meth = NULL; mlen = 0; } if (v->item[PACKET_BODY].type == T_STRING) { body = get_txt(v->item[PACKET_BODY].u.str); blen = mstrsize(v->item[PACKET_BODY].u.str); } else { body = NULL; blen = 0; } packet = psyc_newPacket2(headers[PACKET_ROUTING].modifiers, headers[PACKET_ROUTING].lines, headers[PACKET_ENTITY].modifiers, headers[PACKET_ENTITY].lines, meth, mlen, body, blen, PSYC_PACKET_CHECK_LENGTH); #ifdef DEBUG printf("rendering... packet.length = %ld\n", packet.length); #endif // alloc_mstring creates an *untabled* string suitable for tmp data memsafe(out = alloc_mstring(packet.length), packet.length, "f_psyc_render"); psyc_render(&packet, get_txt(out), packet.length); free_svalue(sp); put_string(sp, out); // stack should take care of freeing the string after use return sp; } /* f_psyc_render */