Annotation of embedaddon/php/main/output.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
                      5:    | Copyright (c) 1997-2012 The PHP Group                                |
                      6:    +----------------------------------------------------------------------+
                      7:    | This source file is subject to version 3.01 of the PHP license,      |
                      8:    | that is bundled with this package in the file LICENSE, and is        |
                      9:    | available through the world-wide-web at the following url:           |
                     10:    | http://www.php.net/license/3_01.txt                                  |
                     11:    | If you did not receive a copy of the PHP license and are unable to   |
                     12:    | obtain it through the world-wide-web, please send a note to          |
                     13:    | license@php.net so we can mail you a copy immediately.               |
                     14:    +----------------------------------------------------------------------+
                     15:    | Authors: Zeev Suraski <zeev@zend.com>                                |
                     16:    |          Thies C. Arntzen <thies@thieso.net>                         |
                     17:    |          Marcus Boerger <helly@php.net>                              |
1.1.1.2 ! misho      18:    | New API: Michael Wallner <mike@php.net>                              |
1.1       misho      19:    +----------------------------------------------------------------------+
                     20: */
                     21: 
1.1.1.2 ! misho      22: /* $Id$ */
        !            23: 
        !            24: #ifndef PHP_OUTPUT_DEBUG
        !            25: # define PHP_OUTPUT_DEBUG 0
        !            26: #endif
        !            27: #ifndef PHP_OUTPUT_NOINLINE
        !            28: # define PHP_OUTPUT_NOINLINE 0
        !            29: #endif
1.1       misho      30: 
                     31: #include "php.h"
                     32: #include "ext/standard/head.h"
                     33: #include "ext/standard/url_scanner_ex.h"
                     34: #include "SAPI.h"
1.1.1.2 ! misho      35: #include "zend_stack.h"
        !            36: #include "php_output.h"
1.1       misho      37: 
1.1.1.2 ! misho      38: ZEND_DECLARE_MODULE_GLOBALS(output);
1.1       misho      39: 
1.1.1.2 ! misho      40: const char php_output_default_handler_name[sizeof("default output handler")] = "default output handler";
        !            41: const char php_output_devnull_handler_name[sizeof("null output handler")] = "null output handler";
1.1       misho      42: 
1.1.1.2 ! misho      43: #if PHP_OUTPUT_NOINLINE || PHP_OUTPUT_DEBUG
        !            44: # undef inline
        !            45: # define inline
1.1       misho      46: #endif
                     47: 
1.1.1.2 ! misho      48: /* {{{ aliases, conflict and reverse conflict hash tables */
        !            49: static HashTable php_output_handler_aliases;
        !            50: static HashTable php_output_handler_conflicts;
        !            51: static HashTable php_output_handler_reverse_conflicts;
        !            52: /* }}} */
        !            53: 
        !            54: /* {{{ forward declarations */
        !            55: static inline int php_output_lock_error(int op TSRMLS_DC);
        !            56: static inline void php_output_op(int op, const char *str, size_t len TSRMLS_DC);
        !            57: 
        !            58: static inline php_output_handler *php_output_handler_init(const char *name, size_t name_len, size_t chunk_size, int flags TSRMLS_DC);
        !            59: static inline php_output_handler_status_t php_output_handler_op(php_output_handler *handler, php_output_context *context);
        !            60: static inline int php_output_handler_append(php_output_handler *handler, const php_output_buffer *buf TSRMLS_DC);
        !            61: static inline zval *php_output_handler_status(php_output_handler *handler, zval *entry);
        !            62: 
        !            63: static inline php_output_context *php_output_context_init(php_output_context *context, int op TSRMLS_DC);
        !            64: static inline void php_output_context_reset(php_output_context *context);
        !            65: static inline void php_output_context_swap(php_output_context *context);
        !            66: static inline void php_output_context_dtor(php_output_context *context);
        !            67: 
        !            68: static inline int php_output_stack_pop(int flags TSRMLS_DC);
1.1       misho      69: 
1.1.1.2 ! misho      70: static int php_output_stack_apply_op(void *h, void *c);
        !            71: static int php_output_stack_apply_clean(void *h, void *c);
        !            72: static int php_output_stack_apply_list(void *h, void *z);
        !            73: static int php_output_stack_apply_status(void *h, void *z);
        !            74: 
        !            75: static int php_output_handler_compat_func(void **handler_context, php_output_context *output_context);
        !            76: static int php_output_handler_default_func(void **handler_context, php_output_context *output_context);
        !            77: static int php_output_handler_devnull_func(void **handler_context, php_output_context *output_context);
        !            78: /* }}} */
        !            79: 
        !            80: /* {{{ static void php_output_init_globals(zend_output_globals *G)
        !            81:  * Initialize the module globals on MINIT */
        !            82: static inline void php_output_init_globals(zend_output_globals *G)
        !            83: {
        !            84:        memset(G, 0, sizeof(*G));
        !            85: }
        !            86: /* }}} */
        !            87: 
        !            88: /* {{{ stderr/stdout writer if not PHP_OUTPUT_ACTIVATED */
        !            89: static int php_output_stdout(const char *str, size_t str_len)
        !            90: {
        !            91:        fwrite(str, 1, str_len, stdout);
        !            92:        return str_len;
        !            93: }
        !            94: static int php_output_stderr(const char *str, size_t str_len)
1.1       misho      95: {
                     96:        fwrite(str, 1, str_len, stderr);
                     97: /* See http://support.microsoft.com/kb/190351 */
                     98: #ifdef PHP_WIN32
                     99:        fflush(stderr);
                    100: #endif
                    101:        return str_len;
                    102: }
1.1.1.2 ! misho     103: static int (*php_output_direct)(const char *str, size_t str_len) = php_output_stderr;
1.1       misho     104: /* }}} */
                    105: 
1.1.1.2 ! misho     106: /* {{{ void php_output_header(TSRMLS_D) */
        !           107: static void php_output_header(TSRMLS_D)
1.1       misho     108: {
1.1.1.2 ! misho     109:        if (!SG(headers_sent)) {
        !           110:                if (!OG(output_start_filename)) {
        !           111:                        if (zend_is_compiling(TSRMLS_C)) {
        !           112:                                OG(output_start_filename) = zend_get_compiled_filename(TSRMLS_C);
        !           113:                                OG(output_start_lineno) = zend_get_compiled_lineno(TSRMLS_C);
        !           114:                        } else if (zend_is_executing(TSRMLS_C)) {
        !           115:                                OG(output_start_filename) = zend_get_executed_filename(TSRMLS_C);
        !           116:                                OG(output_start_lineno) = zend_get_executed_lineno(TSRMLS_C);
        !           117:                        }
        !           118: #if PHP_OUTPUT_DEBUG
        !           119:                        fprintf(stderr, "!!! output started at: %s (%d)\n", OG(output_start_filename), OG(output_start_lineno));
        !           120: #endif
        !           121:                }
        !           122:                if (!php_header(TSRMLS_C)) {
        !           123:                        OG(flags) |= PHP_OUTPUT_DISABLED;
        !           124:                }
        !           125:        }
1.1       misho     126: }
                    127: /* }}} */
                    128: 
1.1.1.2 ! misho     129: /* {{{ void php_output_startup(void)
        !           130:  * Set up module globals and initalize the conflict and reverse conflict hash tables */
1.1       misho     131: PHPAPI void php_output_startup(void)
                    132: {
1.1.1.2 ! misho     133:        ZEND_INIT_MODULE_GLOBALS(output, php_output_init_globals, NULL);
        !           134:        zend_hash_init(&php_output_handler_aliases, 0, NULL, NULL, 1);
        !           135:        zend_hash_init(&php_output_handler_conflicts, 0, NULL, NULL, 1);
        !           136:        zend_hash_init(&php_output_handler_reverse_conflicts, 0, NULL, (void (*)(void *)) zend_hash_destroy, 1);
        !           137:        php_output_direct = php_output_stdout;
        !           138: }
        !           139: /* }}} */
        !           140: 
        !           141: /* {{{ void php_output_shutdown(void)
        !           142:  * Destroy module globals and the conflict and reverse conflict hash tables */
        !           143: PHPAPI void php_output_shutdown(void)
        !           144: {
        !           145:        php_output_direct = php_output_stderr;
        !           146:        zend_hash_destroy(&php_output_handler_aliases);
        !           147:        zend_hash_destroy(&php_output_handler_conflicts);
        !           148:        zend_hash_destroy(&php_output_handler_reverse_conflicts);
        !           149: }
        !           150: /* }}} */
        !           151: 
        !           152: /* {{{ SUCCESS|FAILURE php_output_activate(TSRMLS_D)
        !           153:  * Reset output globals and setup the output handler stack */
        !           154: PHPAPI int php_output_activate(TSRMLS_D)
        !           155: {
1.1       misho     156: #ifdef ZTS
1.1.1.2 ! misho     157:        memset((*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(output_globals_id)], 0, sizeof(zend_output_globals));
1.1       misho     158: #else
1.1.1.2 ! misho     159:        memset(&output_globals, 0, sizeof(zend_output_globals));
1.1       misho     160: #endif
1.1.1.2 ! misho     161: 
        !           162:        zend_stack_init(&OG(handlers));
        !           163:        OG(flags) |= PHP_OUTPUT_ACTIVATED;
        !           164: 
        !           165:        return SUCCESS;
1.1       misho     166: }
                    167: /* }}} */
                    168: 
1.1.1.2 ! misho     169: /* {{{ void php_output_deactivate(TSRMLS_D)
        !           170:  * Destroy the output handler stack */
        !           171: PHPAPI void php_output_deactivate(TSRMLS_D)
        !           172: {
        !           173:        php_output_handler **handler = NULL;
        !           174: 
        !           175:        php_output_header(TSRMLS_C);
        !           176: 
        !           177:        OG(flags) ^= PHP_OUTPUT_ACTIVATED;
        !           178:        OG(active) = NULL;
        !           179:        OG(running) = NULL;
        !           180: 
        !           181:        /* release all output handlers */
        !           182:        if (OG(handlers).elements) {
        !           183:                while (SUCCESS == zend_stack_top(&OG(handlers), (void *) &handler)) {
        !           184:                        php_output_handler_free(handler TSRMLS_CC);
        !           185:                        zend_stack_del_top(&OG(handlers));
        !           186:                }
        !           187:                zend_stack_destroy(&OG(handlers));
        !           188:        }
        !           189: 
1.1       misho     190: }
                    191: /* }}} */
                    192: 
1.1.1.2 ! misho     193: /* {{{ void php_output_register_constants() */
        !           194: PHPAPI void php_output_register_constants(TSRMLS_D)
