/*-------------------------------------------------------------------------*/ void * mb_realloc (membuffer_e buf, size_t size) /* Realloate the memory of buffer <buf> to hold <size> bytes, without * losing the current content, and return the new pointer. * Returns NULL when out of memory (the old memory block will be unaffected * then). */ { void * mem; #ifdef DEBUG if (buf >= mbMax) fatal("mb_alloc: Illegal buf# %d\n", buf); #endif if (membuffers[buf].size >= size) return membuffers[buf].mem; if (membuffers[buf].mem != NULL) mem = rexalloc(membuffers[buf].mem, size); else mem = xalloc(size); if (mem != NULL) { membuffers[buf].mem = mem; membuffers[buf].size = size; } return mem; } /* mb_realloc() */
/*--------------------------------------------------------------------*/ 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() */
/*-------------------------------------------------------------------------*/ Bool assert_simul_efun_object (void) /* (Re)load the simul_efun object and extract all information we need. * Result is TRUE if either the simul_efun object could be loaded, or if * master::get_simul_efun() did not return a string/string vector to * name the simul efun object. The result is FALSE if master::get_simul_efun() * specified a simul efun object, which couldn't be found. * * In other words: after calling assert_simul_efun_object(), the caller * still has to check if simul_efun_object is NULL. * * At the time of call, simul_efun_object must be NULL. */ { svalue_t *svp; object_t *ob; program_t *progp; CBool *visible; /* Flag for every function: visible or not */ string_t *name; int i, j, num_fun; invalidate_simul_efuns(); /* Invalidate the simul_efun information */ free_defines(); /* to prevent #defines hideing places for globals */ /* Get the name(s) of the simul_efun object. */ svp = apply_master(STR_GET_SEFUN, 0); /* If a simul_efun_object appears during the GET_SEFUN call, it * might have been due to a recursive get_simul_efun() call which may * have gotten an old backup copy. This can lead to hard-to-debug * variable and function definition inconsistencies. */ if (simul_efun_object) { printf("%s simul_efun object appeared while asking for it.\n", time_stamp()); return MY_TRUE; } if (svp == NULL) { printf("%s No simul_efun\n", time_stamp()); return MY_TRUE; } if (svp->type == T_POINTER) { simul_efun_vector = svp->u.vec; svp->type = T_NUMBER; if (VEC_SIZE(svp->u.vec)) svp = svp->u.vec->item; } if (svp->type != T_STRING) { printf("%s No simul_efun\n", time_stamp()); return MY_TRUE; } /* Make the (primary) simul_efun name */ name = del_slash(svp->u.str); if (simul_efun_file_name) free_mstring(simul_efun_file_name); simul_efun_file_name = make_tabled(name); /* Get the object and load the program */ ob = find_object(simul_efun_file_name); if (ob == NULL) { fprintf(stderr, "%s The simul_efun file %s was not loaded.\n" , time_stamp(), get_txt(simul_efun_file_name)); fprintf(stderr, "%s The function get_simul_efun() in the master must load it.\n" , time_stamp()); return MY_FALSE; } if (O_PROG_SWAPPED(ob) && load_ob_from_swap(ob) < 0) { fprintf(stderr, "%s Out of memory (unswap object '%s') ==> " "No simul_efun\n", time_stamp(), get_txt(ob->name)); return MY_TRUE; } reference_prog( (simul_efun_program = ob->prog), "get_simul_efun"); num_fun = ob->prog->num_function_names; if (num_fun == 0) return MY_TRUE; if (!simul_efunp) { simul_efunp = xalloc(sizeof (function_t) * num_fun); } else num_fun = total_simul_efun; free_defines(); /* to prevent #defines hideing places for globals */ /* locals and defines are freed now. There are still reserved words, * but it is impossible to define a function with the name being * a reserved word, thus, there will be no clashes with higher-priority * shared identifiers. */ progp = ob->prog; visible = alloca((i = ob->prog->num_functions) * sizeof(*visible)); memset(visible, 0, i); i = ob->prog->num_function_names; while (--i >= 0) visible[progp->function_names[i]] = MY_TRUE; /* The functions .num_function_names+1 .. .num_functions are not * visible by definition. */ /* Loop over the functions in the simul_efun object and * copy the salient information. */ for (i = 0; i < ob->prog->num_functions; i++) { int ix; funflag_t flags, flags2; bytecode_p funstart; mp_int fun_ix_offs, var_ix_offs; program_t *inherit_progp; function_t*funheader; if (!visible[i]) continue; ix = i; flags2 = flags = progp->functions[ix]; flags &= ~FUNSTART_MASK; /* Pinpoint the function, resolving inheritance where * necessary. */ fun_ix_offs = ix; var_ix_offs = 0; inherit_progp = progp; while (flags2 & NAME_INHERITED) { inherit_t *inheritp; inheritp = &inherit_progp->inherit[flags2 & INHERIT_MASK]; ix -= inheritp->function_index_offset; var_ix_offs += inheritp->variable_index_offset; inherit_progp = inheritp->prog; flags2 = inherit_progp->functions[ix]; } fun_ix_offs -= ix; funstart = inherit_progp->program + (flags2 & FUNSTART_MASK); funheader = inherit_progp->function_headers + FUNCTION_HEADER_INDEX(funstart); /* Don't stumble over undefined functions */ if (is_undef_function(funstart)) { flags |= NAME_UNDEFINED; } /* If the function is __INIT, pretend it's a private function */ if ( !(flags & (TYPE_MOD_STATIC|TYPE_MOD_PRIVATE|NAME_UNDEFINED)) ) { if (mstreq(funheader->name, STR_VARINIT)) flags |= TYPE_MOD_PRIVATE; } /* If the function is indeed visible, get its information */ if ( !(flags & (TYPE_MOD_STATIC|TYPE_MOD_PROTECTED|TYPE_MOD_PRIVATE|NAME_UNDEFINED)) ) { string_t *function_name; ident_t *p; unsigned char num_arg; function_name = funheader->name; num_arg = funheader->num_arg; /* Find or make the identifier for the function */ p = make_shared_identifier_mstr(function_name, I_TYPE_GLOBAL, 0); if (p->type == I_TYPE_UNKNOWN) { init_global_identifier(p, /* bVariable: */ MY_FALSE); p->next_all = all_simul_efuns; all_simul_efuns = p; } if (flags & TYPE_MOD_VARARGS) num_arg = SIMUL_EFUN_VARARGS; /* Find the proper index in simul_efunp[] */ switch(0) { default: /* TRY... */ /* Try to find a discarded sefun entry with matching * name, number of arguments and XVARARGS flag to reuse. */ if (all_discarded_simul_efun >= 0) { int last; j = all_discarded_simul_efun; while ( (j = simul_efunp[last = j].offset.next_sefun) >= 0) { if (num_arg != simul_efunp[j].num_arg || 0 != ((simul_efunp[j].flags ^ flags) & TYPE_MOD_XVARARGS) ) continue; if (!mstreq(function_name, simul_efunp[j].name)) continue; /* Found one: remove it from the 'discarded' list */ simul_efunp[last].offset.next_sefun = simul_efunp[j].offset.next_sefun; break; } if (j >= 0) break; /* switch */ } /* New simul_efun: make a new entry */ (void)ref_mstring(function_name); j = num_simul_efun++; if (num_simul_efun > num_fun) { num_fun = num_simul_efun + 12; simul_efunp = rexalloc(simul_efunp , sizeof (function_t) * num_fun ); } simul_efunp[j].name = function_name; simul_efunp[j].num_arg = num_arg; } /* switch() */ /* j now indexes the simul_efunp[] entry to use */ p->u.global.sim_efun = j; simul_efunp[j].flags = funheader->flags; simul_efunp[j].type = funheader->type; simul_efunp[j].num_locals = funheader->num_locals; /* If possible, make an entry in the simul_efun table */ if ((size_t)j < SEFUN_TABLE_SIZE) { simul_efun_table[j].funstart = funstart; simul_efun_table[j].program = inherit_progp; simul_efun_table[j].function_index_offset = fun_ix_offs; simul_efun_table[j].variable_index_offset = var_ix_offs; } } /* if (function visible) */ } /* for ( all functions) */ total_simul_efun = num_fun; simul_efun_object = ob; return MY_TRUE; } /* get_simul_efun_object() */
svalue_t * f_convert_charset (svalue_t *sp) /* EFUN convert_charset() * * string convert_charset(string str, string from_cs, string to_cs) * * Convert the string <str> from charset <from_cs> to charset <to_cs> * and return the converted string. * * The efun is only available on systems with libiconv. */ { iconv_t context; string_t *from_cs, *to_cs, *in_str, *out_str; #if HAS_ICONV_NONCONST_IN # define ICONV_IN_CAST (char**) #else # define ICONV_IN_CAST #endif const char *pIn; /* Input string pointer */ size_t in_len; /* Input length */ size_t in_left; /* Input length left */ char * out_buf; /* Output buffer */ size_t out_size; /* Size of the output buffer */ size_t out_left; /* Size left in output buffer */ char *pOut; /* Output string pointer */ in_str = sp[-2].u.str; from_cs = sp[-1].u.str; to_cs = sp->u.str; pIn = get_txt(in_str); in_len = mstrsize(in_str); in_left = in_len; /* If the input string is empty, we can return immediately * (and in fact must since the allocator will balk at allocating 0 bytes) */ if (!in_len) { sp -= 2; free_string_svalue(sp); free_string_svalue(sp+1); put_string(sp, sp[2].u.str); return sp; } /* Allocate a temporary output string */ out_size = in_len > 65536 ? (in_len + 33) : (2 * in_len); out_left = out_size; xallocate(out_buf, out_size, "iconv buffer"); pOut = out_buf; /* Open the iconv context */ context = iconv_open(get_txt(to_cs), get_txt(from_cs)); if (context == (iconv_t) -1) { xfree(out_buf); if (errno == EINVAL) errorf("convert_charset(): Conversion '%s' -> '%s' not supported.\n" , get_txt(from_cs), get_txt(to_cs) ); else errorf("convert_charset(): Error %d.\n", errno); /* NOTREACHED */ return sp; } /* Convert the string, reallocating the output buffer where necessary */ while (in_left) { size_t rc; rc = iconv(context, ICONV_IN_CAST &pIn, &in_left, &pOut, &out_left); if (rc == (size_t)-1) { if (errno == E2BIG) { /* Reallocate output buffer */ size_t newsize; char * tmp; newsize = out_size + (in_len > 128 ? in_len : 128); tmp = rexalloc(out_buf, newsize); if (!tmp) { iconv_close(context); xfree(out_buf); outofmem(newsize, "iconv buffer"); /* NOTREACHED */ return sp; } out_buf = tmp; pOut = out_buf + out_size; out_left = newsize - out_size; out_size = newsize; continue; } /* Other error: clean up */ iconv_close(context); xfree(out_buf); if (errno == EILSEQ) { errorf("convert_charset(): Invalid character sequence at " "index %td\n", (ptrdiff_t)(pIn - get_txt(in_str))); /* NOTREACHED */ return sp; } if (errno == EINVAL) { errorf("convert_charset(): Incomplete character sequence at " "index %td\n", (ptrdiff_t)(pIn - get_txt(in_str))); /* NOTREACHED */ return sp; } errorf("convert_charset(): Error %d at index %td\n" , errno, (ptrdiff_t)(pIn - get_txt(in_str)) ); /* NOTREACHED */ return sp; } /* if (rc < 0) */ } /* while (in_left) */ /* While the actual conversion is complete, the output stream may now * be in a non-base state. Add the necessary epilogue to get back * to the base state. */ while(1) { size_t rc; rc = iconv(context, NULL, NULL, &pOut, &out_left); if (rc == (size_t)-1) { if (errno == E2BIG) { /* Reallocate output buffer */ size_t newsize; char * tmp; newsize = out_size + (in_len > 128 ? in_len : 128); tmp = rexalloc(out_buf, newsize); if (!tmp) { iconv_close(context); xfree(out_buf); outofmem(newsize, "iconv buffer"); /* NOTREACHED */ return sp; } out_buf = tmp; pOut = out_buf + out_size; out_left = newsize - out_size; out_size = newsize; continue; } /* Other error: clean up */ iconv_close(context); xfree(out_buf); if (errno == EILSEQ) { errorf("convert_charset(): Invalid character sequence at " "index %td\n", (ptrdiff_t)(pIn - get_txt(in_str))); /* NOTREACHED */ return sp; } if (errno == EINVAL) { errorf("convert_charset(): Incomplete character sequence at " "index %td\n", (ptrdiff_t)(pIn - get_txt(in_str))); /* NOTREACHED */ return sp; } errorf("convert_charset(): Error %d at index %td\n" , errno, (ptrdiff_t)(pIn - get_txt(in_str)) ); /* NOTREACHED */ return sp; } /* if (rc < 0) */ /* At this point, the iconv() succeeded: we're done */ break; } /* while(1) */ iconv_close(context); /* Get the return string and prepare the return arguments */ out_str = new_n_mstring(out_buf, out_size - out_left); xfree(out_buf); if (!out_str) { outofmem(out_size - out_left, "convert_charset() result"); /* NOTREACHED */ return sp; } free_string_svalue(sp--); free_string_svalue(sp--); free_string_svalue(sp); put_string(sp, out_str); return sp; } /* f_convert_charset() */