00001 /* Part of the culibs project, <http://www.eideticdew.org/culibs/>. 00002 * Copyright (C) 2007 Petter Urkedal <urkedal@nbi.dk> 00003 * 00004 * This program is free software: you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation, either version 3 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00016 */ 00017 00018 #ifndef CU_DSINK_H 00019 #define CU_DSINK_H 00020 00021 #include <cu/buffer.h> 00022 #include <stdarg.h> 00023 00024 CU_BEGIN_DECLARATIONS 00025 /*!\defgroup cu_dsink_h cu/dsink.h: Generic Data Sink 00026 *@{\ingroup cu_seq_mod 00027 * 00028 * This header provides a data structure with callbacks for defining <i>data 00029 * sinks</i> which are consumers of arbitrary byte streams. 00030 * 00031 * A data sink is said to be <i>clog-free</i> if it's write-callback is 00032 * guaranteed to always cosume all data provided to it. Data sinks derived 00033 * form \ref cu_dsink may or may not be clog-free. This property may be 00034 * essential to some callers, and since this is not checked at compile time, 00035 * it's recommendable that 00036 * <ul> 00037 * <li>It's documentet whether a returned sink is guaranteed to be clog-free. 00038 * <li>It's documentet whether a function sink-parameter is required to be 00039 * clog-free. 00040 * <li>When a clog-free stream is expected, this is verified at run-time by a 00041 * call to \ref cu_dsink_assert_clogfree. 00042 * </ul> 00043 * Any buffer can be turned into a clog-free buffer by stacking a buffer on top 00044 * of it, as done by \ref cu_dsink_stack_buffer. 00045 */ 00046 00047 /* Use odd function codes where flushing any buffered data is required prior to 00048 * passing the control down to sub-sinks, even otherwise. */ 00049 00050 /*!\name Function Codes 00051 * @{*/ 00052 /*!Function code for \ref cu_dsink_is_clogfree, also used by \ref 00053 * cu_dsink_assert_clogfree. If the sink is guaranteed to be clog-free, the 00054 * control dispatcher shall indicate this by returning \ref CU_DSINK_ST_SUCCESS 00055 * as response, otherwise this control need not be implemented. */ 00056 #define CU_DSINK_FN_IS_CLOGFREE 0 00057 00058 #define CU_DSINK_FN_FLUSH 1 00059 /*!< Function code for \ref cu_dsink_flush. */ 00060 #define CU_DSINK_FN_DISCARD 2 00061 /*!< Function code for \ref cu_dsink_discard. */ 00062 #define CU_DSINK_FN_FINISH 3 00063 /*!< Function code for \ref cu_dsink_finish. */ 00064 #define CU_DSINK_FN_DEBUG_DUMP 4 00065 /*!@}*/ 00066 00067 /*!\name Function Exit Codes 00068 * @{*/ 00069 #define CU_DSINK_ST_UNIMPL ((cu_word_t)-3) 00070 /*!< Status returned by control dispatcher when the requested function is 00071 * not implemented. */ 00072 #define CU_DSINK_ST_FAILURE ((cu_word_t)-1) 00073 #define CU_DSINK_ST_SUCCESS 0 00074 /*!< Status which may be returned by a dispatches on successful return when 00075 * no other value is to be returned. */ 00076 /*!@}*/ 00077 00078 /*!\name Sink API 00079 * @{*/ 00080 00081 /*!Base struct for data sinks. */ 00082 struct cu_dsink 00083 { 00084 cu_word_t (*control)(cu_dsink_t source, int op, va_list); 00085 size_t (*write)(cu_dsink_t sink, void const *buf, size_t max_size); 00086 }; 00087 00088 /*!Initialise \a sink with callbacks \a control and \a data. \a control is a C 00089 * function which integrates a set of control functions, and \a write is 00090 * callback which receives data written to \a sink. */ 00091 CU_SINLINE void 00092 cu_dsink_init(cu_dsink_t sink, 00093 cu_word_t (*control)(cu_dsink_t, int, va_list), 00094 size_t (*write)(cu_dsink_t, void const *, size_t)) 00095 { 00096 sink->control = control; 00097 sink->write = write; 00098 } 00099 00100 /*!Tries to write up to \a max_size bytes starting at \a buf to the sink, and 00101 * returns the number of bytes actually consumed. If the sink is clog-free, \a 00102 * max_size is returned. */ 00103 CU_SINLINE size_t 00104 cu_dsink_write(cu_dsink_t sink, void const *buf, size_t max_size) 00105 { 00106 return (*sink->write)(sink, buf, max_size); 00107 } 00108 00109 /*!Call the control function \a fn on \a sink with any additional arguments 00110 * wrapped in \a va. */ 00111 CU_SINLINE cu_word_t 00112 cu_dsink_control_va(cu_dsink_t sink, int fn, va_list va) 00113 { 00114 return (*sink->control)(sink, fn, va); 00115 } 00116 00117 /*!Call the control function \a fn on \a sink possibly with additional 00118 * arguments. See the specific control functions below for a safer 00119 * interface. */ 00120 cu_word_t cu_dsink_control(cu_dsink_t sink, int fn, ...); 00121 00122 /*!True if \a sink is clog-free, as reported by the \ref 00123 * CU_DSINK_FN_IS_CLOGFREE response. */ 00124 CU_SINLINE cu_bool_t cu_dsink_is_clogfree(cu_dsink_t sink) 00125 { return cu_dsink_control(sink, CU_DSINK_FN_IS_CLOGFREE) 00126 == CU_DSINK_ST_SUCCESS; } 00127 00128 /*!Control function to check that \a sink is clog-free. It is recommended to 00129 * call this once before starting to write to a sink where a clog-free sink is 00130 * required for correct operation. */ 00131 void cu_dsink_assert_clogfree(cu_dsink_t sink); 00132 00133 /*!Attempt to write any buffered data and pass down the flush request to 00134 * sub-sinks. */ 00135 CU_SINLINE void 00136 cu_dsink_flush(cu_dsink_t sink) 00137 { cu_dsink_control(sink, CU_DSINK_FN_FLUSH); } 00138 00139 /*!Inform \a sink that no more data will be written. This implies flushing 00140 * any buffered data and closing resources. Some sinks may return constructed 00141 * data. */ 00142 CU_SINLINE void * 00143 cu_dsink_finish(cu_dsink_t sink) 00144 { return (void *)cu_dsink_control(sink, CU_DSINK_FN_FINISH); } 00145 00146 /*!Inform \a sink that no more data will be written, and that the operation is 00147 * considered failed. This means any buffered data may be discarded and 00148 * resources closed. Operations on external resources such as file creation or 00149 * database updates, may or may not be reverted. */ 00150 CU_SINLINE void 00151 cu_dsink_discard(cu_dsink_t sink) 00152 { cu_dsink_control(sink, CU_DSINK_FN_DISCARD); } 00153 00154 /*!@}*/ 00155 /*!\name Sink Implementations 00156 * @{*/ 00157 00158 /*!Creates a clog-free sink of \a subsink by buffering data. */ 00159 cu_dsink_t cu_dsink_stack_buffer(cu_dsink_t subsink); 00160 00161 /*!Returns a sink on which the call to \ref cu_dsink_finish returns a \ref 00162 * cu_str_h "cu_str_t" of the written data. No conversion is done. Writing 00163 * UTF-8 encoded data gives a text string. */ 00164 cu_dsink_t cu_dsink_new_str(void); 00165 00166 /*!Returns a sink on which the call to \ref cu_dsink_finish returns a \ref 00167 * cu_wstring_h "cu_wstring_t" of the written data. No conversion is done. 00168 * Writing \ref cu_wchar_encoding encoded characters gives a text string. */ 00169 cu_dsink_t cu_dsink_new_wstring(void); 00170 00171 /*!A sink which counts the number of bytes written. */ 00172 struct cu_dcountsink 00173 { 00174 cu_inherit (cu_dsink); 00175 size_t count; 00176 }; 00177 00178 CU_SINLINE cu_dsink_t 00179 cu_dcountsink_to_dsink(cu_dcountsink_t sink) 00180 { return cu_to(cu_dsink, sink); } 00181 00182 /*!Initialise \a sink. */ 00183 void cu_dcountsink_init(cu_dcountsink_t sink); 00184 00185 /*!Returns the number of bytes written to \a sink. */ 00186 CU_SINLINE size_t 00187 cu_dcountsink_count(cu_dcountsink_t sink) 00188 { return sink->count; } 00189 00190 /*!A sink which copy the data written into a buffer. */ 00191 struct cu_dbufsink 00192 { 00193 cu_inherit (cu_dsink); 00194 struct cu_buffer buffer; 00195 }; 00196 00197 CU_SINLINE cu_dsink_t 00198 cu_dbufsink_to_dsink(cu_dbufsink_t sink) 00199 { return cu_to(cu_dsink, sink); } 00200 00201 /*!Initialise the buffer sink \a sink. */ 00202 void cu_dbufsink_init(cu_dbufsink_t sink); 00203 00204 /*!The underlying buffer of \a sink. */ 00205 CU_SINLINE cu_buffer_t 00206 cu_dbufsink_buffer(cu_dbufsink_t sink) 00207 { return &sink->buffer; } 00208 00209 /*!@}*/ 00210 /*!@}*/ 00211 CU_END_DECLARATIONS 00212 00213 #endif