1.1       misho     195: {
                    196:        REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_START", PHP_OUTPUT_HANDLER_START, CONST_CS | CONST_PERSISTENT);
1.1.1.2 ! misho     197:        REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_WRITE", PHP_OUTPUT_HANDLER_WRITE, CONST_CS | CONST_PERSISTENT);
        !           198:        REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_FLUSH", PHP_OUTPUT_HANDLER_FLUSH, CONST_CS | CONST_PERSISTENT);
        !           199:        REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CLEAN", PHP_OUTPUT_HANDLER_CLEAN, CONST_CS | CONST_PERSISTENT);
        !           200:        REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_FINAL", PHP_OUTPUT_HANDLER_FINAL, CONST_CS | CONST_PERSISTENT);
        !           201:        REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CONT", PHP_OUTPUT_HANDLER_WRITE, CONST_CS | CONST_PERSISTENT);
        !           202:        REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_END", PHP_OUTPUT_HANDLER_FINAL, CONST_CS | CONST_PERSISTENT);
        !           203: 
        !           204:        REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_CLEANABLE", PHP_OUTPUT_HANDLER_CLEANABLE, CONST_CS | CONST_PERSISTENT);
        !           205:        REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_FLUSHABLE", PHP_OUTPUT_HANDLER_FLUSHABLE, CONST_CS | CONST_PERSISTENT);
        !           206:        REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_REMOVABLE", PHP_OUTPUT_HANDLER_REMOVABLE, CONST_CS | CONST_PERSISTENT);
        !           207:        REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_STDFLAGS", PHP_OUTPUT_HANDLER_STDFLAGS, CONST_CS | CONST_PERSISTENT);
        !           208:        REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_STARTED", PHP_OUTPUT_HANDLER_STARTED, CONST_CS | CONST_PERSISTENT);
        !           209:        REGISTER_MAIN_LONG_CONSTANT("PHP_OUTPUT_HANDLER_DISABLED", PHP_OUTPUT_HANDLER_DISABLED, CONST_CS | CONST_PERSISTENT);
1.1       misho     210: }
                    211: /* }}} */
                    212: 
1.1.1.2 ! misho     213: /* {{{ void php_output_set_status(int status TSRMLS_DC)
        !           214:  * Used by SAPIs to disable output */
        !           215: PHPAPI void php_output_set_status(int status TSRMLS_DC)
1.1       misho     216: {
1.1.1.2 ! misho     217:        OG(flags) = status & 0xf;
1.1       misho     218: }
                    219: /* }}} */
                    220: 
1.1.1.2 ! misho     221: /* {{{ int php_output_get_status(TSRMLS_C)
        !           222:  * Get output control status */
        !           223: PHPAPI int php_output_get_status(TSRMLS_D)
1.1       misho     224: {
1.1.1.2 ! misho     225:        return (
        !           226:                OG(flags)
        !           227:                |       (OG(active) ? PHP_OUTPUT_ACTIVE : 0)
        !           228:                |       (OG(running)? PHP_OUTPUT_LOCKED : 0)
        !           229:        ) & 0xff;
1.1       misho     230: }
                    231: /* }}} */
                    232: 
1.1.1.2 ! misho     233: /* {{{ int php_output_write_unbuffered(const char *str, size_t len TSRMLS_DC)
        !           234:  * Unbuffered write */
        !           235: PHPAPI int php_output_write_unbuffered(const char *str, size_t len TSRMLS_DC)
1.1       misho     236: {
1.1.1.2 ! misho     237:        if (OG(flags) & PHP_OUTPUT_DISABLED) {
1.1       misho     238:                return 0;
                    239:        }
1.1.1.2 ! misho     240:        if (OG(flags) & PHP_OUTPUT_ACTIVATED) {
        !           241:                return sapi_module.ub_write(str, len TSRMLS_CC);
        !           242:        }
        !           243:        return php_output_direct(str, len);
1.1       misho     244: }
                    245: /* }}} */
                    246: 
1.1.1.2 ! misho     247: /* {{{ int php_output_write(const char *str, size_t len TSRMLS_DC)
        !           248:  * Buffered write */
        !           249: PHPAPI int php_output_write(const char *str, size_t len TSRMLS_DC)
1.1       misho     250: {
1.1.1.2 ! misho     251:        if (OG(flags) & PHP_OUTPUT_DISABLED) {
        !           252:                return 0;
1.1       misho     253:        }
1.1.1.2 ! misho     254:        if (OG(flags) & PHP_OUTPUT_ACTIVATED) {
        !           255:                php_output_op(PHP_OUTPUT_HANDLER_WRITE, str, len TSRMLS_CC);
        !           256:                return (int) len;
1.1       misho     257:        }
1.1.1.2 ! misho     258:        return php_output_direct(str, len);
1.1       misho     259: }
                    260: /* }}} */
                    261: 
1.1.1.2 ! misho     262: /* {{{ SUCCESS|FAILURE php_output_flush(TSRMLS_D)
        !           263:  * Flush the most recent output handlers buffer */
        !           264: PHPAPI int php_output_flush(TSRMLS_D)
1.1       misho     265: {
1.1.1.2 ! misho     266:        php_output_context context;
1.1       misho     267: 
1.1.1.2 ! misho     268:        if (OG(active) && (OG(active)->flags & PHP_OUTPUT_HANDLER_FLUSHABLE)) {
        !           269:                php_output_context_init(&context, PHP_OUTPUT_HANDLER_FLUSH TSRMLS_CC);
        !           270:                php_output_handler_op(OG(active), &context);
        !           271:                if (context.out.data && context.out.used) {
        !           272:                        zend_stack_del_top(&OG(handlers));
        !           273:                        php_output_write(context.out.data, context.out.used TSRMLS_CC);
        !           274:                        zend_stack_push(&OG(handlers), &OG(active), sizeof(php_output_handler *));
        !           275:                }
        !           276:                php_output_context_dtor(&context);
        !           277:                return SUCCESS;
        !           278:        }
        !           279:        return FAILURE;
1.1       misho     280: }
                    281: /* }}} */
                    282: 
1.1.1.2 ! misho     283: /* {{{ void php_output_flush_all(TSRMLS_C)
        !           284:  * Flush all output buffers subsequently */
        !           285: PHPAPI void php_output_flush_all(TSRMLS_D)
1.1       misho     286: {
1.1.1.2 ! misho     287:        if (OG(active)) {
        !           288:                php_output_op(PHP_OUTPUT_HANDLER_FLUSH, NULL, 0 TSRMLS_CC);
1.1       misho     289:        }
1.1.1.2 ! misho     290: }
        !           291: /* }}} */
1.1       misho     292: 
1.1.1.2 ! misho     293: /* {{{ SUCCESS|FAILURE php_output_clean(TSRMLS_D)
        !           294:  * Cleans the most recent output handlers buffer if the handler is cleanable */
        !           295: PHPAPI int php_output_clean(TSRMLS_D)
        !           296: {
        !           297:        php_output_context context;
1.1       misho     298: 
1.1.1.2 ! misho     299:        if (OG(active) && (OG(active)->flags & PHP_OUTPUT_HANDLER_CLEANABLE)) {
        !           300:                OG(active)->buffer.used = 0;
        !           301:                php_output_context_init(&context, PHP_OUTPUT_HANDLER_CLEAN TSRMLS_CC);
        !           302:                php_output_handler_op(OG(active), &context);
        !           303:                php_output_context_dtor(&context);
        !           304:                return SUCCESS;
1.1       misho     305:        }
1.1.1.2 ! misho     306:        return FAILURE;
        !           307: }
        !           308: /* }}} */
1.1       misho     309: 
1.1.1.2 ! misho     310: /* {{{ void php_output_clean_all(TSRMLS_D)
        !           311:  * Cleans all output handler buffers, without regard whether the handler is cleanable */
        !           312: PHPAPI void php_output_clean_all(TSRMLS_D)
        !           313: {
        !           314:        php_output_context context;
1.1       misho     315: 
1.1.1.2 ! misho     316:        if (OG(active)) {
        !           317:                php_output_context_init(&context, PHP_OUTPUT_HANDLER_CLEAN TSRMLS_CC);
        !           318:                zend_stack_apply_with_argument(&OG(handlers), ZEND_STACK_APPLY_TOPDOWN, php_output_stack_apply_clean, &context);
1.1       misho     319:        }
1.1.1.2 ! misho     320: }
1.1       misho     321: 
1.1.1.2 ! misho     322: /* {{{ SUCCESS|FAILURE php_output_end(TSRMLS_D)
        !           323:  * Finalizes the most recent output handler at pops it off the stack if the handler is removable */
        !           324: PHPAPI int php_output_end(TSRMLS_D)
        !           325: {
        !           326:        if (php_output_stack_pop(PHP_OUTPUT_POP_TRY TSRMLS_CC)) {
        !           327:                return SUCCESS;
1.1       misho     328:        }
1.1.1.2 ! misho     329:        return FAILURE;
        !           330: }
        !           331: /* }}} */
1.1       misho     332: 
1.1.1.2 ! misho     333: /* {{{ void php_output_end_all(TSRMLS_D)
        !           334:  * Finalizes all output handlers and ends output buffering without regard whether a handler is removable */
        !           335: PHPAPI void php_output_end_all(TSRMLS_D)
        !           336: {
        !           337:        while (OG(active) && php_output_stack_pop(PHP_OUTPUT_POP_FORCE TSRMLS_CC));
        !           338: }
        !           339: /* }}} */
1.1       misho     340: 
1.1.1.2 ! misho     341: /* {{{ SUCCESS|FAILURE php_output_discard(TSRMLS_D)
        !           342:  * Discards the most recent output handlers buffer and pops it off the stack if the handler is removable */
        !           343: PHPAPI int php_output_discard(TSRMLS_D)
        !           344: {
        !           345:        if (php_output_stack_pop(PHP_OUTPUT_POP_DISCARD|PHP_OUTPUT_POP_TRY TSRMLS_CC)) {
        !           346:                return SUCCESS;
1.1       misho     347:        }
1.1.1.2 ! misho     348:        return FAILURE;
        !           349: }
        !           350: /* }}} */
1.1       misho     351: 
1.1.1.2 ! misho     352: /* {{{ void php_output_discard_all(TSRMLS_D)
        !           353:  * Discard all output handlers and buffers without regard whether a handler is removable */
        !           354: PHPAPI void php_output_discard_all(TSRMLS_D)
        !           355: {
        !           356:        while (OG(active)) {
        !           357:                php_output_stack_pop(PHP_OUTPUT_POP_DISCARD|PHP_OUTPUT_POP_FORCE TSRMLS_CC);
1.1       misho     358:        }
1.1.1.2 ! misho     359: }
        !           360: /* }}} */
