%% options copyright owner = Dirk Krause copyright year = 2015-xxxx license = bsd %% header /** @file dk4wxstt.h String tables for wxChars. */ #ifndef DK4CONF_H_INCLUDED #include "dk4conf.h" #endif #ifndef DK4TYPES_H_INCLUDED #include "dk4types.h" #endif #ifndef DK4STRM_H_INCLUDED #include "dk4strm.h" #endif #ifndef DK4ERROR_H_INCLUDED #include "dk4error.h" #endif #ifndef DK4WXCS_H_INCLUDED #include "dk4wxcs.h" #endif #ifndef WX_WXPREC_H_INCLUDED #include #define WX_WXPREC_H_INCLUDED 1 #endif #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #if DK4_HAVE_WX_CHARTYPE_H #ifndef WX_CHARTYPE_H_INCLUDED #include #define WX_CHARTYPE_H_INCLUDED 1 #endif #else #if DK4_HAVE_WX_WXCHAR_H #ifndef WX_WXCHAR_H_INCLUDED #include #define WX_WXCHAR_H_INCLUDED 1 #endif #else #ifndef WX_WX_H_INCLUDED #include #define WX_WX_H_INCLUDED #endif #endif #endif #endif /** String table for wxChar strings. */ typedef struct { dkChar *shrtfn; /**< Short file name. */ wxChar **strings; /**< Strings read from file. */ size_t nstrings; /**< Number of strings. */ } dk4_wx_string_table_t; extern "C" { /** Create string table from file. @param fn Short file name to store in structure. @param sz Number of lines required. @param erp Error report, may be NULL. @return Pointer to new string table structure on success, NULL on error. Error codes: - DK4_E_INVALID_ARGUMENTS
if fn is NULL or sz is 0, - DK4_E_MATH_OVERFLOW
if there was a numeric overflow in size calculations for dynamic memory allocations, - DK4_E_MEMORY_ALLOCATION_FAILED
if there is not enough memory available. */ dk4_wx_string_table_t * dk4wxstt_open(const dkChar *fn, size_t sz, dk4_er_t *erp); /** Apply a text stream to a string table. @param tptr String table to configure. @param strm Text stream, opened for reading. @param pre Processing encoding. @param erp1 Error report for decoding/encoding, may be NULL. @param erp2 Error report for processing, may be NULL. @return True on success, false on error. Error codes erp1: Error codes erp2: - DK4_E_INVALID_ARGUMENTS
if tptr or strm is NULL */ bool dk4wxstt_apply_stream( dk4_wx_string_table_t *tptr, dk4_stream_t *strm, int pre, dk4_er_t *erp1, dk4_er_t *erp2 ); /** Destroy a string table, free allocated memory. @param ptr String table to destroy. */ void dk4wxstt_close(dk4_wx_string_table_t *ptr); /** Mark string table as empty. Release memory for the strings. @param ptr String table to shut down. */ void dk4wxstt_shutdown(dk4_wx_string_table_t *ptr); /** Compare two string tables by short name. @param l Left pointer (always string table). @param r Right pointer (string table or short name). @param cr Comparison criteria (0=string table/string table, 1=string table/short name). @return Comparison result. */ int dk4wxstt_compare(const void *l, const void *r, int cr); } %% module #include "dk4mem.h" #include "dk4enc.h" #include "dk4strd.h" #include "dk4wxtypes.h" #include "dk4strx.h" #include "dk4wxstt.h" #include "dk4tspwx.h" $!trace-include void dk4wxstt_shutdown(dk4_wx_string_table_t *ptr) { wxChar **stptr; size_t nstrings; $? "+ dk4wxstt_shutdown" if (NULL != ptr) { $? ". arg ok" if (NULL != ptr->strings) { $? ". strings ok" stptr = ptr->strings; nstrings = ptr->nstrings; while (0 < nstrings--) { $? ". release one string" dk4mem_release(*stptr); stptr++; } $? ". release array pointer" dk4mem_release(ptr->strings); } } $? "- dk4wxstt_shutdown" } void dk4wxstt_close(dk4_wx_string_table_t *ptr) { $? "+ dk4wxstt_close" if (NULL != ptr) { $? ". arg ok" dk4wxstt_shutdown(ptr); $? ". release short file name" dk4mem_release(ptr->shrtfn); ptr->nstrings = 0; $? ". release string table" dk4mem_free(ptr); } $? "- dk4wxstt_close" } dk4_wx_string_table_t * dk4wxstt_open(const dkChar *fn, size_t sz, dk4_er_t *erp) { dk4_wx_string_table_t *back = NULL; wxChar **stptr = NULL; int ok = 0; $? "+ dk4wxstt_open" if ((NULL != fn) && (0 < sz)) { $? ". fn, sz ok" back = dk4mem_new(dk4_wx_string_table_t,1,erp); if (NULL != back) { $? ". allocated" back->strings = NULL; back->nstrings = 0; back->shrtfn = dk4str_dup(fn, erp); if (NULL != back->shrtfn) { $? ". short file name" back->nstrings = sz; back->strings = dk4mem_new(DK4_PWXCHAR,sz,erp); if (NULL != back->strings) { $? ". array" stptr = back->strings; while (0 < sz--) { *(stptr++) = NULL; } ok = 1; } } if (1 > ok) { $? "! incomplete" dk4wxstt_close(back); back = NULL; } } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } $? "- dk4wxstt_open %d", ((NULL != back) ? 1 : 0) return back; } int dk4wxstt_compare(const void *l, const void *r, int cr) { const dk4_wx_string_table_t *lptr; const dk4_wx_string_table_t *rptr; int back = 0; if (NULL != l) { if (NULL != r) { lptr = (const dk4_wx_string_table_t *)l; switch (cr) { case 1: { if (NULL != lptr->shrtfn) { back = dk4str_pathcmp(lptr->shrtfn, (const dkChar *)r); } else { back = -1; } } break; default : { rptr = (const dk4_wx_string_table_t *)r; if (NULL != lptr->shrtfn) { if (NULL != rptr->shrtfn) { back = dk4str_pathcmp(lptr->shrtfn, rptr->shrtfn); } else { back = 1; } } else { if (NULL != rptr->shrtfn) { back = -1; } } } break; } } else { back = 1; } } else { if (NULL != r) { back = -1; } } return back; } /** Support structure for reading string table from stream. */ typedef struct { dk4_wx_string_table_t *dptr; /**< String table to set up. */ size_t curpos; /**< Current string number. */ } dk4_wx_string_table_reader_t; #if DK4_SIZEOF_WXCHAR > 1 #if DK4_SIZEOF_WXCHAR > 2 #define TO_SIZED_CHAR(x) ((dk4_c32_t)(x)) #else #define TO_SIZED_CHAR(x) ((dk4_c16_t)(x)) #endif #else #define TO_SIZED_CHAR(x) ((char)(x)) #endif /** Handler function for text lines. @param obj Object to modify while processing the character. @param line Text line to process. @param lineno Current line number. @param erp Error report, may be NULL. @return DK4_TSP_RES_OK if the character was processed successfully, DK4_TSP_RES_ERROR if there was an error but we can continue, DK4_TSP_RES_FATAL if there was a fatal error so we should abort processing. */ static int dk4wxstt_line_handler( void *obj, #if DK4_SIZEOF_WXCHAR > 1 #if DK4_SIZEOF_WXCHAR > 2 dk4_c32_t *line, #else dk4_c16_t *line, #endif #else char *line, #endif dk4_um_t lineno, dk4_er_t *erp ) { dk4_wx_string_table_reader_t *reader; wxChar *linecp; int back = DK4_TSP_RES_ERROR; $? "+ dk4wxstt_line_handler" reader = (dk4_wx_string_table_reader_t *)obj; if (wxT('#') != (wxChar)(*line)) { $? ". non-comment" if (reader->curpos < reader->dptr->nstrings) { $? ". save line" linecp = dk4strx_dup((wxChar *)line, NULL); if (NULL != linecp) { (reader->dptr->strings)[reader->curpos] = linecp; reader->curpos += 1; back = DK4_TSP_RES_OK; while (wxT('\0') != (wxChar)(*linecp)) { if (wxT('\\') == (wxChar)(*linecp)) { if (wxT('r') == (wxChar)(linecp[1])) { *linecp = TO_SIZED_CHAR(wxT('\r')); dk4strx_cpy_to_left( (wxChar *)(&(linecp[1])), (wxChar *)(&(linecp[2])) ); } else { if (wxT('n') == wxChar(linecp[1])) { *linecp = TO_SIZED_CHAR(wxT('\n')); dk4strx_cpy_to_left( (wxChar *)(&(linecp[1])), (wxChar *)(&(linecp[2])) ); } else { if (wxT('t') == (wxChar)(linecp[1])) { *linecp = TO_SIZED_CHAR(wxT('\t')); dk4strx_cpy_to_left( (wxChar *)(&(linecp[1])), (wxChar *)(&(linecp[2])) ); } else { dk4strx_cpy_to_left( (wxChar *)(linecp), (wxChar *)(&(linecp[1])) ); if (wxT('\0') == (wxChar)(*linecp)) { linecp--; } } } } } else { if (wxT('\n') == (wxChar)(*linecp)) { *linecp = TO_SIZED_CHAR(wxT('\0')); linecp--; } else { if ((wxT('\r') == (wxChar)(*linecp)) && (wxT('\n') == (wxChar)(linecp[1]))) { *linecp = TO_SIZED_CHAR(wxT('\0')); linecp--; } } } linecp++; } } else { back = DK4_TSP_RES_FATAL; } } else { $? ". line out of range" back = DK4_TSP_RES_OK; } } else { back = DK4_TSP_RES_OK; } $? "- dk4wxstt_line_handler %d", back return back; } bool dk4wxstt_apply_stream( dk4_wx_string_table_t *tptr, dk4_stream_t *strm, int pre, dk4_er_t *erp1, dk4_er_t *erp2 ) { wxChar line[1024]; /* Line buffer */ char buf[4096]; /* Input bytes from stream */ dk4_wx_string_table_reader_t reader; /* Reader structure */ dk4_tspwx_t tspwx; /* Text stream processor */ dk4_er_t e1; /* Error report decoding */ dk4_er_t e2; /* Error report processing */ size_t rdb; /* Number of bytes read */ int cc; /* Flag: Can continue */ bool back = false; /* Function result */ $? "+ dk4wxstt_apply_stream" if ((NULL != tptr) && (NULL != strm)) { $? ". args ok" dk4error_init(&e1); dk4error_init(&e2); reader.dptr = tptr; reader.curpos = 0; cc = dk4tspwx_setup_line( &tspwx, (void *)(&reader), dk4wxstt_line_handler, line, DK4_SIZEOF(line,wxChar), pre, DK4_FILE_ENCODING_UTF8, &e2 ); back = ((cc != 0) ? true : false); if (back) { $? ". tsp setup ok" #if VERSION_BEFORE_20150821 cc = 1; #endif do { cc = 0; rdb = sizeof(buf); if (0 < dk4stream_read(buf, &rdb, strm, NULL)) { if (0 < rdb) { $? ". read ok" switch (dk4tspwx_add_bytes(&tspwx, (unsigned char *)buf, rdb)) { case DK4_TSP_RES_OK: { cc = 1; $? ". byte add ok" } break; case DK4_TSP_RES_ERROR: { cc = 1; $? ". byte add error" } break; default: { back = false; $? ". byte add fatal" } break; } } } } while (0 != cc); if (back) { $? ". finalize tsp" if (DK4_TSP_RES_FATAL == dk4tspwx_finish(&tspwx)) { back = false; $? "! finalize" } if (back) { if (reader.curpos < (reader.dptr)->nstrings) { back = false; $? "! too few" } } } } else { $? "! init" } } else { dk4error_set_simple_error_code(erp2, DK4_E_INVALID_ARGUMENTS); } $? "- dk4wxstt_apply_stream %d", back return back; }