csi_status_t csi_file_new (csi_t *ctx, csi_object_t *obj, const char *path, const char *mode) { csi_file_t *file; file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); if (file == NULL) return _csi_error (CAIRO_STATUS_NO_MEMORY); file->base.type = CSI_OBJECT_TYPE_FILE; file->base.ref = 1; file->data = NULL; file->type = STDIO; file->flags = OWN_STREAM; file->src = fopen (path, mode); if (file->src == NULL) { _csi_slab_free (ctx, file, sizeof (csi_file_t)); return _csi_error (CAIRO_STATUS_FILE_NOT_FOUND); } file->data = _csi_alloc (ctx, CHUNK_SIZE); if (file->data == NULL) { _csi_slab_free (ctx, file, sizeof (csi_file_t)); return _csi_error (CAIRO_STATUS_NO_MEMORY); } file->bp = file->data; file->rem = 0; obj->type = CSI_OBJECT_TYPE_FILE; obj->datum.file = file; return CAIRO_STATUS_SUCCESS; }
csi_status_t csi_file_new_for_stream (csi_t *ctx, csi_object_t *obj, FILE *stream) { csi_file_t *file; file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); if (file == NULL) return _csi_error (CAIRO_STATUS_NO_MEMORY); file->base.type = CSI_OBJECT_TYPE_FILE; file->base.ref = 1; file->data = NULL; file->type = STDIO; file->flags = 0; file->src = stream; if (file->src == NULL) { _csi_slab_free (ctx, file, sizeof (csi_file_t)); return _csi_error (CAIRO_STATUS_FILE_NOT_FOUND); } file->data = _csi_alloc (ctx, CHUNK_SIZE); if (file->data == NULL) { _csi_slab_free (ctx, file, sizeof (csi_file_t)); return _csi_error (CAIRO_STATUS_NO_MEMORY); } file->bp = file->data; file->rem = 0; obj->type = CSI_OBJECT_TYPE_FILE; obj->datum.file = file; return CAIRO_STATUS_SUCCESS; }
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; }
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; }
static csi_status_t _csi_file_new_filter (csi_t *ctx, csi_object_t *obj, csi_object_t *src, const csi_filter_funcs_t *funcs, void *data) { csi_file_t *file; csi_object_t src_file; csi_status_t status; file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); if (file == NULL) return _csi_error (CAIRO_STATUS_NO_MEMORY); obj->type = CSI_OBJECT_TYPE_FILE; obj->datum.file = file; file->base.type = CSI_OBJECT_TYPE_FILE; file->base.ref = 1; file->type = FILTER; file->data = data; file->filter = funcs; status = csi_object_as_file (ctx, src, &src_file); if (status) { csi_object_free (ctx, obj); return status; } file->src = src_file.datum.file; return CAIRO_STATUS_SUCCESS; }
csi_status_t csi_file_new_for_bytes (csi_t *ctx, csi_object_t *obj, const char *bytes, unsigned int length) { csi_file_t *file; file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); if (file == NULL) return _csi_error (CAIRO_STATUS_NO_MEMORY); file->base.type = CSI_OBJECT_TYPE_FILE; file->base.ref = 1; file->type = BYTES; file->src = (uint8_t *) bytes; file->data = (uint8_t *) bytes; file->bp = (uint8_t *) bytes; file->rem = length; obj->type = CSI_OBJECT_TYPE_FILE; obj->datum.file = file; return CAIRO_STATUS_SUCCESS; }
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_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; }
csi_status_t csi_file_new_from_stream (csi_t *ctx, FILE *file, csi_object_t **out) { csi_file_t *obj; obj = (csi_file_t *) _csi_object_new (ctx, CSI_OBJECT_TYPE_FILE); if (obj == NULL) return _csi_error (CAIRO_STATUS_NO_MEMORY); obj->type = STDIO; obj->src = file; obj->data = _csi_alloc (ctx, CHUNK_SIZE); if (obj->data == NULL) { csi_object_free (&obj->base); return _csi_error (CAIRO_STATUS_UNDEFINED_FILENAME_ERROR); } obj->bp = obj->data; obj->rem = 0; *out = &obj->base; return CAIRO_STATUS_SUCCESS; }
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; }
csi_status_t _csi_name_undefine (csi_t *ctx, csi_name_t name) { unsigned int i; for (i = ctx->dstack.len; --i; ) { if (csi_dictionary_has (ctx->dstack.objects[i].datum.dictionary, name)) { csi_dictionary_remove (ctx, ctx->dstack.objects[i].datum.dictionary, name); return CSI_STATUS_SUCCESS; } } return _csi_error (CSI_STATUS_INVALID_SCRIPT); }
/** * _csi_hash_table_create: * @keys_equal: a function to return %TRUE if two keys are equal * * Creates a new hash table which will use the keys_equal() function * to compare hash keys. Data is provided to the hash table in the * form of user-derived versions of #csi_hash_entry_t. A hash entry * must be able to hold both a key (including a hash code) and a * value. Sometimes only the key will be necessary, (as in * _csi_hash_table_remove), and other times both a key and a value * will be necessary, (as in _csi_hash_table_insert). * * See #csi_hash_entry_t for more details. * * Return value: the new hash table or %NULL if out of memory. **/ csi_status_t _csi_hash_table_init (csi_hash_table_t *hash_table, csi_hash_keys_equal_func_t keys_equal) { hash_table->keys_equal = keys_equal; hash_table->arrangement = &hash_table_arrangements[0]; hash_table->entries = calloc (hash_table->arrangement->size, sizeof(csi_hash_entry_t *)); if (hash_table->entries == NULL) return _csi_error (CAIRO_STATUS_NO_MEMORY); hash_table->live_entries = 0; hash_table->used_entries = 0; hash_table->iterating = 0; return CSI_STATUS_SUCCESS; }
csi_status_t _csi_name_lookup (csi_t *ctx, csi_name_t name, csi_object_t *obj) { int i; for (i = ctx->dstack.len; i--; ) { csi_dictionary_t *dict; csi_dictionary_entry_t *entry; dict = ctx->dstack.objects[i].datum.dictionary; entry = _csi_hash_table_lookup (&dict->hash_table, (csi_hash_entry_t *) &name); if (entry != NULL) { *obj = entry->value; return CSI_STATUS_SUCCESS; } } return _csi_error (CSI_STATUS_INVALID_SCRIPT); }
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; }
/** * _csi_hash_table_manage: * @hash_table: a hash table * * Resize the hash table if the number of entries has gotten much * bigger or smaller than the ideal number of entries for the current * size, or control the number of dead entries by moving the entries * within the table. * * Return value: %CAIRO_STATUS_SUCCESS if successful or * %CAIRO_STATUS_NO_MEMORY if out of memory. **/ static csi_status_t _csi_hash_table_manage (csi_hash_table_t *hash_table) { csi_hash_table_t tmp; csi_boolean_t realloc = TRUE; unsigned long i; /* This keeps the size of the hash table between 2 and approximately 8 * times the number of live entries and keeps the proportion of free * entries (search-terminations) > 25%. */ unsigned long high = hash_table->arrangement->high_water_mark; unsigned long low = high >> 2; unsigned long max_used = high + high / 2; tmp = *hash_table; if (hash_table->live_entries > high) { tmp.arrangement = hash_table->arrangement + 1; /* This code is being abused if we can't make a table big enough. */ } else if (hash_table->live_entries < low && /* Can't shrink if we're at the smallest size */ hash_table->arrangement != &hash_table_arrangements[0]) { tmp.arrangement = hash_table->arrangement - 1; } else if (hash_table->used_entries > max_used) { /* Clean out dead entries to prevent lookups from becoming too slow. */ for (i = 0; i < hash_table->arrangement->size; ++i) { if (ENTRY_IS_DEAD (hash_table->entries[i])) hash_table->entries[i] = NULL; } hash_table->used_entries = hash_table->live_entries; /* There is no need to reallocate but some entries may need to be * moved. Typically the proportion of entries needing to be moved is * small, but, if the moving should leave a large number of dead * entries, they will be cleaned out next time this code is * executed. */ realloc = FALSE; } else { return CAIRO_STATUS_SUCCESS; } if (realloc) { tmp.entries = calloc (tmp.arrangement->size, sizeof (csi_hash_entry_t*)); if (tmp.entries == NULL) return _csi_error (CAIRO_STATUS_NO_MEMORY); hash_table->used_entries = 0; } for (i = 0; i < hash_table->arrangement->size; ++i) { csi_hash_entry_t *entry, **pos; entry = hash_table->entries[i]; if (ENTRY_IS_LIVE (entry)) { hash_table->entries[i] = DEAD_ENTRY; pos = _csi_hash_table_lookup_unique_key (&tmp, entry); if (ENTRY_IS_FREE (*pos)) hash_table->used_entries++; *pos = entry; } } if (realloc) { free (hash_table->entries); hash_table->entries = tmp.entries; hash_table->arrangement = tmp.arrangement; } return CAIRO_STATUS_SUCCESS; }