1.1       misho     361: 
1.1.1.2 ! misho     362: /* {{{ int php_output_get_level(TSRMLS_D)
        !           363:  * Get output buffering level, ie. how many output handlers the stack contains */
        !           364: PHPAPI int php_output_get_level(TSRMLS_D)
        !           365: {
        !           366:        return OG(active) ? zend_stack_count(&OG(handlers)) : 0;
        !           367: }
        !           368: /* }}} */
1.1       misho     369: 
1.1.1.2 ! misho     370: /* {{{ SUCCESS|FAILURE php_output_get_contents(zval *z TSRMLS_DC)
        !           371:  * Get the contents of the active output handlers buffer */
        !           372: PHPAPI int php_output_get_contents(zval *p TSRMLS_DC)
        !           373: {
        !           374:        if (OG(active)) {
        !           375:                ZVAL_STRINGL(p, OG(active)->buffer.data, OG(active)->buffer.used, 1);
        !           376:                return SUCCESS;
1.1       misho     377:        } else {
1.1.1.2 ! misho     378:                ZVAL_NULL(p);
        !           379:                return FAILURE;
1.1       misho     380:        }
1.1.1.2 ! misho     381: }
        !           382: 
        !           383: /* {{{ SUCCESS|FAILURE php_output_get_length(zval *z TSRMLS_DC)
        !           384:  * Get the length of the active output handlers buffer */
        !           385: PHPAPI int php_output_get_length(zval *p TSRMLS_DC)
        !           386: {
        !           387:        if (OG(active)) {
        !           388:                ZVAL_LONG(p, OG(active)->buffer.used);
        !           389:                return SUCCESS;
        !           390:        } else {
        !           391:                ZVAL_NULL(p);
        !           392:                return FAILURE;
1.1       misho     393:        }
                    394: }
                    395: /* }}} */
                    396: 
1.1.1.2 ! misho     397: /* {{{ php_output_handler* php_output_get_active_handler(TSRMLS_D)
        !           398:  * Get active output handler */
        !           399: PHPAPI php_output_handler* php_output_get_active_handler(TSRMLS_D)
1.1       misho     400: {
1.1.1.2 ! misho     401:        return OG(active);
1.1       misho     402: }
                    403: /* }}} */
                    404: 
1.1.1.2 ! misho     405: /* {{{ SUCCESS|FAILURE php_output_handler_start_default(TSRMLS_D)
        !           406:  * Start a "default output handler" */
        !           407: PHPAPI int php_output_start_default(TSRMLS_D)
1.1       misho     408: {
1.1.1.2 ! misho     409:        php_output_handler *handler;
        !           410: 
        !           411:        handler = php_output_handler_create_internal(ZEND_STRL(php_output_default_handler_name), php_output_handler_default_func, 0, PHP_OUTPUT_HANDLER_STDFLAGS TSRMLS_CC);
        !           412:        if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
        !           413:                return SUCCESS;
        !           414:        }
        !           415:        php_output_handler_free(&handler TSRMLS_CC);
        !           416:        return FAILURE;
1.1       misho     417: }
                    418: /* }}} */
                    419: 
1.1.1.2 ! misho     420: /* {{{ SUCCESS|FAILURE php_output_handler_start_devnull(TSRMLS_D)
        !           421:  * Start a "null output handler" */
        !           422: PHPAPI int php_output_start_devnull(TSRMLS_D)
1.1       misho     423: {
1.1.1.2 ! misho     424:        php_output_handler *handler;
        !           425: 
        !           426:        handler = php_output_handler_create_internal(ZEND_STRL(php_output_devnull_handler_name), php_output_handler_devnull_func, PHP_OUTPUT_HANDLER_DEFAULT_SIZE, 0 TSRMLS_CC);
        !           427:        if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
        !           428:                return SUCCESS;
        !           429:        }
        !           430:        php_output_handler_free(&handler TSRMLS_CC);
        !           431:        return FAILURE;
1.1       misho     432: }
                    433: /* }}} */
                    434: 
1.1.1.2 ! misho     435: /* {{{ SUCCESS|FAILURE php_output_start_user(zval *handler, size_t chunk_size, int flags TSRMLS_DC)
        !           436:  * Start a user level output handler */
        !           437: PHPAPI int php_output_start_user(zval *output_handler, size_t chunk_size, int flags TSRMLS_DC)
1.1       misho     438: {
1.1.1.2 ! misho     439:        php_output_handler *handler;
        !           440: 
        !           441:        if (output_handler) {
        !           442:                handler = php_output_handler_create_user(output_handler, chunk_size, flags TSRMLS_CC);
        !           443:        } else {
        !           444:                handler = php_output_handler_create_internal(ZEND_STRL(php_output_default_handler_name), php_output_handler_default_func, chunk_size, flags TSRMLS_CC);
        !           445:        }
        !           446:        if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
        !           447:                return SUCCESS;
        !           448:        }
        !           449:        php_output_handler_free(&handler TSRMLS_CC);
        !           450:        return FAILURE;
1.1       misho     451: }
                    452: /* }}} */
                    453: 
1.1.1.2 ! misho     454: /* {{{ SUCCESS|FAILURE php_output_start_internal(zval *name, php_output_handler_func_t handler, size_t chunk_size, int flags TSRMLS_DC)
        !           455:  * Start an internal output handler that does not have to maintain a non-global state */
        !           456: PHPAPI int php_output_start_internal(const char *name, size_t name_len, php_output_handler_func_t output_handler, size_t chunk_size, int flags TSRMLS_DC)
1.1       misho     457: {
1.1.1.2 ! misho     458:        php_output_handler *handler;
        !           459: 
        !           460:        handler = php_output_handler_create_internal(name, name_len, php_output_handler_compat_func, chunk_size, flags TSRMLS_CC);
        !           461:        php_output_handler_set_context(handler, output_handler, NULL TSRMLS_CC);
        !           462:        if (SUCCESS == php_output_handler_start(handler TSRMLS_CC)) {
        !           463:                return SUCCESS;
        !           464:        }
        !           465:        php_output_handler_free(&handler TSRMLS_CC);
        !           466:        return FAILURE;
1.1       misho     467: }
                    468: /* }}} */
                    469: 
1.1.1.2 ! misho     470: /* {{{ php_output_handler *php_output_handler_create_user(zval *handler, size_t chunk_size, int flags TSRMLS_DC)
        !           471:  * Create a user level output handler */
        !           472: PHPAPI php_output_handler *php_output_handler_create_user(zval *output_handler, size_t chunk_size, int flags TSRMLS_DC)
1.1       misho     473: {
1.1.1.2 ! misho     474:        char *handler_name = NULL, *error = NULL;
        !           475:        php_output_handler *handler = NULL;
        !           476:        php_output_handler_alias_ctor_t *alias = NULL;
        !           477:        php_output_handler_user_func_t *user = NULL;
1.1       misho     478: 
1.1.1.2 ! misho     479:        switch (Z_TYPE_P(output_handler)) {
        !           480:                case IS_NULL:
        !           481:                        handler = php_output_handler_create_internal(ZEND_STRL(php_output_default_handler_name), php_output_handler_default_func, chunk_size, flags TSRMLS_CC);
        !           482:                        break;
        !           483:                case IS_STRING:
        !           484:                        if (Z_STRLEN_P(output_handler) && (alias = php_output_handler_alias(Z_STRVAL_P(output_handler), Z_STRLEN_P(output_handler) TSRMLS_CC))) {
        !           485:                                handler = (*alias)(Z_STRVAL_P(output_handler), Z_STRLEN_P(output_handler), chunk_size, flags TSRMLS_CC);
        !           486:                                break;
        !           487:                        }
        !           488:                default:
        !           489:                        user = ecalloc(1, sizeof(php_output_handler_user_func_t));
        !           490:                        if (SUCCESS == zend_fcall_info_init(output_handler, 0, &user->fci, &user->fcc, &handler_name, &error TSRMLS_CC)) {
        !           491:                                handler = php_output_handler_init(handler_name, strlen(handler_name), chunk_size, (flags & ~0xf) | PHP_OUTPUT_HANDLER_USER TSRMLS_CC);
        !           492:                                Z_ADDREF_P(output_handler);
        !           493:                                user->zoh = output_handler;
        !           494:                                handler->func.user = user;
        !           495:                        } else {
        !           496:                                efree(user);
        !           497:                        }
        !           498:                        if (error) {
        !           499:                                php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "%s", error);
        !           500:                                efree(error);
        !           501:                        }
        !           502:                        if (handler_name) {
        !           503:                                efree(handler_name);
        !           504:                        }
1.1       misho     505:        }
1.1.1.2 ! misho     506: 
        !           507:        return handler;
1.1       misho     508: }
                    509: /* }}} */
                    510: 
1.1.1.2 ! misho     511: /* {{{ php_output_handler *php_output_handler_create_internal(zval *name, php_output_handler_context_func_t handler, size_t chunk_size, int flags TSRMLS_DC)
        !           512:  * Create an internal output handler that can maintain a non-global state */
        !           513: PHPAPI php_output_handler *php_output_handler_create_internal(const char *name, size_t name_len, php_output_handler_context_func_t output_handler, size_t chunk_size, int flags TSRMLS_DC)
        !           514: {
        !           515:        php_output_handler *handler;
1.1       misho     516: 
1.1.1.2 ! misho     517:        handler = php_output_handler_init(name, name_len, chunk_size, (flags & ~0xf) | PHP_OUTPUT_HANDLER_INTERNAL TSRMLS_CC);
        !           518:        handler->func.internal = output_handler;
        !           519: 
        !           520:        return handler;
        !           521: }
        !           522: /* }}} */
        !           523: 
        !           524: /* {{{ void php_output_handler_set_context(php_output_handler *handler, void *opaq, void (*dtor)(void* TSRMLS_DC) TSRMLS_DC)
        !           525:  * Set the context/state of an output handler. Calls the dtor of the previous context if there is one */
        !           526: PHPAPI void php_output_handler_set_context(php_output_handler *handler, void *opaq, void (*dtor)(void* TSRMLS_DC) TSRMLS_DC)
