%% options copyright owner = Dirk Krause copyright year = 2011-2014 license = bsd %% header #ifdef __cplusplus extern "C" { #endif /** Create paper sizes collection, read dk3paper.conf files. @param app Application structure for diagnostics and file search, must not be NULL. @return Pointer to new collection on success, NULL on error. */ dk3_paper_size_collection_t * dk3paper_open_app(dk3_app_t *app); /** Find paper size by name. @param psc Paper size collection. @param psn Paper size name. @return Pointer to paper size on success, NULL on error. */ dk3_paper_size_t const * dk3paper_find(dk3_paper_size_collection_t *psc, dkChar const *psn); /** Close paper size collection, release memory. @param psc Collection to close. */ void dk3paper_close(dk3_paper_size_collection_t *psc); /** Prepare traversing the paper size collection for named paper sizes. @param psc Paper size collection. */ void dk3paper_reset(dk3_paper_size_collection_t *psc); /** Retrieve next named paper size from size collection. @param psc Paper size collection. @return Pointer to named paper size on success, NULL on error/end. */ dk3_named_paper_size_t const * dk3paper_next(dk3_paper_size_collection_t *psc); #ifdef __cplusplus } #endif %% module #include "dk3all.h" #include "dk3paper.h" $!trace-include /** Built-in named paper sizes, may be overwritten in configuration files. */ static dkChar const * const dk3paper_default_sizes[] = { $!text macro=dkT A4 = 595 842 Letter = 612 792 a4 = 595 842 56 28 14 14 letter = 612 792 56 28 14 14 $!end }; /** File name for configuration file. */ static dkChar const dk3paper_config_file_name[] = { dkT("dk3paper.conf") }; /** Delete named paper size, release memory. @param nps Data to delete. */ static void dk3paper_nps_delete(dk3_named_paper_size_t *nps) { $? "+ dk3paper_nps_delete \"%s\"", TR_STR(nps->name) if(nps->name) { dk3_release(nps->name); } dk3_delete(nps); $? "- dk3paper_nps_delete" } /** Create named paper size structure, allocate memory. @param app Application structure for diagnostics. @param name Paper size name. @return Pointer to new paper size on success, NULL on error. */ static dk3_named_paper_size_t * dk3paper_nps_new(dk3_app_t *app, dkChar const *name) { dk3_named_paper_size_t *back = NULL; $? "+ dk3paper_nps_new" if((app) && (name)) { back = dk3_new_app(dk3_named_paper_size_t,1,app); if(back) { back->name = NULL; (back->size).w = (back->size).h = 0.0; (back->size).i = (back->size).o = (back->size).t = (back->size).b = 0.0; back->name = dk3str_dup_app(name, app); if(!(back->name)) { dk3paper_nps_delete(back); back = NULL; } } } $? "- dk3paper_nps_new %s", TR_PTR(back) return back; } /** Compare two named paper sizes by name. @param l Left structure. @param r Right structure. @param cr Comparison criteria (0=size/size, 1=size/name). @return Comparison result. */ static int dk3paper_nps_compare(void const *l, void const *r, int cr) { int back = 0; dk3_named_paper_size_t const *pl; /* Pointer to left structure. */ dk3_named_paper_size_t const *pr; /* Pointer to right structure. */ if(l) { if(r) { pl = (dk3_named_paper_size_t const *)l; switch(cr) { case 1: { /* Compare structure against a name string. */ if(pl->name) { back = dk3str_cmp(pl->name, (dkChar const *)r); } else { back = -1; } } break; default: { /* Compare two structures by name. */ pr = (dk3_named_paper_size_t const *)r; if(pl->name) { if(pr->name) { back = dk3str_cmp(pl->name, pr->name); } else { back = 1; } } else { if(pr->name) { back = -1; } } } break; } } else { back = 1; } } else { if(r) { back = -1; } } if(back < -1) back = -1; if(back > 1) back = 1; return back; } /** Set values in a named paper size. @param np Named paper size. @param v Values array. @param num Number of values (2 or 6). Width and height are mandatory, borders are optional. @return 1 on success, 0 on error. */ static int dk3paper_set_values(dk3_named_paper_size_t *np, double const *v, size_t num) { int back = 0; $? "+ dk3paper_set_values" (np->size).i = (np->size).o = (np->size).t = (np->size).b = 0.0; (np->size).w = v[0]; (np->size).h = v[1]; if(num > 2) { (np->size).i = v[2]; (np->size).o = v[3]; (np->size).t = v[4]; (np->size).b = v[5]; } /* Indicate success only if all values are reasonable. */ if((np->size).w > 0.0) { if((np->size).h > 0.0) { if((np->size).i >= 0.0) { if((np->size).o >= 0.0) { if((np->size).t >= 0.0) { if((np->size).b >= 0.0) { back = 1; } } } } } } $? "- dk3paper_set_values %d", back return back; } /** Handler function for one configuration file line. @param obj Paper size collection. @param il Input line to process. @return 1 for OK, 0 for recoverable error, -1 for abort. */ static int dk3paper_const_line_handler(void *obj, dkChar const *il) { dkChar bu[DK3_PAPER_CONFIG_LINE_SIZE]; /* Private copy. */ dkChar *parts[16]; /* Split number sequence. */ double v[8]; /* Values from text line. */ dk3_paper_size_collection_t *psc; /* Paper size collection. */ dk3_named_paper_size_t *np; /* Paper size to edit. */ dkChar *p1; /* Paper size name. */ dkChar *p2; /* Values for that size. */ size_t nparts; /* Number of values. */ size_t i; /* Traverse all values. */ int back = 1; int res = 0; /* Flag: No reporting necessary. */ $? "+ dk3paper_const_line_handler" if((obj) && (il)) { $? ". line=\"%s\"", il psc = (dk3_paper_size_collection_t *)obj; if(dk3str_len(il) < DK3_SIZEOF(bu,dkChar)) { dk3str_cpy_not_overlapped(bu, il); p1 = dk3str_start(bu, NULL); if(p1) { if(*p1 != dkT('#')) { p2 = dk3str_chr(p1, dkT('=')); if(p2) { *(p2++) = dkT('\0'); p2 = dk3str_start(p2, NULL); if(p2) { dk3str_chomp(p1, NULL); nparts = dk3str_explode(parts, 15, p2, NULL); if((nparts == 2) || (nparts == 6)) { /* Line syntax ok so far. */ res = 1; /* Read double value from all text words. */ for(i = 0; i < nparts; i++) { #if VERSION_BEFORE_20140716 if(dk3sf_sscanf3(parts[i], dkT("%lg"), &(v[i])) != 1) #else /* Bugfix 2014-09-01: If the action fails, the res variable is set to failure, not on success. */ #if VERSION_BEFORE_20140901 /* WRONG*/ if (dk3ma_d_from_string(&(v[i]), parts[i], NULL)) #else /* OK */ if (0 == dk3ma_d_from_string(&(v[i]), parts[i], NULL)) #endif #endif { res = 0; } } if(res) { if(dk3str_len(p1) > 0) { /* Attempt to find existing size for that name. */ np = (dk3_named_paper_size_t *)dk3sto_it_find_like( psc->i_sizes, (void *)p1, 1 ); if(np) { /* Entry exists, reconfigure entry. */ res = dk3paper_set_values(np, v, nparts); } else { /* Create new entry. */ np = dk3paper_nps_new(psc->app, p1); if(np) { if(dk3sto_add(psc->s_sizes, (void *)np)) { res = dk3paper_set_values(np, v, nparts); } else { /* ERROR: Memory */ dk3paper_nps_delete(np); np = NULL; back = 0; } } else { /* ERROR: Memory */ back = 0; } } } else { res = 0; } } } } } } else { res = 1; } } else { res = 1; } if(!(res)) { /* ERROR: Syntax */ dk3str_cpy_not_overlapped(bu, il); dk3str_normalize(bu, NULL, dkT(' ')); dk3app_log_i3(psc->app, DK3_LL_ERROR, 211, 212, bu); } } } $? "- dk3paper_const_line_handler %d", back return back; } /** Handler function for one configuration file line. @param obj Paper size collection. @param il Input line to process. @return 1 for OK, 0 for recoverable error, -1 for abort. */ static int dk3paper_line_handler(void *obj, dkChar *il) { int back; back = dk3paper_const_line_handler(obj, il); return back; } dk3_paper_size_collection_t * dk3paper_open_app(dk3_app_t *app) { dkChar bu[DK3_PAPER_CONFIG_LINE_SIZE]; /* Buffer. */ dk3_paper_size_collection_t *back = NULL; dk3_search_t *sr; dkChar const *fn; dkChar const * const *lfdptr; int ok = 0; int res; int de; int se; $? "+ dk3paper_open_app" if(app) { back = dk3_new_app(dk3_paper_size_collection_t,1,app); if(back) { $? ". allocation ok" back->app = app; back->s_sizes = NULL; back->i_sizes = NULL; back->s_sizes = dk3sto_open_app(app); if(back->s_sizes) { $? ". storage ok" dk3sto_set_comp(back->s_sizes, dk3paper_nps_compare, 0); back->i_sizes = dk3sto_it_open(back->s_sizes); if(back->i_sizes) { $? ". iterator ok" ok = 1; /* Read built-in lines. */ lfdptr = dk3paper_default_sizes; while(*lfdptr) { $? ". processing buildin line \"%s\"", *lfdptr if(!dk3paper_const_line_handler((void *)back, *lfdptr)) { ok = 0; $? "! failed" } lfdptr++; } /* Read configuration files. */ sr = dk3app_find_config_file(app, dk3paper_config_file_name, 0); if(sr) { $? ". search results available" dk3search_reset(sr); se = dk3app_get_encoding(app); de = dk3app_get_input_file_encoding(app); while((fn = dk3search_next(sr)) != NULL) { $? ". processing file \"%s\"", fn res = dk3stream_process_filename_lines_app( (void *)back, dk3paper_line_handler, fn, bu, DK3_SIZEOF(bu,dkChar), se, de, app ); if(!(res)) { ok = 0; } } dk3search_close(sr); } else { $? "! no search results" } } else { $? "! iterator alloc failed" } } else { $? "! storage alloc failed" } if(!(ok)) { dk3paper_close(back); back = NULL; } } else { $? "! allocation failed" } } $? "- dk3paper_open_app %s", TR_PTR(back) return back; } void dk3paper_close(dk3_paper_size_collection_t *psc) { dk3_named_paper_size_t *nps; /* Current size to release. */ $? "+ dk3paper_close" if(psc) { if(psc->s_sizes) { if(psc->i_sizes) { dk3sto_it_reset(psc->i_sizes); while((nps = (dk3_named_paper_size_t *)dk3sto_it_next(psc->i_sizes)) != NULL ) { dk3paper_nps_delete(nps); } dk3sto_it_close(psc->i_sizes); } dk3sto_close(psc->s_sizes); } psc->s_sizes = NULL; psc->app = NULL; dk3_delete(psc); } $? "- dk3paper_close" } dk3_paper_size_t const * dk3paper_find(dk3_paper_size_collection_t *psc, dkChar const *psn) { dk3_paper_size_t const *back = NULL; dk3_named_paper_size_t *nps; /* Named size. */ $? "+ dk3paper_find \"%s\"", psn if((psc) && (psn)) { nps = (dk3_named_paper_size_t *)dk3sto_it_find_like( psc->i_sizes, (void *)psn, 1 ); if(nps) { $? ". nps ok" back = (dk3_paper_size_t const *)(&(nps->size)); } } $? "- dk3paper_find %s", TR_PTR(back) return back; } void dk3paper_reset(dk3_paper_size_collection_t *psc) { if(psc) { if(psc->i_sizes) { dk3sto_it_reset(psc->i_sizes); } } } dk3_named_paper_size_t const * dk3paper_next(dk3_paper_size_collection_t *psc) { dk3_named_paper_size_t const *back = NULL; if(psc) { if(psc->i_sizes) { back = (dk3_named_paper_size_t const *)dk3sto_it_next(psc->i_sizes); } } return back; }