1 /*
2 Copyright (C) 2015-2021, Dirk Krause
3 SPDX-License-Identifier: BSD-3-Clause
4 */
5
6 /*
7 WARNING: This file was generated by the dkct program (see
8 http://dktools.sourceforge.net/ for details).
9 Changes you make here will be lost if dkct is run again!
10 You should modify the original source and run dkct on it.
11 Original source: dk4wxpref.cpt
12 */
13
14 /** @file dk4wxpref.cpp The dk4wxpref module.
15 */
16
17
18 #include <libdk4base/dk4strd.h>
19 #include <libdk4wx/dk4strx.h>
20 #include <libdk4wx/dk4recwx.h>
21 #include <libdk4base/dk4mem.h>
22 #include <libdk4base/dk4mpl.h>
23 #include <libdk4c/dk4tspdk.h>
24 #include <libdk4c/dk4fs.h>
25 #include <libdk4wx/dk4wxpref.h>
26
27
28
29
30
31
32 /** Preference reading helper structure.
33 */
34 typedef struct {
35 dk4_sto_t *spref; /**< Preference storage. */
36 dk4_sto_it_t *ipref; /**< Preferences iterator. */
37 const dkChar *nameApp; /**< Application name. */
38 const dkChar *nameGrp; /**< Application group name. */
39 const dkChar *nameLog; /**< Users login name. */
40 const dkChar *nameHost; /**< Host name. */
41 const dkChar *language; /**< Users language. */
42 const dkChar *region; /**< Users region. */
43 wxChar *wx1; /**< One wxChar buffer. */
44 wxChar *wx2; /**< Other wxChar buffer. */
45 size_t szwx; /**< Size of wxChar buffers. */
46 int encWx; /**< Encoding for wxChar. */
47 int encDk; /**< Encoding for dkChar. */
48 int compat; /**< Flag: Compatible mode. */
49 int insc; /**< Flag: In scope. */
50 int lasc; /**< Flag: Previous line was scope. */
51 } dk4_wx_pref_rd_t;
52
53
54
55 /** Constant keywords used by the module, not localized.
56 */
57 static const dkChar * const dk4wxpref_kw_dk[] = {
58 /* 0 */
59 dkT("dk3pref.conf"),
60
61 /* 1 */
62 dkT("dk4pref.conf"),
63
64 /* 2 */
65 dkT("*"),
66
67 NULL
68
69 };
70
71
72
73 /** Names for scope settings.
74 */
75 static const dkChar * const dk4wxpref_scope_names[] = {
76 /* 0 */
77 dkT("user"),
78
79 /* 1 */
80 dkT("application"),
81
82 /* 2 */
83 dkT("application-group"),
84
85 /* 3 */
86 dkT("host"),
87
88 /* 4 */
89 dkT("windows"),
90
91 /* 5 */
92 dkT("non-windows"),
93
94 /* 6 */
95 dkT("language"),
96
97 /* 7 */
98 dkT("region"),
99
100 NULL
101
102 };
103
104
105 void
dk4wxpref_close(dk4_wx_pref_t * ptr)106 dk4wxpref_close(dk4_wx_pref_t *ptr)
107 {
108 if (NULL != ptr) {
109 dk4mem_release(ptr->name);
110 dk4mem_release(ptr->value);
111 dk4mem_free(ptr);
112 }
113 }
114
115
116
117 dk4_wx_pref_t *
dk4wxpref_open(const wxChar * name,const wxChar * value,dk4_er_t * erp)118 dk4wxpref_open(const wxChar *name, const wxChar *value, dk4_er_t *erp)
119 {
120 dk4_wx_pref_t *back = NULL;
121 if ((NULL != name) && (NULL != value)) {
122 back = dk4mem_new(dk4_wx_pref_t,1,erp);
123 if (NULL != back) {
124 back->name = back->value = NULL;
125 back->name = dk4strx_dup(name, erp);
126 back->value = dk4strx_dup(value, erp);
127 if ((NULL == back->name) || (NULL == back->value)) {
128 dk4wxpref_close(back);
129 back = NULL;
130 } else {
131 dk4error_set_simple_error_code(erp, DK4_E_MEMORY_ALLOCATION_FAILED);
132 }
133 } else {
134 dk4error_set_simple_error_code(erp, DK4_E_MEMORY_ALLOCATION_FAILED);
135 }
136 } else {
137 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
138 }
139 return back;
140 }
141
142
143
144 int
dk4wxpref_compare(const void * l,const void * r,int cr)145 dk4wxpref_compare(const void *l, const void *r, int cr)
146 {
147 const dk4_wx_pref_t *lptr;
148 const dk4_wx_pref_t *rptr;
149 int back = 0;
150 if (NULL != l) {
151 if (NULL != r) {
152 lptr = (const dk4_wx_pref_t *)l;
153 switch (cr) {
154 case 1: {
155 if (NULL != lptr->name) {
156 back = dk4strx_cmp(lptr->name, (const wxChar *)r);
157 } else back = -1;
158 } break;
159 default: {
160 rptr = (const dk4_wx_pref_t *)r;
161 if (NULL != lptr->name) {
162 if (NULL != rptr->name) {
163 back = dk4strx_cmp(lptr->name, rptr->name);
164 } else back = 1;
165 } else {
166 if (NULL != rptr->name) back = -1;
167 }
168 } break;
169 }
170 if (-1 > back) back = -1;
171 if ( 1 < back) back = 1;
172 } else back = 1;
173 } else {
174 if (NULL != r) back = -1;
175 }
176 return back;
177 }
178
179
180
181 #if DK4_HAVE_COMPATDKTOOLS3
182
183 /** Modify version 3 preference names to version 4 names.
184 I.e. /a/b/c -> a.b.c
185 @param pstr String to modify.
186 */
187 static
188 void
dk4wxpref_modify_compatible(dkChar * pstr)189 dk4wxpref_modify_compatible(dkChar *pstr)
190 {
191 if (dkT('/') == *pstr) {
192 dk4str_cpy_to_left(pstr, &(pstr[1]));
193 }
194 while (dkT('\0') != *pstr) {
195 if (dkT('/') == *pstr) { *pstr = dkT('.'); }
196 pstr++;
197 }
198 }
199
200 #endif
201
202
203
204 /** Test one scope entry.
205 @param rd Reader object.
206 @param scn Scope part name.
207 @return 1 if test succeeded, 0 otherwise.
208 */
209 static
210 int
dk4wxpref_check_one_scope_entry(dk4_wx_pref_rd_t * rd,dkChar * scn)211 dk4wxpref_check_one_scope_entry(dk4_wx_pref_rd_t *rd, dkChar *scn)
212 {
213 dkChar *scv = NULL;
214 int back = 1;
215 scn = dk4str_start(scn, NULL);
216 if (NULL != scn) {
217 scv = dk4str_chr(scn, dkT('='));
218 if (NULL != scv) {
219 *(scv++) = dkT('\0'); scv = dk4str_start(scv, NULL);
220 }
221 dk4str_normalize(scn, NULL);
222 if (NULL != scv) { dk4str_normalize(scv, NULL); }
223 back = 0;
224 switch (dk4str_array_index(dk4wxpref_scope_names, scn, 0)) {
225 case 0: { /* user */
226 if (NULL != scv) {
227 if (0 == dk4str_cmp(dk4wxpref_kw_dk[2], scv)) {
228 back = 1;
229 } else {
230 if (NULL != rd->nameLog) {
231 #if DK4_HAVE_CASE_INSENSITIVE_USERNAMES
232 if (0 == dk4str_casecmp(rd->nameLog, scv))
233 #else
234 if (0 == dk4str_cmp(rd->nameLog, scv))
235 #endif
236 {
237 back = 1;
238 }
239 }
240 }
241 }
242 } break;
243 case 1: { /* application */
244 if (NULL != scv) {
245 if (0 == dk4str_cmp(dk4wxpref_kw_dk[2], scv)) {
246 back = 1;
247 } else {
248 if (NULL != rd->nameApp) {
249 if (0 == dk4str_cmp(rd->nameApp, scv)) {
250 back = 1;
251 }
252 }
253 }
254 }
255 } break;
256 case 2: { /* application group */
257 if (NULL != scv) {
258 if (0 == dk4str_cmp(dk4wxpref_kw_dk[2], scv)) {
259 back = 1;
260 } else {
261 if (NULL != rd->nameGrp) {
262 if (0 == dk4str_cmp(rd->nameGrp, scv)) {
263 back = 1;
264 }
265 }
266 }
267 }
268 } break;
269 case 3: { /* host */
270 if (NULL != scv) {
271 if (0 == dk4str_cmp(dk4wxpref_kw_dk[2], scv)) {
272 back = 1;
273 } else {
274 if (NULL != rd->nameHost) {
275 if (0 == dk4str_casecmp(rd->nameHost, scv)) {
276 back = 1;
277 }
278 }
279 }
280 }
281 } break;
282 case 4: { /* windows */
283 if (NULL != scv) {
284 if (0 != dk4str_is_on(scv)) {
285 #if DK4_ON_WINDOWS
286 back = 1;
287 #endif
288 } else {
289 #if !(DK4_ON_WINDOWS)
290 back = 1;
291 #endif
292 }
293 } else {
294 #if DK4_ON_WINDOWS
295 back = 1;
296 #endif
297 }
298 } break;
299 case 5: { /* non-windows */
300 if (NULL != scv) {
301 if (0 != dk4str_is_on(scv)) {
302 #if !(DK4_ON_WINDOWS)
303 back = 1;
304 #endif
305 } else {
306 #if DK4_ON_WINDOWS
307 back = 1;
308 #endif
309 }
310 } else {
311 #if !(DK4_ON_WINDOWS)
312 back = 1;
313 #endif
314 }
315 } break;
316 case 6: { /* language */
317 if (NULL != scv) {
318 if (0 == dk4str_cmp(dk4wxpref_kw_dk[2], scv)) {
319 back = 1;
320 } else {
321 if (NULL != rd->language) {
322 if (0 == dk4str_casecmp(rd->language, scv)) {
323 back = 1;
324 }
325 }
326 }
327 }
328 } break;
329 case 7: { /* region */
330 if (NULL != scv) {
331 if (0 == dk4str_cmp(dk4wxpref_kw_dk[2], scv)) {
332 back = 1;
333 } else {
334 if (NULL != rd->region) {
335 if (0 == dk4str_casecmp(rd->region, scv)) {
336 back = 1;
337 }
338 }
339 }
340 }
341 } break;
342 }
343 }
344 return back;
345 }
346
347
348
349 /** Process one input line.
350 @param obj Preferences reader object.
351 @param line Current line to process.
352 @param lineno Line number.
353 @param erp Error report, may be NULL.
354 @return
355 DK4_TSP_RES_OK if processing succeeded,
356 DK4_TSP_RES_ERROR on errors (can continue),
357 DK4_TSP_RES_FATAL on fatal errors (can not continue).
358
359 */
360 static
361 int
dk4wxpref_line_handler(void * obj,dkChar * line,dk4_um_t WXUNUSED (lineno),dk4_er_t * WXUNUSED (erp))362 dk4wxpref_line_handler(
363 void *obj,
364 dkChar *line,
365 dk4_um_t WXUNUSED(lineno),
366 dk4_er_t * WXUNUSED(erp)
367 )
368 {
369 dk4_wx_pref_rd_t *rd; /* Reader object */
370 dk4_wx_pref_t *pptr; /* New pref */
371 dkChar *p1; /* Pref name */
372 dkChar *p2; /* Pref value */
373 wxChar *nv; /* New value */
374 int isneg; /* Flag: Not in scope */
375 int ok; /* Flag: Tests passed */
376 int res; /* Operation result */
377 int back = DK4_TSP_RES_OK; /* Function result */
378
379 rd = (dk4_wx_pref_rd_t *)obj;
380 dk4str_delnl(line);
381 p1 = dk4str_start(line, NULL);
382 if (NULL != p1) {
383 if (dkT('#') != *p1) {
384 if (dkT('[') == *p1) {
385 if (0 == rd->lasc) {
386 rd->insc = 0;
387 }
388 p2 = dk4str_chr(p1, dkT(']'));
389 if (NULL != p2) { *p2 = dkT('\0'); }
390 p1++;
391 if (dkT('-') == *p1) {
392 isneg = 1;
393 p1++;
394 } else {
395 isneg = 0;
396 }
397 ok = 1;
398 while (NULL != p1) {
399 p2 = dk4str_chr(p1, dkT(','));
400 if (NULL != p2) {
401 *(p2++) = dkT('\0'); p2 = dk4str_start(p2, NULL);
402 }
403 if (0 == dk4wxpref_check_one_scope_entry(rd, p1)) { ok = 0; }
404 p1 = p2;
405 }
406 if (1 == ok) {
407 if (0 != isneg) { rd->insc = 0; } else { rd->insc = 1; }
408 }
409 rd->lasc = 1;
410 } else {
411 if (rd->insc) {
412 p2 = dk4str_chr(p1, dkT('='));
413 if (NULL != p2) {
414 *(p2++) = dkT('\0');
415 p2 = dk4str_start(p2, NULL);
416 }
417 if ((NULL != p1) && (NULL != p2)) {
418 dk4str_normalize(p1, NULL);
419 dk4str_rtwh(p2, NULL);
420 #if DK4_HAVE_COMPATDKTOOLS3
421 if (0 != rd->compat) {
422 dk4wxpref_modify_compatible(p1);
423 }
424 #endif
425 res = dk4recwx_dkchar_to_wxchar(
426 rd->wx1, rd->szwx, rd->encWx, p1, rd->encDk, NULL
427 );
428 if (0 < res) {
429 res = dk4recwx_dkchar_to_wxchar(
430 rd->wx2, rd->szwx, rd->encWx, p2, rd->encDk, NULL
431 );
432 if (0 < res) {
433 pptr = (dk4_wx_pref_t *)dk4sto_it_find_like(
434 rd->ipref, rd->wx1, 1
435 );
436 if (NULL != pptr) {
437 nv = dk4strx_dup(rd->wx2, NULL);
438 if (NULL != nv) {
439 dk4mem_release(pptr->value);
440 pptr->value = nv;
441 }
442 } else {
443 pptr = dk4wxpref_open(rd->wx1, rd->wx2, NULL);
444 if (NULL != pptr) {
445 if (0 == dk4sto_add(rd->spref, pptr, NULL)) {
446 dk4wxpref_close(pptr);
447 }
448 }
449 }
450 }
451 }
452 }
453 }
454 rd->lasc = 0;
455 }
456 } else {
457 }
458 } else {
459 }
460 return back;
461 }
462
463
464
465
466 /** Use one file.
467 @param spref Preferences storage.
468 @param ipref Iterator for preferences storage.
469 @param nameApp Application name.
470 @param nameGrp Application group name.
471 @param nameLog Users login name.
472 @param nameHost Host name.
473 @param language Language.
474 @param region Region.
475 @param fn File name.
476 @param encWx Encoding for wxChar strings.
477 @param encDk Encoding for dkChar strings.
478 @param encFile Expected encoding for files.
479 @param compat Flag: In compatibility mode.
480 */
481 static
482 void
dk4wxpref_one_file(dk4_sto_t * spref,dk4_sto_it_t * ipref,const dkChar * nameApp,const dkChar * nameGrp,const dkChar * nameLog,const dkChar * nameHost,const dkChar * language,const dkChar * region,const dkChar * fn,int encWx,int encDk,int encFile,int compat)483 dk4wxpref_one_file(
484 dk4_sto_t *spref,
485 dk4_sto_it_t *ipref,
486 const dkChar *nameApp,
487 const dkChar *nameGrp,
488 const dkChar *nameLog,
489 const dkChar *nameHost,
490 const dkChar *language,
491 const dkChar *region,
492 const dkChar *fn,
493 int encWx,
494 int encDk,
495 int encFile,
496 int compat
497 )
498 {
499 char ib[4096]; /* Input buffer for stream read */
500 wxChar wx1[1024]; /* Buffer for conversion */
501 wxChar wx2[DK4_SIZEOF(wx1,wxChar)]; /* too */
502 dkChar il[1024]; /* Input line */
503 dk4_wx_pref_rd_t rd; /* Reader object */
504 dk4_er_t er; /* Error report */
505 dk4_tspdk_t tsp; /* Text stream processing */
506 dk4_stream_t *istrm; /* Input stream */
507 size_t szil = DK4_SIZEOF(il,dkChar); /* Buffer size */
508 size_t szwx = DK4_SIZEOF(wx1,wxChar); /* Buffer size */
509 size_t rb; /* Bytes read */
510 int res; /* Operation result */
511 int cc; /* Flag: Can continue */
512
513 dk4error_init(&er);
514 istrm = dk4stream_open_file_reader(fn, &er);
515 if (NULL != istrm) {
516 rd.spref = spref; rd.ipref = ipref;
517 rd.nameApp = nameApp; rd.nameGrp = nameGrp; rd.nameLog = nameLog;
518 rd.nameHost = nameHost;
519 rd.language = language; rd.region = region; rd.compat = compat;
520 rd.encWx = encWx; rd.encDk = encDk;
521 rd.insc = 1; rd.lasc = 0;
522 rd.wx1 = wx1; rd.wx2 = wx2; rd.szwx = szwx;
523 res = dk4tspdk_setup_line(
524 &tsp, &rd,
525 (dk4_dk_line_handler_t *)dk4wxpref_line_handler,
526 il, szil, encDk, encFile, &er
527 );
528 if (0 != res) {
529 cc = 1;
530 while (1 == cc) {
531 cc = 0;
532 rb = sizeof(ib);
533 if (0 != dk4stream_read(ib, &rb, istrm, &er)) {
534 if (0 < rb) {
535 cc = 1;
536 res = dk4tspdk_add_bytes(&tsp, (const unsigned char *)ib, rb);
537 if (DK4_TSP_RES_FATAL == res) {
538 cc = -1;
539 }
540 }
541 }
542 }
543 if (0 == cc) {
544 #if VERSION_BEFORE_20150821
545 res = dk4tspdk_finish(&tsp);
546 #else
547 (void)dk4tspdk_finish(&tsp);
548 #endif
549 }
550 }
551 dk4stream_close(istrm, NULL);
552 }
553 }
554
555
556
557 void
dk4wxpref_one_pass(dk4_sto_t * spref,dk4_sto_it_t * ipref,const dkChar * nameApp,const dkChar * nameGrp,const dkChar * nameLog,const dkChar * nameHost,const dkChar * language,const dkChar * region,const dkChar * dirHome,const dkChar * dirEtc,const dkChar * dirShare,int encWx,int encDk,int encFile,int pn)558 dk4wxpref_one_pass(
559 dk4_sto_t *spref,
560 dk4_sto_it_t *ipref,
561 const dkChar *nameApp,
562 const dkChar *nameGrp,
563 const dkChar *nameLog,
564 const dkChar *nameHost,
565 const dkChar *language,
566 const dkChar *region,
567 const dkChar *dirHome,
568 const dkChar *dirEtc,
569 const dkChar *dirShare,
570 int encWx,
571 int encDk,
572 int encFile,
573 int pn
574 )
575 {
576 dkChar fnb[DK4_MAX_PATH];
577 dk4_er_t er;
578 size_t szfnb = DK4_SIZEOF(fnb,dkChar);
579 int res;
580
581 #if DK4_HAVE_COMPATDKTOOLS3
582 dk4error_init(&er);
583 res = dk4fs_config_compat_one(
584 fnb, szfnb, dk4wxpref_kw_dk[0], dirShare, dirEtc, dirHome,
585 nameApp, nameGrp, pn, 1, 1, &er
586 );
587 if (0 != res) {
588 dk4wxpref_one_file(
589 spref, ipref, nameApp, nameGrp, nameLog, nameHost, language, region, fnb,
590 encWx, encDk, encFile, 1
591 );
592 }
593 #endif
594 dk4error_init(&er);
595 res = dk4fs_config_one(
596 fnb, szfnb, dk4wxpref_kw_dk[1], dirShare, dirEtc, dirHome,
597 nameApp, nameGrp, pn, 1, &er
598 );
599 if (0 != res) {
600 dk4wxpref_one_file(
601 spref, ipref, nameApp, nameGrp, nameLog, nameHost, language, region, fnb,
602 encWx, encDk, encFile, 0
603 );
604 }
605 }
606
607