1.1       misho     527: {
1.1.1.2 ! misho     528:        if (handler->dtor && handler->opaq) {
        !           529:                handler->dtor(handler->opaq TSRMLS_CC);
        !           530:        }
        !           531:        handler->dtor = dtor;
        !           532:        handler->opaq = opaq;
        !           533: }
        !           534: /* }}} */
        !           535: 
        !           536: /* {{{ SUCCESS|FAILURE php_output_handler_start(php_output_handler *handler TSRMLS_DC)
        !           537:  * Starts the set up output handler and pushes it on top of the stack. Checks for any conflicts regarding the output handler to start */
        !           538: PHPAPI int php_output_handler_start(php_output_handler *handler TSRMLS_DC)
        !           539: {
        !           540:        HashPosition pos;
        !           541:        HashTable *rconflicts;
        !           542:        php_output_handler_conflict_check_t *conflict;
1.1       misho     543: 
1.1.1.2 ! misho     544:        if (php_output_lock_error(PHP_OUTPUT_HANDLER_START TSRMLS_CC) || !handler) {
        !           545:                return FAILURE;
        !           546:        }
        !           547:        if (SUCCESS == zend_hash_find(&php_output_handler_conflicts, handler->name, handler->name_len+1, (void *) &conflict)) {
        !           548:                if (SUCCESS != (*conflict)(handler->name, handler->name_len TSRMLS_CC)) {
        !           549:                        return FAILURE;
        !           550:                }
        !           551:        }
        !           552:        if (SUCCESS == zend_hash_find(&php_output_handler_reverse_conflicts, handler->name, handler->name_len+1, (void *) &rconflicts)) {
        !           553:                for (zend_hash_internal_pointer_reset_ex(rconflicts, &pos);
        !           554:                        zend_hash_get_current_data_ex(rconflicts, (void *) &conflict, &pos) == SUCCESS;
        !           555:                        zend_hash_move_forward_ex(rconflicts, &pos)
        !           556:                ) {
        !           557:                        if (SUCCESS != (*conflict)(handler->name, handler->name_len TSRMLS_CC)) {
        !           558:                                return FAILURE;
        !           559:                        }
1.1       misho     560:                }
1.1.1.2 ! misho     561:        }
        !           562:        /* zend_stack_push never returns SUCCESS but FAILURE or stack level */
        !           563:        if (FAILURE == (handler->level = zend_stack_push(&OG(handlers), &handler, sizeof(php_output_handler *)))) {
        !           564:                return FAILURE;
        !           565:        }
        !           566:        OG(active) = handler;
        !           567:        return SUCCESS;
        !           568: }
        !           569: /* }}} */
1.1       misho     570: 
1.1.1.2 ! misho     571: /* {{{ int php_output_handler_started(zval *name TSRMLS_DC)
        !           572:  * Check whether a certain output handler is in use */
        !           573: PHPAPI int php_output_handler_started(const char *name, size_t name_len TSRMLS_DC)
        !           574: {
        !           575:        php_output_handler ***handlers;
        !           576:        int i, count = php_output_get_level(TSRMLS_C);
        !           577: 
        !           578:        if (count) {
        !           579:                handlers = (php_output_handler ***) zend_stack_base(&OG(handlers));
        !           580: 
        !           581:                for (i = 0; i < count; ++i) {
        !           582:                        if (name_len == (*(handlers[i]))->name_len && !memcmp((*(handlers[i]))->name, name, name_len)) {
        !           583:                                return 1;
        !           584:                        }
        !           585:                }
1.1       misho     586:        }
1.1.1.2 ! misho     587: 
        !           588:        return 0;
1.1       misho     589: }
                    590: /* }}} */
                    591: 
1.1.1.2 ! misho     592: /* {{{ int php_output_handler_conflict(zval *handler_new, zval *handler_old TSRMLS_DC)
        !           593:  * Check whether a certain handler is in use and issue a warning that the new handler would conflict with the already used one */
        !           594: PHPAPI int php_output_handler_conflict(const char *handler_new, size_t handler_new_len, const char *handler_set, size_t handler_set_len TSRMLS_DC)
        !           595: {
        !           596:        if (php_output_handler_started(handler_set, handler_set_len TSRMLS_CC)) {
        !           597:                if (handler_new_len != handler_set_len || memcmp(handler_new, handler_set, handler_set_len)) {
        !           598:                        php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler '%s' conflicts with '%s'", handler_new, handler_set);
        !           599:                } else {
        !           600:                        php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "output handler '%s' cannot be used twice", handler_new);
        !           601:                }
1.1       misho     602:                return 1;
                    603:        }
                    604:        return 0;
                    605: }
                    606: /* }}} */
                    607: 
1.1.1.2 ! misho     608: /* {{{ SUCCESS|FAILURE php_output_handler_conflict_register(zval *name, php_output_handler_conflict_check_t check_func TSRMLS_DC)
        !           609:  * Register a conflict checking function on MINIT */
        !           610: PHPAPI int php_output_handler_conflict_register(const char *name, size_t name_len, php_output_handler_conflict_check_t check_func TSRMLS_DC)
1.1       misho     611: {
1.1.1.2 ! misho     612:        if (!EG(current_module)) {
        !           613:                zend_error(E_ERROR, "Cannot register an output handler conflict outside of MINIT");
        !           614:                return FAILURE;
        !           615:        }
        !           616:        return zend_hash_update(&php_output_handler_conflicts, name, name_len+1, &check_func, sizeof(php_output_handler_conflict_check_t *), NULL);
        !           617: }
        !           618: /* }}} */
1.1       misho     619: 
1.1.1.2 ! misho     620: /* {{{ SUCCESS|FAILURE php_output_handler_reverse_conflict_register(zval *name, php_output_handler_conflict_check_t check_func TSRMLS_DC)
        !           621:  * Register a reverse conflict checking function on MINIT */
        !           622: PHPAPI int php_output_handler_reverse_conflict_register(const char *name, size_t name_len, php_output_handler_conflict_check_t check_func TSRMLS_DC)
        !           623: {
        !           624:        HashTable rev, *rev_ptr = NULL;
        !           625: 
        !           626:        if (!EG(current_module)) {
        !           627:                zend_error(E_ERROR, "Cannot register a reverse output handler conflict outside of MINIT");
1.1       misho     628:                return FAILURE;
                    629:        }
                    630: 
1.1.1.2 ! misho     631:        if (SUCCESS == zend_hash_find(&php_output_handler_reverse_conflicts, name, name_len+1, (void *) &rev_ptr)) {
        !           632:                return zend_hash_next_index_insert(rev_ptr, &check_func, sizeof(php_output_handler_conflict_check_t *), NULL);
        !           633:        } else {
        !           634:                zend_hash_init(&rev, 1, NULL, NULL, 1);
        !           635:                if (SUCCESS != zend_hash_next_index_insert(&rev, &check_func, sizeof(php_output_handler_conflict_check_t *), NULL)) {
        !           636:                        zend_hash_destroy(&rev);
1.1       misho     637:                        return FAILURE;
                    638:                }
1.1.1.2 ! misho     639:                if (SUCCESS != zend_hash_update(&php_output_handler_reverse_conflicts, name, name_len+1, &rev, sizeof(HashTable), NULL)) {
        !           640:                        zend_hash_destroy(&rev);
        !           641:                        return FAILURE;
1.1       misho     642:                }
1.1.1.2 ! misho     643:                return SUCCESS;
1.1       misho     644:        }
                    645: }
                    646: /* }}} */
                    647: 
1.1.1.2 ! misho     648: /* {{{ php_output_handler_alias_ctor_t php_output_handler_alias(zval *name TSRMLS_DC)
        !           649:  * Get an internal output handler for a user handler if it exists */
        !           650: PHPAPI php_output_handler_alias_ctor_t *php_output_handler_alias(const char *name, size_t name_len TSRMLS_DC)
1.1       misho     651: {
1.1.1.2 ! misho     652:        php_output_handler_alias_ctor_t *func = NULL;
1.1       misho     653: 
1.1.1.2 ! misho     654:        zend_hash_find(&php_output_handler_aliases, name, name_len+1, (void *) &func);
        !           655:        return func;
1.1       misho     656: }
                    657: /* }}} */
                    658: 
1.1.1.2 ! misho     659: /* {{{ SUCCESS|FAILURE php_output_handler_alias_register(zval *name, php_output_handler_alias_ctor_t func TSRMLS_DC)
        !           660:  * Registers an internal output handler as alias for a user handler */
        !           661: PHPAPI int php_output_handler_alias_register(const char *name, size_t name_len, php_output_handler_alias_ctor_t func TSRMLS_DC)
1.1       misho     662: {
1.1.1.2 ! misho     663:        if (!EG(current_module)) {
        !           664:                zend_error(E_ERROR, "Cannot register an output handler alias outside of MINIT");
        !           665:                return FAILURE;
        !           666:        }
        !           667:        return zend_hash_update(&php_output_handler_aliases, name, name_len+1, &func, sizeof(php_output_handler_alias_ctor_t *), NULL);
        !           668: }
        !           669: /* }}} */
1.1       misho     670: 
1.1.1.2 ! misho     671: /* {{{ SUCCESS|FAILURE php_output_handler_hook(php_output_handler_hook_t type, void *arg TSMRLS_DC)
        !           672:  * Output handler hook for output handler functions to check/modify the current handlers abilities */
        !           673: PHPAPI int php_output_handler_hook(php_output_handler_hook_t type, void *arg TSRMLS_DC)
        !           674: {
        !           675:        if (OG(running)) {
        !           676:                switch (type) {
        !           677:                        case PHP_OUTPUT_HANDLER_HOOK_GET_OPAQ:
        !           678:                                *(void ***) arg = &OG(running)->opaq;
        !           679:                                return SUCCESS;
        !           680:                        case PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS:
        !           681:                                *(int *) arg = OG(running)->flags;
        !           682:                                return SUCCESS;
        !           683:                        case PHP_OUTPUT_HANDLER_HOOK_GET_LEVEL:
        !           684:                                *(int *) arg = OG(running)->level;
        !           685:                 return SUCCESS;
        !           686:                        case PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE:
        !           687:                                OG(running)->flags &= ~(PHP_OUTPUT_HANDLER_REMOVABLE|PHP_OUTPUT_HANDLER_CLEANABLE);
        !           688:                                return SUCCESS;
        !           689:                        case PHP_OUTPUT_HANDLER_HOOK_DISABLE:
        !           690:                                OG(running)->flags |= PHP_OUTPUT_HANDLER_DISABLED;
        !           691:                                return SUCCESS;
        !           692:                        default:
        !           693:                                break;
1.1       misho     694:                }
                    695:        }
1.1.1.2 ! misho     696:        return FAILURE;
1.1       misho     697: }
                    698: /* }}} */
                    699: 
1.1.1.2 ! misho     700: /* {{{ void php_output_handler_dtor(php_output_handler *handler TSRMLS_DC)
        !           701:  * Destroy an output handler */
        !           702: PHPAPI void php_output_handler_dtor(php_output_handler *handler TSRMLS_DC)
1.1       misho     703: {
1.1.1.2 ! misho     704:        STR_FREE(handler->name);
        !           705:        STR_FREE(handler->buffer.data);
        !           706:        if (handler->flags & PHP_OUTPUT_HANDLER_USER) {
        !           707:                zval_ptr_dtor(&handler->func.user->zoh);
        !           708:                efree(handler->func.user);
        !           709:        }
        !           710:        if (handler->dtor && handler->opaq) {
        !           711:                handler->dtor(handler->opaq TSRMLS_CC);
        !           712:        }
        !           713:        memset(handler, 0, sizeof(*handler));
1.1       misho     714: }
                    715: /* }}} */
                    716: 
