csi_status_t _csi_stack_grow (csi_t *ctx, csi_stack_t *stack, csi_integer_t cnt) { csi_integer_t newsize; csi_object_t *newstack; if (_csi_likely (cnt <= stack->size)) return CSI_STATUS_SUCCESS; if (_csi_unlikely ((unsigned) cnt >= INT_MAX / sizeof (csi_object_t))) return _csi_error (CSI_STATUS_NO_MEMORY); newsize = stack->size; do { newsize *= 2; } while (newsize <= cnt); newstack = _csi_realloc (ctx, stack->objects, newsize * sizeof (csi_object_t)); if (_csi_unlikely (newstack == NULL)) return _csi_error (CSI_STATUS_NO_MEMORY); stack->objects = newstack; stack->size = newsize; return CSI_STATUS_SUCCESS; }
void * _csi_perm_alloc (csi_t *ctx, int size) { csi_chunk_t *chunk; void *ptr; size = (size + sizeof (void *)-1) & -sizeof (void *); chunk = ctx->perm_chunk; if (chunk == NULL || chunk->rem < size) { int chunk_size = (size + 8191) & -8192; chunk = _csi_alloc (ctx, sizeof (csi_chunk_t) + chunk_size); if (_csi_unlikely (chunk == NULL)) return NULL; chunk->rem = chunk_size; chunk->ptr = (char *) (chunk + 1); chunk->next = ctx->perm_chunk; ctx->perm_chunk = chunk; } ptr = chunk->ptr; chunk->ptr += size; chunk->rem -= size; return ptr; }
csi_status_t _csi_intern_string (csi_t *ctx, const char **str_inout, int len) { char *str = (char *) *str_inout; csi_intern_string_t tmpl, *istring; csi_status_t status = CSI_STATUS_SUCCESS; tmpl.hash_entry.hash = _intern_string_hash (str, len); tmpl.len = len; tmpl.string = (char *) str; istring = _csi_hash_table_lookup (&ctx->strings, &tmpl.hash_entry); if (istring == NULL) { istring = _csi_perm_alloc (ctx, sizeof (csi_intern_string_t) + len + 1); if (istring != NULL) { istring->hash_entry.hash = tmpl.hash_entry.hash; istring->len = tmpl.len; istring->string = (char *) (istring + 1); memcpy (istring->string, str, len); istring->string[len] = '\0'; status = _csi_hash_table_insert (&ctx->strings, &istring->hash_entry); if (_csi_unlikely (status)) { _csi_free (ctx, istring); return status; } } else return _csi_error (CSI_STATUS_NO_MEMORY); } *str_inout = istring->string; return CSI_STATUS_SUCCESS; }
csi_object_t * _csi_stack_peek (csi_stack_t *stack, csi_integer_t i) { if (_csi_unlikely (stack->len < i)) return NULL; return &stack->objects[stack->len - i -1]; }
void _csi_free (csi_t *ctx, void *ptr) { if (_csi_unlikely (ptr == NULL)) return; free (ptr); }
void _csi_stack_pop (csi_t *ctx, csi_stack_t *stack, csi_integer_t count) { if (_csi_unlikely (stack->len < count)) count = stack->len; while (count--) csi_object_free (ctx, &stack->objects[--stack->len]); }
csi_status_t _csi_stack_roll (csi_t *ctx, csi_stack_t *stack, csi_integer_t mod, csi_integer_t n) { csi_object_t stack_copy[128]; csi_object_t *copy; csi_integer_t last, i, len; switch (mod) { /* special cases */ case 1: last = stack->len - 1; stack_copy[0] = stack->objects[last]; for (i = last; --n; i--) stack->objects[i] = stack->objects[i-1]; stack->objects[i] = stack_copy[0]; return CSI_STATUS_SUCCESS; case -1: last = stack->len - 1; stack_copy[0] = stack->objects[i = last - n + 1]; for (; --n; i++) stack->objects[i] = stack->objects[i+1]; stack->objects[i] = stack_copy[0]; return CSI_STATUS_SUCCESS; } /* fall back to a copy */ if (n > ARRAY_LENGTH (stack_copy)) { if (_csi_unlikely ((unsigned) n > INT_MAX / sizeof (csi_object_t))) return _csi_error (CSI_STATUS_NO_MEMORY); copy = _csi_alloc (ctx, n * sizeof (csi_object_t)); if (copy == NULL) return _csi_error (CSI_STATUS_NO_MEMORY); } else copy = stack_copy; i = stack->len - n; memcpy (copy, stack->objects + i, n * sizeof (csi_object_t)); mod = -mod; if (mod < 0) mod += n; last = mod; for (len = n; n--; i++) { stack->objects[i] = copy[last]; if (++last == len) last = 0; } if (copy != stack_copy) _csi_free (ctx, copy); return CSI_STATUS_SUCCESS; }
csi_status_t _csi_stack_push_internal (csi_t *ctx, csi_stack_t *stack, const csi_object_t *obj) { csi_status_t status; status = _csi_stack_grow (ctx, stack, stack->size + 1); if (_csi_unlikely (status)) return status; stack->objects[stack->len++] = *obj; return CSI_STATUS_SUCCESS; }
csi_status_t _csi_stack_init (csi_t *ctx, csi_stack_t *stack, csi_integer_t size) { csi_status_t status = CSI_STATUS_SUCCESS; stack->len = 0; stack->size = size; /* assert ((unsigned) size < INT_MAX / sizeof (csi_object_t)); */ stack->objects = _csi_alloc (ctx, size * sizeof (csi_object_t)); if (_csi_unlikely (stack->objects == NULL)) status = _csi_error (CSI_STATUS_NO_MEMORY); return status; }
void _csi_slab_free (csi_t *ctx, void *ptr, int size) { int chunk_size; void **free_list; if (_csi_unlikely (ptr == NULL)) return; chunk_size = 2 * sizeof (void *); chunk_size = (size + chunk_size - 1) / chunk_size; free_list = ptr; *free_list = ctx->slabs[chunk_size].free_list; ctx->slabs[chunk_size].free_list = ptr; }
csi_status_t _csi_stack_exch (csi_stack_t *stack) { csi_object_t tmp; csi_integer_t n; if (_csi_unlikely (stack->len < 2)) return _csi_error (CSI_STATUS_INVALID_SCRIPT); n = stack->len - 1; tmp = stack->objects[n]; stack->objects[n] = stack->objects[n - 1]; stack->objects[n - 1] = tmp; return CSI_STATUS_SUCCESS; }
void * _csi_slab_alloc (csi_t *ctx, int size) { #if CSI_DEBUG_MALLOC return malloc (size); #else int chunk_size; csi_chunk_t *chunk; void *ptr; chunk_size = 2 * sizeof (void *); chunk_size = (size + chunk_size - 1) / chunk_size; if (ctx->slabs[chunk_size].free_list) { ptr = ctx->slabs[chunk_size].free_list; ctx->slabs[chunk_size].free_list = *(void **) ptr; return ptr; } chunk = ctx->slabs[chunk_size].chunk; if (chunk == NULL || ! chunk->rem) { int cnt = MAX (128, 8192 / (chunk_size * 2 * sizeof (void *))); chunk = _csi_alloc (ctx, sizeof (csi_chunk_t) + cnt * chunk_size * 2 * sizeof (void *)); if (_csi_unlikely (chunk == NULL)) return NULL; chunk->rem = cnt; chunk->ptr = (char *) (chunk + 1); chunk->next = ctx->slabs[chunk_size].chunk; ctx->slabs[chunk_size].chunk = chunk; } ptr = chunk->ptr; chunk->ptr += chunk_size * 2 * sizeof (void *); chunk->rem--; return ptr; #endif }
void _csi_slab_free (csi_t *ctx, void *ptr, int size) { int chunk_size; void **free_list; if (_csi_unlikely (ptr == NULL)) return; #if CSI_DEBUG_MALLOC free (ptr); #else chunk_size = 2 * sizeof (void *); chunk_size = (size + chunk_size - 1) / chunk_size; free_list = ptr; *free_list = ctx->slabs[chunk_size].free_list; ctx->slabs[chunk_size].free_list = ptr; #endif }
/** * _csi_hash_table_insert: * @hash_table: a hash table * @key_and_value: an entry to be inserted * * Insert the entry #key_and_value into the hash table. * * WARNING: There must not be an existing entry in the hash table * with a matching key. * * WARNING: It is a fatal error to insert an element while * an iterator is running * * Instead of using insert to replace an entry, consider just editing * the entry obtained with _csi_hash_table_lookup. Or if absolutely * necessary, use _csi_hash_table_remove first. * * Return value: %CAIRO_STATUS_SUCCESS if successful or * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available. **/ csi_status_t _csi_hash_table_insert (csi_hash_table_t *hash_table, csi_hash_entry_t *key_and_value) { csi_status_t status; csi_hash_entry_t **entry; hash_table->live_entries++; status = _csi_hash_table_manage (hash_table); if (_csi_unlikely (status)) { /* abort the insert... */ hash_table->live_entries--; return status; } entry = _csi_hash_table_lookup_unique_key (hash_table, key_and_value); if (ENTRY_IS_FREE (*entry)) hash_table->used_entries++; *entry = key_and_value; return CAIRO_STATUS_SUCCESS; }
static csi_status_t _init_dictionaries (csi_t *ctx) { csi_status_t status; csi_stack_t *stack; csi_object_t obj; csi_dictionary_t *dict; const csi_operator_def_t *odef; const csi_integer_constant_def_t *idef; const csi_real_constant_def_t *rdef; stack = &ctx->dstack; status = _csi_stack_init (ctx, stack, 4); if (_csi_unlikely (status)) return status; /* systemdict */ status = csi_dictionary_new (ctx, &obj); if (_csi_unlikely (status)) return status; status = _csi_stack_push (ctx, stack, &obj); if (_csi_unlikely (status)) return status; dict = obj.datum.dictionary; /* fill systemdict with operators */ for (odef = _csi_operators (); odef->name != NULL; odef++) { status = _add_operator (ctx, dict, odef); if (_csi_unlikely (status)) return status; } /* add constants */ for (idef = _csi_integer_constants (); idef->name != NULL; idef++) { status = _add_integer_constant (ctx, dict, idef); if (_csi_unlikely (status)) return status; } for (rdef = _csi_real_constants (); rdef->name != NULL; rdef++) { status = _add_real_constant (ctx, dict, rdef); if (_csi_unlikely (status)) return status; } /* and seal */ //dict.type &= ~CSI_OBJECT_ATTR_WRITABLE; /* globaldict */ status = csi_dictionary_new (ctx, &obj); if (_csi_unlikely (status)) return status; status = _csi_stack_push (ctx, stack, &obj); if (_csi_unlikely (status)) return status; /* userdict */ status = csi_dictionary_new (ctx, &obj); if (_csi_unlikely (status)) return status; status = _csi_stack_push (ctx, stack, &obj); if (_csi_unlikely (status)) return status; return CSI_STATUS_SUCCESS; }
csi_status_t csi_file_new_from_string (csi_t *ctx, csi_object_t *obj, csi_string_t *src) { csi_file_t *file; file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); if (_csi_unlikely (file == NULL)) return _csi_error (CAIRO_STATUS_NO_MEMORY); file->base.type = CSI_OBJECT_TYPE_FILE; file->base.ref = 1; if (src->deflate) { uLongf len = src->deflate; csi_object_t tmp_obj; csi_string_t *tmp_str; csi_status_t status; status = csi_string_new (ctx, &tmp_obj, NULL, src->deflate); if (_csi_unlikely (status)) return status; tmp_str = tmp_obj.datum.string; switch (src->method) { case NONE: default: status = _csi_error (CAIRO_STATUS_NO_MEMORY); break; case ZLIB: #if HAVE_ZLIB if (uncompress ((Bytef *) tmp_str->string, &len, (Bytef *) src->string, src->len) != Z_OK) #endif status = _csi_error (CAIRO_STATUS_NO_MEMORY); break; case LZO: #if HAVE_LZO if (lzo2a_decompress ((lzo_bytep) src->string, src->len, (lzo_bytep) tmp_str->string, &len, NULL)) #endif status = _csi_error (CAIRO_STATUS_NO_MEMORY); break; } if (_csi_unlikely (status)) { csi_string_free (ctx, tmp_str); _csi_slab_free (ctx, file, sizeof (csi_file_t)); return status; } file->src = tmp_str; file->data = tmp_str->string; file->rem = tmp_str->len; } else { file->src = src; src->base.ref++; file->data = src->string; file->rem = src->len; } file->type = BYTES; file->bp = file->data; obj->type = CSI_OBJECT_TYPE_FILE; obj->datum.file = file; return CAIRO_STATUS_SUCCESS; }
static csi_status_t _init_dictionaries (csi_t *ctx) { csi_status_t status; csi_stack_t *stack; csi_object_t obj; csi_dictionary_t *dict, *opcodes; const csi_operator_def_t *odef; const csi_integer_constant_def_t *idef; const csi_real_constant_def_t *rdef; unsigned n; stack = &ctx->dstack; status = _csi_stack_init (ctx, stack, 4); if (_csi_unlikely (status)) return status; /* systemdict */ status = csi_dictionary_new (ctx, &obj); if (_csi_unlikely (status)) return status; status = _csi_stack_push (ctx, stack, &obj); if (_csi_unlikely (status)) return status; dict = obj.datum.dictionary; status = csi_dictionary_new (ctx, &obj); if (_csi_unlikely (status)) return status; opcodes = obj.datum.dictionary; n = 0; csi_integer_new (&obj, n); status = csi_dictionary_put (ctx, opcodes, 0, &obj); if (_csi_unlikely (status)) return status; ctx->opcode[n++] = NULL; /* fill systemdict with operators */ for (odef = _csi_operators (); odef->name != NULL; odef++) { status = _add_operator (ctx, dict, odef); if (_csi_unlikely (status)) return status; if (! csi_dictionary_has (opcodes, (csi_name_t) odef->op)) { csi_integer_new (&obj, n); status = csi_dictionary_put (ctx, opcodes, (csi_name_t) odef->op, &obj); if (_csi_unlikely (status)) return status; assert (n < sizeof (ctx->opcode) / sizeof (ctx->opcode[0])); ctx->opcode[n++] = odef->op; } } csi_dictionary_free (ctx, opcodes); /* add constants */ for (idef = _csi_integer_constants (); idef->name != NULL; idef++) { status = _add_integer_constant (ctx, dict, idef); if (_csi_unlikely (status)) return status; } for (rdef = _csi_real_constants (); rdef->name != NULL; rdef++) { status = _add_real_constant (ctx, dict, rdef); if (_csi_unlikely (status)) return status; } /* and seal */ //dict.type &= ~CSI_OBJECT_ATTR_WRITABLE; /* globaldict */ status = csi_dictionary_new (ctx, &obj); if (_csi_unlikely (status)) return status; status = _csi_stack_push (ctx, stack, &obj); if (_csi_unlikely (status)) return status; /* userdict */ status = csi_dictionary_new (ctx, &obj); if (_csi_unlikely (status)) return status; status = _csi_stack_push (ctx, stack, &obj); if (_csi_unlikely (status)) return status; return CSI_STATUS_SUCCESS; }