/* Copyright (c) 2000-2010, Dirk Krause All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Dirk Krause nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file dkstream.c Stream I/O module. */ #include "dk.h" #include "dkmem.h" #include "dktypes.h" #include "dkstr.h" #include "dksf.h" #include "dkenc.h" #if DK_HAVE_ZLIB_H #include #endif #if DK_HAVE_BZLIB_H #include #endif /** Inside the dkstream module. */ #define DK_STREAM_C 1 #include "dkstream.h" $(trace-include) #include /** Newline. */ static char str_nl[] = { "\n" }; dk_stream_t * dkstream_new DK_P2(void *, data, dk_stream_fct_t *, fct) { dk_stream_t *back = NULL; $? "+ dkstream_new %s %s", TR_PTR(data), TR_PTR(fct) if(data && fct) { $? ". args ok" back = dk_new(dk_stream_t,1); $? ". dk_new %s", TR_PTR(back) if(back) { back->data = data; back->fct = fct; (back->api).strm = (void *)back; back->bytes = 0UL; back->flags = 0; back->opt = 0; } } $? "- dkstream_new %s", TR_PTR(back) return back; } size_t dkstream_write DK_P3(dk_stream_t *, st, char *, b, size_t, l) { size_t back = 0; unsigned long size_to_add; dk_stream_fct_t *f; void *d; dk_stream_api_t *a; $? "+ dkstream_write %s %s %lu", TR_PTR(st), TR_PTR(b), (unsigned long)l if(st && b && l) { $? ". arguments ok" d = st->data; f = st->fct; a = &(st->api); if(d && f) { $? ". stream setup ok" a->cmd = DK_STREAM_CMD_WRBUF; (a->params).buffer = b; (a->params).length = l; (a->results).buffer = b; (a->results).length = l; (*f)(a); $? ". low level function executed, result=%d", a->return_value if(a->return_value) { $? ". bytes written %lu", (a->results).used back = (a->results).used; size_to_add = (unsigned long)back; st->bytes = st->bytes + size_to_add; } } } $? "- dkstream_write %lu", (unsigned long)back return back; } size_t dkstream_read DK_P3(dk_stream_t *, st, char *, b, size_t, l) { size_t back = 0; dk_stream_fct_t *f; void *d; dk_stream_api_t *a; $? "+ dkstream_read %s %s %u", TR_PTR(st), TR_PTR(b), l if(st && b && l) { $? ". arguments ok" d = st->data; f = st->fct; a = &(st->api); if(d && f) { $? ". stream setup ok" a->cmd = DK_STREAM_CMD_RDBUF; (a->params).buffer = b; (a->params).length = l; (a->results).buffer = b; (a->results).length = l; (*f)(a); $? ". low level function returned %d", a->return_value if(a->return_value) { $? ". bytes read %u", (a->results).used back = (a->results).used; } else { a->cmd = DK_STREAM_CMD_TEST; (a->params).cmd = DK_STREAM_CMD_AT_END; (*f)(a); if(a->return_value) { a->cmd = DK_STREAM_CMD_AT_END; (*f)(a); if(a->return_value) { st->flags |= 1; } } } } } $? "- dkstream_read %u", back return back; } void dkstream_delete DK_P1(dk_stream_t *, st) { dk_stream_api_t *a; dk_stream_fct_t *f; $? "+ dkstream_delete %s", TR_PTR(st) if(st) { if((st->data) && (st->fct)) { a = &(st->api); f = st->fct; a->cmd = DK_STREAM_CMD_FINAL; (*f)(a); } st->data = NULL; st->fct = NULL; (st->api).strm = NULL; $? ". going to free memory" dk_delete(st); } $? "- dkstream_delete" } /** Low-level function for uncompressed streams, closing. @param a Stream API structure. */ void file_stream_fct DK_P1(dk_stream_api_t *, a) { dk_stream_t *s; void *d; FILE *f; char *b; size_t l, x; $? "+ file_stream_fct %s", TR_PTR(a) if(a) { $? ". API pointer ok" a->return_value = 0; s = (dk_stream_t *)(a->strm); if(s) { $? ". stream pointer ok" d = s->data; f = (FILE *)d; if(f) { $? ". FILE* ok" switch(a->cmd) { case DK_STREAM_CMD_TEST: { switch( (a->params).cmd ) { case DK_STREAM_CMD_TEST: a->return_value = 1; break; case DK_STREAM_CMD_AT_END: a->return_value = 1; break; case DK_STREAM_CMD_RDBUF: a->return_value = 1; break; case DK_STREAM_CMD_WRBUF: a->return_value = 1; break; case DK_STREAM_CMD_FINAL: a->return_value = 1; break; case DK_STREAM_CMD_FINISH: a->return_value = 1; break; case DK_STREAM_CMD_REWIND: a->return_value = 1; break; case DK_STREAM_CMD_FLUSH: a->return_value = 1; break; case DK_STREAM_CMD_GETS: a->return_value = 1; break; /* Bugfix 2005/01/05 On some systems the fputs() function returns the number of bytes successfully written, on other systems it returns 0 to indicate success. So we can not use it. */ case DK_STREAM_CMD_PUTS: a->return_value = 0; break; } } break; case DK_STREAM_CMD_GETS: { b = (a->params).buffer; l = (a->params).length; if(b && l) { $? ". buffer and length ok" if(fgets(b,l,f)) { a->return_value = 1; } } } break; case DK_STREAM_CMD_PUTS: { /* Bugfix 2005/01/05 Do not use the fputs() function as it has different return values on different systems. On some systems it returns the number of bytes successfully written, on other systems it returns 0 to indicate success. */ #if USE_BROKEN_FPUTS int i; b = (a->params).buffer; if(b) { $? ". buffer and length ok" i = fputs(b,f); if(i >= 0) { a->return_value = 1; (a->results).length = i; } } #else b = (a->params).buffer; /* l = (a->params).length; */ l = strlen((a->params).buffer); if(b && l) { $? ". buffer and length ok" x = fwrite((void *)b, 1, l, f); $? ". fwrite %u", x if(x) { $? ". successfully written %u bytes", x (a->results).used = (a->results).length = x; a->return_value = 1; } } #endif } break; case DK_STREAM_CMD_AT_END: { $? ". test fo file end" if(feof(f)) { a->return_value = 1; } else { a->return_value = 0; } } break; case DK_STREAM_CMD_RDBUF: { $? ". read to buffer" b = (a->params).buffer; l = (a->params).length; if(b && l) { $? ". buffer and length ok" x = fread((void *)b, 1, l, f); $? ". fread %u", x if(x) { $? ". sucessfully read %u bytes", x (a->results).used = x; a->return_value = 1; } } } break; case DK_STREAM_CMD_WRBUF: { $? ". write buffer" b = (a->params).buffer; l = (a->params).length; if(b && l) { $? ". buffer and length ok" x = fwrite((void *)b, 1, l, f); $? ". fwrite %u", x if(x) { $? ". successfully written %u bytes", x (a->results).used = x; a->return_value = 1; } } } break; case DK_STREAM_CMD_FINAL: { $? ". finalize" if(fflush(f) == 0) { a->return_value = 1; } } break; case DK_STREAM_CMD_FINISH: { $? ". finish and close" if(fclose(f) == 0) { a->return_value = 1; } s->data = NULL; /* file is closed now */ s->fct = NULL; /* nothing more to do */ } break; case DK_STREAM_CMD_REWIND: { $? ". rewind" rewind(f); a->return_value = 1; } break; case DK_STREAM_CMD_FLUSH: { $? ". flush" if(fflush(f) == 0) { a->return_value = 1; } } break; } } else { /* NO FILE */ $? "! no FILE *" } } else { /* INVALID POINTER TO STREAM */ $? "! invalid pointer to stream" } $? "- file_stream_fct %d", a->return_value } else { /* INVALID API POINTER */ $? "! invalid API pointer" $? "- file_stream_fct" } } /** Low-level function for uncompressed streams, non-closing. @param a Stream API structure. */ void file_stream_function DK_P1(dk_stream_api_t *, a) { if(a) { if(a->cmd == DK_STREAM_CMD_FINISH) { a->cmd = DK_STREAM_CMD_FINAL; file_stream_fct(a); a->cmd = DK_STREAM_CMD_FINISH; } else { file_stream_fct(a); } } } /** Low-level function for bzip2 compressed streams, closing. @param a Stream API structure. */ void bz2_stream_fct DK_P1(dk_stream_api_t *, a) { #if DK_HAVE_BZLIB_H BZFILE *bzf; dk_stream_t *st; void *d; void *b; int l; int x; #endif if(a) { a->return_value = 0; #if DK_HAVE_BZLIB_H st = (dk_stream_t *)(a->strm); if(st) { d = st->data; bzf = (BZFILE *)d; switch(a->cmd) { case DK_STREAM_CMD_TEST : { switch((a->params).cmd) { case DK_STREAM_CMD_TEST : { a->return_value = 1; } break; case DK_STREAM_CMD_RDBUF : { a->return_value = 1; } break; case DK_STREAM_CMD_WRBUF : { a->return_value = 1; } break; case DK_STREAM_CMD_FINAL : { a->return_value = 1; } break; case DK_STREAM_CMD_FINISH : { a->return_value = 1; } break; case DK_STREAM_CMD_REWIND : { } break; case DK_STREAM_CMD_FLUSH : { a->return_value = 1; } break; case DK_STREAM_CMD_AT_END : { } break; case DK_STREAM_CMD_GETS : { } break; case DK_STREAM_CMD_PUTS : { } break; } } break; case DK_STREAM_CMD_RDBUF : { if(!((st->flags) & 1)) { b = ((void *)((a->params).buffer)); l = ((int)((a->params).length)); if(b && (l > 0)) { x = BZ2_bzread(bzf,b,l); if(x > 0) { (a->results).used = x; a->return_value = 1; } else { st->flags |= 1; } } } } break; case DK_STREAM_CMD_WRBUF : { b = ((void *)((a->params).buffer)); l = ((int)((a->params).length)); if(b && (l > 0)) { x = BZ2_bzwrite(bzf,b,l); if(x > 0) { (a->results).used = x; a->return_value = 1; } } } break; case DK_STREAM_CMD_FINAL : { BZ2_bzflush(bzf); a->return_value = 1; } break; case DK_STREAM_CMD_FINISH : { BZ2_bzclose(bzf); a->return_value = 1; st->data = NULL; st->fct = NULL; } break; case DK_STREAM_CMD_REWIND : { } break; case DK_STREAM_CMD_FLUSH : { BZ2_bzflush(bzf); a->return_value = 1; } break; case DK_STREAM_CMD_AT_END : { } break; case DK_STREAM_CMD_GETS : { } break; case DK_STREAM_CMD_PUTS : { } break; } } #endif } } /** Low-level function for bzip2 compressed streams, non-closing. @param a Stream API structure. */ void bz2_stream_function DK_P1(dk_stream_api_t *, a) { #if DK_HAVE_BZLIB_H if(a) { if(a->cmd == DK_STREAM_CMD_FINISH) { a->cmd = DK_STREAM_CMD_FINAL; bz2_stream_fct(a); a->cmd = DK_STREAM_CMD_FINISH; } else { bz2_stream_fct(a); } } #endif } /** Low-level function for gzip compressed streams, closing. @param a Stream API structure. */ void gz_stream_fct DK_P1(dk_stream_api_t *, a) { #if DK_HAVE_ZLIB_H gzFile gzf; dk_stream_t *st; char *b; size_t l; void *d; int x; #endif $? "+ gz_stream_fct %s", TR_PTR(a) if(a) { a->return_value = 0; #if DK_HAVE_ZLIB_H st = (dk_stream_t *)(a->strm); if(st) { $? ". stream poiner ok" d = st->data; if(d) { $? ". gz file pointer ok" gzf = (gzFile)d; switch(a->cmd) { case DK_STREAM_CMD_TEST: { $? ". testing command" switch( (a->params).cmd) { case DK_STREAM_CMD_TEST: { a->return_value = 1; } break; case DK_STREAM_CMD_RDBUF: { a->return_value = 1; } break; case DK_STREAM_CMD_WRBUF: { a->return_value = 1; } break; case DK_STREAM_CMD_FINAL: { a->return_value = 1; } break; case DK_STREAM_CMD_FINISH: { a->return_value = 1; } break; case DK_STREAM_CMD_REWIND: { a->return_value = 1; } break; case DK_STREAM_CMD_FLUSH: { a->return_value = 1; } break; case DK_STREAM_CMD_AT_END: { a->return_value = 1; } break; case DK_STREAM_CMD_GETS: { a->return_value = 1; } break; case DK_STREAM_CMD_PUTS: { a->return_value = 1; } break; } } break; case DK_STREAM_CMD_RDBUF: { $? ". read buffer" b = (a->params).buffer; l = (a->params).length; if(b && l) { $? ". buffer settings ok" x = gzread(gzf,b,l); if(x > 0) { $? ". gzread -> %u", x (a->results).used = x; a->return_value = 1; } } } break; case DK_STREAM_CMD_WRBUF: { $? ". write buffer" b = (a->params).buffer; l = (a->params).length; if(b && l) { $? ". buffer settings ok" x = gzwrite(gzf,b,l); if(x > 0) { $? ". gzwrite -> %u", x (a->results).used = x; a->return_value = 1; } } } break; case DK_STREAM_CMD_FINAL: { $? ". finalize" if(gzflush(gzf, Z_FULL_FLUSH) == Z_OK) { $? ". ok" a->return_value = 1; } } break; case DK_STREAM_CMD_FINISH: { $? ". finish+close" if(gzclose(gzf) == Z_OK) { $? ". ok" a->return_value = 1; } st->data = NULL; st->fct = NULL; } break; case DK_STREAM_CMD_REWIND: { $? ". rewind" if(gzrewind(gzf) == Z_OK) { $? ". ok" a->return_value = 1; } } break; case DK_STREAM_CMD_FLUSH: { $? ". flush" if(gzflush(gzf, Z_FULL_FLUSH) == Z_OK) { $? ". ok" a->return_value = 1; } } break; case DK_STREAM_CMD_AT_END: { $? ". end check" if(gzeof(gzf) == 1) { $? ". end found" a->return_value = 1; } } break; case DK_STREAM_CMD_GETS: { $? ". get string" b = (a->params).buffer; l = (a->params).length; (a->results).buffer = b; (a->results).length = l; if(b && l) { if(gzgets(gzf,b,l)) { $? ". ok" a->return_value = 1; } } } break; case DK_STREAM_CMD_PUTS: { int i; $? ". put string" b = (a->params).buffer; if(b) { i = gzputs(gzf,b); if(i > 0) { a->return_value = 1; (a->results).length = i; } } } break; } } else { $? "! invalid data pointer" } } else { $? "! invalid stream pointer" } #endif $? "- gz_stream_fct %d", a->return_value } else { $? "- gz_stream_fct" } } /** Low-level function for gzip compressed streams, non-closing. @param a Stream API structure. */ void gz_stream_function DK_P1(dk_stream_api_t *, a) { #if DK_HAVE_ZLIB_H if(a) { if(a->cmd == DK_STREAM_CMD_FINISH) { a->cmd = DK_STREAM_CMD_FINAL; gz_stream_fct(a); a->cmd = DK_STREAM_CMD_FINISH; } else { gz_stream_fct(a); } } #endif } int dkstream_puts DK_P2(dk_stream_t *, st, char *, str) { int back = 0; dk_stream_api_t *a; dk_stream_fct_t *fct; if(st && str) { a = (dk_stream_api_t *)(&(st->api)); a->cmd = DK_STREAM_CMD_TEST; (a->params).cmd = DK_STREAM_CMD_PUTS; fct = st->fct; (*fct)(a); if(a->return_value) { a->cmd = DK_STREAM_CMD_PUTS; (a->params).buffer = str; (*fct)(a); back = a->return_value; if(back) { st->bytes += strlen(str); } } else { size_t sz; sz = strlen(str); a->cmd = DK_STREAM_CMD_WRBUF; (a->params).buffer = str; (a->params).length = sz; (a->results).buffer = str; (a->results).length = sz; (*fct)(a); back = a->return_value; if(back) { st->bytes += (a->results).used; } if(((a->results).length) != sz) { back = 0; } } } return back; } int dkstream_puts_double_use_exp DK_P2(dk_stream_t *, st, double, d) { int back; char buffer[64]; sprintf(buffer, "%lg", d); back = dkstream_puts(st, buffer); return back; } int dkstream_puts_double DK_P2(dk_stream_t *, st, double, d) { int back; if((st->opt) & DK_STREAM_OPT_DOUBLE_NO_EXPONENT) { back = dkstream_puts_double_no_exp(st, d); } else { back = dkstream_puts_double_use_exp(st, d); } return back; } int dkstream_puts_ul DK_P2(dk_stream_t *, st, unsigned long, ul) { int back; char buffer[64]; sprintf(buffer, "%lu", ul); back = dkstream_puts(st, buffer); return back; } int dkstream_puts_long DK_P2(dk_stream_t *, st, long, l) { int back; char buffer[64]; sprintf(buffer, "%ld", l); back = dkstream_puts(st, buffer); return back; } char * dkstream_gets DK_P3(dk_stream_t *, st, char *, b, size_t, l) { char *back = NULL; dk_stream_api_t *a; void *d; dk_stream_fct_t *fct; int goon; char c; size_t used; $? "+ dkstream_gets %s %s %u", TR_PTR(st), TR_PTR(b), l if(st && b && l) { $? ". arguments ok" a = &(st->api); d = st->data; fct = st->fct; if(d && fct) { $? ". d and fct ok" a->cmd = DK_STREAM_CMD_TEST; (a->params).cmd = DK_STREAM_CMD_GETS; (*fct)(a); if(a->return_value) { $? ". gets-Funktion einlesen" (a->params).buffer = b; (a->params).length = l; a->cmd = DK_STREAM_CMD_GETS; (*fct)(a); if(a->return_value) { back = b; } } else { $? ". zeichenweise einlesen" goon = 1; used = 0; while(goon) { (a->params).buffer = &c; (a->params).length = 1; (a->results).buffer = &c; (a->results).length = 1; a->cmd = DK_STREAM_CMD_RDBUF; (*fct)(a); if(a->return_value) { if(((a->results).used) == 1) { switch(c) { case '\0': { b[used++] = '\0'; goon = 0; } break; case '\r': case '\n': { b[used++] = c; b[used] = '\0'; goon = 0; } break; default: { b[used++] = c; if(used >= (l - 1)) { goon = 0; b[used] = '\0'; } } break; } } else { b[used] = '\0'; goon = 0; } } else { b[used] = '\0'; goon = 0; } } if(used) { back = b; } } } } $? "- dkstream_gets %s", TR_PTR(back) return back; } dk_stream_t * dkstream_openfile DK_P4(char *, name, char *, mode, int, ign, int *, reason) { FILE *fipo; dk_stream_t *back = NULL; if(name && mode) { #if NO_FOPEN_CHECKING #if DK_HAVE_LARGEFILE64_SOURCE && DK_HAVE_FOPEN64 fipo = fopen64(name, mode); #else fipo = fopen(name, mode); #endif #else fipo = dksf_msfo(name,mode,ign,reason); #endif if(fipo) { back = dkstream_new((void *)fipo, file_stream_fct); if(!back) { fclose(fipo); } } } return back; } dk_stream_t * dkstream_for_file DK_P1(FILE *, fipo) { dk_stream_t *back = NULL; if(fipo) { back = dkstream_new((void *)fipo, file_stream_function); } return back; } #if DK_HAVE_ZLIB_H /** Correct the open mode for gzip compressed files. @param m Mode suggested by the application. @param l Length of buffer used by \a m. */ static void correct_gz_mode(char *m, size_t l) { int want_to_write; int have_compression_level; char *ptr; size_t lgt; $? "+ correct_gz_mode %s", TR_STR(m) want_to_write = 0; have_compression_level = 0; lgt = strlen(m); ptr = m; while(*ptr) { switch(*ptr) { case 'w': { want_to_write = 1; } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { have_compression_level = 1; } break; } ptr++; } if(want_to_write && (!have_compression_level)) { if(lgt < (l - 1)) { m[lgt] = '9'; m[lgt+1] = '\0'; } } $? "- correct_mode_gz %s", TR_STR(m) } #endif /** Check whether the open mode indicates write operations. @param mode File open mode string. @return 1 for write operations, 0 for no write operations. */ static int is_open_mode_write DK_P1(char *,mode) { int back = 0; char *ptr; if(mode) { ptr = mode; while(*ptr) { switch(*ptr) { case 'w': case 'a': case '+': { back = 1; } break; } ptr++; } } $? "= is_open_mode_write %s %d", TR_STR(mode), back return back; } dk_stream_t * dkstream_opengz DK_P4(char *, name, char *, mode, int, ign, int *, reason) { dk_stream_t *back = NULL; #if DK_HAVE_ZLIB_H size_t my_mode_used; char my_mode[8]; gzFile gzf; if(name && mode) { my_mode_used = strlen(mode); if(my_mode_used < sizeof(my_mode)) { strcpy(my_mode, mode); correct_gz_mode(my_mode, sizeof(my_mode)); #if NO_FOPEN_CHECKING gzf = gzopen(name, my_mode); #else gzf = NULL; if(is_open_mode_write(my_mode)) { if(dksf_allowed_to_write(name,ign,reason)) { gzf = gzopen(name, my_mode); } } else { gzf = gzopen(name, my_mode); } #endif if(gzf) { back = dkstream_new((void *)gzf, gz_stream_fct); if(!back) { gzclose(gzf); } } } } #endif return back; } #if DK_HAVE_ZLIB_H dk_stream_t * dkstream_for_gz DK_P1(gzFile, gzf) { dk_stream_t *back = NULL; if(gzf) { back = dkstream_new((void *)gzf, gz_stream_function); } return back; } #endif dk_stream_t * dkstream_openbz2 DK_P4(char *, name, char *, mode, int, ign, int *, reason) { dk_stream_t *back = NULL; #if DK_HAVE_BZLIB_H BZFILE *bzf; if(name && mode) { #if NO_FOPEN_CHECKING bzf = BZ2_bzopen(name,mode); #else bzf = NULL; if(is_open_mode_write(mode)) { if(dksf_allowed_to_write(name,ign,reason)) { bzf = BZ2_bzopen(name,mode); } } else { bzf = BZ2_bzopen(name,mode); } #endif if(bzf) { back = dkstream_new((void *)bzf, bz2_stream_fct); if(!back) { BZ2_bzclose(bzf); } } } #endif return back; } #if DK_HAVE_BZLIB_H dk_stream_t * dkstream_for_bz2 DK_P1(BZFILE *, bzf) { dk_stream_t *back = NULL; if(bzf) { back = dkstream_new((void *)bzf, bz2_stream_function); } return back; } #endif void dkstream_close DK_P1(dk_stream_t *, st) { dk_stream_api_t *a; dk_stream_fct_t *f; void *d; if(st) { f = st->fct; d = st->data; if(f && d) { a = &(st->api); a->cmd = DK_STREAM_CMD_FINISH; (*f)(a); /* ##### 2001/07/04 - D. Krause */ /* prevent FINAL from dkstream_delte() after FINISH */ st->fct = NULL; st->data = NULL; /* ##### */ } dkstream_delete(st); } } $* The following functions do not depend on low level functionality directly. $* int dkstream_wb_word DK_P2(dk_stream_t *, st, dk_word, w) { int back = 0; dk_word x; if(st) { x = dkenc_htons(w); if(dkstream_write(st, ((char *)(&x)), sizeof(dk_word)) == sizeof(dk_word)) { back = 1; } } return back; } int dkstream_wb_uword DK_P2(dk_stream_t *, st, dk_uword, w) { int back = 0; dk_uword x; if(st) { x = dkenc_htons(w); if(dkstream_write(st, ((char *)(&x)), sizeof(dk_uword)) == sizeof(dk_uword)) { back = 1; } } return back; } int dkstream_wb_dword DK_P2(dk_stream_t *, st, dk_dword, w) { int back = 0; dk_dword x; if(st) { x = dkenc_htonl(w); if(dkstream_write(st, ((char *)(&x)), sizeof(dk_dword)) == sizeof(dk_dword)) { back = 1; } } return back; } int dkstream_wb_udword DK_P2(dk_stream_t *, st, dk_udword, w) { int back = 0; dk_udword x; if(st) { x = dkenc_htonl(w); if(dkstream_write(st, ((char *)(&x)), sizeof(dk_udword)) == sizeof(dk_udword)) { back = 1; } } return back; } int dkstream_rb_word DK_P2(dk_stream_t *, st, dk_word *, w) { int back = 0; dk_word x; if(st && w) { if(dkstream_read(st, ((char *)(&x)), sizeof(dk_word)) == sizeof(dk_word)) { *w = dkenc_ntohs(x); back = 1; } } return back; } int dkstream_rb_uword DK_P2(dk_stream_t *, st, dk_uword *, w) { int back = 0; dk_uword x; if(st && w) { if(dkstream_read(st, ((char *)(&x)), sizeof(dk_uword)) == sizeof(dk_uword)) { *w = dkenc_ntohs(x); back = 1; } } return back; } int dkstream_rb_dword DK_P2(dk_stream_t *, st, dk_dword *, w) { int back = 0; dk_dword x; if(st && w) { if(dkstream_read(st, ((char *)(&x)), sizeof(dk_dword)) == sizeof(dk_dword)) { *w = dkenc_ntohl(x); back = 1; } } return back; } int dkstream_rb_udword DK_P2(dk_stream_t *, st, dk_udword *, w) { int back = 0; dk_udword x; if(st && w) { if(dkstream_read(st, ((char *)(&x)), sizeof(dk_udword)) == sizeof(dk_udword)) { *w = dkenc_ntohl(x); back = 1; } } return back; } int dkstream_wb_string DK_P2(dk_stream_t *,st, char *,str) { int back = 0; /**< return value */ size_t sl; /**< string length from strlen() */ dk_uword lgt; /**< string length saved to stream */ if(st) { if(str) { sl = strlen(str); sl++; if(sl) { if(sl <= (size_t)0xFFFFU) { lgt = (dk_uword)sl; if(dkstream_wb_uword(st,lgt)) { if(dkstream_write(st, str, lgt) == lgt) { back = 1; /* success */ } else { /* number of bytes differs */ } } else { /* failed to write length */ } } else { /* numeric overflow */ } } else { /* numeric overflow */ } } } return back; } char * dkstream_rb_string DK_P1(dk_stream_t *, st) { char *back = NULL; dk_uword lgt; if(st) { if(dkstream_rb_uword(st,&lgt)) { if(lgt > 0) { back = dk_new(char,lgt); if(back) { if(dkstream_read(st, back, lgt) == lgt) { back[lgt-1] = '\0'; } else { dk_delete(back); back = NULL; } } } } } return back; } /** No suffix for plain (uncompressed) files. */ static char suffix_none[] = { "" }; #if DK_HAVE_ZLIB_H /** Suffix for gzip compressed files. */ static char suffix_gz[] = { ".gz" }; #endif #if DK_HAVE_BZLIB_H /** Suffix for bzip2 compressed files. */ static char suffix_bz2[] = { ".bz2" }; #endif /** Table for file types to read. */ dk_stream_suffix_t dkstream_read_suffix_list[] = { { suffix_none, (dk_stream_open_fct_t *)dkstream_openfile }, #if DK_HAVE_ZLIB_H { suffix_gz, (dk_stream_open_fct_t *)dkstream_opengz }, #endif #if DK_HAVE_BZLIB_H { suffix_bz2, (dk_stream_open_fct_t *)dkstream_openbz2 }, #endif { NULL, (dk_stream_open_fct_t *)NULL } }; /** Table for file types to write. */ dk_stream_suffix_t dkstream_write_suffix_list[] = { #if DK_HAVE_BZLIB_H { suffix_bz2, (dk_stream_open_fct_t *)dkstream_openbz2 }, #endif #if DK_HAVE_ZLIB_H { suffix_gz, (dk_stream_open_fct_t *)dkstream_opengz }, #endif { suffix_none, (dk_stream_open_fct_t *)dkstream_openfile }, { NULL, (dk_stream_open_fct_t *)NULL } }; dk_stream_suffix_t *dkstream_get_read_suffixes DK_P0() { return dkstream_read_suffix_list; } dk_stream_suffix_t *dkstream_get_write_suffixes DK_P0() { return dkstream_write_suffix_list; } unsigned long dkstream_get_bytes_written DK_P1(dk_stream_t *,st) { unsigned long back = 0UL; if(st) { back = st->bytes; } return back; } int dkstream_puts_array DK_P2(dk_stream_t *,st, char **,array) { int back = 0; char **ptr = NULL; $? "+ dkstream_puts_array %s %s", TR_PTR(st), TR_PTR(array) if(st && array) { back = 1; ptr = array; while(*ptr) { if(!dkstream_puts(st, *ptr)) { back = 0; } if(!dkstream_puts(st, str_nl)) { back = 0; } ptr++; } } $? "- dkstream_puts_array %d", back return back; } /** Check whether a character is a digit 1-9. @param c Character to check. @return 1 on true, 0 on false. */ static int is_non_zero DK_P1(char,c) { int back = 0; switch(c) { case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { back = 1; } break; } return back; } /** Index of first non-zero digit in text. @param s Text to search. @return Position index of the first non-zero digit in \a s. */ static int first_non_zero DK_P1(char *,s) { int back = -1, i = 0; char *p; p = s; i = 0; while((back == -1) && (*p)) { if(is_non_zero(*p)) { back = i; } p++; i++; } return back; } /** Used to print a double value as text. */ static char str_0[] = { "0" }; /** Used to print a double value as text. */ static char str_d[] = { "." }; /** Used to print a double value as text. */ static char str_e[] = { "e" }; int dkstream_puts_double_str_no_exp DK_P2(dk_stream_t *,stream, char *,s) { int back = 0; char buffer[64]; char *p1, *p2, *pe, *sptr, *dptr; int evalue, itest, dotpos, fnz, max, i, sl; size_t sz; p1 = dkstr_start(s, NULL); if(p1) { back = 1; if(*p1 == '-') { if(dkstream_write(stream, p1++, 1) < 1) { back = 0; } } pe = strchr(p1, 'e'); if(!pe) { pe = strchr(p1, 'E'); } if(pe) { *(pe++) = '\0'; if(sscanf(pe, "%d", &itest) == 1) { evalue = itest; if(evalue != 0) { p2 = strchr(p1, '.'); if(p2) { *(p2++) = '\0'; } sz = 0; if(p1) { sz += strlen(p1); } if(p2) { sz += strlen(p2); } if(sz < sizeof(buffer)) { buffer[0] = '\0'; if(p1) { strcat(buffer, p1); } if(p2) { strcat(buffer, p2); } dotpos = 0; if(p1) { dotpos = strlen(p1); } fnz = first_non_zero(buffer); if(fnz > -1) { if(fnz > 0) { dptr = buffer; sptr = &(buffer[fnz]); while(*sptr) { *(dptr++) = *(sptr++); } *dptr = '\0'; dotpos -= fnz; } dotpos += evalue; if(dotpos <= 0) { $? ". dot left" if(!dkstream_puts(stream, str_0)) { back = 0; } if(!dkstream_puts(stream, str_d)) { back = 0; } max = 0 - dotpos; for(i = 0; i < max; i++) { if(!dkstream_puts(stream, str_0)) { back = 0; } } if(!dkstream_puts(stream, buffer)) { back = 0; } } else { $? ". dot in text or right" sl = max = strlen(buffer); if(dotpos > max) { max = dotpos; } for(i = 0; i < max; i++) { if(i < sl) { if(dkstream_write(stream, &(buffer[i]), 1) < 1) { back = 0; } } else { if(!dkstream_puts(stream, str_0)) { back = 0; } } if(((i + 1) == dotpos) && (dotpos < sl)) { if(!dkstream_puts(stream, str_d)) { back = 0; } } } #if 0 if(dotpos >= sl) { if(!dkstream_puts(stream, str_0)) { back = 0; } } #endif } } else { $? ". all zeroes" back = dkstream_puts(stream, str_0); } } else { $? "! string too long" back = 0; if(p1) { dkstream_puts(stream, p1); } if(p2) { dkstream_puts(stream, str_d); dkstream_puts(stream, p2); } dkstream_puts(stream, str_e); dkstream_puts_long(stream, (long)evalue); } } else { $? "· exponent is 0" back = dkstream_puts(stream, p1); } } else { $? "! exponent is not a number" dkstream_puts(stream, p1); back = 0; } } else { $? ". no pe" back = dkstream_puts(stream, p1); } } else { $? "! no text in string" dkstream_puts(stream, str_0); } return back; } int dkstream_puts_double_no_exp DK_P2(dk_stream_t *,stream, double,d) { int back = 0; char buffer[64]; sprintf(buffer, "%lg", d); dkstream_puts_double_str_no_exp(stream, buffer); return back; } void dkstream_set_double_no_exponent DK_P2(dk_stream_t *,s, int,f) { if(s) { if(f) { s->opt |= DK_STREAM_OPT_DOUBLE_NO_EXPONENT; } else { s->opt &= (~(DK_STREAM_OPT_DOUBLE_NO_EXPONENT)); } } } int dkstream_get_double_no_exponent DK_P1(dk_stream_t *,s) { int back = 0; if(s) { if((s->opt) & DK_STREAM_OPT_DOUBLE_NO_EXPONENT) { back = 1; } } return back; }