1.1.1.2 ! misho     717: /* {{{ void php_output_handler_free(php_output_handler **handler TSMRLS_DC)
        !           718:  * Destroy and free an output handler */
        !           719: PHPAPI void php_output_handler_free(php_output_handler **h TSRMLS_DC)
1.1       misho     720: {
1.1.1.2 ! misho     721:        if (*h) {
        !           722:                php_output_handler_dtor(*h TSRMLS_CC);
        !           723:                efree(*h);
        !           724:                *h = NULL;
1.1       misho     725:        }
                    726: }
                    727: /* }}} */
                    728: 
1.1.1.2 ! misho     729: /* void php_output_set_implicit_flush(int enabled TSRMLS_DC)
        !           730:  * Enable or disable implicit flush */
        !           731: PHPAPI void php_output_set_implicit_flush(int flush TSRMLS_DC)
1.1       misho     732: {
1.1.1.2 ! misho     733:        if (flush) {
        !           734:                OG(flags) |= PHP_OUTPUT_IMPLICITFLUSH;
        !           735:        } else {
        !           736:                OG(flags) &= ~PHP_OUTPUT_IMPLICITFLUSH;
1.1       misho     737:        }
                    738: }
                    739: /* }}} */
                    740: 
1.1.1.2 ! misho     741: /* {{{ char *php_output_get_start_filename(TSRMLS_D)
        !           742:  * Get the file name where output has started */
        !           743: PHPAPI const char *php_output_get_start_filename(TSRMLS_D)
1.1       misho     744: {
1.1.1.2 ! misho     745:        return OG(output_start_filename);
        !           746: }
        !           747: /* }}} */
1.1       misho     748: 
1.1.1.2 ! misho     749: /* {{{ int php_output_get_start_lineno(TSRMLS_D)
        !           750:  * Get the line number where output has started */
        !           751: PHPAPI int php_output_get_start_lineno(TSRMLS_D)
        !           752: {
        !           753:        return OG(output_start_lineno);
        !           754: }
        !           755: /* }}} */
1.1       misho     756: 
1.1.1.2 ! misho     757: /* {{{ static int php_output_lock_error(int op TSRMLS_DC)
        !           758:  * Checks whether an unallowed operation is attempted from within the output handler and issues a fatal error */
        !           759: static inline int php_output_lock_error(int op TSRMLS_DC)
        !           760: {
        !           761:        /* if there's no ob active, ob has been stopped */
        !           762:        if (op && OG(active) && OG(running)) {
        !           763:                /* fatal error */
        !           764:                php_output_deactivate(TSRMLS_C);
        !           765:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_ERROR, "Cannot use output buffering in output buffering display handlers");
        !           766:                return 1;
1.1       misho     767:        }
1.1.1.2 ! misho     768:        return 0;
1.1       misho     769: }
                    770: /* }}} */
                    771: 
1.1.1.2 ! misho     772: /* {{{ static php_output_context *php_output_context_init(php_output_context *context, int op TSRMLS_DC)
        !           773:  * Initialize a new output context */
        !           774: static inline php_output_context *php_output_context_init(php_output_context *context, int op TSRMLS_DC)
1.1       misho     775: {
1.1.1.2 ! misho     776:        if (!context) {
        !           777:                context = emalloc(sizeof(php_output_context));
        !           778:        }
1.1       misho     779: 
1.1.1.2 ! misho     780:        memset(context, 0, sizeof(php_output_context));
        !           781:        TSRMLS_SET_CTX(context->tsrm_ls);
        !           782:        context->op = op;
        !           783: 
        !           784:        return context;
        !           785: }
        !           786: /* }}} */
1.1       misho     787: 
1.1.1.2 ! misho     788: /* {{{ static void php_output_context_reset(php_output_context *context)
        !           789:  * Reset an output context */
        !           790: static inline void php_output_context_reset(php_output_context *context)
        !           791: {
        !           792:        int op = context->op;
        !           793:        php_output_context_dtor(context);
        !           794:        memset(context, 0, sizeof(php_output_context));
        !           795:        context->op = op;
        !           796: }
        !           797: /* }}} */
1.1       misho     798: 
1.1.1.2 ! misho     799: /* {{{ static void php_output_context_feed(php_output_context *context, char *, size_t, size_t)
        !           800:  * Feed output contexts input buffer */
        !           801: static inline void php_output_context_feed(php_output_context *context, char *data, size_t size, size_t used, zend_bool free)
        !           802: {
        !           803:        if (context->in.free && context->in.data) {
        !           804:                efree(context->in.data);
1.1       misho     805:        }
1.1.1.2 ! misho     806:        context->in.data = data;
        !           807:        context->in.used = used;
        !           808:        context->in.free = free;
        !           809:        context->in.size = size;
1.1       misho     810: }
1.1.1.2 ! misho     811: /* }}} */
1.1       misho     812: 
1.1.1.2 ! misho     813: /* {{{ static void php_output_context_swap(php_output_context *context)
        !           814:  * Swap output contexts buffers */
        !           815: static inline void php_output_context_swap(php_output_context *context)
1.1       misho     816: {
1.1.1.2 ! misho     817:        if (context->in.free && context->in.data) {
        !           818:                efree(context->in.data);
1.1       misho     819:        }
1.1.1.2 ! misho     820:        context->in.data = context->out.data;
        !           821:        context->in.used = context->out.used;
        !           822:        context->in.free = context->out.free;
        !           823:        context->in.size = context->out.size;
        !           824:        context->out.data = NULL;
        !           825:        context->out.used = 0;
        !           826:        context->out.free = 0;
        !           827:        context->out.size = 0;
1.1       misho     828: }
                    829: /* }}} */
                    830: 
1.1.1.2 ! misho     831: /* {{{ static void php_output_context_pass(php_output_context *context)
        !           832:  * Pass input to output buffer */
        !           833: static inline void php_output_context_pass(php_output_context *context)
1.1       misho     834: {
1.1.1.2 ! misho     835:        context->out.data = context->in.data;
        !           836:        context->out.used = context->in.used;
        !           837:        context->out.size = context->in.size;
        !           838:        context->out.free = context->in.free;
        !           839:        context->in.data = NULL;
        !           840:        context->in.used = 0;
        !           841:        context->in.free = 0;
        !           842:        context->in.size = 0;
        !           843: }
        !           844: /* }}} */
        !           845: 
        !           846: /* {{{ static void php_output_context_dtor(php_output_context *context)
        !           847:  * Destroy the contents of an output context */
        !           848: static inline void php_output_context_dtor(php_output_context *context)
        !           849: {
        !           850:        if (context->in.free && context->in.data) {
        !           851:                efree(context->in.data);
        !           852:                context->in.data = NULL;
        !           853:        }
        !           854:        if (context->out.free && context->out.data) {
        !           855:                efree(context->out.data);
        !           856:                context->out.data = NULL;
1.1       misho     857:        }
                    858: }
                    859: /* }}} */
                    860: 
1.1.1.2 ! misho     861: /* {{{ static php_output_handler *php_output_handler_init(zval *name, size_t chunk_size, int flags TSRMLS_DC)
        !           862:  * Allocates and initializes a php_output_handler structure */
        !           863: static inline php_output_handler *php_output_handler_init(const char *name, size_t name_len, size_t chunk_size, int flags TSRMLS_DC)
        !           864: {
        !           865:        php_output_handler *handler;
1.1       misho     866: 
1.1.1.2 ! misho     867:        handler = ecalloc(1, sizeof(php_output_handler));
        !           868:        handler->name = estrndup(name, name_len);
        !           869:        handler->name_len = name_len;
        !           870:        handler->size = chunk_size;
        !           871:        handler->flags = flags;
        !           872:        handler->buffer.size = PHP_OUTPUT_HANDLER_INITBUF_SIZE(chunk_size);
        !           873:        handler->buffer.data = emalloc(handler->buffer.size);
        !           874: 
        !           875:        return handler;
        !           876: }
        !           877: /* }}} */
        !           878: 
        !           879: /* {{{ static int php_output_handler_appen(php_output_handler *handler, const php_output_buffer *buf TSRMLS_DC)
        !           880:  * Appends input to the output handlers buffer and indicates whether the buffer does not have to be processed by the output handler */
        !           881: static inline int php_output_handler_append(php_output_handler *handler, const php_output_buffer *buf TSRMLS_DC)
1.1       misho     882: {
1.1.1.2 ! misho     883:        if (buf->used) {
        !           884:                OG(flags) |= PHP_OUTPUT_WRITTEN;
        !           885:                /* store it away */
        !           886:                if ((handler->buffer.size - handler->buffer.used) <= buf->used) {
        !           887:                        size_t grow_int = PHP_OUTPUT_HANDLER_INITBUF_SIZE(handler->size);
        !           888:                        size_t grow_buf = PHP_OUTPUT_HANDLER_INITBUF_SIZE(buf->used - (handler->buffer.size - handler->buffer.used));
        !           889:                        size_t grow_max = MAX(grow_int, grow_buf);
        !           890: 
        !           891:                        handler->buffer.data = erealloc(handler->buffer.data, handler->buffer.size + grow_max);
        !           892:                        handler->buffer.size += grow_max;
        !           893:                }
        !           894:                memcpy(handler->buffer.data + handler->buffer.used, buf->data, buf->used);
        !           895:                handler->buffer.used += buf->used;
        !           896: 
        !           897:                /* chunked buffering */
        !           898:                if (handler->size && (handler->buffer.used >= handler->size)) {
        !           899:                        /* store away errors and/or any intermediate output */
        !           900:                        return OG(running) ? 1 : 0;
        !           901:                }
        !           902:        }
        !           903:        return 1;
1.1       misho     904: }
1.1.1.2 ! misho     905: /* }}} */
1.1       misho     906: 
1.1.1.2 ! misho     907: /* {{{ static php_output_handler_status_t php_output_handler_op(php_output_handler *handler, php_output_context *context)
        !           908:  * Output handler operation dispatcher, applying context op to the php_output_handler handler */
        !           909: static inline php_output_handler_status_t php_output_handler_op(php_output_handler *handler, php_output_context *context)
