diff --git a/.travis.yml b/.travis.yml index bde2636..f1aab60 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,11 @@ language: php php: - 7.0 - 7.1 - - nightly + - 7.2 + +before_install: + - sudo apt-get update -qq + - sudo apt-get install -qq valgrind script: - phpize @@ -12,4 +16,4 @@ script: - export NO_INTERACTION=1 - export REPORT_EXIT_STATUS=1 - export TEST_PHP_EXECUTABLE=`which php` - - php -n run-tests.php -n -d extension_dir=./modules/ -d extension=extcss3.so --show-diff + - php -n run-tests.php -m -n -d extension_dir=./modules/ -d extension=extcss3.so --show-diff diff --git a/INSTALL b/INSTALL deleted file mode 100644 index a68fc2e..0000000 --- a/INSTALL +++ /dev/null @@ -1,7 +0,0 @@ -To build and install the extcss3 run: - phpize - ./configure - make - -And finally install it via: - make install diff --git a/README.md b/README.md index c20ba24..6f82d77 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,27 @@ -[![Software license][ico-license]](LICENSE) -[![Build status][ico-travis]][link-travis] +| php-ext-css stand alone | MPZ stand alone | php-ext-css MPZ edition | +| :---: | :---: | :---: | +| [![Software license][ico-license]](https://github.com/sevenval/php-ext-css/blob/master/LICENSE) | [![Software license][ico-license-mpz]](https://github.com/alex-schneider/mpz/blob/master/LICENSE) | [![Software license][ico-license-mpz]](mpz/LICENSE) | +| [![Build status][ico-travis]][link-travis] | No own builds | [![Build status][ico-travis-mpz]][link-travis-mpz] | -# `extcss3` +# php-ext-css MPZ edition -`extcss3` is a fast PHP7 extension for the handling of CSS3 strings -(see [W3C Candidate Recommendation](https://www.w3.org/TR/css-syntax-3/)). -It supports preprocessing, tokenizing and minifying. Furthermore, -`extcss3` implements an API that can be used to analyse, augment or -correct the style sheet while it is being processed. +`php-ext-css` is a fast PHP7 extension for the handling of CSS3 strings (see +[W3C Candidate Recommendation](https://www.w3.org/TR/css-syntax-3/)). It supports +preprocessing, tokenizing and minifying. Furthermore, `php-ext-css` implements an +API that can be used to analyse, augment or correct the style sheet while it is +being processed. +The MPZ edition uses the [Memory-Pool-Z](https://alex-schneider.github.io/mpz/) +to increase the real processing speed of `php-ext-css` to over 35 % while reducing +the user time to over 40% and system time to over 10 %. ## Library Features * Written in pure C99. * Doesn't require any external libraries. * Implements an intervention API. -* PHP 7 and PHP 7.1 ready. - +* PHP 7.x ready. +* Well tested. ## Minifying Features @@ -28,136 +33,177 @@ correct the style sheet while it is being processed. * Minifying of numeric values (e.g. `005` to `5` or `0.1em` to `.1em`). * Optional: Removal of vendor-prefixed declarations. - ## Current Limitations * The CSS string must be UTF-8 encoded. -* String and URL tokens are returned to the registered callbacks with - quotes ("xxx" or 'xxx') as given in the original CSS string. -* The code compiles and runs on Linux systems. Other platforms have not - been tested. +* String and URL tokens are returned to the registered callbacks with quotes ("xxx" + or 'xxx') as given in the original CSS string. +* The code compiles and runs on Linux systems. Other platforms have not been tested. +## Installation -## PHP Class (`CSS3Processor`) +To build the `php-ext-css` MPZ edition extension run: + +```bash +phpize +./configure +make +``` + +and finally install it via: +```bash +make install ``` + +## PHP Class (`CSS3Processor`) + +### CSS3Processor::__construct() + +```php public CSS3Processor::__construct(void) : CSS3Processor ``` * Constructs a new `CSS3Processor` object. * Throws exceptions on errors. +### CSS3Processor::setNotifier() +```php +public CSS3Processor::setNotifier(int $type, callable $callback) : bool ``` + +* Registers a callback for the given token `$type` that will be called during tokenisation. + The callback gets an info array of the current token and context. +* All return values from the callback are discarded. +* The parameter `$type` can be set to any of the `php-ext-css` Type Constants listed + below. +* If a Modifier is registered for the same token type, the Notifier is allways called + bevore the Modifier. +* Multiple notifier callbacks per token type are possible. +* Returns `true` on success. +* Throws exceptions on errors. + +### CSS3Processor::setModifier() + +```php public CSS3Processor::setModifier(int $type, callable $callback) : bool ``` -* Registers a callback for the given token `$type` that will be called - during tokenisation. The callback gets an info array of the current - token and context. -* The callback should return a string with a (new) value that replaces - the given token in the result string. If the return value is not a string, - the original value is left unmodified. -* The parameter `$type` can be set to any of the `extcss3` Type Constants - listed below that are marked as `modifiable`. -* Only one modifier callback per token type is possible. Any subsequent call - to `::setModifier()` replaces previously set callbacks for the same type. +* Registers a callback for the given token `$type` that will be called during tokenisation. + The callback gets an info array of the current token and context. +* The callback should return a string with a (new) value that replaces the given + token in the result string. If the return value is not a string, the original + value is left unmodified. +* The parameter `$type` can be set to any of the `php-ext-css` Type Constants listed + below that are marked as `modifiable`. +* If a Notifier is registered for the same token type, the Notifier is allways called + bevore the Modifier. +* Only one modifier callback per token type is possible. Any subsequent call to + `::setModifier()` replaces previously set callbacks for the same type. * Returns `true` on success. * Throws exceptions on errors. +### CSS3Processor::dump() -``` +```php public CSS3Processor::dump(string $css) : string ``` -* Applies preprocessing and the registered modifiers to `$css` - and returns the resulting string. +* Applies preprocessing, the registered notifiers and modifiers to `$css` and returns + the resulting string. * Throws exceptions on errors. +### CSS3Processor::minify() -``` +```php public CSS3Processor::minify(string $css [, array $vendors ]) : string ``` -* Returns the minimized result string considering the registered modifiers +* Returns the minimized result string considering the registered notifiers, modifiers and the blacklist of vendor prefixes given in the `$vendors` array. * Throws exceptions on errors. +## PHP Class Constants + +### Type Constants + +```php +`CSS3Processor::TYPE_IDENT` 1 +`CSS3Processor::TYPE_FUNCTION` 2 +`CSS3Processor::TYPE_AT_KEYWORD` 3 +`CSS3Processor::TYPE_HASH` 4 +`CSS3Processor::TYPE_STRING` 5 (modifiable) +`CSS3Processor::TYPE_BAD_STRING` 6 (modifiable) +`CSS3Processor::TYPE_URL` 7 (modifiable) +`CSS3Processor::TYPE_BAD_URL` 8 (modifiable) +`CSS3Processor::TYPE_DELIM` 9 +`CSS3Processor::TYPE_NUMBER` 10 +`CSS3Processor::TYPE_PERCENTAGE` 11 +`CSS3Processor::TYPE_DIMENSION` 12 +`CSS3Processor::TYPE_UNICODE_RANGE` 13 +`CSS3Processor::TYPE_INCLUDE_MATCH` 14 +`CSS3Processor::TYPE_DASH_MATCH` 15 +`CSS3Processor::TYPE_PREFIX_MATCH` 16 +`CSS3Processor::TYPE_SUFFIX_MATCH` 17 +`CSS3Processor::TYPE_SUBSTR_MATCH` 18 +`CSS3Processor::TYPE_COLUMN` 19 +`CSS3Processor::TYPE_WS` 20 +`CSS3Processor::TYPE_CDO` 21 +`CSS3Processor::TYPE_CDC` 22 +`CSS3Processor::TYPE_COLON` 23 +`CSS3Processor::TYPE_SEMICOLON` 24 +`CSS3Processor::TYPE_COMMA` 25 +`CSS3Processor::TYPE_BR_RO` 26 +`CSS3Processor::TYPE_BR_RC` 27 +`CSS3Processor::TYPE_BR_SO` 28 +`CSS3Processor::TYPE_BR_SC` 29 +`CSS3Processor::TYPE_BR_CO` 30 +`CSS3Processor::TYPE_BR_CC` 31 +`CSS3Processor::TYPE_COMMENT` 32 (modifiable) +`CSS3Processor::TYPE_EOF` 33 +``` -### PHP Class Constants - - -#### Type Constants - -* `TYPE_IDENT` 1 -* `TYPE_FUNCTION` 2 -* `TYPE_AT_KEYWORD` 3 -* `TYPE_HASH` 4 -* `TYPE_STRING` 5 (modifiable) -* `TYPE_BAD_STRING` 6 (modifiable) -* `TYPE_URL` 7 (modifiable) -* `TYPE_BAD_URL` 8 (modifiable) -* `TYPE_DELIM` 9 -* `TYPE_NUMBER` 10 -* `TYPE_PERCENTAGE` 11 -* `TYPE_DIMENSION` 12 -* `TYPE_UNICODE_RANGE` 13 -* `TYPE_INCLUDE_MATCH` 14 -* `TYPE_DASH_MATCH` 15 -* `TYPE_PREFIX_MATCH` 16 -* `TYPE_SUFFIX_MATCH` 17 -* `TYPE_SUBSTR_MATCH` 18 -* `TYPE_COLUMN` 19 -* `TYPE_WS` 20 -* `TYPE_CDO` 21 -* `TYPE_CDC` 22 -* `TYPE_COLON` 23 -* `TYPE_SEMICOLON` 24 -* `TYPE_COMMA` 25 -* `TYPE_BR_RO` 26 -* `TYPE_BR_RC` 27 -* `TYPE_BR_SO` 28 -* `TYPE_BR_SC` 29 -* `TYPE_BR_CO` 30 -* `TYPE_BR_CC` 31 -* `TYPE_COMMENT` 32 (modifiable) -* `TYPE_EOF` 33 - - -#### Flag Constants - -* `FLAG_ID` 1 -* `FLAG_UNRESTRICTED` 2 -* `FLAG_INTEGER` 3 -* `FLAG_NUMBER` 4 -* `FLAG_STRING` 5 -* `FLAG_AT_URL_STRING` 6 - - -#### Exception Code Constants - -* `ERR_MEMORY` 1 -* `ERR_BYTES_CORRUPTION` 2 -* `ERR_NULL_PTR` 3 -* `ERR_INV_PARAM` 4 - - -### Examples +### Flag Constants +```php +`CSS3Processor::FLAG_ID` 1 +`CSS3Processor::FLAG_UNRESTRICTED` 2 +`CSS3Processor::FLAG_INTEGER` 3 +`CSS3Processor::FLAG_NUMBER` 4 +`CSS3Processor::FLAG_STRING` 5 +`CSS3Processor::FLAG_AT_URL_STRING` 6 ``` + +### Exception Code Constants + +```php +`CSS3Processor::ERR_MEMORY` 1 +`CSS3Processor::ERR_BYTES_CORRUPTION` 2 +`CSS3Processor::ERR_NULL_PTR` 3 +`CSS3Processor::ERR_INV_PARAM` 4 +`CSS3Processor::ERR_INV_VALUE` 5 +``` + +## Example + +```php $css = file_get_contents('style.css'); try { - $proc = new \CSS3Processor(); + $proc = new \CSS3Processor(); - $min = $proc->minify($css, ['-ms', '-moz', '-o']); + $min = $proc->minify($css, ['-ms', '-moz', '-o']); } catch (Exception $e) { - ... + ... } ``` -More examples coming soon... +See the tests for more examples. [ico-license]: https://img.shields.io/github/license/mashape/apistatus.svg [ico-travis]: https://travis-ci.org/sevenval/php-ext-css.svg?branch=master [link-travis]: https://travis-ci.org/sevenval/php-ext-css +[ico-license-mpz]: https://img.shields.io/github/license/mashape/apistatus.svg +[ico-travis-mpz]: https://api.travis-ci.org/alex-schneider/php-ext-css.svg?branch=master +[link-travis-mpz]: https://travis-ci.org/alex-schneider/php-ext-css diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..c419263 --- /dev/null +++ b/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-cayman \ No newline at end of file diff --git a/config.m4 b/config.m4 index bc04ebb..9061fb6 100644 --- a/config.m4 +++ b/config.m4 @@ -1,21 +1,22 @@ -PHP_ARG_WITH(extcss3, whether to enable the extcss3 extension, - [--with-extcss3 Enable extcss3 support]) +PHP_ARG_WITH(extcss3, whether to enable the extcss3 MPZ eidition extension, + [--with-extcss3 Enable extcss3 MPZ edition support]) if test "$PHP_EXTCSS3" != "no"; then PHP_SUBST(EXTCSS3_SHARED_LIBADD) PHP_NEW_EXTENSION(extcss3, - extcss3/intern.c \ - extcss3/utils.c \ - extcss3/dumper/dumper.c \ - extcss3/minifier/minifier.c \ - extcss3/minifier/tree.c \ - extcss3/minifier/types/numeric.c \ - extcss3/minifier/types/hash.c \ - extcss3/minifier/types/function.c \ - extcss3/tokenizer/preprocessor.c \ - extcss3/tokenizer/context.c \ - extcss3/tokenizer/tokenizer.c \ + mpz/src/mpz_alloc.c \ + extcss3/intern.c \ + extcss3/utils.c \ + extcss3/dumper/dumper.c \ + extcss3/minifier/minifier.c \ + extcss3/minifier/tree.c \ + extcss3/minifier/types/numeric.c \ + extcss3/minifier/types/hash.c \ + extcss3/minifier/types/function.c \ + extcss3/tokenizer/preprocessor.c \ + extcss3/tokenizer/context.c \ + extcss3/tokenizer/tokenizer.c \ php_extcss3.c, - $ext_shared, , "-Wall") + $ext_shared, , "-Wall -Wextra") fi diff --git a/extcss3/dumper/dumper.c b/extcss3/dumper/dumper.c index accb687..ce58654 100644 --- a/extcss3/dumper/dumper.c +++ b/extcss3/dumper/dumper.c @@ -22,6 +22,7 @@ char *extcss3_dump_rules(extcss3_intern *intern, extcss3_rule *rule, unsigned in if ((intern == NULL) || (intern->copy.str == NULL) || (rule == NULL)) { return _extcss3_set_error_code(error, EXTCSS3_ERR_NULL_PTR); } else if ((result = curr = (char *)calloc(intern->copy.len + intern->modifier.user_strlen_diff + 1, sizeof(char))) == NULL) { + /* Use calloc(), because the user has to free the result. */ return _extcss3_set_error_code(error, EXTCSS3_ERR_MEMORY); } @@ -46,6 +47,7 @@ char *extcss3_dump_tokens(extcss3_intern *intern, unsigned int *error) } else if ((token = intern->base_token) == NULL) { return _extcss3_set_error_code(error, EXTCSS3_ERR_NULL_PTR); } else if ((result = pos = (char *)calloc(intern->copy.len + intern->modifier.user_strlen_diff + 1, sizeof(char))) == NULL) { + /* Use calloc(), because the user has to free the result. */ return _extcss3_set_error_code(error, EXTCSS3_ERR_MEMORY); } @@ -82,9 +84,6 @@ char *extcss3_dump_tokens(extcss3_intern *intern, unsigned int *error) /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - extcss3_release_tokens_list(intern->base_token); - intern->base_token = NULL; - return result; } diff --git a/extcss3/intern.c b/extcss3/intern.c index 0c73772..2c61022 100644 --- a/extcss3/intern.c +++ b/extcss3/intern.c @@ -5,63 +5,182 @@ /* ==================================================================================================== */ -extcss3_intern *extcss3_create_intern(void) +extcss3_intern *extcss3_reset_intern(extcss3_intern *intern, unsigned int *error) { - return (extcss3_intern *)calloc(1, sizeof(extcss3_intern)); + if (NULL == intern) { + *error = EXTCSS3_ERR_NULL_PTR; + return NULL; + } + + mpz_pool_destroy(intern->pool); + + if (NULL == (intern->pool = mpz_pool_create())) { + *error = EXTCSS3_ERR_MEMORY; + return NULL; + } + + intern->copy.str = NULL; + intern->base_token = NULL; + intern->base_vendor = NULL; + + return intern; } -extcss3_vendor *extcss3_create_vendor(void) +extcss3_intern *extcss3_create_intern(void) { - return (extcss3_vendor *)calloc(1, sizeof(extcss3_vendor)); + extcss3_intern *intern; + + if (NULL == (intern = malloc(sizeof(*intern)))) { + return NULL; + } else if (NULL == (intern->pool = mpz_pool_create())) { + free(intern); + return NULL; + } + + intern->orig.str = NULL; + intern->orig.len = 0; + intern->copy.str = NULL; + intern->copy.len = 0; + + intern->base_token = NULL; + intern->last_token = NULL; + intern->base_ctxt = NULL; + intern->last_ctxt = NULL; + intern->base_vendor = NULL; + intern->last_vendor = NULL; + + intern->notifier.base = NULL; + intern->notifier.last = NULL; + intern->notifier.callback = NULL; + intern->notifier.destructor = NULL; + + intern->modifier.string = NULL; + intern->modifier.bad_string = NULL; + intern->modifier.url = NULL; + intern->modifier.bad_url = NULL; + intern->modifier.comment = NULL; + intern->modifier.callback = NULL; + intern->modifier.destructor = NULL; + intern->modifier.user_strlen_diff = 0; + + intern->state.reader = NULL; + intern->state.cursor = NULL; + intern->state.writer = NULL; + intern->state.rest = 0; + + return intern; } -extcss3_token *extcss3_create_token(void) +extcss3_vendor *extcss3_create_vendor(mpz_pool_t *pool) { - return (extcss3_token *)calloc(1, sizeof(extcss3_token)); + extcss3_vendor *vendor = (extcss3_vendor *)mpz_pmalloc(pool, sizeof(extcss3_vendor)); + + if (NULL != vendor) { + vendor->next = NULL; + vendor->name.str = NULL; + vendor->name.len = 0; + } + + return vendor; } -extcss3_ctxt *extcss3_create_ctxt(void) +extcss3_token *extcss3_create_token(mpz_pool_t *pool) { - return (extcss3_ctxt *)calloc(1, sizeof(extcss3_ctxt)); + extcss3_token *token = (extcss3_token *)mpz_pmalloc(pool, sizeof(extcss3_token)); + + if (NULL != token) { + token->data.str = NULL; + token->data.len = 0; + token->info.str = NULL; + token->info.len = 0; + token->user.str = NULL; + token->user.len = 0; + token->prev = NULL; + token->next = NULL; + token->type = 0; + token->flag = 0; + } + + return token; } -extcss3_rule *extcss3_create_rule(void) +extcss3_ctxt *extcss3_create_ctxt(mpz_pool_t *pool) { - return (extcss3_rule *)calloc(1, sizeof(extcss3_rule)); + extcss3_ctxt *ctxt = (extcss3_ctxt *)mpz_pmalloc(pool, sizeof(extcss3_ctxt)); + + if (NULL != ctxt) { + ctxt->level = 0; + ctxt->token = NULL; + ctxt->prev = NULL; + ctxt->next = NULL; + } + + return ctxt; } -extcss3_block *extcss3_create_block(void) +extcss3_rule *extcss3_create_rule(mpz_pool_t *pool) { - return (extcss3_block *)calloc(1, sizeof(extcss3_block)); + extcss3_rule *rule = (extcss3_rule *)mpz_pmalloc(pool, sizeof(extcss3_rule)); + + if (NULL != rule) { + rule->base_selector = NULL; + rule->last_selector = NULL; + rule->block = NULL; + rule->prev = NULL; + rule->next = NULL; + rule->level = 0; + } + + return rule; } -extcss3_decl *extcss3_create_decl(void) +extcss3_block *extcss3_create_block(mpz_pool_t *pool) { - return (extcss3_decl *)calloc(1, sizeof(extcss3_decl)); -} + extcss3_block *block = (extcss3_block *)mpz_pmalloc(pool, sizeof(extcss3_block)); -/* ==================================================================================================== */ + if (NULL != block) { + block->base = NULL; + block->last = NULL; + block->rules = NULL; + block->decls = NULL; + } -void extcss3_release_intern(extcss3_intern *intern) + return block; +} + +extcss3_decl *extcss3_create_decl(mpz_pool_t *pool) { - if (intern == NULL) { - return; - } + extcss3_decl *decl = (extcss3_decl *)mpz_pmalloc(pool, sizeof(extcss3_decl)); - if (intern->copy.str != NULL) { - free(intern->copy.str); + if (NULL != decl) { + decl->base = NULL; + decl->last = NULL; + decl->prev = NULL; + decl->next = NULL; } - if (intern->base_vendor != NULL) { - extcss3_release_vendors_list(intern->base_vendor); - } + return decl; +} + +extcss3_sig *extcss3_create_signal(void) +{ + extcss3_sig *sig = (extcss3_sig *)malloc(sizeof(extcss3_sig)); - if (intern->base_token != NULL) { - extcss3_release_tokens_list(intern->base_token); + if (NULL != sig) { + sig->type = 0; + sig->next = NULL; + sig->callable = NULL; } - if (intern->base_ctxt != NULL) { - extcss3_release_ctxts_list(intern->base_ctxt); + return sig; +} + +/* ==================================================================================================== */ + +void extcss3_release_intern(extcss3_intern *intern) +{ + if (intern == NULL) { + return; } if (intern->modifier.destructor != NULL) { @@ -86,23 +205,29 @@ void extcss3_release_intern(extcss3_intern *intern) } } + if (intern->notifier.base != NULL) { + extcss3_release_signals_list(&intern->notifier); + } + + mpz_pool_destroy(intern->pool); + free(intern); } -void extcss3_release_vendor(extcss3_vendor *vendor) +void extcss3_release_vendor(mpz_pool_t *pool, extcss3_vendor *vendor) { if (vendor == NULL) { return; } if (vendor->name.str != NULL) { - free(vendor->name.str); + mpz_free(pool, vendor->name.str); } - free(vendor); + mpz_free(pool, vendor); } -void extcss3_release_vendors_list(extcss3_vendor *list) +void extcss3_release_vendors_list(mpz_pool_t *pool, extcss3_vendor *list) { extcss3_vendor *next; @@ -112,27 +237,27 @@ void extcss3_release_vendors_list(extcss3_vendor *list) while (list->next != NULL) { next = list->next->next; - extcss3_release_vendor(list->next); + extcss3_release_vendor(pool, list->next); list->next = next; } - extcss3_release_vendor(list); + extcss3_release_vendor(pool, list); } -void extcss3_release_token(extcss3_token *token) +void extcss3_release_token(mpz_pool_t *pool, extcss3_token *token) { if (token == NULL) { return; } if (token->user.str != NULL) { - free(token->user.str); + mpz_free(pool, token->user.str); } - free(token); + mpz_free(pool, token); } -void extcss3_release_tokens_list(extcss3_token *list) +void extcss3_release_tokens_list(mpz_pool_t *pool, extcss3_token *list) { extcss3_token *next; @@ -142,23 +267,23 @@ void extcss3_release_tokens_list(extcss3_token *list) while (list->next != NULL) { next = list->next->next; - extcss3_release_token(list->next); + extcss3_release_token(pool, list->next); list->next = next; } - extcss3_release_token(list); + extcss3_release_token(pool, list); } -void extcss3_release_ctxt(extcss3_ctxt *ctxt) +void extcss3_release_ctxt(mpz_pool_t *pool, extcss3_ctxt *ctxt) { if (ctxt == NULL) { return; } - free(ctxt); + mpz_free(pool, ctxt); } -void extcss3_release_ctxts_list(extcss3_ctxt *list) +void extcss3_release_ctxts_list(mpz_pool_t *pool, extcss3_ctxt *list) { extcss3_ctxt *next; @@ -168,27 +293,27 @@ void extcss3_release_ctxts_list(extcss3_ctxt *list) while (list->next != NULL) { next = list->next->next; - extcss3_release_ctxt(list->next); + extcss3_release_ctxt(pool, list->next); list->next = next; } - extcss3_release_ctxt(list); + extcss3_release_ctxt(pool, list); } -void extcss3_release_rule(extcss3_rule *rule) +void extcss3_release_rule(mpz_pool_t *pool, extcss3_rule *rule) { if (rule == NULL) { return; } if (rule->block != NULL) { - extcss3_release_block(rule->block); + extcss3_release_block(pool, rule->block); } - free(rule); + mpz_free(pool, rule); } -void extcss3_release_rules_list(extcss3_rule *list) +void extcss3_release_rules_list(mpz_pool_t *pool, extcss3_rule *list) { extcss3_rule *next; @@ -198,40 +323,40 @@ void extcss3_release_rules_list(extcss3_rule *list) while (list->next != NULL) { next = list->next->next; - extcss3_release_rule(list->next); + extcss3_release_rule(pool, list->next); list->next = next; } - extcss3_release_rule(list); + extcss3_release_rule(pool, list); } -void extcss3_release_block(extcss3_block *block) +void extcss3_release_block(mpz_pool_t *pool, extcss3_block *block) { if (block == NULL) { return; } if (block->rules != NULL) { - extcss3_release_rules_list(block->rules); + extcss3_release_rules_list(pool, block->rules); } if (block->decls != NULL) { - extcss3_release_decls_list(block->decls); + extcss3_release_decls_list(pool, block->decls); } - free(block); + mpz_free(pool, block); } -void extcss3_release_decl(extcss3_decl *decl) +void extcss3_release_decl(mpz_pool_t *pool, extcss3_decl *decl) { if (decl == NULL) { return; } - free(decl); + mpz_free(pool, decl); } -void extcss3_release_decls_list(extcss3_decl *list) +void extcss3_release_decls_list(mpz_pool_t *pool, extcss3_decl *list) { extcss3_decl *next; @@ -241,11 +366,41 @@ void extcss3_release_decls_list(extcss3_decl *list) while (list->next != NULL) { next = list->next->next; - extcss3_release_decl(list->next); + extcss3_release_decl(pool, list->next); list->next = next; } - extcss3_release_decl(list); + extcss3_release_decl(pool, list); +} + +void extcss3_release_signal(extcss3_not *notifier, extcss3_sig *sig) +{ + if (sig == NULL) { + return; + } + + if ((sig->callable != NULL) && (notifier != NULL) && (notifier->destructor != NULL)) { + notifier->destructor(sig->callable); + } + + free(sig); +} + +void extcss3_release_signals_list(extcss3_not *notifier) +{ + extcss3_sig *next, *list = notifier->base; + + if (list == NULL) { + return; + } + + while (list->next != NULL) { + next = list->next->next; + extcss3_release_signal(notifier, list->next); + list->next = next; + } + + extcss3_release_signal(notifier, list); } /* ==================================================================================================== */ @@ -257,7 +412,7 @@ bool extcss3_set_css_string(extcss3_intern *intern, char *css, size_t len, unsig return EXTCSS3_FAILURE; } else if (intern->copy.str != NULL) { - free(intern->copy.str); + mpz_free(intern->pool, intern->copy.str); } intern->orig.str = css; @@ -274,7 +429,7 @@ bool extcss3_set_css_string(extcss3_intern *intern, char *css, size_t len, unsig */ intern->copy.len = len * 3; - intern->copy.str = (char *)calloc(intern->copy.len + 1, sizeof(char)); + intern->copy.str = (char *)mpz_pmalloc(intern->pool, (intern->copy.len + 1) * sizeof(char)); if (intern->copy.str == NULL) { *error = EXTCSS3_ERR_MEMORY; @@ -298,6 +453,36 @@ bool extcss3_set_css_string(extcss3_intern *intern, char *css, size_t len, unsig return EXTCSS3_SUCCESS; } +bool extcss3_set_notifier(extcss3_intern *intern, unsigned int type, void *callable, unsigned int *error) +{ + extcss3_sig *sig; + + if ((intern == NULL) || (intern->notifier.destructor == NULL) || (intern->notifier.callback == NULL) || (callable == NULL)) { + *error = EXTCSS3_ERR_NULL_PTR; + + return EXTCSS3_FAILURE; + } + + if ((sig = extcss3_create_signal()) == NULL) { + *error = EXTCSS3_ERR_MEMORY; + + return EXTCSS3_FAILURE; + } + + sig->type = type; + sig->callable = callable; + + if (intern->notifier.base == NULL) { + intern->notifier.base = sig; + } else { + intern->notifier.last->next = sig; + } + + intern->notifier.last = sig; + + return EXTCSS3_SUCCESS; +} + bool extcss3_set_modifier(extcss3_intern *intern, unsigned int type, void *callable, unsigned int *error) { if ((intern == NULL) || (intern->modifier.destructor == NULL) || (intern->modifier.callback == NULL) || (callable == NULL)) { @@ -372,7 +557,7 @@ bool extcss3_set_vendor_string(extcss3_intern *intern, char *name, size_t len, u } intern->last_vendor->name.len = len; - intern->last_vendor->name.str = (char *)calloc(intern->last_vendor->name.len, sizeof(char)); + intern->last_vendor->name.str = (char *)mpz_pmalloc(intern->pool, intern->last_vendor->name.len * sizeof(char)); if (intern->last_vendor->name.str == NULL) { *error = EXTCSS3_ERR_MEMORY; diff --git a/extcss3/intern.h b/extcss3/intern.h index afdf93f..c68e2fa 100644 --- a/extcss3/intern.h +++ b/extcss3/intern.h @@ -5,28 +5,32 @@ /* ==================================================================================================== */ +extcss3_intern *extcss3_reset_intern(extcss3_intern *intern, unsigned int *error); extcss3_intern *extcss3_create_intern(void); -extcss3_vendor *extcss3_create_vendor(void); -extcss3_token *extcss3_create_token(void); -extcss3_ctxt *extcss3_create_ctxt(void); -extcss3_rule *extcss3_create_rule(void); -extcss3_block *extcss3_create_block(void); -extcss3_decl *extcss3_create_decl(void); +extcss3_vendor *extcss3_create_vendor(mpz_pool_t *pool); +extcss3_token *extcss3_create_token(mpz_pool_t *pool); +extcss3_ctxt *extcss3_create_ctxt(mpz_pool_t *pool); +extcss3_rule *extcss3_create_rule(mpz_pool_t *pool); +extcss3_block *extcss3_create_block(mpz_pool_t *pool); +extcss3_decl *extcss3_create_decl(mpz_pool_t *pool); void extcss3_release_intern(extcss3_intern *intern); -void extcss3_release_vendor(extcss3_vendor *vendor); -void extcss3_release_vendors_list(extcss3_vendor *list); -void extcss3_release_token(extcss3_token *token); -void extcss3_release_tokens_list(extcss3_token *list); -void extcss3_release_ctxt(extcss3_ctxt *ctxt); -void extcss3_release_ctxts_list(extcss3_ctxt *list); -void extcss3_release_rule(extcss3_rule *rule); -void extcss3_release_rules_list(extcss3_rule *list); -void extcss3_release_block(extcss3_block *block); -void extcss3_release_decl(extcss3_decl *decl); -void extcss3_release_decls_list(extcss3_decl *list); +void extcss3_release_vendor(mpz_pool_t *pool, extcss3_vendor *vendor); +void extcss3_release_vendors_list(mpz_pool_t *pool, extcss3_vendor *list); +void extcss3_release_token(mpz_pool_t *pool, extcss3_token *token); +void extcss3_release_tokens_list(mpz_pool_t *pool, extcss3_token *list); +void extcss3_release_ctxt(mpz_pool_t *pool, extcss3_ctxt *ctxt); +void extcss3_release_ctxts_list(mpz_pool_t *pool, extcss3_ctxt *list); +void extcss3_release_rule(mpz_pool_t *pool, extcss3_rule *rule); +void extcss3_release_rules_list(mpz_pool_t *pool, extcss3_rule *list); +void extcss3_release_block(mpz_pool_t *pool, extcss3_block *block); +void extcss3_release_decl(mpz_pool_t *pool, extcss3_decl *decl); +void extcss3_release_decls_list(mpz_pool_t *pool, extcss3_decl *list); +void extcss3_release_signal(extcss3_not *notifier, extcss3_sig *sig); +void extcss3_release_signals_list(extcss3_not *notifier); bool extcss3_set_css_string(extcss3_intern *intern, char *css, size_t len, unsigned int *error); +bool extcss3_set_notifier(extcss3_intern *intern, unsigned int type, void *callable, unsigned int *error); bool extcss3_set_modifier(extcss3_intern *intern, unsigned int type, void *callable, unsigned int *error); bool extcss3_set_vendor_string(extcss3_intern *intern, char *name, size_t len, unsigned int *error); diff --git a/extcss3/minifier/minifier.c b/extcss3/minifier/minifier.c index b4889ad..fdf12a7 100644 --- a/extcss3/minifier/minifier.c +++ b/extcss3/minifier/minifier.c @@ -23,13 +23,13 @@ static extcss3_decl *_extcss3_minify_declaration(extcss3_intern *intern, extcss3 static extcss3_token *_extcss3_get_decl_name(extcss3_decl *decl); static extcss3_token *_extcss3_get_decl_sep(extcss3_token *name, extcss3_decl *decl); -static extcss3_token *_extcss3_get_decl_value(extcss3_token *last, extcss3_decl *decl); +static extcss3_token *_extcss3_get_decl_value(extcss3_intern *intern, extcss3_token *last, extcss3_decl *decl); -static void _extcss3_trim_left(extcss3_token *curr); -static void _extcss3_trim_right(extcss3_token *curr, extcss3_token **last); -static void _extcss3_trim_around(extcss3_token *curr, extcss3_token **last); +static void _extcss3_trim_left(extcss3_intern *intern, extcss3_token *curr); +static void _extcss3_trim_right(extcss3_intern *intern, extcss3_token *curr, extcss3_token **last); +static void _extcss3_trim_around(extcss3_intern *intern, extcss3_token *curr, extcss3_token **last); -static void _extcss3_remove_token(extcss3_token **base, extcss3_token **token, extcss3_token *repl); +static void _extcss3_remove_token(extcss3_intern *intern, extcss3_token **base, extcss3_token **token, extcss3_token *repl); static bool _extcss3_check_at_rule_is_valid_charset(extcss3_intern *intern, extcss3_rule *rule); static bool _extcss3_check_at_rule_is_valid_import(extcss3_rule *rule); @@ -53,7 +53,7 @@ char *extcss3_minify(extcss3_intern *intern, unsigned int *error) return _extcss3_set_error_code(error, *error, NULL, NULL); } else if ((token = intern->base_token) == NULL) { return _extcss3_set_error_code(error, EXTCSS3_ERR_NULL_PTR, NULL, NULL); - } else if ((tree = extcss3_create_tree(&token, NULL, 0, error)) == NULL) { + } else if ((tree = extcss3_create_tree(intern, &token, NULL, 0, error)) == NULL) { return _extcss3_set_error_code(error, *error, NULL, intern); } else if (tree->base_selector == NULL) { return _extcss3_set_error_code(error, EXTCSS3_ERR_NULL_PTR, tree, intern); @@ -73,8 +73,6 @@ char *extcss3_minify(extcss3_intern *intern, unsigned int *error) /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - _extcss3_set_error_code(error, 0, tree, intern); - return result; } @@ -85,11 +83,11 @@ static inline void *_extcss3_set_error_code(unsigned int *error, unsigned int co *error = code; if (tree != NULL) { - extcss3_release_rules_list(tree); + extcss3_release_rules_list(intern->pool, tree); } if ((intern != NULL) && (intern->base_token != NULL)) { - extcss3_release_tokens_list(intern->base_token); + extcss3_release_tokens_list(intern->pool, intern->base_token); intern->base_token = NULL; } @@ -121,7 +119,7 @@ static extcss3_rule *_extcss3_minify_tree(extcss3_intern *intern, extcss3_rule * } next = curr->next; - extcss3_release_rule(curr); + extcss3_release_rule(intern->pool, curr); curr = next; continue; @@ -131,7 +129,7 @@ static extcss3_rule *_extcss3_minify_tree(extcss3_intern *intern, extcss3_rule * } if ((*tree)->base_selector == NULL) { - extcss3_release_rules_list(*tree); + extcss3_release_rules_list(intern->pool, *tree); *tree = NULL; } @@ -226,45 +224,45 @@ static inline extcss3_token *_extcss3_minify_selectors(extcss3_intern *intern, e while (selector != NULL) { // Remove whitespace and comments after... if ( - (selector->type == EXTCSS3_TYPE_BR_SO) || - (selector->type == EXTCSS3_TYPE_BR_RO) || - (selector->type == EXTCSS3_TYPE_COLON) || - (selector->type == EXTCSS3_TYPE_FUNCTION) || + (selector->type == EXTCSS3_TYPE_BR_SO) || + (selector->type == EXTCSS3_TYPE_BR_RO) || + (selector->type == EXTCSS3_TYPE_COLON) || + (selector->type == EXTCSS3_TYPE_FUNCTION) || (selector->type == EXTCSS3_TYPE_STRING) ) { - _extcss3_trim_right(selector, &rule->last_selector); + _extcss3_trim_right(intern, selector, &rule->last_selector); } // Remove whitespace and comments before... if ( - (selector->type == EXTCSS3_TYPE_BR_SC) || - (selector->type == EXTCSS3_TYPE_BR_RC) || - (selector->type == EXTCSS3_TYPE_BAD_STRING) || + (selector->type == EXTCSS3_TYPE_BR_SC) || + (selector->type == EXTCSS3_TYPE_BR_RC) || + (selector->type == EXTCSS3_TYPE_BAD_STRING) || ( (selector->type == EXTCSS3_TYPE_STRING) && (EXTCSS3_SUCCESS != _extcss3_check_at_rule_is_valid_charset(intern, rule)) ) || ( - (selector->type == EXTCSS3_TYPE_BR_RO) && - (selector->prev != NULL) && - (selector->prev->prev != NULL) && + (selector->type == EXTCSS3_TYPE_BR_RO) && + (selector->prev != NULL) && + (selector->prev->prev != NULL) && (_EXTCSS3_TYPE_EMPTY_EX(selector->prev)) && (selector->prev->prev->type != EXTCSS3_TYPE_IDENT) ) ) { - _extcss3_trim_left(selector); + _extcss3_trim_left(intern, selector); } // Remove whitespace and comments around... if ( - (selector->flag == EXTCSS3_FLAG_AT_URL_STRING) || - (selector->type == EXTCSS3_TYPE_COMMA) || - (selector->type == EXTCSS3_TYPE_SUFFIX_MATCH) || - (selector->type == EXTCSS3_TYPE_SUBSTR_MATCH) || - (selector->type == EXTCSS3_TYPE_PREFIX_MATCH) || - (selector->type == EXTCSS3_TYPE_DASH_MATCH) || - (selector->type == EXTCSS3_TYPE_INCLUDE_MATCH) || - (selector->type == EXTCSS3_TYPE_COLUMN) || + (selector->flag == EXTCSS3_FLAG_AT_URL_STRING) || + (selector->type == EXTCSS3_TYPE_COMMA) || + (selector->type == EXTCSS3_TYPE_SUFFIX_MATCH) || + (selector->type == EXTCSS3_TYPE_SUBSTR_MATCH) || + (selector->type == EXTCSS3_TYPE_PREFIX_MATCH) || + (selector->type == EXTCSS3_TYPE_DASH_MATCH) || + (selector->type == EXTCSS3_TYPE_INCLUDE_MATCH) || + (selector->type == EXTCSS3_TYPE_COLUMN) || ( (selector->type == EXTCSS3_TYPE_DELIM) && ( @@ -275,32 +273,32 @@ static inline extcss3_token *_extcss3_minify_selectors(extcss3_intern *intern, e ) ) || ( - (selector->type == EXTCSS3_TYPE_BR_RC) && - (rule->base_selector->type == EXTCSS3_TYPE_AT_KEYWORD) && + (selector->type == EXTCSS3_TYPE_BR_RC) && + (rule->base_selector->type == EXTCSS3_TYPE_AT_KEYWORD) && (rule->base_selector->data.len == 6 /*strlen("@media")*/) && (EXTCSS3_SUCCESS == extcss3_ascii_strncasecmp(rule->base_selector->data.str, "@media", 6)) ) ) { - _extcss3_trim_around(selector, &rule->last_selector); + _extcss3_trim_around(intern, selector, &rule->last_selector); } if (selector->type == EXTCSS3_TYPE_COMMENT) { if ((selector->prev != NULL) && (selector->prev->type == EXTCSS3_TYPE_WS)) { if ((selector->next != NULL) && (selector->next->type == EXTCSS3_TYPE_WS)) { - _extcss3_trim_right(selector, &rule->last_selector); + _extcss3_trim_right(intern, selector, &rule->last_selector); } } if (selector->user.str == NULL) { - _extcss3_remove_token(&rule->base_selector, &selector, selector->next); + _extcss3_remove_token(intern, &rule->base_selector, &selector, selector->next); continue; } } if ( - (selector->type == EXTCSS3_TYPE_BR_SC) && - (selector->prev != NULL) && - (selector->prev->user.str == NULL) && + (selector->type == EXTCSS3_TYPE_BR_SC) && + (selector->prev != NULL) && + (selector->prev->user.str == NULL) && (selector->prev->type == EXTCSS3_TYPE_STRING) ) { size_t i = 1, n = selector->prev->data.len - 1; @@ -327,12 +325,12 @@ static inline extcss3_token *_extcss3_minify_selectors(extcss3_intern *intern, e } if ( - (selector->type == EXTCSS3_TYPE_NUMBER) || - (selector->type == EXTCSS3_TYPE_PERCENTAGE) || + (selector->type == EXTCSS3_TYPE_NUMBER) || + (selector->type == EXTCSS3_TYPE_PERCENTAGE) || (selector->type == EXTCSS3_TYPE_DIMENSION) ) { if ( - (selector->prev != NULL) && + (selector->prev != NULL) && (selector->prev->type == EXTCSS3_TYPE_IDENT) && ( ( @@ -348,9 +346,9 @@ static inline extcss3_token *_extcss3_minify_selectors(extcss3_intern *intern, e ) { preserve_sign = true; } else if ( - (selector->prev != NULL) && + (selector->prev != NULL) && (selector->prev->type == EXTCSS3_TYPE_DIMENSION) && - (selector->prev->info.len == 1) && + (selector->prev->info.len == 1) && (selector->prev->info.str[0] == 'n') ) { preserve_sign = true; @@ -358,12 +356,8 @@ static inline extcss3_token *_extcss3_minify_selectors(extcss3_intern *intern, e preserve_sign = false; } - if (selector->type == EXTCSS3_TYPE_PERCENTAGE && rule->base_selector == selector && rule->last_selector == selector) { - // Do nothing - } else { - if (EXTCSS3_SUCCESS != extcss3_minify_numeric(selector, preserve_sign, error)) { - return NULL; - } + if (EXTCSS3_SUCCESS != extcss3_minify_numeric(intern, selector, preserve_sign, false, error)) { + return NULL; } } @@ -371,8 +365,8 @@ static inline extcss3_token *_extcss3_minify_selectors(extcss3_intern *intern, e if ((vendor = intern->base_vendor) != NULL) { while (vendor != NULL) { if ( - (selector->data.len > vendor->name.len) && - (selector->data.str[vendor->name.len + 1] == '-') && + (selector->data.len > vendor->name.len) && + (selector->data.str[vendor->name.len + 1] == '-') && (EXTCSS3_SUCCESS == extcss3_ascii_strncasecmp(selector->data.str + 2, vendor->name.str + 1, vendor->name.len - 1)) ) { return rule->base_selector = rule->last_selector = NULL; @@ -382,18 +376,18 @@ static inline extcss3_token *_extcss3_minify_selectors(extcss3_intern *intern, e } } } else if ( - (selector->type == EXTCSS3_TYPE_COLON) && - (selector->prev != NULL) && - (selector->prev->type == EXTCSS3_TYPE_COLON) && - (selector->next != NULL) && - (selector->next->type == EXTCSS3_TYPE_IDENT) && + (selector->type == EXTCSS3_TYPE_COLON) && + (selector->prev != NULL) && + (selector->prev->type == EXTCSS3_TYPE_COLON) && + (selector->next != NULL) && + (selector->next->type == EXTCSS3_TYPE_IDENT) && (selector->next->data.str[0] == '-') ) { if ((vendor = intern->base_vendor) != NULL) { while (vendor != NULL) { if ( - (selector->next->data.len > vendor->name.len) && - (selector->next->data.str[vendor->name.len] == '-') && + (selector->next->data.len > vendor->name.len) && + (selector->next->data.str[vendor->name.len] == '-') && (EXTCSS3_SUCCESS == extcss3_ascii_strncasecmp(selector->next->data.str + 1, vendor->name.str + 1, vendor->name.len - 1)) ) { range_base = range_last = selector; @@ -412,7 +406,7 @@ static inline extcss3_token *_extcss3_minify_selectors(extcss3_intern *intern, e if (selector == rule->last_selector) { break; } else if (selector->type == EXTCSS3_TYPE_COMMA) { - _extcss3_trim_around(selector, &rule->last_selector); + _extcss3_trim_around(intern, selector, &rule->last_selector); break; } @@ -445,15 +439,15 @@ static inline extcss3_token *_extcss3_minify_selectors(extcss3_intern *intern, e } while ((range_base != NULL) && (range_base != range_last)) { - _extcss3_remove_token(&rule->base_selector, &range_base, range_base->next); + _extcss3_remove_token(intern, &rule->base_selector, &range_base, range_base->next); selector = range_base; } if ((range_base != NULL) && (range_base == range_last)) { - _extcss3_remove_token(&rule->base_selector, &range_base, NULL); - selector = range_last->next; + + _extcss3_remove_token(intern, &rule->base_selector, &range_base, NULL); } } @@ -490,7 +484,7 @@ static inline extcss3_block *_extcss3_minify_declarations(extcss3_intern *intern while (curr != NULL) { if (_extcss3_minify_declaration(intern, curr, error) == NULL) { if (*error > 0) { - extcss3_release_block(block); + extcss3_release_block(intern->pool, block); return NULL; } @@ -511,7 +505,7 @@ static inline extcss3_block *_extcss3_minify_declarations(extcss3_intern *intern } temp = curr->next; - extcss3_release_decl(curr); + extcss3_release_decl(intern->pool, curr); curr = temp; continue; @@ -523,7 +517,7 @@ static inline extcss3_block *_extcss3_minify_declarations(extcss3_intern *intern /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ if (block->decls == NULL) { - extcss3_release_block(block); + extcss3_release_block(intern->pool, block); return NULL; } @@ -534,20 +528,21 @@ static inline extcss3_decl *_extcss3_minify_declaration(extcss3_intern *intern, { extcss3_token *name = NULL, *sep = NULL, *value = NULL, *temp; extcss3_vendor *vendor; + int preserve_dimension = 0; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ name = _extcss3_get_decl_name(decl); if (name != NULL) { - _extcss3_trim_around(name, &decl->last); + _extcss3_trim_around(intern, name, &decl->last); sep = _extcss3_get_decl_sep(name, decl); if (sep != NULL) { - _extcss3_trim_around(sep, &decl->last); + _extcss3_trim_around(intern, sep, &decl->last); - value = _extcss3_get_decl_value(sep, decl); + value = _extcss3_get_decl_value(intern, sep, decl); } } @@ -565,8 +560,8 @@ static inline extcss3_decl *_extcss3_minify_declaration(extcss3_intern *intern, if ((vendor = intern->base_vendor) != NULL) { while (vendor != NULL) { if ( - (name->data.len > vendor->name.len) && - (name->data.str[vendor->name.len] == '-') && + (name->data.len > vendor->name.len) && + (name->data.str[vendor->name.len] == '-') && (EXTCSS3_SUCCESS == extcss3_ascii_strncasecmp(name->data.str + 1, vendor->name.str + 1, vendor->name.len - 1)) ) { return NULL; @@ -596,12 +591,22 @@ static inline extcss3_decl *_extcss3_minify_declaration(extcss3_intern *intern, return NULL; } + // Handle round braces while processing "calc()" function + if (preserve_dimension) { + if (value->type == EXTCSS3_TYPE_BR_RO) { + preserve_dimension++; + } else if (value->type == EXTCSS3_TYPE_BR_RC) { + preserve_dimension--; + } + } + // Remove whitespace and comments after... if ( (value->type == EXTCSS3_TYPE_FUNCTION) || - (value->type == EXTCSS3_TYPE_BR_RO) + (value->type == EXTCSS3_TYPE_BR_RO) || + (value->type == EXTCSS3_TYPE_STRING) ) { - _extcss3_trim_right(value, &decl->last); + _extcss3_trim_right(intern, value, &decl->last); } // Remove whitespace and comments before... @@ -609,7 +614,7 @@ static inline extcss3_decl *_extcss3_minify_declaration(extcss3_intern *intern, (value->type == EXTCSS3_TYPE_BR_RC) || ((value->type == EXTCSS3_TYPE_DELIM) && (*value->data.str == '!')) ) { - _extcss3_trim_left(value); + _extcss3_trim_left(intern, value); if ((*value->data.str == '+') || (*value->data.str == '-')) { temp = value->next; @@ -619,11 +624,11 @@ static inline extcss3_decl *_extcss3_minify_declaration(extcss3_intern *intern, } if ( - (temp->type != EXTCSS3_TYPE_NUMBER) && - (temp->type != EXTCSS3_TYPE_PERCENTAGE) && + (temp->type != EXTCSS3_TYPE_NUMBER) && + (temp->type != EXTCSS3_TYPE_PERCENTAGE) && (temp->type != EXTCSS3_TYPE_DIMENSION) ) { - _extcss3_trim_right(value, &decl->last); + _extcss3_trim_right(intern, value, &decl->last); value = temp; continue; } @@ -632,8 +637,7 @@ static inline extcss3_decl *_extcss3_minify_declaration(extcss3_intern *intern, // Remove whitespace and comments around... if ( - (value->type == EXTCSS3_TYPE_COMMA) || - (value->type == EXTCSS3_TYPE_STRING) || + (value->type == EXTCSS3_TYPE_COMMA) || (value->type == EXTCSS3_TYPE_SEMICOLON) || ( (value->type == EXTCSS3_TYPE_DELIM) && @@ -644,7 +648,7 @@ static inline extcss3_decl *_extcss3_minify_declaration(extcss3_intern *intern, ) ) ) { - _extcss3_trim_around(value, &decl->last); + _extcss3_trim_around(intern, value, &decl->last); } // Remove the trailing whitespace @@ -652,7 +656,7 @@ static inline extcss3_decl *_extcss3_minify_declaration(extcss3_intern *intern, if (value->type == EXTCSS3_TYPE_WS) { decl->last = decl->last->prev; - _extcss3_trim_left(value); + _extcss3_trim_left(intern, value); } } @@ -662,8 +666,8 @@ static inline extcss3_decl *_extcss3_minify_declaration(extcss3_intern *intern, if ((vendor = intern->base_vendor) != NULL) { while (vendor != NULL) { if ( - (value->data.len > vendor->name.len) && - (value->data.str[vendor->name.len] == '-') && + (value->data.len > vendor->name.len) && + (value->data.str[vendor->name.len] == '-') && (EXTCSS3_SUCCESS == extcss3_ascii_strncasecmp(value->data.str + 1, vendor->name.str + 1, vendor->name.len - 1)) ) { return NULL; @@ -677,25 +681,25 @@ static inline extcss3_decl *_extcss3_minify_declaration(extcss3_intern *intern, /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ if (value->user.str != NULL) { - value = _extcss3_get_decl_value(value, decl); + value = _extcss3_get_decl_value(intern, value, decl); continue; } else if ((decl->next == NULL) && (value->type == EXTCSS3_TYPE_SEMICOLON)) { decl->last = value->prev; break; } else if (value->type == EXTCSS3_TYPE_HASH) { - if (EXTCSS3_SUCCESS != extcss3_minify_hash(value->data.str + 1, value->data.len - 1, value, error)) { + if (EXTCSS3_SUCCESS != extcss3_minify_hash(intern, value->data.str + 1, value->data.len - 1, value, error)) { return NULL; } } else if (EXTCSS3_SUCCESS == _extcss3_check_minify_color(name, value)) { - if (EXTCSS3_SUCCESS != extcss3_minify_color(value, error)) { + if (EXTCSS3_SUCCESS != extcss3_minify_color(intern, value, error)) { return NULL; } } else if ( - (value->type == EXTCSS3_TYPE_NUMBER) || - (value->type == EXTCSS3_TYPE_PERCENTAGE) || + (value->type == EXTCSS3_TYPE_NUMBER) || + (value->type == EXTCSS3_TYPE_PERCENTAGE) || (value->type == EXTCSS3_TYPE_DIMENSION) ) { - if (EXTCSS3_SUCCESS != extcss3_minify_numeric(value, false, error)) { + if (EXTCSS3_SUCCESS != extcss3_minify_numeric(intern, value, false, (preserve_dimension > 0), error)) { return NULL; } } else if (value->type == EXTCSS3_TYPE_FUNCTION) { @@ -710,7 +714,7 @@ static inline extcss3_decl *_extcss3_minify_declaration(extcss3_intern *intern, (value->data.len == 3) && (EXTCSS3_SUCCESS == extcss3_ascii_strncasecmp(value->data.str, "rgb", 3)) ) { - if (EXTCSS3_SUCCESS != extcss3_minify_function_rgb_a(&value, decl, error)) { + if (EXTCSS3_SUCCESS != extcss3_minify_function_rgb_a(intern, &value, decl, error)) { return NULL; } @@ -720,10 +724,15 @@ static inline extcss3_decl *_extcss3_minify_declaration(extcss3_intern *intern, } else if (value->type == EXTCSS3_TYPE_BR_CC) { break; } + } else if ( + (value->data.len == 4) && + (EXTCSS3_SUCCESS == extcss3_ascii_strncasecmp(value->data.str, "calc", 4)) + ) { + preserve_dimension = 1; } } - value = _extcss3_get_decl_value(value, decl); + value = _extcss3_get_decl_value(intern, value, decl); } return decl; @@ -774,7 +783,7 @@ static inline extcss3_token *_extcss3_get_decl_sep(extcss3_token *name, extcss3_ return NULL; } -static inline extcss3_token *_extcss3_get_decl_value(extcss3_token *last, extcss3_decl *decl) +static inline extcss3_token *_extcss3_get_decl_value(extcss3_intern *intern, extcss3_token *last, extcss3_decl *decl) { extcss3_token *curr = last->next, *term = decl->last->next; @@ -785,7 +794,7 @@ static inline extcss3_token *_extcss3_get_decl_value(extcss3_token *last, extcss } else if (curr->type == EXTCSS3_TYPE_COMMENT) { if ((curr->prev != NULL) && (curr->prev->type == EXTCSS3_TYPE_WS)) { if ((curr->next != NULL) && (curr->next->type == EXTCSS3_TYPE_WS)) { - _extcss3_trim_right(curr, &decl->last); + _extcss3_trim_right(intern, curr, &decl->last); } } @@ -794,7 +803,7 @@ static inline extcss3_token *_extcss3_get_decl_value(extcss3_token *last, extcss ((curr->prev != NULL) && (curr->prev->type == EXTCSS3_TYPE_WS)) || ((curr->next != NULL) && (curr->next->type == EXTCSS3_TYPE_WS)) ) { - _extcss3_remove_token(&decl->base, &curr, curr->next); + _extcss3_remove_token(intern, &decl->base, &curr, curr->next); continue; } } @@ -808,20 +817,20 @@ static inline extcss3_token *_extcss3_get_decl_value(extcss3_token *last, extcss /* ==================================================================================================== */ -static inline void _extcss3_trim_left(extcss3_token *curr) +static inline void _extcss3_trim_left(extcss3_intern *intern, extcss3_token *curr) { extcss3_token *temp; while ((curr->prev != NULL) && _EXTCSS3_TYPE_EMPTY_EX(curr->prev)) { if ((temp = curr->prev->prev) != NULL) { temp->next = curr; - extcss3_release_token(curr->prev); + extcss3_release_token(intern->pool, curr->prev); curr->prev = temp; } } } -static inline void _extcss3_trim_right(extcss3_token *curr, extcss3_token **last) +static inline void _extcss3_trim_right(extcss3_intern *intern, extcss3_token *curr, extcss3_token **last) { extcss3_token *temp; @@ -832,21 +841,21 @@ static inline void _extcss3_trim_right(extcss3_token *curr, extcss3_token **last } temp->prev = curr; - extcss3_release_token(curr->next); + extcss3_release_token(intern->pool, curr->next); curr->next = temp; } } } -static inline void _extcss3_trim_around(extcss3_token *curr, extcss3_token **last) +static inline void _extcss3_trim_around(extcss3_intern *intern, extcss3_token *curr, extcss3_token **last) { - _extcss3_trim_left(curr); - _extcss3_trim_right(curr, last); + _extcss3_trim_left(intern, curr); + _extcss3_trim_right(intern, curr, last); } /* ==================================================================================================== */ -static inline void _extcss3_remove_token(extcss3_token **base, extcss3_token **token, extcss3_token *repl) +static inline void _extcss3_remove_token(extcss3_intern *intern, extcss3_token **base, extcss3_token **token, extcss3_token *repl) { if ((base != NULL) && (*base == *token)) { *base = (*token)->next; @@ -861,7 +870,7 @@ static inline void _extcss3_remove_token(extcss3_token **base, extcss3_token **t (*token)->prev->next = (*token)->next; } - extcss3_release_token(*token); + extcss3_release_token(intern->pool, *token); *token = repl; } @@ -871,18 +880,18 @@ static inline void _extcss3_remove_token(extcss3_token **base, extcss3_token **t static inline bool _extcss3_check_at_rule_is_valid_charset(extcss3_intern *intern, extcss3_rule *rule) { if ( - (rule->level == 0) && - (rule->base_selector->data.len == 8 /* strlen("@charset") */) && - (rule->base_selector->next) && - (rule->base_selector->next->type == EXTCSS3_TYPE_WS) && - (rule->base_selector->next->data.len == 1) && - (rule->base_selector->next->data.str[0] == ' ') && - (rule->base_selector->next->next) && - (rule->base_selector->next->next->type == EXTCSS3_TYPE_STRING) && - (rule->base_selector->next->next->data.str[0] == '"') && - (rule->base_selector->next->next->next) && - (rule->base_selector->next->next->next->type == EXTCSS3_TYPE_SEMICOLON) && - (rule->base_selector->data.str == intern->copy.str) && + (rule->level == 0) && + (rule->base_selector->data.len == 8 /* strlen("@charset") */) && + (rule->base_selector->next) && + (rule->base_selector->next->type == EXTCSS3_TYPE_WS) && + (rule->base_selector->next->data.len == 1) && + (rule->base_selector->next->data.str[0] == ' ') && + (rule->base_selector->next->next) && + (rule->base_selector->next->next->type == EXTCSS3_TYPE_STRING) && + (rule->base_selector->next->next->data.str[0] == '"') && + (rule->base_selector->next->next->next) && + (rule->base_selector->next->next->next->type == EXTCSS3_TYPE_SEMICOLON) && + (rule->base_selector->data.str == intern->copy.str) && (memcmp(rule->base_selector->data.str, "@charset", 8) == 0) ) { return EXTCSS3_SUCCESS; @@ -975,10 +984,10 @@ static inline bool _extcss3_check_at_rule_is_valid_namespace(extcss3_rule *rule) static inline bool _extcss3_check_minify_color(extcss3_token *name, extcss3_token *value) { if ( - (name->data.len >= 10) && - (value->user.str == NULL) && - (value->type == EXTCSS3_TYPE_IDENT) && - (value->data.len > 4) && + (name->data.len >= 10) && + (value->user.str == NULL) && + (value->type == EXTCSS3_TYPE_IDENT) && + (value->data.len > 4) && ( (EXTCSS3_SUCCESS == extcss3_ascii_strncasecmp(name->data.str + name->data.len - 10, "background", 10)) || (EXTCSS3_SUCCESS == extcss3_ascii_strncasecmp(name->data.str + name->data.len - 10, "decoration", 10)) @@ -986,9 +995,9 @@ static inline bool _extcss3_check_minify_color(extcss3_token *name, extcss3_toke ) { return EXTCSS3_SUCCESS; } else if ( - (name->data.len >= 6) && - (value->user.str == NULL) && - (value->type == EXTCSS3_TYPE_IDENT) && + (name->data.len >= 6) && + (value->user.str == NULL) && + (value->type == EXTCSS3_TYPE_IDENT) && (value->data.len > 4) && ( (EXTCSS3_SUCCESS == extcss3_ascii_strncasecmp(name->data.str + name->data.len - 6, "shadow", 6)) || @@ -997,10 +1006,10 @@ static inline bool _extcss3_check_minify_color(extcss3_token *name, extcss3_toke ) { return EXTCSS3_SUCCESS; } else if ( - (name->data.len >= 5) && - (value->user.str == NULL) && - (value->type == EXTCSS3_TYPE_IDENT) && - (value->data.len > 4) && + (name->data.len >= 5) && + (value->user.str == NULL) && + (value->type == EXTCSS3_TYPE_IDENT) && + (value->data.len > 4) && (EXTCSS3_SUCCESS == extcss3_ascii_strncasecmp(name->data.str + name->data.len - 5, "color", 5)) ) { return EXTCSS3_SUCCESS; diff --git a/extcss3/minifier/tree.c b/extcss3/minifier/tree.c index 24af4ec..383da4b 100644 --- a/extcss3/minifier/tree.c +++ b/extcss3/minifier/tree.c @@ -4,14 +4,14 @@ /* ==================================================================================================== */ -static void *_extcss3_set_error_code(unsigned int *error, unsigned int code, extcss3_rule *tree); +static void *_extcss3_set_error_code(extcss3_intern *intern, unsigned int *error, unsigned int code, extcss3_rule *tree); -static bool _extcss3_tree_fork_rule(extcss3_rule **rule, unsigned int *error); -static bool _extcss3_tree_fork_decl(extcss3_decl **decl, unsigned int *error); +static bool _extcss3_tree_fork_rule(extcss3_intern *intern, extcss3_rule **rule, unsigned int *error); +static bool _extcss3_tree_fork_decl(extcss3_intern *intern, extcss3_decl **decl, unsigned int *error); /* ==================================================================================================== */ -extcss3_rule *extcss3_create_tree(extcss3_token **token, extcss3_token *max, unsigned int level, unsigned int *error) +extcss3_rule *extcss3_create_tree(extcss3_intern *intern, extcss3_token **token, extcss3_token *max, unsigned int level, unsigned int *error) { extcss3_token *search; extcss3_rule *tree, *rule; @@ -20,8 +20,8 @@ extcss3_rule *extcss3_create_tree(extcss3_token **token, extcss3_token *max, uns /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - if ((tree = rule = extcss3_create_rule()) == NULL) { - return _extcss3_set_error_code(error, EXTCSS3_ERR_MEMORY, tree); + if ((tree = rule = extcss3_create_rule(intern->pool)) == NULL) { + return _extcss3_set_error_code(intern, error, EXTCSS3_ERR_MEMORY, tree); } rule->level = level; @@ -36,8 +36,8 @@ extcss3_rule *extcss3_create_tree(extcss3_token **token, extcss3_token *max, uns rule->base_selector = rule->last_selector = *token; // Fork the next rule - if (EXTCSS3_SUCCESS != _extcss3_tree_fork_rule(&rule, error)) { - return _extcss3_set_error_code(error, *error, tree); + if (EXTCSS3_SUCCESS != _extcss3_tree_fork_rule(intern, &rule, error)) { + return _extcss3_set_error_code(intern, error, *error, tree); } *token = (*token)->next; @@ -78,8 +78,8 @@ extcss3_rule *extcss3_create_tree(extcss3_token **token, extcss3_token *max, uns rule->base_selector = rule->last_selector = *token; // Fork the next rule - if (EXTCSS3_SUCCESS != _extcss3_tree_fork_rule(&rule, error)) { - return _extcss3_set_error_code(error, *error, tree); + if (EXTCSS3_SUCCESS != _extcss3_tree_fork_rule(intern, &rule, error)) { + return _extcss3_set_error_code(intern, error, *error, tree); } } @@ -95,19 +95,19 @@ extcss3_rule *extcss3_create_tree(extcss3_token **token, extcss3_token *max, uns } // Beginn a new rule by a valid selector type else if ( - ((*token)->type == EXTCSS3_TYPE_AT_KEYWORD) || - ((*token)->type == EXTCSS3_TYPE_IDENT) || - ((*token)->type == EXTCSS3_TYPE_HASH) || - ((*token)->type == EXTCSS3_TYPE_DELIM) || - ((*token)->type == EXTCSS3_TYPE_BR_SO) || - ((*token)->type == EXTCSS3_TYPE_COLON) || + ((*token)->type == EXTCSS3_TYPE_AT_KEYWORD) || + ((*token)->type == EXTCSS3_TYPE_IDENT) || + ((*token)->type == EXTCSS3_TYPE_HASH) || + ((*token)->type == EXTCSS3_TYPE_DELIM) || + ((*token)->type == EXTCSS3_TYPE_BR_SO) || + ((*token)->type == EXTCSS3_TYPE_COLON) || ((*token)->type == EXTCSS3_TYPE_PERCENTAGE) ) { rule->base_selector = rule->last_selector = *token; } else if ((*token)->type != EXTCSS3_TYPE_WS && (*token)->type != EXTCSS3_TYPE_COMMENT) { // Skip all tokens until the next '{' while ( - (*token != NULL) && + (*token != NULL) && ((*token)->type != EXTCSS3_TYPE_EOF) && ((*token)->type != EXTCSS3_TYPE_BR_CO) ) { @@ -148,8 +148,8 @@ extcss3_rule *extcss3_create_tree(extcss3_token **token, extcss3_token *max, uns *token = (*token)->next; } } else { - if ((rule->block = extcss3_create_block()) == NULL) { - return _extcss3_set_error_code(error, EXTCSS3_ERR_MEMORY, tree); + if ((rule->block = extcss3_create_block(intern->pool)) == NULL) { + return _extcss3_set_error_code(intern, error, EXTCSS3_ERR_MEMORY, tree); } // Set the '{' @@ -164,8 +164,8 @@ extcss3_rule *extcss3_create_tree(extcss3_token **token, extcss3_token *max, uns // Consume all nested rules (recursive) if (nested > 0) { - if ((rule->block->rules = extcss3_create_tree(token, search, level + 1, error)) == NULL) { - return _extcss3_set_error_code(error, *error, tree); + if ((rule->block->rules = extcss3_create_tree(intern, token, search, level + 1, error)) == NULL) { + return _extcss3_set_error_code(intern, error, *error, tree); } } // Consume all declarations in the current block @@ -181,12 +181,12 @@ extcss3_rule *extcss3_create_tree(extcss3_token **token, extcss3_token *max, uns } if (last == NULL) { - if ((rule->block->decls = decl = last = extcss3_create_decl()) == NULL) { - return _extcss3_set_error_code(error, EXTCSS3_ERR_MEMORY, tree); + if ((rule->block->decls = decl = last = extcss3_create_decl(intern->pool)) == NULL) { + return _extcss3_set_error_code(intern, error, EXTCSS3_ERR_MEMORY, tree); } } else { - if (EXTCSS3_SUCCESS != _extcss3_tree_fork_decl(&last, error)) { - return _extcss3_set_error_code(error, *error, tree); + if (EXTCSS3_SUCCESS != _extcss3_tree_fork_decl(intern, &last, error)) { + return _extcss3_set_error_code(intern, error, *error, tree); } decl = last; @@ -207,8 +207,8 @@ extcss3_rule *extcss3_create_tree(extcss3_token **token, extcss3_token *max, uns } // Fork the next rule - if (EXTCSS3_SUCCESS != _extcss3_tree_fork_rule(&rule, error)) { - return _extcss3_set_error_code(error, *error, tree); + if (EXTCSS3_SUCCESS != _extcss3_tree_fork_rule(intern, &rule, error)) { + return _extcss3_set_error_code(intern, error, *error, tree); } } @@ -221,8 +221,8 @@ extcss3_rule *extcss3_create_tree(extcss3_token **token, extcss3_token *max, uns // Pseudo-rule for the token if ((*token)->type == EXTCSS3_TYPE_EOF) { // Fork the next rule - if (EXTCSS3_SUCCESS != _extcss3_tree_fork_rule(&rule, error)) { - return _extcss3_set_error_code(error, *error, tree); + if (EXTCSS3_SUCCESS != _extcss3_tree_fork_rule(intern, &rule, error)) { + return _extcss3_set_error_code(intern, error, *error, tree); } rule->base_selector = rule->last_selector = *token; @@ -237,8 +237,8 @@ extcss3_rule *extcss3_create_tree(extcss3_token **token, extcss3_token *max, uns rule->base_selector->type == EXTCSS3_TYPE_AT_KEYWORD && (*token)->type == EXTCSS3_TYPE_SEMICOLON ) { - if (EXTCSS3_SUCCESS != _extcss3_tree_fork_rule(&rule, error)) { - return _extcss3_set_error_code(error, *error, tree); + if (EXTCSS3_SUCCESS != _extcss3_tree_fork_rule(intern, &rule, error)) { + return _extcss3_set_error_code(intern, error, *error, tree); } } } @@ -254,46 +254,46 @@ extcss3_rule *extcss3_create_tree(extcss3_token **token, extcss3_token *max, uns /* ==================================================================================================== */ -static inline void *_extcss3_set_error_code(unsigned int *error, unsigned int code, extcss3_rule *tree) +static inline void *_extcss3_set_error_code(extcss3_intern *intern, unsigned int *error, unsigned int code, extcss3_rule *tree) { *error = code; if (tree != NULL) { - extcss3_release_rules_list(tree); + extcss3_release_rules_list(intern->pool, tree); } return NULL; } -static inline bool _extcss3_tree_fork_rule(extcss3_rule **rule, unsigned int *error) +static inline bool _extcss3_tree_fork_rule(extcss3_intern *intern, extcss3_rule **rule, unsigned int *error) { extcss3_rule *fork; - if ((fork = extcss3_create_rule()) == NULL) { + if ((fork = extcss3_create_rule(intern->pool)) == NULL) { *error = EXTCSS3_ERR_MEMORY; return EXTCSS3_FAILURE; } - fork->level = (*rule)->level; - fork->prev = *rule; - (*rule)->next = fork; - *rule = fork; + fork->level = (*rule)->level; + fork->prev = *rule; + (*rule)->next = fork; + *rule = fork; return EXTCSS3_SUCCESS; } -static inline bool _extcss3_tree_fork_decl(extcss3_decl **decl, unsigned int *error) +static inline bool _extcss3_tree_fork_decl(extcss3_intern *intern, extcss3_decl **decl, unsigned int *error) { extcss3_decl *fork; - if ((fork = extcss3_create_decl()) == NULL) { + if ((fork = extcss3_create_decl(intern->pool)) == NULL) { *error = EXTCSS3_ERR_MEMORY; return EXTCSS3_FAILURE; } - fork->prev = *decl; - (*decl)->next = fork; - *decl = fork; + fork->prev = *decl; + (*decl)->next = fork; + *decl = fork; return EXTCSS3_SUCCESS; } diff --git a/extcss3/minifier/tree.h b/extcss3/minifier/tree.h index 3b9b04b..f0ed9e8 100644 --- a/extcss3/minifier/tree.h +++ b/extcss3/minifier/tree.h @@ -5,6 +5,6 @@ /* ==================================================================================================== */ -extcss3_rule *extcss3_create_tree(extcss3_token **token, extcss3_token *max, unsigned int level, unsigned int *error); +extcss3_rule *extcss3_create_tree(extcss3_intern *intern, extcss3_token **token, extcss3_token *max, unsigned int level, unsigned int *error); #endif /* EXTCSS3_MINIFIER_TREE_H */ diff --git a/extcss3/minifier/types/function.c b/extcss3/minifier/types/function.c index 950c5e5..4ed36a5 100644 --- a/extcss3/minifier/types/function.c +++ b/extcss3/minifier/types/function.c @@ -9,13 +9,13 @@ /* ==================================================================================================== */ -bool extcss3_minify_function_rgb_a(extcss3_token **token, extcss3_decl *decl, unsigned int *error) +bool extcss3_minify_function_rgb_a(extcss3_intern *intern, extcss3_token **token, extcss3_decl *decl, unsigned int *error) { extcss3_token *temp, *curr = (*token)->next; - double value; - char hex[9]; - unsigned int idx = 0, percentages = 0, numbers = 0; - bool valid = true; + double value; + char hex[9]; + unsigned int idx = 0, percentages = 0, numbers = 0; + bool valid = true; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -77,7 +77,7 @@ bool extcss3_minify_function_rgb_a(extcss3_token **token, extcss3_decl *decl, un /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ if ((((*token)->data.len == 3) && (idx == 6)) || (((*token)->data.len == 4) && (idx == 8))) { - if (EXTCSS3_SUCCESS != extcss3_minify_hash(hex, idx, *token, error)) { + if (EXTCSS3_SUCCESS != extcss3_minify_hash(intern, hex, idx, *token, error)) { return EXTCSS3_FAILURE; } @@ -85,7 +85,7 @@ bool extcss3_minify_function_rgb_a(extcss3_token **token, extcss3_decl *decl, un if ((*token)->user.str == NULL) { (*token)->user.len = idx + 1; - if (((*token)->user.str = (char *)calloc((*token)->user.len, sizeof(char))) == NULL) { + if (((*token)->user.str = (char *)mpz_pmalloc(intern->pool, (*token)->user.len * sizeof(char))) == NULL) { *error = EXTCSS3_ERR_MEMORY; return EXTCSS3_FAILURE; } @@ -105,7 +105,7 @@ bool extcss3_minify_function_rgb_a(extcss3_token **token, extcss3_decl *decl, un curr->prev->next = curr->next; temp = curr->prev; - extcss3_release_token(curr); + extcss3_release_token(intern->pool, curr); curr = temp; } @@ -113,8 +113,8 @@ bool extcss3_minify_function_rgb_a(extcss3_token **token, extcss3_decl *decl, un temp = (*token)->next; // Create a new whitespace token - if (((*token)->next = extcss3_create_token()) == NULL) { - extcss3_release_tokens_list(temp); + if (((*token)->next = extcss3_create_token(intern->pool)) == NULL) { + extcss3_release_tokens_list(intern->pool, temp); *error = EXTCSS3_ERR_MEMORY; return EXTCSS3_FAILURE; diff --git a/extcss3/minifier/types/function.h b/extcss3/minifier/types/function.h index fc706bc..0d47b20 100644 --- a/extcss3/minifier/types/function.h +++ b/extcss3/minifier/types/function.h @@ -5,6 +5,6 @@ /* ==================================================================================================== */ -bool extcss3_minify_function_rgb_a(extcss3_token **token, extcss3_decl *decl, unsigned int *error); +bool extcss3_minify_function_rgb_a(extcss3_intern *intern, extcss3_token **token, extcss3_decl *decl, unsigned int *error); #endif /* EXTCSS3_MINIFIER_TYPES_FUNCTION_H */ diff --git a/extcss3/minifier/types/hash.c b/extcss3/minifier/types/hash.c index 93b7f68..521d23a 100644 --- a/extcss3/minifier/types/hash.c +++ b/extcss3/minifier/types/hash.c @@ -167,9 +167,10 @@ const char *extcss3_color_hashes_xx[11][2] = { /* ==================================================================================================== */ -bool extcss3_minify_hash(char *str, unsigned int len, extcss3_token *token, unsigned int *error) +bool extcss3_minify_hash(extcss3_intern *intern, char *str, unsigned int len, extcss3_token *token, unsigned int *error) { unsigned int i; + char f = 'f'; if ((token == NULL) || (str == NULL)) { *error = EXTCSS3_ERR_NULL_PTR; @@ -179,12 +180,12 @@ bool extcss3_minify_hash(char *str, unsigned int len, extcss3_token *token, unsi /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ if (len == 4) { - if (EXTCSS3_CHARS_EQ(str[3], 'f')) { - return extcss3_minify_hash(str, 3, token, error); + if (EXTCSS3_CHARS_EQ(str[3], f)) { + return extcss3_minify_hash(intern, str, 3, token, error); } } else if (len == 8) { - if (EXTCSS3_CHARS_EQ(str[6], 'f') && EXTCSS3_CHARS_EQ(str[7], 'f')) { - return extcss3_minify_hash(str, 6, token, error); + if (EXTCSS3_CHARS_EQ(str[6], f) && EXTCSS3_CHARS_EQ(str[7], f)) { + return extcss3_minify_hash(intern, str, 6, token, error); } else if ( EXTCSS3_CHARS_EQ(str[0], str[1]) && EXTCSS3_CHARS_EQ(str[2], str[3]) && @@ -192,7 +193,7 @@ bool extcss3_minify_hash(char *str, unsigned int len, extcss3_token *token, unsi EXTCSS3_CHARS_EQ(str[6], str[7]) ) { token->user.len = 5; - if ((token->user.str = (char *)calloc(token->user.len, sizeof(char))) == NULL) { + if ((token->user.str = (char *)mpz_pmalloc(intern->pool, token->user.len * sizeof(char))) == NULL) { *error = EXTCSS3_ERR_MEMORY; return EXTCSS3_FAILURE; } @@ -209,9 +210,9 @@ bool extcss3_minify_hash(char *str, unsigned int len, extcss3_token *token, unsi EXTCSS3_CHARS_EQ(str[2], str[3]) && EXTCSS3_CHARS_EQ(str[4], str[5]) ) { - if (EXTCSS3_CHARS_EQ(str[0], 'f') && (str[2] == '0') && (str[4] == '0')) { + if (EXTCSS3_CHARS_EQ(str[0], f) && (str[2] == '0') && (str[4] == '0')) { token->user.len = 3; - if ((token->user.str = (char *)calloc(token->user.len, sizeof(char))) == NULL) { + if ((token->user.str = (char *)mpz_pmalloc(intern->pool, token->user.len * sizeof(char))) == NULL) { *error = EXTCSS3_ERR_MEMORY; return EXTCSS3_FAILURE; } @@ -219,7 +220,7 @@ bool extcss3_minify_hash(char *str, unsigned int len, extcss3_token *token, unsi memcpy(token->user.str, "red", 3); } else { token->user.len = 4; - if ((token->user.str = (char *)calloc(token->user.len, sizeof(char))) == NULL) { + if ((token->user.str = (char *)mpz_pmalloc(intern->pool, token->user.len * sizeof(char))) == NULL) { *error = EXTCSS3_ERR_MEMORY; return EXTCSS3_FAILURE; } @@ -233,7 +234,7 @@ bool extcss3_minify_hash(char *str, unsigned int len, extcss3_token *token, unsi for (i = (sizeof(extcss3_hash_colors) / sizeof(extcss3_hash_colors[0])); i--; ) { if (EXTCSS3_SUCCESS == extcss3_ascii_strncasecmp(str, extcss3_hash_colors[i][0], 6)) { token->user.len = strlen(extcss3_hash_colors[i][1]); - if ((token->user.str = (char *)calloc(token->user.len, sizeof(char))) == NULL) { + if ((token->user.str = (char *)mpz_pmalloc(intern->pool, token->user.len * sizeof(char))) == NULL) { *error = EXTCSS3_ERR_MEMORY; return EXTCSS3_FAILURE; } @@ -243,9 +244,9 @@ bool extcss3_minify_hash(char *str, unsigned int len, extcss3_token *token, unsi } } } else if (len == 3) { - if (EXTCSS3_CHARS_EQ(str[0], 'f') && (str[1] == '0') && (str[2] == '0')) { + if (EXTCSS3_CHARS_EQ(str[0], f) && (str[1] == '0') && (str[2] == '0')) { token->user.len = 3; - if ((token->user.str = (char *)calloc(token->user.len, sizeof(char))) == NULL) { + if ((token->user.str = (char *)mpz_pmalloc(intern->pool, token->user.len * sizeof(char))) == NULL) { *error = EXTCSS3_ERR_MEMORY; return EXTCSS3_FAILURE; } @@ -257,7 +258,7 @@ bool extcss3_minify_hash(char *str, unsigned int len, extcss3_token *token, unsi return EXTCSS3_SUCCESS; } -bool extcss3_minify_color(extcss3_token *token, unsigned int *error) +bool extcss3_minify_color(extcss3_intern *intern, extcss3_token *token, unsigned int *error) { unsigned int i, elements; const char *(*map)[2]; @@ -320,7 +321,7 @@ bool extcss3_minify_color(extcss3_token *token, unsigned int *error) ) { token->user.len = strlen(map[i][1]) + 1; - if ((token->user.str = (char *)calloc(token->user.len, sizeof(char))) == NULL) { + if ((token->user.str = (char *)mpz_pmalloc(intern->pool, token->user.len * sizeof(char))) == NULL) { *error = EXTCSS3_ERR_MEMORY; return EXTCSS3_FAILURE; } diff --git a/extcss3/minifier/types/hash.h b/extcss3/minifier/types/hash.h index 204fac0..b4b273f 100644 --- a/extcss3/minifier/types/hash.h +++ b/extcss3/minifier/types/hash.h @@ -5,7 +5,7 @@ /* ==================================================================================================== */ -bool extcss3_minify_hash(char *str, unsigned int len, extcss3_token *token, unsigned int *error); -bool extcss3_minify_color(extcss3_token *token, unsigned int *error); +bool extcss3_minify_hash(extcss3_intern *intern, char *str, unsigned int len, extcss3_token *token, unsigned int *error); +bool extcss3_minify_color(extcss3_intern *intern, extcss3_token *token, unsigned int *error); #endif /* EXTCSS3_MINIFIER_TYPES_HASH_H */ diff --git a/extcss3/minifier/types/numeric.c b/extcss3/minifier/types/numeric.c index 9c58f88..0101d98 100644 --- a/extcss3/minifier/types/numeric.c +++ b/extcss3/minifier/types/numeric.c @@ -55,18 +55,18 @@ static inline bool _extcss3_minify_numeric_preserve_dimension(extcss3_token *tok /* ==================================================================================================== */ -bool extcss3_minify_numeric(extcss3_token *token, bool preserve_sign, unsigned int *error) +bool extcss3_minify_numeric(extcss3_intern *intern, extcss3_token *token, bool preserve_sign, bool preserve_dimension, unsigned int *error) { - char *base, *last; - double num; - unsigned int val_is_signed = 0; + char *base, *last; + double num; + unsigned int val_is_signed = 0; if (token == NULL) { *error = EXTCSS3_ERR_NULL_PTR; return EXTCSS3_FAILURE; } else if ( - (token->type != EXTCSS3_TYPE_NUMBER) && - (token->type != EXTCSS3_TYPE_PERCENTAGE) && + (token->type != EXTCSS3_TYPE_NUMBER) && + (token->type != EXTCSS3_TYPE_PERCENTAGE) && (token->type != EXTCSS3_TYPE_DIMENSION) ) { return EXTCSS3_SUCCESS; @@ -83,7 +83,7 @@ bool extcss3_minify_numeric(extcss3_token *token, bool preserve_sign, unsigned i token->user.len = 1 + token->info.len; } - if ((token->user.str = (char *)calloc(token->user.len + token->info.len, sizeof(char))) == NULL) { + if ((token->user.str = (char *)mpz_pmalloc(intern->pool, (token->user.len + token->info.len) * sizeof(char))) == NULL) { *error = EXTCSS3_ERR_MEMORY; return EXTCSS3_FAILURE; } @@ -137,7 +137,7 @@ bool extcss3_minify_numeric(extcss3_token *token, bool preserve_sign, unsigned i token->user.len = last - base + val_is_signed + token->info.len; - if ((token->user.str = (char *)calloc(token->user.len, sizeof(char))) == NULL) { + if ((token->user.str = (char *)mpz_pmalloc(intern->pool, token->user.len * sizeof(char))) == NULL) { *error = EXTCSS3_ERR_MEMORY; return EXTCSS3_FAILURE; } @@ -151,7 +151,11 @@ bool extcss3_minify_numeric(extcss3_token *token, bool preserve_sign, unsigned i /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - if ((num != 0) || (EXTCSS3_SUCCESS == _extcss3_minify_numeric_preserve_dimension(token))) { + if (!preserve_dimension) { + preserve_dimension = (num == 0) && (token->type == EXTCSS3_TYPE_PERCENTAGE); + } + + if (preserve_dimension || (num != 0) || (EXTCSS3_SUCCESS == _extcss3_minify_numeric_preserve_dimension(token))) { memcpy(token->user.str + token->user.len - token->info.len, token->info.str, token->info.len); } else if (token->user.str != NULL) { token->user.len -= token->info.len; diff --git a/extcss3/minifier/types/numeric.h b/extcss3/minifier/types/numeric.h index 82d7e5c..09e4375 100644 --- a/extcss3/minifier/types/numeric.h +++ b/extcss3/minifier/types/numeric.h @@ -5,6 +5,6 @@ /* ==================================================================================================== */ -bool extcss3_minify_numeric(extcss3_token *token, bool preserve_sign, unsigned int *error); +bool extcss3_minify_numeric(extcss3_intern *intern, extcss3_token *token, bool preserve_sign, bool preserve_dimension, unsigned int *error); #endif /* EXTCSS3_MINIFIER_TYPES_NUMERIC_H */ diff --git a/extcss3/tokenizer/context.c b/extcss3/tokenizer/context.c index 8856f9f..ecb98a8 100644 --- a/extcss3/tokenizer/context.c +++ b/extcss3/tokenizer/context.c @@ -10,7 +10,7 @@ static inline void _extcss3_ctxt_parent(extcss3_intern *intern) if ((intern->last_ctxt != NULL) && (intern->last_ctxt->prev != NULL)) { prev = intern->last_ctxt->prev; prev->next = NULL; - extcss3_release_ctxt(intern->last_ctxt); + extcss3_release_ctxt(intern->pool, intern->last_ctxt); intern->last_ctxt = prev; } } @@ -30,7 +30,7 @@ bool extcss3_ctxt_update(extcss3_intern *intern, unsigned int *error) case EXTCSS3_TYPE_BR_SO: case EXTCSS3_TYPE_BR_CO: { - if ((intern->last_ctxt->next = extcss3_create_ctxt()) == NULL) { + if ((intern->last_ctxt->next = extcss3_create_ctxt(intern->pool)) == NULL) { *error = EXTCSS3_ERR_MEMORY; return EXTCSS3_FAILURE; diff --git a/extcss3/tokenizer/preprocessor.c b/extcss3/tokenizer/preprocessor.c index ab10c0c..b0d687f 100644 --- a/extcss3/tokenizer/preprocessor.c +++ b/extcss3/tokenizer/preprocessor.c @@ -10,7 +10,8 @@ */ static inline bool _extcss3_check_bytes_corruption(extcss3_intern *intern, unsigned int *error) { - unsigned int i, j; + int i; + unsigned int j; if (EXTCSS3_IS_NON_ASCII(*intern->state.cursor)) { i = 7; diff --git a/extcss3/tokenizer/tokenizer.c b/extcss3/tokenizer/tokenizer.c index 0501e7c..cc9d4a4 100644 --- a/extcss3/tokenizer/tokenizer.c +++ b/extcss3/tokenizer/tokenizer.c @@ -9,18 +9,18 @@ /* ==================================================================================================== */ -#define _EXTCSS3_NEXT(intern, error) do { \ - bool result = _extcss3_next_char(intern, error); \ - if (EXTCSS3_SUCCESS != result) { \ - return EXTCSS3_FAILURE; \ - } \ +#define _EXTCSS3_NEXT(intern, error) do { \ + bool result = _extcss3_next_char(intern, error); \ + if (EXTCSS3_SUCCESS != result) { \ + return EXTCSS3_FAILURE; \ + } \ } while (0) -#define _EXTCSS3_FILL_FIXED_TOKEN(intern, token, type, chars, error) do { \ - bool result = _extcss3_fill_fixed_token(intern, token, type, chars, error); \ - if (EXTCSS3_SUCCESS != result) { \ - return _extcss3_cleanup_tokenizer(*error, intern, true, true); \ - } \ +#define _EXTCSS3_FILL_FIXED_TOKEN(intern, token, type, chars, error) do { \ + bool result = _extcss3_fill_fixed_token(intern, token, type, chars, error); \ + if (EXTCSS3_SUCCESS != result) { \ + return _extcss3_cleanup_tokenizer(*error, intern, true, true); \ + } \ } while (0) /* ==================================================================================================== */ @@ -66,11 +66,11 @@ bool extcss3_tokenize(extcss3_intern *intern, unsigned int *error) if ((intern == NULL) || (intern->copy.str == NULL)) { return _extcss3_cleanup_tokenizer(*error = EXTCSS3_ERR_NULL_PTR, NULL, false, false); - } else if ((intern->base_token = token = extcss3_create_token()) == NULL) { + } else if ((intern->base_token = token = extcss3_create_token(intern->pool)) == NULL) { return _extcss3_cleanup_tokenizer(*error = EXTCSS3_ERR_MEMORY, NULL, false, false); } else if ( - EXTCSS3_HAS_MODIFIER(intern) && - ((intern->base_ctxt = intern->last_ctxt = extcss3_create_ctxt()) == NULL) + ((intern->notifier.base != NULL) || EXTCSS3_HAS_MODIFIER(intern)) && + ((intern->base_ctxt = intern->last_ctxt = extcss3_create_ctxt(intern->pool)) == NULL) ) { return _extcss3_cleanup_tokenizer(*error = EXTCSS3_ERR_MEMORY, intern, true, false); } @@ -352,7 +352,7 @@ bool extcss3_tokenize(extcss3_intern *intern, unsigned int *error) if (token->type == EXTCSS3_TYPE_EOF) { break; - } else if ((token = extcss3_create_token()) == NULL) { + } else if ((token = extcss3_create_token(intern->pool)) == NULL) { return _extcss3_cleanup_tokenizer(*error = EXTCSS3_ERR_MEMORY, intern, true, true); } } @@ -369,12 +369,12 @@ static inline bool _extcss3_cleanup_tokenizer(unsigned int error, extcss3_intern { if (intern != NULL) { if (token && (intern->base_token != NULL)) { - extcss3_release_tokens_list(intern->base_token); + extcss3_release_tokens_list(intern->pool, intern->base_token); intern->base_token = NULL; } if (ctxt && (intern->base_ctxt != NULL)) { - extcss3_release_ctxts_list(intern->base_ctxt); + extcss3_release_ctxts_list(intern->pool, intern->base_ctxt); intern->base_ctxt = NULL; } } @@ -396,6 +396,7 @@ static inline bool _extcss3_next_char(extcss3_intern *intern, unsigned int *erro static inline bool _extcss3_token_add(extcss3_intern *intern, extcss3_token *token, unsigned int *error) { extcss3_token *prev; + extcss3_sig *sig; if ((token->prev = intern->last_token) != NULL) { intern->last_token->next = token; @@ -431,6 +432,24 @@ static inline bool _extcss3_token_add(extcss3_intern *intern, extcss3_token *tok /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ if (intern->base_ctxt != NULL) { + /* Calling notifier(s) */ + if (((sig = intern->notifier.base) != NULL) && (intern->notifier.callback != NULL)) { + while (sig != NULL) { + if (sig->type == token->type) { + intern->notifier.callback(intern, sig); + + if ((token->user.str != NULL) || (token->user.len != 0)) { + *error = EXTCSS3_ERR_INV_VALUE; + + return EXTCSS3_FAILURE; + } + } + + sig = sig->next; + } + } + + /* Calling modifier */ if (EXTCSS3_TYPE_IS_MODIFIABLE(token->type) && (intern->modifier.callback != NULL)) { intern->modifier.callback(intern); @@ -631,6 +650,8 @@ static inline bool _extcss3_fill_unicode_range_token(extcss3_intern *intern, ext */ static inline bool _extcss3_fill_ident_like_token(extcss3_intern *intern, extcss3_token *token, unsigned int *error) { + char u = 'u', r = 'r', l = 'l'; + token->data.str = intern->state.reader; if (EXTCSS3_SUCCESS != _extcss3_consume_name(intern, error)) { @@ -640,9 +661,9 @@ static inline bool _extcss3_fill_ident_like_token(extcss3_intern *intern, extcss if (*intern->state.reader == '(') { if ( ((intern->state.reader - token->data.str) == 3) && - EXTCSS3_CHARS_EQ(token->data.str[0], 'u') && - EXTCSS3_CHARS_EQ(token->data.str[1], 'r') && - EXTCSS3_CHARS_EQ(token->data.str[2], 'l') + EXTCSS3_CHARS_EQ(token->data.str[0], u) && + EXTCSS3_CHARS_EQ(token->data.str[1], r) && + EXTCSS3_CHARS_EQ(token->data.str[2], l) ) { return _extcss3_fill_url_token(intern, token, error); } else { @@ -841,6 +862,8 @@ static inline bool _extcss3_fill_string_token(extcss3_intern *intern, extcss3_to */ static inline bool _extcss3_fill_number_token(extcss3_intern *intern, extcss3_token *token, unsigned int *error) { + char e = 'e'; + token->flag = EXTCSS3_FLAG_INTEGER; token->data.str = intern->state.reader; @@ -862,7 +885,7 @@ static inline bool _extcss3_fill_number_token(extcss3_intern *intern, extcss3_to } } - if (EXTCSS3_CHARS_EQ(*intern->state.reader, 'e')) { + if (EXTCSS3_CHARS_EQ(*intern->state.reader, e)) { if (EXTCSS3_IS_DIGIT(intern->state.reader[1])) { _EXTCSS3_NEXT(intern, error); diff --git a/extcss3/types.h b/extcss3/types.h index 625326a..54be43c 100644 --- a/extcss3/types.h +++ b/extcss3/types.h @@ -4,248 +4,269 @@ #include #include +#include "../mpz/src/mpz_alloc.h" + /* ==================================================================================================== */ -#define EXTCSS3_SUCCESS (true) -#define EXTCSS3_FAILURE (false) +#define EXTCSS3_SUCCESS (true) +#define EXTCSS3_FAILURE (false) /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ -#define EXTCSS3_ERR_MEMORY ((unsigned int)1) -#define EXTCSS3_ERR_BYTES_CORRUPTION ((unsigned int)2) -#define EXTCSS3_ERR_NULL_PTR ((unsigned int)3) -#define EXTCSS3_ERR_INV_PARAM ((unsigned int)4) +#define EXTCSS3_ERR_MEMORY ((unsigned int)1) +#define EXTCSS3_ERR_BYTES_CORRUPTION ((unsigned int)2) +#define EXTCSS3_ERR_NULL_PTR ((unsigned int)3) +#define EXTCSS3_ERR_INV_PARAM ((unsigned int)4) +#define EXTCSS3_ERR_INV_VALUE ((unsigned int)5) /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ -#define EXTCSS3_REPLACEMENT_CHR ("\xEF\xBF\xBD") -#define EXTCSS3_REPLACEMENT_LEN ((unsigned int)3) +#define EXTCSS3_REPLACEMENT_CHR ("\xEF\xBF\xBD") +#define EXTCSS3_REPLACEMENT_LEN ((unsigned int)3) /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ -#define EXTCSS3_FLAG_ID ((unsigned int)1) -#define EXTCSS3_FLAG_UNRESTRICTED ((unsigned int)2) -#define EXTCSS3_FLAG_INTEGER ((unsigned int)3) -#define EXTCSS3_FLAG_NUMBER ((unsigned int)4) -#define EXTCSS3_FLAG_STRING ((unsigned int)5) -#define EXTCSS3_FLAG_AT_URL_STRING ((unsigned int)6) +#define EXTCSS3_FLAG_ID ((unsigned int)1) +#define EXTCSS3_FLAG_UNRESTRICTED ((unsigned int)2) +#define EXTCSS3_FLAG_INTEGER ((unsigned int)3) +#define EXTCSS3_FLAG_NUMBER ((unsigned int)4) +#define EXTCSS3_FLAG_STRING ((unsigned int)5) +#define EXTCSS3_FLAG_AT_URL_STRING ((unsigned int)6) -#define EXTCSS3_FLAG_ID_STR ("id") -#define EXTCSS3_FLAG_UNRESTRICTED_STR ("unrestricted") -#define EXTCSS3_FLAG_INTEGER_STR ("int") -#define EXTCSS3_FLAG_NUMBER_STR ("num") -#define EXTCSS3_FLAG_STRING_STR ("string") -#define EXTCSS3_FLAG_AT_URL_STRING_STR ("at_url_string") +#define EXTCSS3_FLAG_ID_STR ("id") +#define EXTCSS3_FLAG_UNRESTRICTED_STR ("unrestricted") +#define EXTCSS3_FLAG_INTEGER_STR ("int") +#define EXTCSS3_FLAG_NUMBER_STR ("num") +#define EXTCSS3_FLAG_STRING_STR ("string") +#define EXTCSS3_FLAG_AT_URL_STRING_STR ("at_url_string") /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ -#define EXTCSS3_UNDEFINED ((unsigned int)0) -#define EXTCSS3_UNDEFINED_STR ("undefined") - -#define EXTCSS3_TYPE_IDENT ((unsigned int)1) -#define EXTCSS3_TYPE_FUNCTION ((unsigned int)2) -#define EXTCSS3_TYPE_AT_KEYWORD ((unsigned int)3) -#define EXTCSS3_TYPE_HASH ((unsigned int)4) -#define EXTCSS3_TYPE_STRING ((unsigned int)5) -#define EXTCSS3_TYPE_BAD_STRING ((unsigned int)6) -#define EXTCSS3_TYPE_URL ((unsigned int)7) -#define EXTCSS3_TYPE_BAD_URL ((unsigned int)8) -#define EXTCSS3_TYPE_DELIM ((unsigned int)9) -#define EXTCSS3_TYPE_NUMBER ((unsigned int)10) -#define EXTCSS3_TYPE_PERCENTAGE ((unsigned int)11) -#define EXTCSS3_TYPE_DIMENSION ((unsigned int)12) -#define EXTCSS3_TYPE_UNICODE_RANGE ((unsigned int)13) -#define EXTCSS3_TYPE_INCLUDE_MATCH ((unsigned int)14) -#define EXTCSS3_TYPE_DASH_MATCH ((unsigned int)15) -#define EXTCSS3_TYPE_PREFIX_MATCH ((unsigned int)16) -#define EXTCSS3_TYPE_SUFFIX_MATCH ((unsigned int)17) -#define EXTCSS3_TYPE_SUBSTR_MATCH ((unsigned int)18) -#define EXTCSS3_TYPE_COLUMN ((unsigned int)19) -#define EXTCSS3_TYPE_WS ((unsigned int)20) -#define EXTCSS3_TYPE_CDO ((unsigned int)21) -#define EXTCSS3_TYPE_CDC ((unsigned int)22) -#define EXTCSS3_TYPE_COLON ((unsigned int)23) -#define EXTCSS3_TYPE_SEMICOLON ((unsigned int)24) -#define EXTCSS3_TYPE_COMMA ((unsigned int)25) -#define EXTCSS3_TYPE_BR_RO ((unsigned int)26) -#define EXTCSS3_TYPE_BR_RC ((unsigned int)27) -#define EXTCSS3_TYPE_BR_SO ((unsigned int)28) -#define EXTCSS3_TYPE_BR_SC ((unsigned int)29) -#define EXTCSS3_TYPE_BR_CO ((unsigned int)30) -#define EXTCSS3_TYPE_BR_CC ((unsigned int)31) -#define EXTCSS3_TYPE_COMMENT ((unsigned int)32) -#define EXTCSS3_TYPE_EOF ((unsigned int)33) - -#define EXTCSS3_TYPE_IDENT_STR ("ident") -#define EXTCSS3_TYPE_FUNCTION_STR ("function") -#define EXTCSS3_TYPE_AT_KEYWORD_STR ("at_keyword") -#define EXTCSS3_TYPE_HASH_STR ("hash") -#define EXTCSS3_TYPE_STRING_STR ("string") -#define EXTCSS3_TYPE_BAD_STRING_STR ("bad_string") -#define EXTCSS3_TYPE_URL_STR ("url") -#define EXTCSS3_TYPE_BAD_URL_STR ("bad_url") -#define EXTCSS3_TYPE_DELIM_STR ("delim") -#define EXTCSS3_TYPE_NUMBER_STR ("number") -#define EXTCSS3_TYPE_PERCENTAGE_STR ("percentage") -#define EXTCSS3_TYPE_DIMENSION_STR ("dimension") -#define EXTCSS3_TYPE_UNICODE_RANGE_STR ("unicode_range") -#define EXTCSS3_TYPE_INCLUDE_MATCH_STR ("include_match") -#define EXTCSS3_TYPE_DASH_MATCH_STR ("dash") -#define EXTCSS3_TYPE_PREFIX_MATCH_STR ("prefix_match") -#define EXTCSS3_TYPE_SUFFIX_MATCH_STR ("suffix_match") -#define EXTCSS3_TYPE_SUBSTR_MATCH_STR ("substring_match") -#define EXTCSS3_TYPE_COLUMN_STR ("column") -#define EXTCSS3_TYPE_WS_STR ("whitespace") -#define EXTCSS3_TYPE_CDO_STR ("cdo") -#define EXTCSS3_TYPE_CDC_STR ("cdc") -#define EXTCSS3_TYPE_COLON_STR ("colon") -#define EXTCSS3_TYPE_SEMICOLON_STR ("semicolon") -#define EXTCSS3_TYPE_COMMA_STR ("comma") -#define EXTCSS3_TYPE_BR_RO_STR ("br_ro") -#define EXTCSS3_TYPE_BR_RC_STR ("br_rc") -#define EXTCSS3_TYPE_BR_SO_STR ("br_so") -#define EXTCSS3_TYPE_BR_SC_STR ("br_sc") -#define EXTCSS3_TYPE_BR_CO_STR ("br_co") -#define EXTCSS3_TYPE_BR_CC_STR ("br_cc") -#define EXTCSS3_TYPE_COMMENT_STR ("comment") -#define EXTCSS3_TYPE_EOF_STR ("eof") +#define EXTCSS3_UNDEFINED ((unsigned int)0) +#define EXTCSS3_UNDEFINED_STR ("undefined") + +#define EXTCSS3_TYPE_IDENT ((unsigned int)1) +#define EXTCSS3_TYPE_FUNCTION ((unsigned int)2) +#define EXTCSS3_TYPE_AT_KEYWORD ((unsigned int)3) +#define EXTCSS3_TYPE_HASH ((unsigned int)4) +#define EXTCSS3_TYPE_STRING ((unsigned int)5) +#define EXTCSS3_TYPE_BAD_STRING ((unsigned int)6) +#define EXTCSS3_TYPE_URL ((unsigned int)7) +#define EXTCSS3_TYPE_BAD_URL ((unsigned int)8) +#define EXTCSS3_TYPE_DELIM ((unsigned int)9) +#define EXTCSS3_TYPE_NUMBER ((unsigned int)10) +#define EXTCSS3_TYPE_PERCENTAGE ((unsigned int)11) +#define EXTCSS3_TYPE_DIMENSION ((unsigned int)12) +#define EXTCSS3_TYPE_UNICODE_RANGE ((unsigned int)13) +#define EXTCSS3_TYPE_INCLUDE_MATCH ((unsigned int)14) +#define EXTCSS3_TYPE_DASH_MATCH ((unsigned int)15) +#define EXTCSS3_TYPE_PREFIX_MATCH ((unsigned int)16) +#define EXTCSS3_TYPE_SUFFIX_MATCH ((unsigned int)17) +#define EXTCSS3_TYPE_SUBSTR_MATCH ((unsigned int)18) +#define EXTCSS3_TYPE_COLUMN ((unsigned int)19) +#define EXTCSS3_TYPE_WS ((unsigned int)20) +#define EXTCSS3_TYPE_CDO ((unsigned int)21) +#define EXTCSS3_TYPE_CDC ((unsigned int)22) +#define EXTCSS3_TYPE_COLON ((unsigned int)23) +#define EXTCSS3_TYPE_SEMICOLON ((unsigned int)24) +#define EXTCSS3_TYPE_COMMA ((unsigned int)25) +#define EXTCSS3_TYPE_BR_RO ((unsigned int)26) +#define EXTCSS3_TYPE_BR_RC ((unsigned int)27) +#define EXTCSS3_TYPE_BR_SO ((unsigned int)28) +#define EXTCSS3_TYPE_BR_SC ((unsigned int)29) +#define EXTCSS3_TYPE_BR_CO ((unsigned int)30) +#define EXTCSS3_TYPE_BR_CC ((unsigned int)31) +#define EXTCSS3_TYPE_COMMENT ((unsigned int)32) +#define EXTCSS3_TYPE_EOF ((unsigned int)33) + +#define EXTCSS3_TYPE_IDENT_STR ("ident") +#define EXTCSS3_TYPE_FUNCTION_STR ("function") +#define EXTCSS3_TYPE_AT_KEYWORD_STR ("at_keyword") +#define EXTCSS3_TYPE_HASH_STR ("hash") +#define EXTCSS3_TYPE_STRING_STR ("string") +#define EXTCSS3_TYPE_BAD_STRING_STR ("bad_string") +#define EXTCSS3_TYPE_URL_STR ("url") +#define EXTCSS3_TYPE_BAD_URL_STR ("bad_url") +#define EXTCSS3_TYPE_DELIM_STR ("delim") +#define EXTCSS3_TYPE_NUMBER_STR ("number") +#define EXTCSS3_TYPE_PERCENTAGE_STR ("percentage") +#define EXTCSS3_TYPE_DIMENSION_STR ("dimension") +#define EXTCSS3_TYPE_UNICODE_RANGE_STR ("unicode_range") +#define EXTCSS3_TYPE_INCLUDE_MATCH_STR ("include_match") +#define EXTCSS3_TYPE_DASH_MATCH_STR ("dash") +#define EXTCSS3_TYPE_PREFIX_MATCH_STR ("prefix_match") +#define EXTCSS3_TYPE_SUFFIX_MATCH_STR ("suffix_match") +#define EXTCSS3_TYPE_SUBSTR_MATCH_STR ("substring_match") +#define EXTCSS3_TYPE_COLUMN_STR ("column") +#define EXTCSS3_TYPE_WS_STR ("whitespace") +#define EXTCSS3_TYPE_CDO_STR ("cdo") +#define EXTCSS3_TYPE_CDC_STR ("cdc") +#define EXTCSS3_TYPE_COLON_STR ("colon") +#define EXTCSS3_TYPE_SEMICOLON_STR ("semicolon") +#define EXTCSS3_TYPE_COMMA_STR ("comma") +#define EXTCSS3_TYPE_BR_RO_STR ("br_ro") +#define EXTCSS3_TYPE_BR_RC_STR ("br_rc") +#define EXTCSS3_TYPE_BR_SO_STR ("br_so") +#define EXTCSS3_TYPE_BR_SC_STR ("br_sc") +#define EXTCSS3_TYPE_BR_CO_STR ("br_co") +#define EXTCSS3_TYPE_BR_CC_STR ("br_cc") +#define EXTCSS3_TYPE_COMMENT_STR ("comment") +#define EXTCSS3_TYPE_EOF_STR ("eof") /* ==================================================================================================== */ -#pragma pack(push) -#pragma pack() +typedef struct _extcss3_str extcss3_str; + +typedef struct _extcss3_state extcss3_state; -typedef struct _extcss3_str extcss3_str; +typedef struct _extcss3_token extcss3_token; -typedef struct _extcss3_state extcss3_state; +typedef struct _extcss3_ctxt extcss3_ctxt; -typedef struct _extcss3_token extcss3_token; +typedef struct _extcss3_vendor extcss3_vendor; -typedef struct _extcss3_ctxt extcss3_ctxt; +typedef struct _extcss3_sig extcss3_sig; -typedef struct _extcss3_vendor extcss3_vendor; +typedef struct _extcss3_not extcss3_not; -typedef struct _extcss3_mod extcss3_mod; +typedef struct _extcss3_mod extcss3_mod; -typedef struct _extcss3_decl extcss3_decl; +typedef struct _extcss3_decl extcss3_decl; -typedef struct _extcss3_block extcss3_block; +typedef struct _extcss3_block extcss3_block; -typedef struct _extcss3_rule extcss3_rule; +typedef struct _extcss3_rule extcss3_rule; -typedef struct _extcss3_intern extcss3_intern; +typedef struct _extcss3_intern extcss3_intern; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ struct _extcss3_str { - char *str; - size_t len; + char *str; + size_t len; }; struct _extcss3_state { - char *reader; - char *cursor; - char *writer; + char *reader; + char *cursor; + char *writer; - size_t rest; + size_t rest; }; struct _extcss3_token { - unsigned int type; + extcss3_str data; + extcss3_str info; + extcss3_str user; - extcss3_str data; - extcss3_str info; - extcss3_str user; + extcss3_token *prev; + extcss3_token *next; - extcss3_token *prev; - extcss3_token *next; - - unsigned int flag; + unsigned int type; + unsigned int flag; }; struct _extcss3_ctxt { - size_t level; - extcss3_token *token; + size_t level; + extcss3_token *token; - extcss3_ctxt *prev; - extcss3_ctxt *next; + extcss3_ctxt *prev; + extcss3_ctxt *next; }; struct _extcss3_vendor { - extcss3_str name; - extcss3_vendor *next; + extcss3_str name; + extcss3_vendor *next; +}; + +struct _extcss3_sig +{ + unsigned int type; + extcss3_sig *next; + + void *callable; +}; + +struct _extcss3_not +{ + extcss3_sig *base; + extcss3_sig *last; + + void (*callback)(extcss3_intern *intern, extcss3_sig *sig); + void (*destructor)(void *callable); }; struct _extcss3_mod { - void *string; - void *bad_string; - void *url; - void *bad_url; - void *comment; + void *string; + void *bad_string; + void *url; + void *bad_url; + void *comment; - void (*callback)(extcss3_intern *intern); - void (*destructor)(void *modifier); + void (*callback)(extcss3_intern *intern); + void (*destructor)(void *modifier); - long long user_strlen_diff; + long long user_strlen_diff; }; struct _extcss3_decl { - extcss3_token *base; - extcss3_token *last; + extcss3_token *base; + extcss3_token *last; - extcss3_decl *prev; - extcss3_decl *next; + extcss3_decl *prev; + extcss3_decl *next; }; struct _extcss3_block { - extcss3_token *base; - extcss3_token *last; + extcss3_token *base; + extcss3_token *last; - extcss3_rule *rules; - extcss3_decl *decls; + extcss3_rule *rules; + extcss3_decl *decls; }; struct _extcss3_rule { - unsigned int level; + extcss3_token *base_selector; + extcss3_token *last_selector; - extcss3_token *base_selector; - extcss3_token *last_selector; + extcss3_block *block; - extcss3_block *block; + extcss3_rule *prev; + extcss3_rule *next; - extcss3_rule *prev; - extcss3_rule *next; + unsigned int level; }; struct _extcss3_intern { - extcss3_state state; + mpz_pool_t *pool; - extcss3_str orig; - extcss3_str copy; + extcss3_str orig; + extcss3_str copy; - extcss3_token *base_token; - extcss3_token *last_token; + extcss3_token *base_token; + extcss3_token *last_token; - extcss3_ctxt *base_ctxt; - extcss3_ctxt *last_ctxt; + extcss3_ctxt *base_ctxt; + extcss3_ctxt *last_ctxt; - extcss3_vendor *base_vendor; - extcss3_vendor *last_vendor; + extcss3_vendor *base_vendor; + extcss3_vendor *last_vendor; - extcss3_mod modifier; -}; + extcss3_not notifier; + extcss3_mod modifier; -#pragma pack(pop) + extcss3_state state; +}; /* ==================================================================================================== */ diff --git a/extcss3/utils.c b/extcss3/utils.c index 0c0862c..4de989e 100644 --- a/extcss3/utils.c +++ b/extcss3/utils.c @@ -7,7 +7,8 @@ */ inline unsigned int extcss3_char_len(char c) { - unsigned int i = 7, j = 0; + int i = 7; + unsigned int j = 0; while ((i >= 0) && ((c >> i) & 1)) { i--; diff --git a/mpz/LICENSE b/mpz/LICENSE new file mode 100644 index 0000000..b88e176 --- /dev/null +++ b/mpz/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018 Alex Schneider + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/mpz/README.md b/mpz/README.md new file mode 100644 index 0000000..cc497fa --- /dev/null +++ b/mpz/README.md @@ -0,0 +1,300 @@ +[![Software license][ico-license]](https://github.com/alex-schneider/mpz/blob/master/LICENSE) +[![Latest Release][ico-release]](https://github.com/alex-schneider/mpz/releases/latest) + +# MEMORY-POOL-Z (MPZ) + +The MPZ is a simple implementation of a very fast and effective memory pool. It's +designed for using in applications with a lot of memory space allocations of the +repeatedly sizes up to 1.024 bytes (default, configurable) per allocation, e.g. +for structs in tokenization applications. + +## Features + +* Written in pure `C`. +* Doesn't require any external libraries. +* Optimized for 32 and 64 bit systems on little-endian machines. +* Prevents internal memory space fragmentation (freed memory space is reusable). +* Implements [memory space alignment](https://en.wikipedia.org/wiki/Data_structure_alignment) + to avoid wasting CPU cycles when accessing the data. +* Implements a very fast reset of the allocated memory space to permitt the memory + space to be efficiently reused, which in most memory pool implementations is + either unavailable or quite slow. +* Constant time for the memory space allocations from the internal memory space + unless the MPZ needs to grab a new memory space from the OS via `malloc()`. +* Constant time for the `free` operations unless the MPZ needs to release the memory + space back to the OS via `free()`. +* Implements simple security checks for `segmentation faults` and `double free` + errors. +* Very easy to modify or extend. + +## Limitations + +* The maximum allocation size from MPZ is limited to `2^30 - 1` (1.073.741.823) + bytes per allocation request. +* The code compiles and runs on Linux systems. Other platforms haven't been tested. + +## TODOs + +* Implementation of a `mpz_prealloc()` function. + +## Bugs + +* No bugs known! + +## About MPZ + +The MPZ implements memory space alignment to avoid wasting CPU cycles when accessing +the data. The alignment is continuously implemented for the accessing internal metadata +as well as for the return pointers to the user. The alignment size for memory space +allocations from the OS is borrowed from GNU libc and is defined as `2 * sizeof(size_t)` +which is 16 bytes on 64 bit systems. By the way, the memory pool of [nginx](http://nginx.org) +is one of the fastest pools today (as of year 2018) and it also uses this alignment, +too. To allow a finer granulated usage of the memory space inside the MPZ, the MPZ +implements binning of `slots`. The size of the memory space alignment for `slots` +inside the MPZ is 8 bytes (default, configurable). + +### Pool + +The `pool` is the main object of MPZ. It's the owner of: + +* an array of linked lists for the free `slots` in the `pool` grouped by aligned + size of the `slots` (binning). +* a doubly-linked list of the allocated `slabs` from the OS (stack). + +The size of a MPZ `pool` is 1.040 bytes on 64 bit systems. + +### Slabs + +Every memory block allocated from the OS in MPZ is called `slab`. A `slab` consists +of a small metadata (16 bytes on 64 bit systems) and of an 1-to-n number of +`slots`, where `n` is defined as `MPZ_SLAB_ALLOC_MUL` constant (default `16`, +configurable). + +### Regular slots + +Every chunk allocated from the `pool` in MPZ is called `slot`. A `slot` consists +of a small metadata (32 bits for a header and 32 bits for a footer) and of a `data` +part. The `data` part is the memory space that is returned to a user on an +allocation request. The regular `slots` have a size of up to 1.024 bytes (default, +configurable) and are managed by the bins-array of the `pool`. + +### Huge slots + +In cases that the used needs memory space that is larger as the configurable default +of 1.024 bytes, the MPZ will allocate an extra memory space from the OS and assign +this space to a single `slot` in an extra `slab`. The differences to the regular +`slots` are: + +* The huge `slabs` aren't managed by the bins-array of the `pool` and they are + consequently not reusable. +* If a huge `slab` is freed, their memory space is immediately released back to + the OS. + +### Illustrations + +#### Illustration of a MPZ `pool` + +```markdown +SLABS (stack) + + / +||============================================|| \ ||=====================|| +|| slab 1 || slab 2 || / || slab n || +|| || || \ || || +|| metadata | slots || metadata | slots || / || metadata | slots || +|| | || | || \ || | || +|| prev | next | ..... || prev | next | ..... || / || prev | next | ..... || +||===\======\==========/===/=======\==========|| \ ||==/=======\==========|| + \ \ \ / / \ / / \ + \ \ \ / / \ ... / \ + \ NULL \____/ / \________/ \/ NULL + \__________________/ + + +BINS (binning) + +||===============================================================|| +|| 0 | ..... | 7 | 8 | ..... | 96 | ..... | 127 || <<< bin-index +||---------------------------------------------------------------|| +|| 8 | ..... | 64 | 72 | ..... | 776 | ..... | 1024 || <<< size in bytes per slot +||===============================================================|| + | | | + | | | + |=======| |=======| |=======| + | | | | | | + |=======| |=======| |=======| + | | + | | <<< free slots + |=======| |=======| + | | | | + |=======| |=======| + | + | + |=======| + | | + |=======| + +``` + +#### Illustration of the regular MPZ `slots` inside the bins-list + +```markdown + slot from slab x slot from slab y + / +||==============================================|| \ ||==============================================|| +|| header | data part | footer | || / || header | data part | footer | || +|| | | | || \ || | | | || +|| (32 bits) | (min 8 bytes) | (32 bits) | next || / || (32 bits) | (min 8 bytes) | (32 bits) | next || +||===========================================\==|| \ ||===========================================\==|| + \ / / \ + \____/ NULL +``` + +#### Illustration of a MPZ `slot` header + +The header contains the metadata of the `slot`. All of the 32 bits of the footer +a filled with `1`. This fact allows to detect `segmentation fault` errors if an +application writes over the allocated memory space (unreliable but simple). + +```markdown +======= +| 31 | <<< "huge" flag (MSB on little-endian machines) +------- +| 30 | <<< "used" flag (allows to detect "double free" errors) +------- +| 29 | <<< currently unused (reserved for possible extensions) +------- +| 28 |\ +------- \ +| ... | <<< represent the slot size +------- / +| 0 |/ (LSB on little-endian machines) +======= +``` + +## MPZ API + +### mpz_pool_create() + +Allocates an aligned memory space for the `pool`, initializes the allocated memory +space to zero and returns a pointer to the `pool` object. Returns `NULL` if failed. + +```c +mpz_pool_t *mpz_pool_create(mpz_void_t); +``` + +### mpz_pool_reset() + +Resets the allocated memory space to permitt him to be efficiently reused by the +`pool`. Note that the memory space of huge `slots` is immediately released back +to the OS. + +```c +mpz_void_t mpz_pool_reset(mpz_pool_t *pool); +``` + +### mpz_pool_destroy() + +Destroys the `pool`. The total allocated memory space inclusive the memory space +of the `pool` itself is released back to the OS. + +```c +mpz_void_t mpz_pool_destroy(mpz_pool_t *pool); +``` + +### mpz_pmalloc() + +Allocates `size` bytes of the memory space from the `pool`. If the requested size +is greater than the configurable default of 1.024 bytes, a huge `slot` is directly +allocated from the OS like described above in the section `Huge slots`. If the `pool` +hasn't enouth free memory space to serve the requested `size` of bytes, a new `slab` +is allocated from the OS. Returns `NULL` if failed. + +```c +mpz_void_t *mpz_pmalloc(mpz_pool_t *pool, mpz_csize_t size); +``` + +### mpz_pcalloc() + +Allocates `size` bytes of the memory space from the `pool` like `mpz_pmalloc()` +function. Additionaly, all bits of the allocated memory space are initialized with +zero. Returns `NULL` if failed. + +```note +Note that the `mpz_pcalloc()` function is always slower than the `mpz_pmalloc()`, +because the initializing of the bits in the memory space with zero requires an extra +iteration over the requested memory space. +``` + +```c +mpz_void_t *mpz_pcalloc(mpz_pool_t *pool, mpz_csize_t size); +``` + +### mpz_free() + +Releases the allocated memory space back to the `pool`. The memory space of huge +`slots` are immediately released back to the OS. + +```c +mpz_void_t mpz_free(mpz_pool_t *pool, mpz_void_t *data); +``` + +## Using MPZ + +The user should use the MPZ API. The direct usage of functions outside the MPZ-API +can lead to unpredictable consequences if there is a lack of knowledge about the +internal implementation. To modify or extend the MPZ see the description `FOR +DEVELOPER WHO WANT TO ADAPT THE MPZ TO THE REQUIREMENTS OF THEIR APPLICATIONS` in +the `mpz_core.h`. + +The MPZ should be used wisely. Note that the MPZ is a high-level application. It's +a simple interface between the user and the `malloc()` and the `free()` functions. +The MPZ doesn't interact with the OS directly. Any invalid read/write errors are +difficultly to detect than using `malloc()` function directly. For example, many +users forget to allocate an extra byte to terminate a string with a `\0` byte. Here +is a big difference between the allocation of memory space from the `malloc()` function +and the MPZ. If the user allocates 5 bytes of memory space from the MPZ to write +a `Hello` string into the allocated memory space, the MPZ provides at least 8 bytes +of the memory space, where, by contrast, the `malloc()` function would provide only +5 bytes of really usable memory space. The invalid writing of the final 0-byte could +easy be detected by the direct usage of the `malloc()` function. Using the MPZ, +this error wouldn't be detected. + +### Example + +```c +#include "mpz_alloc.h" + +int example_function() +{ + mpz_pool_t *pool; + void *data; + + pool = mpz_pool_create(); + + if (NULL == pool) { + return 1; + } + + data = mpz_pmalloc(pool, 123); + + if (NULL == data) { + mpz_pool_destroy(pool); + + return 1; + } + + /* Do here something with the "data"... */ + + mpz_free(pool, data); + + /* Do other operations with the pool... */ + + mpz_pool_destroy(pool); + + return 0; +} +``` + +[ico-license]: https://img.shields.io/github/license/mashape/apistatus.svg +[ico-release]: https://img.shields.io/github/release/alex-schneider/mpz.svg diff --git a/mpz/src/mpz_alloc.c b/mpz/src/mpz_alloc.c new file mode 100644 index 0000000..04b2e81 --- /dev/null +++ b/mpz/src/mpz_alloc.c @@ -0,0 +1,400 @@ + +/** + * Copyright (c) Alex Schneider + */ + +#include "mpz_core.h" + +/* ==================================================================================================== */ +/* PRIVATE STUFF: DECLARATIONS */ + +#define mpz_memalign(a, s) ({ mpz_void_t *p; (0 != posix_memalign(&p, (a), (s)) ? NULL : p); }) +#define mpz_memzero(p, n) ({ memset((mpz_void_t *)(p), 0, (n)); }) +#define mpz_align(s, a) (((s) + ((a) - 1)) & ~((a) - 1)) + +#define MPZ_ALLOC_ALIGNMENT (2 * sizeof(mpz_void_t *)) + +#define MPZ_CHECK_VOID(p) ({ if (NULL == (p)) return; }) +#define MPZ_CHECK_NULL(p) ({ if (NULL == (p)) return NULL; }) + +#ifdef MPZ_RAISE_SIGSEGV_ON_MEM_ERRORS +# define MPZ_SLOT_OVERHEAD (sizeof(mpz_uint32_t) * 2) +#else +# define MPZ_SLOT_OVERHEAD (sizeof(mpz_uint32_t) * 1) +#endif /* MPZ_RAISE_SIGSEGV_ON_MEM_ERRORS */ + +#define MPZ_SLOT_SIZE (sizeof(mpz_slot_t *) + MPZ_SLOT_OVERHEAD) +#define MPZ_SLAB_SIZE (mpz_align(sizeof(mpz_slab_t), MPZ_ALLOC_ALIGNMENT)) +#define MPZ_POOL_SIZE (mpz_align(sizeof(mpz_pool_t), MPZ_ALLOC_ALIGNMENT)) + +#define MPZ_SLAB_TO_SLOT(s) ((mpz_slot_t *)(((mpz_uchar_t *)(s)) + MPZ_SLAB_SIZE)) +#define MPZ_SLOT_TO_SLAB(s) ((mpz_slab_t *)(((mpz_uchar_t *)(s)) - MPZ_SLAB_SIZE)) +#define MPZ_SLOT_TO_DATA(s) ((mpz_void_t *)(((mpz_uchar_t *)(s)) + sizeof(mpz_uint32_t))) +#define MPZ_DATA_TO_SLOT(d) ((mpz_slot_t *)(((mpz_uchar_t *)(d)) - sizeof(mpz_uint32_t))) + +#define MPZ_SLOT_FLAG_USED ((mpz_cuint32_t)(1 << 30)) +#define MPZ_SLOT_FLAG_HUGE ((mpz_cuint32_t)(1 << 31)) + +#define MPZ_POOL_MIN_ALLOC (MPZ_SLOTS_ALIGNMENT) +#define MPZ_POOL_MAX_ALLOC ((mpz_cuint32_t)((1 << 29) - 1)) + +#define MPZ_SLOT_READ_HEAD(s) ( \ + (mpz_uint32_t *)(s) \ +) +#define MPZ_SLOT_READ_SIZE(s) ( \ + (mpz_uint32_t)((*MPZ_SLOT_READ_HEAD(s) << 2) >> 2) \ +) + +#ifdef MPZ_RAISE_SIGSEGV_ON_MEM_ERRORS + +#define MPZ_FOOTER_MARK (0xFFFFFFFF) + +#define MPZ_SLOT_GOTO_FOOT(sl, si) ( \ + (mpz_uint32_t *)((mpz_uchar_t *)(sl) + sizeof(mpz_uint32_t) + (si)) \ +) +#define MPZ_SLOT_READ_FOOT(s) ( \ + (mpz_uint32_t *)MPZ_SLOT_GOTO_FOOT((s), MPZ_SLOT_READ_SIZE(s)) \ +) + +#endif /* MPZ_RAISE_SIGSEGV_ON_MEM_ERRORS */ + +#if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# ifdef __GNUC__ +# define MPZ_FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define MPZ_FORCE_INLINE static inline +# endif /* __GNUC__ */ +#else +# define MPZ_FORCE_INLINE static +#endif /* __STDC_VERSION__ */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +MPZ_FORCE_INLINE mpz_void_t _mpz_pool_gc( + mpz_pool_t *pool, mpz_cuint_t soft +); + +MPZ_FORCE_INLINE mpz_void_t *_mpz_palloc( + mpz_pool_t *pool, mpz_size_t size, mpz_cuint_t zeroize +); + +MPZ_FORCE_INLINE mpz_void_t *_mpz_slab_create( + mpz_pool_t *pool, mpz_csize_t size +); + +MPZ_FORCE_INLINE mpz_void_t _mpz_slab_init( + mpz_pool_t *pool, mpz_slab_t *slab, mpz_cuint32_t size +); + +MPZ_FORCE_INLINE mpz_void_t _mpz_slab_push( + mpz_pool_t *pool, mpz_slab_t *slab +); + +MPZ_FORCE_INLINE mpz_void_t _mpz_slab_free( + mpz_pool_t *pool, mpz_slot_t *slot +); + +MPZ_FORCE_INLINE mpz_void_t _mpz_slot_init( + mpz_slot_t *slot, mpz_cuint32_t size, mpz_cuint32_t flags +); + +/* ==================================================================================================== */ +/* PUBLIC API */ + +mpz_pool_t *mpz_pool_create( + mpz_void_t +) { + mpz_pool_t *pool; + mpz_uint_t idx; + + MPZ_CHECK_NULL(pool = mpz_memalign(MPZ_ALLOC_ALIGNMENT, MPZ_POOL_SIZE)); + + for (idx = MPZ_BINS; idx--; ) { + pool->bins[idx] = NULL; + } + + pool->slabs = NULL; + + return pool; +} + +mpz_void_t mpz_pool_reset( + mpz_pool_t *pool +) { + _mpz_pool_gc(pool, 1); +} + +mpz_void_t mpz_pool_destroy( + mpz_pool_t *pool +) { + _mpz_pool_gc(pool, 0); + + free(pool); +} + +mpz_void_t *mpz_pmalloc( + mpz_pool_t *pool, mpz_csize_t size +) { + return _mpz_palloc(pool, size, 0); +} + +mpz_void_t *mpz_pcalloc( + mpz_pool_t *pool, mpz_csize_t size +) { + return _mpz_palloc(pool, size, 1); +} + +mpz_void_t mpz_free( + mpz_pool_t *pool, mpz_cvoid_t *data +) { + mpz_slot_t *slot; + mpz_uint32_t *head, size; + mpz_uint_t idx; + + MPZ_CHECK_VOID(pool); + MPZ_CHECK_VOID(data); + + slot = MPZ_DATA_TO_SLOT(data); + head = MPZ_SLOT_READ_HEAD(slot); + +#ifdef MPZ_RAISE_SIGSEGV_ON_MEM_ERRORS + + /* Check both "segmentation faults" and "double free" errors. */ + if ((MPZ_FOOTER_MARK != *MPZ_SLOT_READ_FOOT(slot)) || (!(*head & MPZ_SLOT_FLAG_USED))) { + raise(SIGSEGV); + } + +#endif /* MPZ_RAISE_SIGSEGV_ON_MEM_ERRORS */ + + if (*head & MPZ_SLOT_FLAG_HUGE) { + return _mpz_slab_free(pool, slot); + } + + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + size = MPZ_SLOT_READ_SIZE(slot); + +#ifdef MPZ_RAISE_SIGSEGV_ON_MEM_ERRORS + + /* Remove the "used" mark. */ + _mpz_slot_init(slot, size, 0); + +#endif /* MPZ_RAISE_SIGSEGV_ON_MEM_ERRORS */ + + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + /* Push the slot into the bins-array. */ + + idx = MPZ_BIN_IDX(size); + + slot->next = pool->bins[idx]; + + pool->bins[idx] = slot; +} + +/* ==================================================================================================== */ +/* PRIVATE STUFF: DEFINITIONS */ + +MPZ_FORCE_INLINE mpz_void_t _mpz_pool_gc( + mpz_pool_t *pool, mpz_cuint_t soft +) { + mpz_slab_t *slab, *next; + mpz_slot_t *slot; + mpz_uint_t idx; + + MPZ_CHECK_VOID(pool); + MPZ_CHECK_VOID(pool->slabs); + + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + for (idx = MPZ_BINS; idx--; ) { + pool->bins[idx] = NULL; + } + + slab = pool->slabs; + pool->slabs = NULL; + + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + /** + * Slabs contain a huge slot are immediately destroyed. If "soft" + * is set to 0, all other slabs are immediately destroyed, too, + * otherwise the other slabs are reseted to theirs initial state + * to permitt the pool to be efficiently reused. + */ + + while (NULL != slab) { + next = slab->next; + slot = MPZ_SLAB_TO_SLOT(slab); + + if (!soft || (*MPZ_SLOT_READ_HEAD(slot) & MPZ_SLOT_FLAG_HUGE)) { + _mpz_slab_free(pool, slot); + } else { + _mpz_slab_push(pool, slab); + _mpz_slab_init(pool, slab, MPZ_SLOT_READ_SIZE(slot)); + } + + slab = next; + } +} + +MPZ_FORCE_INLINE mpz_void_t *_mpz_palloc( + mpz_pool_t *pool, mpz_size_t size, mpz_cuint_t zeroize +) { + mpz_slab_t *slab; + mpz_slot_t *slot; + mpz_uint_t idx; + + MPZ_CHECK_NULL(pool); + + if (size < MPZ_POOL_MIN_ALLOC) { + size = MPZ_POOL_MIN_ALLOC; + } else if (size > MPZ_POOL_MAX_ALLOC) { + return NULL; + } + + size += MPZ_SLOT_OVERHEAD; + size = mpz_align(size, MPZ_SLOTS_ALIGNMENT); + + if (size > (MPZ_BINS << MPZ_BINS_BIT_SHIFT)) { + /* We have to grab a new memory space from the OS. */ + slab = _mpz_slab_create(pool, size + MPZ_SLOT_SIZE); + + MPZ_CHECK_NULL(slab); + + /* The new slab contains only a single huge slot. */ + _mpz_slot_init(slot = MPZ_SLAB_TO_SLOT(slab), size, MPZ_SLOT_FLAG_HUGE|MPZ_SLOT_FLAG_USED); + + return MPZ_SLOT_TO_DATA(slot); + } + + idx = MPZ_BIN_IDX(size); + slot = pool->bins[idx]; + + if (NULL == slot) { + /** + * The pool is either completely empty (new) or consists of slabs + * without empty slots for the requested size in the bins-list. + * We have to grab a new memory space from the OS. + */ + slab = _mpz_slab_create(pool, (size + MPZ_SLOT_SIZE) * MPZ_SLAB_ALLOC_MUL); + + MPZ_CHECK_NULL(slab); + + _mpz_slab_init(pool, slab, size); + } + + /* Pop a slot from the bins-array. */ + slot = pool->bins[idx]; + pool->bins[idx] = slot->next; + +#ifdef MPZ_RAISE_SIGSEGV_ON_MEM_ERRORS + + /* Mark the slot as "used". */ + _mpz_slot_init(slot, size, MPZ_SLOT_FLAG_USED); + +#endif /* MPZ_RAISE_SIGSEGV_ON_MEM_ERRORS */ + + if (zeroize) { + mpz_memzero(MPZ_SLOT_TO_DATA(slot), size); + } + + return MPZ_SLOT_TO_DATA(slot); +} + +MPZ_FORCE_INLINE mpz_void_t *_mpz_slab_create( + mpz_pool_t *pool, mpz_csize_t size +) { + mpz_slab_t *slab = mpz_memalign(MPZ_ALLOC_ALIGNMENT, size + MPZ_SLAB_SIZE); + + MPZ_CHECK_NULL(slab); + + _mpz_slab_push(pool, slab); + + return slab; +} + +MPZ_FORCE_INLINE mpz_void_t _mpz_slab_init( + mpz_pool_t *pool, mpz_slab_t *slab, mpz_cuint32_t size +) { + mpz_slot_t *slot = MPZ_SLAB_TO_SLOT(slab); + mpz_uint_t idx, i; + + idx = MPZ_BIN_IDX(size); + + for (i = 0; i < MPZ_SLAB_ALLOC_MUL; ++i) { + /* Set slot metadata. */ + _mpz_slot_init(slot, size, 0); + + if (i == (MPZ_SLAB_ALLOC_MUL - 1)) { + /** + * Handle the last slot: + * + * Append the content of the current bin at the + * last slot of our slab and let the first slot + * of our slab be the leader of the current bin. + */ + + slot->next = pool->bins[idx]; + + pool->bins[idx] = MPZ_SLAB_TO_SLOT(slab); + } else { + /* Jump to the next slot. */ + slot->next = (mpz_slot_t *)((mpz_uchar_t *)slot + (size + MPZ_SLOT_SIZE)); + + slot = slot->next; + } + } +} + +MPZ_FORCE_INLINE mpz_void_t _mpz_slab_push( + mpz_pool_t *pool, mpz_slab_t *slab +) { + slab->prev = NULL; + slab->next = pool->slabs; + + if (NULL != slab->next) { + slab->next->prev = slab; + } + + pool->slabs = slab; +} + +MPZ_FORCE_INLINE mpz_void_t _mpz_slab_free( + mpz_pool_t *pool, mpz_slot_t *slot +) { + mpz_slab_t *slab = MPZ_SLOT_TO_SLAB(slot); + + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + /* Remove the slab from the slabs list. */ + + if (NULL != slab->prev) { + slab->prev->next = slab->next; + } else { + pool->slabs = slab->next; + } + + if (NULL != slab->next) { + slab->next->prev = slab->prev; + } + + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + free(slab); +} + +MPZ_FORCE_INLINE mpz_void_t _mpz_slot_init( + mpz_slot_t *slot, mpz_cuint32_t size, mpz_cuint32_t flags +) { + /** + * We have always to reset current state + * using "0" in this bitwise operation. + */ + *MPZ_SLOT_READ_HEAD(slot) = (0 | flags | size); + +#ifdef MPZ_RAISE_SIGSEGV_ON_MEM_ERRORS + + *MPZ_SLOT_GOTO_FOOT(slot, size) = MPZ_FOOTER_MARK; + +#endif /* MPZ_RAISE_SIGSEGV_ON_MEM_ERRORS */ + +} diff --git a/mpz/src/mpz_alloc.h b/mpz/src/mpz_alloc.h new file mode 100644 index 0000000..4977467 --- /dev/null +++ b/mpz/src/mpz_alloc.h @@ -0,0 +1,39 @@ + +/** + * Copyright (c) Alex Schneider + */ + +#ifndef _MEMPOOLZ_API_H_INCLUDE +#define _MEMPOOLZ_API_H_INCLUDE + +#include "mpz_core.h" + +/* ==================================================================================================== */ + +mpz_pool_t *mpz_pool_create( + mpz_void_t +); + +mpz_void_t mpz_pool_reset( + mpz_pool_t *pool +); + +mpz_void_t mpz_pool_destroy( + mpz_pool_t *pool +); + +mpz_void_t *mpz_pmalloc( + mpz_pool_t *pool, mpz_csize_t size +); + +mpz_void_t *mpz_pcalloc( + mpz_pool_t *pool, mpz_csize_t size +); + +mpz_void_t mpz_free( + mpz_pool_t *pool, mpz_cvoid_t *data +); + +/* ==================================================================================================== */ + +#endif /* _MEMPOOLZ_API_H_INCLUDE */ diff --git a/mpz/src/mpz_core.h b/mpz/src/mpz_core.h new file mode 100644 index 0000000..5147b98 --- /dev/null +++ b/mpz/src/mpz_core.h @@ -0,0 +1,138 @@ + +/** + * Copyright (c) Alex Schneider + */ + +#ifndef _MEMPOOLZ_CORE_H_INCLUDE +#define _MEMPOOLZ_CORE_H_INCLUDE + +/* ==================================================================================================== */ + +#include +#include +#include + +/* ==================================================================================================== */ +/* ==================================================================================================== */ +/* ==================================================================================================== */ + +/* FOR DEVELOPER WHO WANT TO ADAPT THE MPZ TO THE REQUIREMENTS OF THEIR APPLICATIONS */ + +/** + * Every project is unique and therefore has also individual requirements. Below + * are some of the most important settings explained that developers can try out + * for fine tuning of MPZ for their applications. + * + * + * IMPORTANT INTRODUCTION: + * + * Among other things, MPZ is so fast because it works without expensive arithmetic + * operations (e.g. divisions or modulo-operator) and works with a lot of very + * fast bitshift operations. For that an important prerequisite must be fulfilled: + * Using of power-of-two numbers for alignment, binning and indexing. +*/ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/** + * The MPZ implements simple checks for "segmentation faults" and "double free" + * errors. In cases that an error is detected MPZ immediately raises an "SIGSEGV" + * error. To disable this behavior just comment out the following definement. + * + * Disabling of this feature increases a little bit the performance of the MPZ. +*/ +//#define MPZ_RAISE_SIGSEGV_ON_MEM_ERRORS + +/** + * Total number of indexes in the bins-array (0 - 127). You can increase this number, + * e.g. to be able to serve larger memory space directly from the pool, instead of + * again and again allocating huge slabs from the OS. +*/ +#define MPZ_BINS (128) + +/** + * This alignment is used at all allocations of slots from the pool. At the same + * time it is also the difference in bytes between each bin in the bins-array. So + * a slot with the size of 8 bytes is stored in the bin with the index 0 and a slot + * with the size of 1.024 bytes is stored in the bin with the index 127. If this + * constant is modified, don't forget to modify the following const MPZ_BINS_BIT_SHIFT, + * too. +*/ +#define MPZ_SLOTS_ALIGNMENT (8) + +/** + * This is the bit-shift using to calculate the index of the bins-array, as well, + * for example, to determine if the MPZ needs to allocate a huge slab from the OS. + * The constant MPZ_SLOTS_ALIGNMENT described above is very closely linked to this + * constant, so changes should be applied to both constants simultaneously. +*/ +#define MPZ_BINS_BIT_SHIFT (3) + +/** + * If a new slab has to be allocated from the OS, the MPZ uses this multiplier to + * allocate MPZ_SLAB_ALLOC_MUL numbers of the same requested slot size simultaneously + * and to be able immediately to provide the remaining slots to the user if needed. + * + * Long detailed research has shown that a multiplier of 16 is optimal for both + * small and large numbers of allocations, without the overhead becoming too large. +*/ +#define MPZ_SLAB_ALLOC_MUL (16) + +/** + * Since the given size has to be already aligned before calling this operation, + * this operation is equals to "size / 8 - 1", but we don't want to use expensive + * division operations. +*/ +#define MPZ_BIN_IDX(size) (((size) >> MPZ_BINS_BIT_SHIFT) - 1) + +/* ==================================================================================================== */ +/* ==================================================================================================== */ +/* ==================================================================================================== */ + +typedef void mpz_void_t; +typedef const void mpz_cvoid_t; +typedef unsigned char mpz_uchar_t; +typedef unsigned int mpz_uint_t; +typedef const unsigned int mpz_cuint_t; +typedef uint32_t mpz_uint32_t; +typedef const uint32_t mpz_cuint32_t; +typedef size_t mpz_size_t; +typedef const size_t mpz_csize_t; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +typedef struct _mpz_pool_s mpz_pool_t; +typedef struct _mpz_slab_s mpz_slab_t; +typedef struct _mpz_slot_s mpz_slot_t; + +struct _mpz_slot_s +{ + mpz_void_t *data; + mpz_slot_t *next; +}; + +struct _mpz_slab_s +{ + mpz_slab_t *prev; + mpz_slab_t *next; +}; + +struct _mpz_pool_s +{ + mpz_slot_t *bins[MPZ_BINS]; + mpz_slab_t *slabs; +}; + +/* ==================================================================================================== */ + +#ifdef MPZ_RAISE_SIGSEGV_ON_MEM_ERRORS +#include +#endif /* MPZ_RAISE_SIGSEGV_ON_MEM_ERRORS */ + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +#include "mpz_alloc.h" + +/* ==================================================================================================== */ + +#endif /* _MEMPOOLZ_CORE_H_INCLUDE */ diff --git a/php_extcss3.c b/php_extcss3.c index e564f3f..418c310 100644 --- a/php_extcss3.c +++ b/php_extcss3.c @@ -62,6 +62,9 @@ static inline void php_extcss3_throw_exception(unsigned int error) case EXTCSS3_ERR_INV_PARAM: zend_throw_exception(zend_ce_exception, "extcss3: Invalid paramenter or parameter type given", EXTCSS3_ERR_INV_PARAM); break; + case EXTCSS3_ERR_INV_VALUE: + zend_throw_exception(zend_ce_exception, "extcss3: Invalid, unallowed or unexpected value found", EXTCSS3_ERR_INV_VALUE); + break; default: zend_throw_exception(zend_ce_exception, "extcss3: Unknown internal error", 0); } @@ -138,6 +141,32 @@ static inline void php_extcss3_make_data_array(extcss3_intern *intern, zval *dat zval_ptr_dtor(&empty); } +static void php_extcss3_notifier_callback(extcss3_intern *intern, extcss3_sig *sig) +{ + zval data, retval, *args, *callable; + + if ((intern == NULL) || (intern->last_token == NULL) || (sig == NULL)) { + return; + } + + if ((callable = sig->callable) == NULL) { + return; + } + + php_extcss3_make_data_array(intern, &data); + + args = safe_emalloc(sizeof(zval), 1, 0); + ZVAL_COPY(&args[0], &data); + + call_user_function_ex(EG(function_table), NULL, callable, &retval, 1, args, 0, NULL); + + zval_ptr_dtor(&data); + zval_ptr_dtor(&args[0]); + zval_ptr_dtor(&retval); + + efree(args); +} + static void php_extcss3_modifier_callback(extcss3_intern *intern) { zval data, retval, *args, *callable = NULL; @@ -178,9 +207,11 @@ static void php_extcss3_modifier_callback(extcss3_intern *intern) if (SUCCESS == call_user_function_ex(EG(function_table), NULL, callable, &retval, 1, args, 0, NULL)) { if (Z_TYPE(retval) == IS_STRING) { intern->last_token->user.len = Z_STRLEN(retval); - intern->last_token->user.str = (char *)calloc(intern->last_token->user.len, sizeof(char)); + intern->last_token->user.str = (char *)mpz_pmalloc(intern->pool, intern->last_token->user.len * sizeof(char)); - memcpy(intern->last_token->user.str, Z_STRVAL(retval), Z_STRLEN(retval)); + if (NULL != intern->last_token->user.str) { + memcpy(intern->last_token->user.str, Z_STRVAL(retval), Z_STRLEN(retval)); + } } } @@ -191,9 +222,9 @@ static void php_extcss3_modifier_callback(extcss3_intern *intern) efree(args); } -static void php_extcss3_modifier_destructor(void *modifier) +static void php_extcss3_callable_destructor(void *callable) { - zval *ptr = (zval *)modifier; + zval *ptr = (zval *)callable; if (ptr == NULL) { return; @@ -232,13 +263,50 @@ PHP_METHOD(CSS3Processor, __construct) if (intern == NULL) { php_extcss3_throw_exception(EXTCSS3_ERR_MEMORY); } else { - intern->modifier.callback = php_extcss3_modifier_callback; - intern->modifier.destructor = php_extcss3_modifier_destructor; + intern->notifier.callback = php_extcss3_notifier_callback; + intern->notifier.destructor = php_extcss3_callable_destructor; + + intern->modifier.callback = php_extcss3_modifier_callback; + intern->modifier.destructor = php_extcss3_callable_destructor; object->intern = intern; } } +PHP_METHOD(CSS3Processor, setNotifier) +{ + extcss3_object *object = extcss3_object_fetch(Z_OBJ_P(getThis())); + extcss3_intern *intern = object->intern; + zval *callable, *copy; + size_t type; + unsigned int error = 0; + + if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "lz", &type, &callable)) { + return; + } else if (intern == NULL) { + php_extcss3_throw_exception(EXTCSS3_ERR_NULL_PTR); + return; + } + + copy = (zval *)ecalloc(1, sizeof(zval)); + + if (copy == NULL) { + php_extcss3_throw_exception(EXTCSS3_ERR_MEMORY); + return; + } + + ZVAL_COPY(copy, callable); + + if (EXTCSS3_SUCCESS != extcss3_set_notifier(intern, type, copy, &error)) { + intern->notifier.destructor(copy); + + php_extcss3_throw_exception(error); + return; + } + + RETURN_TRUE; +} + PHP_METHOD(CSS3Processor, setModifier) { extcss3_object *object = extcss3_object_fetch(Z_OBJ_P(getThis())); @@ -290,6 +358,8 @@ PHP_METHOD(CSS3Processor, dump) php_extcss3_throw_exception(EXTCSS3_ERR_NULL_PTR); } else if (!len) { RETURN_EMPTY_STRING(); + } else if (NULL == extcss3_reset_intern(intern, &error)) { + php_extcss3_throw_exception(error); } else if (EXTCSS3_SUCCESS != extcss3_set_css_string(intern, css, len, &error)) { php_extcss3_throw_exception(error); } else if ((result = extcss3_dump_tokens(intern, &error)) == NULL) { @@ -316,13 +386,15 @@ PHP_METHOD(CSS3Processor, minify) return; } else if (!len) { RETURN_EMPTY_STRING(); + } else if (NULL == extcss3_reset_intern(intern, &error)) { + php_extcss3_throw_exception(error); } else if (EXTCSS3_SUCCESS != extcss3_set_css_string(intern, css, len, &error)) { php_extcss3_throw_exception(error); return; } if ((intern->base_vendor != NULL) || (intern->last_vendor != NULL)) { - extcss3_release_vendors_list(intern->base_vendor); + extcss3_release_vendors_list(intern->pool, intern->base_vendor); intern->base_vendor = intern->last_vendor = NULL; } @@ -333,9 +405,9 @@ PHP_METHOD(CSS3Processor, minify) } if (intern->last_vendor == NULL) { - intern->base_vendor = intern->last_vendor = extcss3_create_vendor(); + intern->base_vendor = intern->last_vendor = extcss3_create_vendor(intern->pool); } else { - intern->last_vendor->next = extcss3_create_vendor(); + intern->last_vendor->next = extcss3_create_vendor(intern->pool); intern->last_vendor = intern->last_vendor->next; } @@ -357,10 +429,11 @@ PHP_METHOD(CSS3Processor, minify) /* ==================================================================================================== */ zend_function_entry extcss3_methods[] = { - PHP_ME(CSS3Processor, __construct, arginfo_EXTCSS3_void, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) + PHP_ME(CSS3Processor, __construct, arginfo_EXTCSS3_void, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) + PHP_ME(CSS3Processor, setNotifier, arginfo_EXTCSS3_setModifier, ZEND_ACC_PUBLIC) PHP_ME(CSS3Processor, setModifier, arginfo_EXTCSS3_setModifier, ZEND_ACC_PUBLIC) - PHP_ME(CSS3Processor, dump, arginfo_EXTCSS3_dump, ZEND_ACC_PUBLIC) - PHP_ME(CSS3Processor, minify, arginfo_EXTCSS3_minify, ZEND_ACC_PUBLIC) + PHP_ME(CSS3Processor, dump, arginfo_EXTCSS3_dump, ZEND_ACC_PUBLIC) + PHP_ME(CSS3Processor, minify, arginfo_EXTCSS3_minify, ZEND_ACC_PUBLIC) PHP_FE_END }; @@ -383,55 +456,56 @@ PHP_MINIT_FUNCTION(extcss3) /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_IDENT", EXTCSS3_TYPE_IDENT); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_FUNCTION", EXTCSS3_TYPE_FUNCTION); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_AT_KEYWORD", EXTCSS3_TYPE_AT_KEYWORD); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_HASH", EXTCSS3_TYPE_HASH); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_STRING", EXTCSS3_TYPE_STRING); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_BAD_STRING", EXTCSS3_TYPE_BAD_STRING); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_URL", EXTCSS3_TYPE_URL); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_BAD_URL", EXTCSS3_TYPE_BAD_URL); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_DELIM", EXTCSS3_TYPE_DELIM); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_NUMBER", EXTCSS3_TYPE_NUMBER); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_PERCENTAGE", EXTCSS3_TYPE_PERCENTAGE); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_DIMENSION", EXTCSS3_TYPE_DIMENSION); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_UNICODE_RANGE", EXTCSS3_TYPE_UNICODE_RANGE); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_INCLUDE_MATCH", EXTCSS3_TYPE_INCLUDE_MATCH); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_DASH_MATCH", EXTCSS3_TYPE_DASH_MATCH); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_PREFIX_MATCH", EXTCSS3_TYPE_PREFIX_MATCH); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_SUFFIX_MATCH", EXTCSS3_TYPE_SUFFIX_MATCH); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_SUBSTR_MATCH", EXTCSS3_TYPE_SUBSTR_MATCH); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_COLUMN", EXTCSS3_TYPE_COLUMN); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_WS", EXTCSS3_TYPE_WS); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_CDO", EXTCSS3_TYPE_CDO); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_CDC", EXTCSS3_TYPE_CDC); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_COLON", EXTCSS3_TYPE_COLON); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_SEMICOLON", EXTCSS3_TYPE_SEMICOLON); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_COMMA", EXTCSS3_TYPE_COMMA); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_BR_RO", EXTCSS3_TYPE_BR_RO); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_BR_RC", EXTCSS3_TYPE_BR_RC); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_BR_SO", EXTCSS3_TYPE_BR_SO); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_BR_SC", EXTCSS3_TYPE_BR_SC); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_BR_CO", EXTCSS3_TYPE_BR_CO); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_BR_CC", EXTCSS3_TYPE_BR_CC); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_COMMENT", EXTCSS3_TYPE_COMMENT); - EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_EOF", EXTCSS3_TYPE_EOF); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_IDENT", EXTCSS3_TYPE_IDENT); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_FUNCTION", EXTCSS3_TYPE_FUNCTION); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_AT_KEYWORD", EXTCSS3_TYPE_AT_KEYWORD); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_HASH", EXTCSS3_TYPE_HASH); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_STRING", EXTCSS3_TYPE_STRING); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_BAD_STRING", EXTCSS3_TYPE_BAD_STRING); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_URL", EXTCSS3_TYPE_URL); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_BAD_URL", EXTCSS3_TYPE_BAD_URL); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_DELIM", EXTCSS3_TYPE_DELIM); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_NUMBER", EXTCSS3_TYPE_NUMBER); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_PERCENTAGE", EXTCSS3_TYPE_PERCENTAGE); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_DIMENSION", EXTCSS3_TYPE_DIMENSION); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_UNICODE_RANGE", EXTCSS3_TYPE_UNICODE_RANGE); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_INCLUDE_MATCH", EXTCSS3_TYPE_INCLUDE_MATCH); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_DASH_MATCH", EXTCSS3_TYPE_DASH_MATCH); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_PREFIX_MATCH", EXTCSS3_TYPE_PREFIX_MATCH); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_SUFFIX_MATCH", EXTCSS3_TYPE_SUFFIX_MATCH); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_SUBSTR_MATCH", EXTCSS3_TYPE_SUBSTR_MATCH); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_COLUMN", EXTCSS3_TYPE_COLUMN); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_WS", EXTCSS3_TYPE_WS); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_CDO", EXTCSS3_TYPE_CDO); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_CDC", EXTCSS3_TYPE_CDC); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_COLON", EXTCSS3_TYPE_COLON); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_SEMICOLON", EXTCSS3_TYPE_SEMICOLON); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_COMMA", EXTCSS3_TYPE_COMMA); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_BR_RO", EXTCSS3_TYPE_BR_RO); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_BR_RC", EXTCSS3_TYPE_BR_RC); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_BR_SO", EXTCSS3_TYPE_BR_SO); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_BR_SC", EXTCSS3_TYPE_BR_SC); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_BR_CO", EXTCSS3_TYPE_BR_CO); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_BR_CC", EXTCSS3_TYPE_BR_CC); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_COMMENT", EXTCSS3_TYPE_COMMENT); + EXTCSS3_REGISTER_LONG_CLASS_CONST("TYPE_EOF", EXTCSS3_TYPE_EOF); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - EXTCSS3_REGISTER_LONG_CLASS_CONST("FLAG_ID", EXTCSS3_FLAG_ID); - EXTCSS3_REGISTER_LONG_CLASS_CONST("FLAG_UNRESTRICTED", EXTCSS3_FLAG_UNRESTRICTED); - EXTCSS3_REGISTER_LONG_CLASS_CONST("FLAG_INTEGER", EXTCSS3_FLAG_INTEGER); - EXTCSS3_REGISTER_LONG_CLASS_CONST("FLAG_NUMBER", EXTCSS3_FLAG_NUMBER); - EXTCSS3_REGISTER_LONG_CLASS_CONST("FLAG_STRING", EXTCSS3_FLAG_STRING); - EXTCSS3_REGISTER_LONG_CLASS_CONST("FLAG_AT_URL_STRING", EXTCSS3_FLAG_AT_URL_STRING); - + EXTCSS3_REGISTER_LONG_CLASS_CONST("FLAG_ID", EXTCSS3_FLAG_ID); + EXTCSS3_REGISTER_LONG_CLASS_CONST("FLAG_UNRESTRICTED", EXTCSS3_FLAG_UNRESTRICTED); + EXTCSS3_REGISTER_LONG_CLASS_CONST("FLAG_INTEGER", EXTCSS3_FLAG_INTEGER); + EXTCSS3_REGISTER_LONG_CLASS_CONST("FLAG_NUMBER", EXTCSS3_FLAG_NUMBER); + EXTCSS3_REGISTER_LONG_CLASS_CONST("FLAG_STRING", EXTCSS3_FLAG_STRING); + EXTCSS3_REGISTER_LONG_CLASS_CONST("FLAG_AT_URL_STRING", EXTCSS3_FLAG_AT_URL_STRING); + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - EXTCSS3_REGISTER_LONG_CLASS_CONST("ERR_MEMORY", EXTCSS3_ERR_MEMORY); - EXTCSS3_REGISTER_LONG_CLASS_CONST("ERR_BYTES_CORRUPTION", EXTCSS3_ERR_BYTES_CORRUPTION); - EXTCSS3_REGISTER_LONG_CLASS_CONST("ERR_NULL_PTR", EXTCSS3_ERR_NULL_PTR); - EXTCSS3_REGISTER_LONG_CLASS_CONST("ERR_INV_PARAM", EXTCSS3_ERR_INV_PARAM); + EXTCSS3_REGISTER_LONG_CLASS_CONST("ERR_MEMORY", EXTCSS3_ERR_MEMORY); + EXTCSS3_REGISTER_LONG_CLASS_CONST("ERR_BYTES_CORRUPTION", EXTCSS3_ERR_BYTES_CORRUPTION); + EXTCSS3_REGISTER_LONG_CLASS_CONST("ERR_NULL_PTR", EXTCSS3_ERR_NULL_PTR); + EXTCSS3_REGISTER_LONG_CLASS_CONST("ERR_INV_PARAM", EXTCSS3_ERR_INV_PARAM); + EXTCSS3_REGISTER_LONG_CLASS_CONST("ERR_INV_VALUE", EXTCSS3_ERR_INV_VALUE); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ diff --git a/php_extcss3.h b/php_extcss3.h index 43cce24..cda8e4e 100644 --- a/php_extcss3.h +++ b/php_extcss3.h @@ -5,15 +5,15 @@ #include "extcss3/types.h" -#define PHP_EXTCSS3_EXTNAME "extcss3" -#define PHP_EXTCSS3_EXTVER "1.0.1" +#define PHP_EXTCSS3_EXTNAME "php-ext-css" +#define PHP_EXTCSS3_EXTVER "2.0" #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ extern zend_module_entry extcss3_module_entry; -#define phpext_extcss3_ptr &extcss3_module_entry; +#define phpext_extcss3_ptr &extcss3_module_entry typedef struct _extcss3_object { diff --git a/tests/minify_numeric_tokens.phpt b/tests/minify_numeric_tokens.phpt index 97a80d6..5c5243a 100644 --- a/tests/minify_numeric_tokens.phpt +++ b/tests/minify_numeric_tokens.phpt @@ -405,7 +405,7 @@ array(8) { [3]=> string(405) "a01:0;b01:0;c01:0;a02:1.1E3px;b02:-1.1E3px;c02:1.1E3px;a03:0;b03:0;c03:0;a04:0;b04:0;c04:0;a05:0;b05:0;c05:0;a06:5px;b06:-5px;c06:5px;a07:5px;b07:-5px;c07:5px;a07:5.001px;b07:-5.001px;c07:5.001px;a08:12345px;b08:-12345px;c08:12345px;a09:123.45px;b09:-123.45px;c09:123.45px;a10:0;b10:0;c10:0;a11:.1px;b11:-.1px;c11:.1px;a12:500px;b12:-500px;c12:500px;a13:.1px;b13:-.1px;c13:.1px;a14:10px;b14:-10px;c14:10px" [4]=> - string(375) "a01:0;b01:0;c01:0;a02:1.1E3%;b02:-1.1E3%;c02:1.1E3%;a03:0;b03:0;c03:0;a04:0;b04:0;c04:0;a05:0;b05:0;c05:0;a06:5%;b06:-5%;c06:5%;a07:5%;b07:-5%;c07:5%;a07:5.001%;b07:-5.001%;c07:5.001%;a08:12345%;b08:-12345%;c08:12345%;a09:123.45%;b09:-123.45%;c09:123.45%;a10:0;b10:0;c10:0;a11:.1%;b11:-.1%;c11:.1%;a12:500%;b12:-500%;c12:500%;a13:.1%;b13:-.1%;c13:.1%;a14:10%;b14:-10%;c14:10%" + string(390) "a01:0%;b01:0%;c01:0%;a02:1.1E3%;b02:-1.1E3%;c02:1.1E3%;a03:0%;b03:0%;c03:0%;a04:0%;b04:0%;c04:0%;a05:0%;b05:0%;c05:0%;a06:5%;b06:-5%;c06:5%;a07:5%;b07:-5%;c07:5%;a07:5.001%;b07:-5.001%;c07:5.001%;a08:12345%;b08:-12345%;c08:12345%;a09:123.45%;b09:-123.45%;c09:123.45%;a10:0%;b10:0%;c10:0%;a11:.1%;b11:-.1%;c11:.1%;a12:500%;b12:-500%;c12:500%;a13:.1%;b13:-.1%;c13:.1%;a14:10%;b14:-10%;c14:10%" [5]=> string(345) "a01:0;b01:0;c01:0;a02:1.1E3;b02:-1.1E3;c02:1.1E3;a03:0;b03:0;c03:0;a04:0;b04:0;c04:0;a05:0;b05:0;c05:0;a06:5;b06:-5;c06:5;a07:5;b07:-5;c07:5;a07:5.001;b07:-5.001;c07:5.001;a08:12345;b08:-12345;c08:12345;a09:123.45;b09:-123.45;c09:123.45;a10:0;b10:0;c10:0;a11:.1;b11:-.1;c11:.1;a12:500;b12:-500;c12:500;a13:.1;b13:-.1;c13:.1;a14:10;b14:-10;c14:10" [6]=> diff --git a/tests/minify_preserve_dimensions.phpt b/tests/minify_preserve_dimensions.phpt new file mode 100644 index 0000000..773b2bd --- /dev/null +++ b/tests/minify_preserve_dimensions.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test CSS3Processor::minify() method (preserving dimensions) +--FILE-- +minify('div { height: calc(20px - (0% + 0px)) foo bar; height: 0%; }')); + +?> +===DONE=== +--EXPECT-- +string(53) "div{height:calc(20px - (0% + 0px)) foo bar;height:0%}" +===DONE=== diff --git a/tests/minify_special_cases.phpt b/tests/minify_special_cases.phpt index a99c644..0c966b4 100644 --- a/tests/minify_special_cases.phpt +++ b/tests/minify_special_cases.phpt @@ -44,6 +44,9 @@ var_dump($oProcessor->minify($sCSS)); $sCSS = ' } --> '; var_dump($oProcessor->minify($sCSS)); +$sCSS = 'x {a: b c "Open Sans" , Arial} y { a: func(b) "s3"; }'; +var_dump($oProcessor->minify($sCSS)); + ?> ===DONE=== --EXPECT-- @@ -54,4 +57,5 @@ string(10) "x{y:1px\9}" string(48) "@media(min-width:30em)and (max-height:60em){a:b}" string(16) ":not(x) foo{a:b}" string(28) "@media screen{}" +string(43) "x{a:b c "Open Sans",Arial}y{a:func(b) "s3"}" ===DONE=== diff --git a/tests/setNotifier.phpt b/tests/setNotifier.phpt new file mode 100644 index 0000000..171cf24 --- /dev/null +++ b/tests/setNotifier.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test CSS3Processor::setNotifier() method +--FILE-- +setNotifier(CSS3Processor::TYPE_AT_KEYWORD, ['Test_Notifier', 'A'])); +var_dump($oProcessor->setNotifier(CSS3Processor::TYPE_AT_KEYWORD, ['Test_Notifier', 'B'])); +$oProcessor->dump('@charset "UTF-8";'); +?> +===DONE=== +--EXPECT-- +bool(true) +bool(true) +string(11) "A: @charset" +string(11) "B: @charset" +===DONE===