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