1.1       misho     910: {
1.1.1.2 ! misho     911:        php_output_handler_status_t status;
        !           912:        int original_op = context->op;
        !           913:        PHP_OUTPUT_TSRMLS(context);
1.1       misho     914: 
1.1.1.2 ! misho     915: #if PHP_OUTPUT_DEBUG
        !           916:        fprintf(stderr, ">>> op(%d, "
        !           917:                                        "handler=%p, "
        !           918:                                        "name=%s, "
        !           919:                                        "flags=%d, "
        !           920:                                        "buffer.data=%s, "
        !           921:                                        "buffer.used=%zu, "
        !           922:                                        "buffer.size=%zu, "
        !           923:                                        "in.data=%s, "
        !           924:                                        "in.used=%zu)\n",
        !           925:                        context->op,
        !           926:                        handler,
        !           927:                        handler->name,
        !           928:                        handler->flags,
        !           929:                        handler->buffer.used?handler->buffer.data:"",
        !           930:                        handler->buffer.used,
        !           931:                        handler->buffer.size,
        !           932:                        context->in.used?context->in.data:"",
        !           933:                        context->in.used
        !           934:        );
        !           935: #endif
        !           936: 
        !           937:        if (php_output_lock_error(context->op TSRMLS_CC)) {
        !           938:                /* fatal error */
        !           939:                return PHP_OUTPUT_HANDLER_FAILURE;
1.1       misho     940:        }
                    941: 
1.1.1.2 ! misho     942:        /* storable? */
        !           943:        if (php_output_handler_append(handler, &context->in TSRMLS_CC) && !context->op) {
        !           944:                context->op = original_op;
        !           945:                return PHP_OUTPUT_HANDLER_NO_DATA;
        !           946:        } else {
        !           947:                /* need to start? */
        !           948:                if (!(handler->flags & PHP_OUTPUT_HANDLER_STARTED)) {
        !           949:                        context->op |= PHP_OUTPUT_HANDLER_START;
        !           950:                }
        !           951: 
        !           952:                OG(running) = handler;
        !           953:                if (handler->flags & PHP_OUTPUT_HANDLER_USER) {
        !           954:                        zval *retval = NULL, *ob_data, *ob_mode;
        !           955: 
        !           956:                        MAKE_STD_ZVAL(ob_data);
        !           957:                        ZVAL_STRINGL(ob_data, handler->buffer.data, handler->buffer.used, 1);
        !           958:                        MAKE_STD_ZVAL(ob_mode);
        !           959:                        ZVAL_LONG(ob_mode, (long) context->op);
        !           960:                        zend_fcall_info_argn(&handler->func.user->fci TSRMLS_CC, 2, &ob_data, &ob_mode);
        !           961: 
        !           962: #define PHP_OUTPUT_USER_SUCCESS(retval) (retval && !(Z_TYPE_P(retval) == IS_BOOL && Z_BVAL_P(retval)==0))
        !           963:                        if (SUCCESS == zend_fcall_info_call(&handler->func.user->fci, &handler->func.user->fcc, &retval, NULL TSRMLS_CC) && PHP_OUTPUT_USER_SUCCESS(retval)) {
        !           964:                                /* user handler may have returned TRUE */
        !           965:                                status = PHP_OUTPUT_HANDLER_NO_DATA;
        !           966:                                if (Z_TYPE_P(retval) != IS_BOOL) {
        !           967:                                        convert_to_string_ex(&retval);
        !           968:                                        if (Z_STRLEN_P(retval)) {
        !           969:                                                context->out.data = estrndup(Z_STRVAL_P(retval), Z_STRLEN_P(retval));
        !           970:                                                context->out.used = Z_STRLEN_P(retval);
        !           971:                                                context->out.free = 1;
        !           972:                                                status = PHP_OUTPUT_HANDLER_SUCCESS;
        !           973:                                        }
        !           974:                                }
        !           975:                        } else {
        !           976:                                /* call failed, pass internal buffer along */
        !           977:                                status = PHP_OUTPUT_HANDLER_FAILURE;
        !           978:                        }
        !           979: 
        !           980:                        zend_fcall_info_argn(&handler->func.user->fci TSRMLS_CC, 0);
        !           981:                        zval_ptr_dtor(&ob_data);
        !           982:                        zval_ptr_dtor(&ob_mode);
        !           983:                        if (retval) {
        !           984:                                zval_ptr_dtor(&retval);
        !           985:                        }
        !           986: 
        !           987:                } else {
1.1       misho     988: 
1.1.1.2 ! misho     989:                        php_output_context_feed(context, handler->buffer.data, handler->buffer.size, handler->buffer.used, 0);
        !           990: 
        !           991:                        if (SUCCESS == handler->func.internal(&handler->opaq, context)) {
        !           992:                                if (context->out.used) {
        !           993:                                        status = PHP_OUTPUT_HANDLER_SUCCESS;
        !           994:                                } else {
        !           995:                                        status = PHP_OUTPUT_HANDLER_NO_DATA;
        !           996:                                }
        !           997:                        } else {
        !           998:                                status = PHP_OUTPUT_HANDLER_FAILURE;
        !           999:                        }
        !          1000:                }
        !          1001:                handler->flags |= PHP_OUTPUT_HANDLER_STARTED;
        !          1002:                OG(running) = NULL;
1.1       misho    1003:        }
                   1004: 
1.1.1.2 ! misho    1005:        switch (status) {
        !          1006:                case PHP_OUTPUT_HANDLER_FAILURE:
        !          1007:                        /* disable this handler */
        !          1008:                        handler->flags |= PHP_OUTPUT_HANDLER_DISABLED;
        !          1009:                        /* discard any output */
        !          1010:                        if (context->out.data && context->out.free) {
        !          1011:                                efree(context->out.data);
        !          1012:                        }
        !          1013:                        /* returns handlers buffer */
        !          1014:                        context->out.data = handler->buffer.data;
        !          1015:                        context->out.used = handler->buffer.used;
        !          1016:                        context->out.free = 1;
        !          1017:                        handler->buffer.data = NULL;
        !          1018:                        handler->buffer.used = 0;
        !          1019:                        handler->buffer.size = 0;
        !          1020:                        break;
        !          1021:                case PHP_OUTPUT_HANDLER_NO_DATA:
        !          1022:                        /* handler ate all */
        !          1023:                        php_output_context_reset(context);
        !          1024:                        /* no break */
        !          1025:                case PHP_OUTPUT_HANDLER_SUCCESS:
        !          1026:                        /* no more buffered data */
        !          1027:                        handler->buffer.used = 0;
        !          1028:                        break;
        !          1029:        }
        !          1030: 
        !          1031:        context->op = original_op;
        !          1032:        return status;
1.1       misho    1033: }
                   1034: /* }}} */
                   1035: 
                   1036: 
1.1.1.2 ! misho    1037: /* {{{ static void php_output_op(int op, const char *str, size_t len TSRMLS_DC)
        !          1038:  * Output op dispatcher, passes input and output handlers output through the output handler stack until it gets written to the SAPI */
        !          1039: static inline void php_output_op(int op, const char *str, size_t len TSRMLS_DC)
        !          1040: {
        !          1041:        php_output_context context;
        !          1042:        php_output_handler **active;
        !          1043:        int obh_cnt;
        !          1044: 
        !          1045:        if (php_output_lock_error(op TSRMLS_CC)) {
        !          1046:                return;
        !          1047:        }
        !          1048: 
        !          1049:        php_output_context_init(&context, op TSRMLS_CC);
        !          1050: 
        !          1051:        /*
        !          1052:         * broken up for better performance:
        !          1053:         *  - apply op to the one active handler; note that OG(active) might be popped off the stack on a flush
        !          1054:         *  - or apply op to the handler stack
        !          1055:         */
        !          1056:        if (OG(active) && (obh_cnt = zend_stack_count(&OG(handlers)))) {
        !          1057:                context.in.data = (char *) str;
        !          1058:                context.in.used = len;
        !          1059: 
        !          1060:                if (obh_cnt > 1) {
        !          1061:                        zend_stack_apply_with_argument(&OG(handlers), ZEND_STACK_APPLY_TOPDOWN, php_output_stack_apply_op, &context);
        !          1062:                } else if ((SUCCESS == zend_stack_top(&OG(handlers), (void *) &active)) && (!((*active)->flags & PHP_OUTPUT_HANDLER_DISABLED))) {
        !          1063:                        php_output_handler_op(*active, &context);
        !          1064:                } else {
        !          1065:                        php_output_context_pass(&context);
1.1       misho    1066:                }
1.1.1.2 ! misho    1067:        } else {
        !          1068:                context.out.data = (char *) str;
        !          1069:                context.out.used = len;
1.1       misho    1070:        }
1.1.1.2 ! misho    1071: 
        !          1072:        if (context.out.data && context.out.used) {
        !          1073:                php_output_header(TSRMLS_C);
        !          1074: 
        !          1075:                if (!(OG(flags) & PHP_OUTPUT_DISABLED)) {
        !          1076: #if PHP_OUTPUT_DEBUG
        !          1077:                        fprintf(stderr, "::: sapi_write('%s', %zu)\n", context.out.data, context.out.used);
        !          1078: #endif
        !          1079:                        sapi_module.ub_write(context.out.data, context.out.used TSRMLS_CC);
        !          1080: 
        !          1081:                        if (OG(flags) & PHP_OUTPUT_IMPLICITFLUSH) {
        !          1082:                                sapi_flush(TSRMLS_C);
        !          1083:                        }
        !          1084: 
        !          1085:                        OG(flags) |= PHP_OUTPUT_SENT;
1.1       misho    1086:                }
1.1.1.2 ! misho    1087:        }
        !          1088:        php_output_context_dtor(&context);
        !          1089: }
        !          1090: /* }}} */
        !          1091: 
        !          1092: /* {{{ static int php_output_stack_apply_op(void *h, void *c)
        !          1093:  * Operation callback for the stack apply function */
        !          1094: static int php_output_stack_apply_op(void *h, void *c)
        !          1095: {
        !          1096:        int was_disabled;
        !          1097:        php_output_handler_status_t status;
        !          1098:        php_output_handler *handler = *(php_output_handler **) h;
        !          1099:        php_output_context *context = (php_output_context *) c;
1.1       misho    1100: 
1.1.1.2 ! misho    1101:        if ((was_disabled = (handler->flags & PHP_OUTPUT_HANDLER_DISABLED))) {
        !          1102:                status = PHP_OUTPUT_HANDLER_FAILURE;
        !          1103:        } else {
        !          1104:                status = php_output_handler_op(handler, context);
1.1       misho    1105:        }
                   1106: 
1.1.1.2 ! misho    1107:        /*
        !          1108:         * handler ate all => break
        !          1109:         * handler returned data or failed resp. is disabled => continue
        !          1110:         */
        !          1111:        switch (status) {
        !          1112:                case PHP_OUTPUT_HANDLER_NO_DATA:
        !          1113:                        return 1;
        !          1114: 
        !          1115:                case PHP_OUTPUT_HANDLER_SUCCESS:
        !          1116:                        /* swap contexts buffers, unless this is the last handler in the stack */
        !          1117:                        if (handler->level) {
        !          1118:                                php_output_context_swap(context);
        !          1119:                        }
        !          1120:                        return 0;
        !          1121: 
        !          1122:                case PHP_OUTPUT_HANDLER_FAILURE:
        !          1123:                default:
        !          1124:                        if (was_disabled) {
        !          1125:                                /* pass input along, if it's the last handler in the stack */
        !          1126:                                if (!handler->level) {
        !          1127:                                        php_output_context_pass(context);
        !          1128:                                }
        !          1129:                        } else {
        !          1130:                                /* swap buffers, unless this is the last handler */
        !          1131:                                if (handler->level) {
        !          1132:                                        php_output_context_swap(context);
        !          1133:                                }
        !          1134:                        }
        !          1135:                        return 0;
        !          1136:        }
1.1       misho    1137: }
                   1138: /* }}} */
                   1139: 
1.1.1.2 ! misho    1140: /* {{{ static int php_output_stack_apply_clean(void *h, void *c)
        !          1141:  * Clean callback for the stack apply function */
        !          1142: static int php_output_stack_apply_clean(void *h, void *c)
        !          1143: {
        !          1144:        php_output_handler *handler = *(php_output_handler **) h;
        !          1145:        php_output_context *context = (php_output_context *) c;
        !          1146: 
        !          1147:        handler->buffer.used = 0;
        !          1148:        php_output_handler_op(handler, context);
        !          1149:        php_output_context_reset(context);
        !          1150:        return 0;
        !          1151: }
        !          1152: /* }}} */
        !          1153: 
        !          1154: /* {{{ static int php_output_stack_apply_list(void *h, void *z)
        !          1155:  * List callback for the stack apply function */
        !          1156: static int php_output_stack_apply_list(void *h, void *z)
        !          1157: {
        !          1158:        php_output_handler *handler = *(php_output_handler **) h;
        !          1159:        zval *array = (zval *) z;
        !          1160: 
        !          1161:        add_next_index_stringl(array, handler->name, handler->name_len, 1);
        !          1162:        return 0;
        !          1163: }
        !          1164: /* }}} */
        !          1165: 
        !          1166: /* {{{ static int php_output_stack_apply_status(void *h, void *z)
        !          1167:  * Status callback for the stack apply function */
        !          1168: static int php_output_stack_apply_status(void *h, void *z)
1.1       misho    1169: {
1.1.1.2 ! misho    1170:        php_output_handler *handler = *(php_output_handler **) h;
        !          1171:        zval *array = (zval *) z;
        !          1172: 
        !          1173:        add_next_index_zval(array, php_output_handler_status(handler, NULL));
1.1       misho    1174: 
1.1.1.2 ! misho    1175:        return 0;
        !          1176: }
1.1       misho    1177: 
1.1.1.2 ! misho    1178: /* {{{ static zval *php_output_handler_status(php_output_handler *handler, zval *entry)
        !          1179:  * Returns an array with the status of the output handler */
        !          1180: static inline zval *php_output_handler_status(php_output_handler *handler, zval *entry)
        !          1181: {
        !          1182:        if (!entry) {
        !          1183:                MAKE_STD_ZVAL(entry);
        !          1184:                array_init(entry);
1.1       misho    1185:        }
1.1.1.2 ! misho    1186: 
        !          1187:        add_assoc_stringl(entry, "name", handler->name, handler->name_len, 1);
        !          1188:        add_assoc_long(entry, "type", (long) (handler->flags & 0xf));
        !          1189:        add_assoc_long(entry, "flags", (long) handler->flags);
        !          1190:        add_assoc_long(entry, "level", (long) handler->level);
        !          1191:        add_assoc_long(entry, "chunk_size", (long) handler->size);
        !          1192:        add_assoc_long(entry, "buffer_size", (long) handler->buffer.size);
        !          1193:        add_assoc_long(entry, "buffer_used", (long) handler->buffer.used);
        !          1194: 
        !          1195:        return entry;
        !          1196: }
        !          1197: /* }}} */
        !          1198: 
        !          1199: /* {{{ static int php_output_stack_pop(int flags TSRMLS_DC)
        !          1200:  * Pops an output handler off the stack */
        !          1201: static inline int php_output_stack_pop(int flags TSRMLS_DC)
        !          1202: {
        !          1203:        php_output_context context;
        !          1204:        php_output_handler **current, *orphan = OG(active);
        !          1205: 
        !          1206:        if (!orphan) {
        !          1207:                if (!(flags & PHP_OUTPUT_POP_SILENT)) {
        !          1208:                        php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to %s buffer. No buffer to %s", (flags&PHP_OUTPUT_POP_DISCARD)?"discard":"send", (flags&PHP_OUTPUT_POP_DISCARD)?"discard":"send");
        !          1209:                }
        !          1210:                return 0;
        !          1211:        } else if (!(flags & PHP_OUTPUT_POP_FORCE) && !(orphan->flags & PHP_OUTPUT_HANDLER_REMOVABLE)) {
        !          1212:                if (!(flags & PHP_OUTPUT_POP_SILENT)) {
        !          1213:                        php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to %s buffer of %s (%d)", (flags&PHP_OUTPUT_POP_DISCARD)?"discard":"send", orphan->name, orphan->level);
        !          1214:                }
        !          1215:                return 0;
1.1       misho    1216:        } else {
1.1.1.2 ! misho    1217:                php_output_context_init(&context, PHP_OUTPUT_HANDLER_FINAL TSRMLS_CC);
        !          1218: 
        !          1219:                /* don't run the output handler if it's disabled */
        !          1220:                if (!(orphan->flags & PHP_OUTPUT_HANDLER_DISABLED)) {
        !          1221:                        /* didn't it start yet? */
        !          1222:                        if (!(orphan->flags & PHP_OUTPUT_HANDLER_STARTED)) {
        !          1223:                                context.op |= PHP_OUTPUT_HANDLER_START;
        !          1224:                        }
        !          1225:                        /* signal that we're cleaning up */
        !          1226:                        if (flags & PHP_OUTPUT_POP_DISCARD) {
        !          1227:                                context.op |= PHP_OUTPUT_HANDLER_CLEAN;
        !          1228:                                orphan->buffer.used = 0;
        !          1229:                        }
        !          1230:                        php_output_handler_op(orphan, &context);
        !          1231:                }
        !          1232: 
        !          1233:                /* pop it off the stack */
        !          1234:                zend_stack_del_top(&OG(handlers));
        !          1235:                if (SUCCESS == zend_stack_top(&OG(handlers), (void *) &current)) {
        !          1236:                        OG(active) = *current;
        !          1237:                } else {
        !          1238:                        OG(active) = NULL;
        !          1239:                }
        !          1240: 
        !          1241:                /* pass output along */
        !          1242:                if (context.out.data && context.out.used && !(flags & PHP_OUTPUT_POP_DISCARD)) {
        !          1243:                        php_output_write(context.out.data, context.out.used TSRMLS_CC);
        !          1244:                }
        !          1245: 
        !          1246:                /* destroy the handler (after write!) */
        !          1247:                php_output_handler_free(&orphan TSRMLS_CC);
        !          1248:                php_output_context_dtor(&context);
        !          1249: 
        !          1250:                return 1;
        !          1251:        }
        !          1252: }
        !          1253: /* }}} */
        !          1254: 
        !          1255: /* {{{ static SUCCESS|FAILURE php_output_handler_compat_func(void *ctx, php_output_context *)
        !          1256:  * php_output_handler_context_func_t for php_output_handler_func_t output handlers */
        !          1257: static int php_output_handler_compat_func(void **handler_context, php_output_context *output_context)
        !          1258: {
        !          1259:        php_output_handler_func_t func = *(php_output_handler_func_t *) handler_context;
        !          1260:        PHP_OUTPUT_TSRMLS(output_context);
        !          1261: 
        !          1262:        if (func) {
        !          1263:                char *out_str = NULL;
        !          1264:                uint out_len = 0;
        !          1265: 
        !          1266:                func(output_context->in.data, output_context->in.used, &out_str, &out_len, output_context->op TSRMLS_CC);
        !          1267: 
        !          1268:                if (out_str) {
        !          1269:                        output_context->out.data = out_str;
        !          1270:                        output_context->out.used = out_len;
        !          1271:                        output_context->out.free = 1;
        !          1272:                } else {
        !          1273:                        php_output_context_pass(output_context);
        !          1274:                }
        !          1275: 
        !          1276:                return SUCCESS;
1.1       misho    1277:        }
1.1.1.2 ! misho    1278:        return FAILURE;
        !          1279: }
        !          1280: /* }}} */
        !          1281: 
        !          1282: /* {{{ static SUCCESS|FAILURE php_output_handler_default_func(void *ctx, php_output_context *)
        !          1283:  * Default output handler */
        !          1284: static int php_output_handler_default_func(void **handler_context, php_output_context *output_context)
        !          1285: {
        !          1286:        php_output_context_pass(output_context);
        !          1287:        return SUCCESS;
        !          1288: }
        !          1289: /* }}} */
1.1       misho    1290: 
1.1.1.2 ! misho    1291: /* {{{ static SUCCESS|FAILURE php_output_handler_devnull_func(void *ctx, php_output_context *)
        !          1292:  * Null output handler */
        !          1293: static int php_output_handler_devnull_func(void **handler_context, php_output_context *output_context)
        !          1294: {
1.1       misho    1295:        return SUCCESS;
                   1296: }
                   1297: /* }}} */
                   1298: 
                   1299: /*
                   1300:  * USERLAND (nearly 1:1 of old output.c)
                   1301:  */
                   1302: 
1.1.1.2 ! misho    1303: /* {{{ proto bool ob_start([string|array user_function [, int chunk_size [, int flags]]])
1.1       misho    1304:    Turn on Output Buffering (specifying an optional output handler). */
                   1305: PHP_FUNCTION(ob_start)
                   1306: {
                   1307:        zval *output_handler = NULL;
                   1308:        long chunk_size = 0;
1.1.1.2 ! misho    1309:        long flags = PHP_OUTPUT_HANDLER_STDFLAGS;
1.1       misho    1310: 
1.1.1.2 ! misho    1311:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z/ll", &output_handler, &chunk_size, &flags) == FAILURE) {
1.1       misho    1312:                return;
                   1313:        }
                   1314: 
                   1315:        if (chunk_size < 0) {
                   1316:                chunk_size = 0;
                   1317:        }
                   1318: 
1.1.1.2 ! misho    1319:        if (php_output_start_user(output_handler, chunk_size, flags TSRMLS_CC) == FAILURE) {
        !          1320:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to create buffer");
1.1       misho    1321:                RETURN_FALSE;
                   1322:        }
                   1323:        RETURN_TRUE;
                   1324: }
                   1325: /* }}} */
                   1326: 
                   1327: /* {{{ proto bool ob_flush(void)
                   1328:    Flush (send) contents of the output buffer. The last buffer content is sent to next buffer */
                   1329: PHP_FUNCTION(ob_flush)
                   1330: {
                   1331:        if (zend_parse_parameters_none() == FAILURE) {
                   1332:                return;
                   1333:        }
                   1334: 
1.1.1.2 ! misho    1335:        if (!OG(active)) {
1.1       misho    1336:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to flush buffer. No buffer to flush");
                   1337:                RETURN_FALSE;
                   1338:        }
                   1339: 
1.1.1.2 ! misho    1340:        if (SUCCESS != php_output_flush(TSRMLS_C)) {
        !          1341:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to flush buffer of %s (%d)", OG(active)->name, OG(active)->level);
1.1       misho    1342:                RETURN_FALSE;
                   1343:        }
                   1344:        RETURN_TRUE;
                   1345: }
                   1346: /* }}} */
                   1347: 
                   1348: /* {{{ proto bool ob_clean(void)
                   1349:    Clean (delete) the current output buffer */
                   1350: PHP_FUNCTION(ob_clean)
                   1351: {
                   1352:        if (zend_parse_parameters_none() == FAILURE) {
                   1353:                return;
                   1354:        }
                   1355: 
1.1.1.2 ! misho    1356:        if (!OG(active)) {
1.1       misho    1357:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
                   1358:                RETURN_FALSE;
                   1359:        }
                   1360: 
1.1.1.2 ! misho    1361:        if (SUCCESS != php_output_clean(TSRMLS_C)) {
        !          1362:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer of %s (%d)", OG(active)->name, OG(active)->level);
1.1       misho    1363:                RETURN_FALSE;
                   1364:        }
                   1365:        RETURN_TRUE;
                   1366: }
                   1367: /* }}} */
                   1368: 
                   1369: /* {{{ proto bool ob_end_flush(void)
                   1370:    Flush (send) the output buffer, and delete current output buffer */
                   1371: PHP_FUNCTION(ob_end_flush)
                   1372: {
                   1373:        if (zend_parse_parameters_none() == FAILURE) {
                   1374:                return;
                   1375:        }
                   1376: 
1.1.1.2 ! misho    1377:        if (!OG(active)) {
1.1       misho    1378:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush");
                   1379:                RETURN_FALSE;
                   1380:        }
                   1381: 
1.1.1.2 ! misho    1382:        RETURN_BOOL(SUCCESS == php_output_end(TSRMLS_C));
1.1       misho    1383: }
                   1384: /* }}} */
                   1385: 
                   1386: /* {{{ proto bool ob_end_clean(void)
                   1387:    Clean the output buffer, and delete current output buffer */
                   1388: PHP_FUNCTION(ob_end_clean)
                   1389: {
                   1390:        if (zend_parse_parameters_none() == FAILURE) {
                   1391:                return;
                   1392:        }
                   1393: 
1.1.1.2 ! misho    1394:        if (!OG(active)) {
1.1       misho    1395:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
                   1396:                RETURN_FALSE;
                   1397:        }
                   1398: 
1.1.1.2 ! misho    1399:        RETURN_BOOL(SUCCESS == php_output_discard(TSRMLS_C));
1.1       misho    1400: }
                   1401: /* }}} */
                   1402: 
                   1403: /* {{{ proto bool ob_get_flush(void)
                   1404:    Get current buffer contents, flush (send) the output buffer, and delete current output buffer */
                   1405: PHP_FUNCTION(ob_get_flush)
                   1406: {
                   1407:        if (zend_parse_parameters_none() == FAILURE) {
                   1408:                return;
                   1409:        }
                   1410: 
1.1.1.2 ! misho    1411:        if (php_output_get_contents(return_value TSRMLS_CC) == FAILURE) {
1.1       misho    1412:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush");
                   1413:                RETURN_FALSE;
                   1414:        }
                   1415: 
1.1.1.2 ! misho    1416:        if (SUCCESS != php_output_end(TSRMLS_C)) {
        !          1417:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer of %s (%d)", OG(active)->name, OG(active)->level);
1.1       misho    1418:        }
                   1419: }
                   1420: /* }}} */
                   1421: 
                   1422: /* {{{ proto bool ob_get_clean(void)
                   1423:    Get current buffer contents and delete current output buffer */
                   1424: PHP_FUNCTION(ob_get_clean)
                   1425: {
                   1426:        if (zend_parse_parameters_none() == FAILURE) {
                   1427:                return;
                   1428:        }
                   1429: 
1.1.1.2 ! misho    1430:        if(!OG(active)) {
1.1       misho    1431:                RETURN_FALSE;
                   1432:        }
                   1433: 
1.1.1.2 ! misho    1434:        if (php_output_get_contents(return_value TSRMLS_CC) == FAILURE) {
1.1       misho    1435:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete");
                   1436:                RETURN_FALSE;
                   1437:        }
                   1438: 
1.1.1.2 ! misho    1439:        if (SUCCESS != php_output_discard(TSRMLS_C)) {
        !          1440:                php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer of %s (%d)", OG(active)->name, OG(active)->level);
        !          1441:        }
1.1       misho    1442: }
                   1443: /* }}} */
                   1444: 
                   1445: /* {{{ proto string ob_get_contents(void)
                   1446:    Return the contents of the output buffer */
                   1447: PHP_FUNCTION(ob_get_contents)
                   1448: {
                   1449:        if (zend_parse_parameters_none() == FAILURE) {
                   1450:                return;
                   1451:        }
                   1452: 
1.1.1.2 ! misho    1453:        if (php_output_get_contents(return_value TSRMLS_CC) == FAILURE) {
1.1       misho    1454:                RETURN_FALSE;
                   1455:        }
                   1456: }
                   1457: /* }}} */
                   1458: 
                   1459: /* {{{ proto int ob_get_level(void)
                   1460:    Return the nesting level of the output buffer */
                   1461: PHP_FUNCTION(ob_get_level)
                   1462: {
                   1463:        if (zend_parse_parameters_none() == FAILURE) {
                   1464:                return;
                   1465:        }
                   1466: 
1.1.1.2 ! misho    1467:        RETURN_LONG(php_output_get_level(TSRMLS_C));
1.1       misho    1468: }
                   1469: /* }}} */
                   1470: 
                   1471: /* {{{ proto int ob_get_length(void)
                   1472:    Return the length of the output buffer */
                   1473: PHP_FUNCTION(ob_get_length)
                   1474: {
                   1475:        if (zend_parse_parameters_none() == FAILURE) {
                   1476:                return;
                   1477:        }
                   1478: 
1.1.1.2 ! misho    1479:        if (php_output_get_length(return_value TSRMLS_CC) == FAILURE) {
1.1       misho    1480:                RETURN_FALSE;
                   1481:        }
                   1482: }
                   1483: /* }}} */
                   1484: 
                   1485: /* {{{ proto false|array ob_list_handlers()
                   1486:    List all output_buffers in an array */
                   1487: PHP_FUNCTION(ob_list_handlers)
                   1488: {
                   1489:        if (zend_parse_parameters_none() == FAILURE) {
                   1490:                return;
                   1491:        }
                   1492: 
                   1493:        array_init(return_value);
                   1494: 
1.1.1.2 ! misho    1495:        if (!OG(active)) {
        !          1496:                return;
1.1       misho    1497:        }
1.1.1.2 ! misho    1498: 
        !          1499:        zend_stack_apply_with_argument(&OG(handlers), ZEND_STACK_APPLY_BOTTOMUP, php_output_stack_apply_list, return_value);
1.1       misho    1500: }
                   1501: /* }}} */
                   1502: 
                   1503: /* {{{ proto false|array ob_get_status([bool full_status])
                   1504:    Return the status of the active or all output buffers */
                   1505: PHP_FUNCTION(ob_get_status)
                   1506: {
                   1507:        zend_bool full_status = 0;
                   1508: 
                   1509:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &full_status) == FAILURE) {
                   1510:                return;
                   1511:        }
                   1512: 
                   1513:        array_init(return_value);
                   1514: 
1.1.1.2 ! misho    1515:        if (!OG(active)) {
        !          1516:                return;
        !          1517:        }
        !          1518: 
1.1       misho    1519:        if (full_status) {
1.1.1.2 ! misho    1520:                zend_stack_apply_with_argument(&OG(handlers), ZEND_STACK_APPLY_BOTTOMUP, php_output_stack_apply_status, return_value);
        !          1521:        } else {
        !          1522:                php_output_handler_status(OG(active), return_value);
1.1       misho    1523:        }
                   1524: }
                   1525: /* }}} */
                   1526: 
                   1527: /* {{{ proto void ob_implicit_flush([int flag])
                   1528:    Turn implicit flush on/off and is equivalent to calling flush() after every output call */
                   1529: PHP_FUNCTION(ob_implicit_flush)
                   1530: {
                   1531:        long flag = 1;
                   1532: 
                   1533:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flag) == FAILURE) {
                   1534:                return;
                   1535:        }
                   1536: 
1.1.1.2 ! misho    1537:        php_output_set_implicit_flush(flag TSRMLS_CC);
1.1       misho    1538: }
                   1539: /* }}} */
                   1540: 
                   1541: /* {{{ proto bool output_reset_rewrite_vars(void)
                   1542:    Reset(clear) URL rewriter values */
                   1543: PHP_FUNCTION(output_reset_rewrite_vars)
                   1544: {
                   1545:        if (php_url_scanner_reset_vars(TSRMLS_C) == SUCCESS) {
                   1546:                RETURN_TRUE;
                   1547:        } else {
                   1548:                RETURN_FALSE;
                   1549:        }
                   1550: }
                   1551: /* }}} */
                   1552: 
                   1553: /* {{{ proto bool output_add_rewrite_var(string name, string value)
                   1554:    Add URL rewriter values */
                   1555: PHP_FUNCTION(output_add_rewrite_var)
                   1556: {
                   1557:        char *name, *value;
                   1558:        int name_len, value_len;
                   1559: 
                   1560:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &name, &name_len, &value, &value_len) == FAILURE) {
                   1561:                return;
                   1562:        }
                   1563: 
                   1564:        if (php_url_scanner_add_var(name, name_len, value, value_len, 1 TSRMLS_CC) == SUCCESS) {
                   1565:                RETURN_TRUE;
                   1566:        } else {
                   1567:                RETURN_FALSE;
                   1568:        }
                   1569: }
                   1570: /* }}} */
                   1571: 
                   1572: /*
                   1573:  * Local variables:
                   1574:  * tab-width: 4
                   1575:  * c-basic-offset: 4
                   1576:  * End:
                   1577:  * vim600: sw=4 ts=4 fdm=marker
                   1578:  * vim<600: sw=4 ts=4
                   1579:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>