1 /*
2 Copyright (C) 2017-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: dk4opt07.ctr
12 */
13
14 /** @file dk4opt07.c The dk4opt07 module.
15 */
16
17
18 #include "dk4conf.h"
19 #include <libdk4base/dk4types.h>
20 #include <libdk4base/dk4error.h>
21 #include <libdk4c/dk4opt.h>
22 #include <libdk4maiodd/dk4maidddi.h>
23 #include <libdk4maiodd/dk4maidddu.h>
24 #include <libdk4maiodd/dk4maiddsz.h>
25 #include <libdk4maiodd/dk4maiddbl.h>
26 #include <libdk4base/dk4strd.h>
27 #include <libdk4c/dk4fput.h>
28
29 #if DK4_HAVE_ASSERT_H
30 #ifndef ASSERT_H_INCLUDED
31 #include <assert.h>
32 #define ASSERT_H_INCLUDED 1
33 #endif
34 #endif
35
36
37
38
39
40
41 static const dkChar * const dk4opt_kwnl[] = {
42 /* 0 */
43 dkT("\n"),
44
45 /* 1 */
46 dkT("ERROR: Option "),
47
48 /* 2 */
49 dkT("-"),
50
51 /* 3 */
52 dkT("/"),
53
54 /* 4 */
55 dkT("--"),
56
57 /* 5 */
58 dkT(" requires "),
59
60 /* 6 */
61 dkT("boolean "),
62
63 /* 7 */
64 dkT("size "),
65
66 /* 8 */
67 dkT("integer "),
68
69 /* 9 */
70 dkT("unsigned integer "),
71
72 /* 10 */
73 dkT("double "),
74
75 /* 11 */
76 dkT("string "),
77
78 /* 12 */
79 dkT("argument!\n"),
80
81 /* 13 */
82 dkT("Illegal argument text: \""),
83
84 /* 14 */
85 dkT("\"!\n"),
86
87 /* 15 */
88 dkT(": "),
89
90 /* 16 */
91 dkT("ERROR: No file names expected!\n"),
92
93 /* 17 */
94 dkT("ERROR: Too many file names!\n"),
95
96 /* 18 */
97 dkT("ERROR: Illegal option: \""),
98
99 /* 19 */
100 dkT("\"!\n"),
101
102 /* 20 */
103 dkT("Warning: Option used multiple times: \""),
104
105 /* 21 */
106 dkT("\".\n"),
107
108 /* 22 */
109 dkT("Warning: Unused argument in option: \""),
110
111 /* 23 */
112 dkT("\".\n"),
113
114 NULL
115
116 };
117
118
119
120 static
121 void
dk4opt_log_1(size_t kwind,const dkChar * progname,int logstderr)122 dk4opt_log_1(
123 size_t kwind,
124 const dkChar *progname,
125 int logstderr
126 )
127 {
128 if (0 != logstderr) {
129 dk4fput_initialize_stderr();
130 if (NULL != progname) {
131 dk4fputs(progname, stderr, NULL);
132 dk4fputs(dk4opt_kwnl[15], stderr, NULL);
133 }
134 dk4fputs(dk4opt_kwnl[kwind], stderr, NULL);
135 fflush(stderr);
136 }
137 }
138
139
140
141 static
142 void
dk4opt_log_3(size_t kwi1,size_t kwi2,const dkChar * vartext,const dkChar * progname,int logstderr)143 dk4opt_log_3(
144 size_t kwi1,
145 size_t kwi2,
146 const dkChar *vartext,
147 const dkChar *progname,
148 int logstderr
149 )
150 {
151 if (0 != logstderr) {
152 dk4fput_initialize_stderr();
153 if (NULL != progname) {
154 dk4fputs(progname, stderr, NULL);
155 dk4fputs(dk4opt_kwnl[15], stderr, NULL);
156 }
157 dk4fputs(dk4opt_kwnl[kwi1], stderr, NULL);
158 if (NULL != vartext) {
159 dk4fputs(vartext, stderr, NULL);
160 }
161 dk4fputs(dk4opt_kwnl[kwi2], stderr, NULL);
162 fflush(stderr);
163 }
164 }
165
166
167 static
168 void
dk4opt_complain_argument(dk4_option_t * opt,const dkChar * valstr,const dkChar * argv0,int progname,int logstderr)169 dk4opt_complain_argument(
170 dk4_option_t *opt,
171 const dkChar *valstr,
172 const dkChar *argv0,
173 int progname,
174 int logstderr
175 )
176 {
177 #if DK4_USE_ASSERT
178 assert(NULL != opt);
179 #endif
180 if (0 != logstderr) {
181 if ((dkT('\0') != opt->spec.c) || (NULL != opt->spec.longopt)) {
182 dk4fput_initialize_stderr();
183 if ((0 != progname) && (NULL != argv0)) {
184 dk4fputs(argv0, stderr, NULL);
185 dk4fputs(dk4opt_kwnl[15], stderr, NULL);
186 }
187 dk4fputs(dk4opt_kwnl[1], stderr, NULL);
188 if (dkT('\0') != opt->spec.c) {
189 dk4fputs(dk4opt_kwnl[2], stderr, NULL);
190 dk4fputc(opt->spec.c, stderr, NULL);
191 if (NULL != opt->spec.longopt) {
192 dk4fputs(dk4opt_kwnl[3], stderr, NULL);
193 }
194 }
195 if (NULL != opt->spec.longopt) {
196 dk4fputs(dk4opt_kwnl[4], stderr, NULL);
197 dk4fputs(opt->spec.longopt, stderr, NULL);
198 }
199 dk4fputs(dk4opt_kwnl[5], stderr, NULL);
200 switch (opt->spec.argtype) {
201 case DK4_OPT_ARG_BOOL : {
202 dk4fputs(dk4opt_kwnl[6], stderr, NULL);
203 } break;
204 case DK4_OPT_ARG_SIZE : {
205 dk4fputs(dk4opt_kwnl[7], stderr, NULL);
206 } break;
207 case DK4_OPT_ARG_INT : {
208 dk4fputs(dk4opt_kwnl[8], stderr, NULL);
209 } break;
210 case DK4_OPT_ARG_UNSIGNED : {
211 dk4fputs(dk4opt_kwnl[9], stderr, NULL);
212 } break;
213 case DK4_OPT_ARG_DOUBLE : {
214 dk4fputs(dk4opt_kwnl[10], stderr, NULL);
215 } break;
216 }
217 dk4fputs(dk4opt_kwnl[12], stderr, NULL);
218 if (NULL != valstr) {
219 dk4fputs(dk4opt_kwnl[13], stderr, NULL);
220 dk4fputs(valstr, stderr, NULL);
221 dk4fputs(dk4opt_kwnl[14], stderr, NULL);
222 }
223 fflush(stderr);
224 }
225 }
226 }
227
228
229
230 /** Find first position of equal sign in string.
231 Before calling this function we manually checked there is no
232 equal sign at position 0.
233 @param str String to check.
234 @return Position of first equal sign on success, 0 on error.
235 */
236 static
237 size_t
dk4opt_i_equal_sign_position(const dkChar * str)238 dk4opt_i_equal_sign_position(const dkChar *str)
239 {
240 size_t back = 0;
241 size_t num = 0;
242 while ((dkT('\0') != *str) && (0 == back)) {
243 if (dkT('=') == *str) {
244 back = num;
245 } else {
246 str++; num++;
247 }
248 }
249 return back;
250 }
251
252
253
254 /** Set argument for one option.
255 @param opt Option to set.
256 @param valstr String containing the value.
257 @param logstderr Flag: Logging to stderr allowed.
258 @param progname Program name or NULL.
259 @return 1 on success, 0 on error.
260 */
261 static
262 int
dk4opt_i_set_value(dk4_option_t * opt,dkChar * valstr,int logstderr,const dkChar * progname)263 dk4opt_i_set_value(
264 dk4_option_t *opt,
265 dkChar *valstr,
266 int logstderr,
267 const dkChar *progname
268 )
269 {
270 const dkChar *ep = NULL; /* First unconvertable char */
271 double d = 0.0; /* Default double value */
272 dk4_um_t um = (dk4_um_t)0UL; /* Default unsigned value */
273 dk4_im_t im = (dk4_im_t)0L; /* Default integer value */
274 size_t sz = (size_t)0UL; /* Default size value */
275 int back = 0; /* Result */
276
277 #if DK4_USE_ASSERT
278 assert(NULL != opt);
279 #endif
280 switch (opt->spec.argtype) {
281 case DK4_OPT_ARG_BOOL : {
282 opt->val.b = 0;
283 opt->found = 0;
284 if (0 != dk4str_is_bool(valstr)) {
285 opt->val.b = ((0 != dk4str_is_on(valstr)) ? 1 : 0);
286 opt->found = 1;
287 back = 1;
288 } else {
289 back = dk4ma_input_dk_dec_dk4_im_t(&im, valstr, &ep, 1, NULL);
290 if (0 != back) {
291 opt->val.b = (((dk4_im_t)0L != im) ? 1 : 0);
292 opt->found = 1;
293 } else {
294 /* ERROR: Not a boolean */
295 dk4opt_complain_argument(
296 opt, valstr, progname, ((NULL != progname) ? 1 : 0), logstderr
297 );
298 }
299 }
300 } break;
301 case DK4_OPT_ARG_SIZE : {
302 opt->val.s = (size_t)0UL;
303 opt->found = 0;
304 back = dk4ma_input_dk_dec_size_t(&sz, valstr, &ep, 1, NULL);
305 if (0 != back) {
306 opt->val.s = sz;
307 opt->found = 1;
308 } else {
309 /* ERROR: Not a size */
310 dk4opt_complain_argument(
311 opt, valstr, progname, ((NULL != progname) ? 1 : 0), logstderr
312 );
313 }
314 } break;
315 case DK4_OPT_ARG_INT : {
316 opt->val.i = (dk4_im_t)0L;
317 opt->found = 0;
318 back = dk4ma_input_dk_dec_dk4_im_t(&im, valstr, &ep, 1, NULL);
319 if (0 != back) {
320 opt->val.i = im;
321 opt->found = 1;
322 } else {
323 /* ERROR: Not an int */
324 dk4opt_complain_argument(
325 opt, valstr, progname, ((NULL != progname) ? 1 : 0), logstderr
326 );
327 }
328 } break;
329 case DK4_OPT_ARG_UNSIGNED : {
330 opt->val.u = (dk4_um_t)0UL;
331 opt->found = 0;
332 back = dk4ma_input_dk_dec_dk4_um_t(&um, valstr, &ep, 1, NULL);
333 if (0 != back) {
334 opt->val.u = um;
335 opt->found = 1;
336 } else {
337 /* ERROR: Not an unsigned number */
338 dk4opt_complain_argument(
339 opt, valstr, progname, ((NULL != progname) ? 1 : 0), logstderr
340 );
341 }
342 } break;
343 case DK4_OPT_ARG_DOUBLE : {
344 opt->val.d = 0.0;
345 opt->found = 0;
346 back = dk4ma_input_dk_double(&d, valstr, &ep, 1, NULL);
347 if (0 != back) {
348 opt->val.d = d;
349 opt->found = 1;
350 } else {
351 /* ERROR: Not a double */
352 dk4opt_complain_argument(
353 opt, valstr, progname, ((NULL != progname) ? 1 : 0), logstderr
354 );
355 }
356 } break;
357 case DK4_OPT_ARG_STRING : {
358 opt->val.t = valstr;
359 opt->found = 1;
360 if (NULL != valstr) { back = 1; }
361 } break;
362 }
363 return back;
364 }
365
366
367
368 int
dk4opt_process_argv(dk4_option_t * optptr,size_t szoptptr,int argc,dkChar * argv[],dkChar ** filenames,size_t * nfilenames,int progname,int logstderr,dk4_er_t * erp)369 dk4opt_process_argv(
370 dk4_option_t *optptr,
371 size_t szoptptr,
372 int argc,
373 dkChar *argv[],
374 dkChar **filenames,
375 size_t *nfilenames,
376 int progname,
377 int logstderr,
378 dk4_er_t *erp
379 )
380 {
381 dkChar *curptr = NULL; /* Current argument to process */
382 dkChar *ocurptr = NULL; /* Original (complete) argument */
383 size_t fnused = 0; /* Used elements in filenames */
384 size_t j = 0; /* Option index to test */
385 size_t eqpos = 0; /* Equal sign position */
386 int i = 0; /* Current argument index */
387 int found = 0; /* Flag: current opt found in set */
388 int res = 0; /* Operation result */
389 int back = 0;
390
391 #if DK4_USE_ASSERT
392 assert(NULL != optptr);
393 assert(0 < szoptptr);
394 #endif
395 if ((NULL != optptr) && (0 < szoptptr)) {
396 for (j = 0; j < szoptptr; j++) {
397 optptr[j].found = 0;
398 optptr[j].val.t = NULL;
399 }
400 if ((0 < argc) && (NULL != argv)) {
401 if ((NULL != filenames) && (NULL != nfilenames)) {
402 for (fnused = 0; fnused < *nfilenames; fnused++) {
403 filenames[fnused] = NULL;
404 }
405 fnused = 0;
406 }
407 back = 1;
408 i = 0;
409 if (0 != progname) { i = 1; }
410 while(i < argc) {
411 ocurptr = curptr = argv[i];
412 if (dkT('-') == *curptr) {
413 curptr++;
414 if (dkT('-') == *curptr) {
415 curptr++;
416 if (dkT('\0' != *curptr)) {
417 if (dkT('=') != *curptr) {
418 eqpos = dk4opt_i_equal_sign_position(curptr);
419 found = 0;
420 for (j = 0; ((j < szoptptr) && (0 == found)); j++) {
421 if (NULL != optptr[j].spec.longopt) {
422 if (0 != eqpos) {
423 if (eqpos == dk4str_len(optptr[j].spec.longopt)) {
424 res = dk4str_ncmp(curptr,optptr[j].spec.longopt,eqpos);
425 } else {
426 res = 1;
427 }
428 } else {
429 res = dk4str_cmp(curptr, optptr[j].spec.longopt);
430 }
431 if (0 == res) {
432 if (0 != optptr[j].found) {
433 /* WARNING: Option used multiple times */
434 dk4opt_log_3(
435 20, 21, ocurptr, ((0 != progname) ? argv[0] : NULL),
436 logstderr
437 );
438 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
439 }
440 found = 1;
441 switch (optptr[j].spec.argtype) {
442 case DK4_OPT_ARG_BOOL :
443 case DK4_OPT_ARG_SIZE :
444 case DK4_OPT_ARG_INT :
445 case DK4_OPT_ARG_UNSIGNED :
446 case DK4_OPT_ARG_DOUBLE :
447 case DK4_OPT_ARG_STRING : {
448 if (0 < eqpos) {
449 curptr = &(curptr[eqpos+1]);
450 if (dkT('\0') == *curptr) {
451 curptr = NULL;
452 }
453 } else {
454 curptr = NULL;
455 }
456 if (NULL == curptr) {
457 if (++i < argc) {
458 curptr = argv[i];
459 }
460 }
461 if (NULL != curptr) {
462 res = dk4opt_i_set_value(
463 &(optptr[j]), curptr, logstderr,
464 ((0 != progname) ? argv[0] : NULL)
465 );
466 if (0 == res) {
467 back = 0;
468 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
469 }
470 } else {
471 back = 0;
472 /* ERROR: Option required argument */
473 dk4opt_complain_argument(
474 &(optptr[j]), NULL, argv[0], progname, logstderr
475 );
476 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
477 }
478 } break;
479 default : {
480 optptr[j].found = 1;
481 if (0 < eqpos) {
482 /* WARNING: Option does not use argument */
483 dk4opt_log_3(
484 22, 23, ocurptr,
485 ((0 != progname) ? argv[0] : NULL), logstderr
486 );
487 }
488 } break;
489 }
490 }
491 }
492 }
493 if (0 == found) {
494 back = 0;
495 /* ERROR: Illegal option */
496 dk4opt_log_3(
497 18,19,ocurptr,((0 != progname) ? argv[0] : NULL),logstderr
498 );
499 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
500 }
501 } else {
502 back = 0;
503 /* ERROR: Long option without name */
504 dk4opt_log_3(
505 18, 19, ocurptr, ((0 != progname) ? argv[0] : NULL), logstderr
506 );
507 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
508 }
509 } else {
510 if ((NULL != filenames) && (NULL != nfilenames)) {
511 if (fnused < *nfilenames) {
512 filenames[fnused++] = ocurptr;
513 } else {
514 back = 0;
515 /* ERROR: Too many file names */
516 dk4opt_log_1(17,((0 != progname) ? argv[0] : NULL),logstderr);
517 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
518 }
519 } else {
520 back = 0;
521 /*ERROR: No file names expected */
522 dk4opt_log_1(16, ((0 != progname) ? argv[0] : NULL), logstderr);
523 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
524 }
525 }
526 } else {
527 if (dkT('\0') != *curptr) {
528 found = 0;
529 for (j = 0; ((j < szoptptr) && (0 == found)); j++) {
530 if (optptr[j].spec.c == *curptr) {
531 if (0 != optptr[j].found) {
532 /* WARNING: Option used multiple times */
533 dk4opt_log_3(
534 20,21,ocurptr,((0 != progname) ? argv[0] : NULL),logstderr
535 );
536 }
537 found = 1;
538 switch(optptr[j].spec.argtype) {
539 case DK4_OPT_ARG_BOOL :
540 case DK4_OPT_ARG_SIZE :
541 case DK4_OPT_ARG_INT :
542 case DK4_OPT_ARG_UNSIGNED :
543 case DK4_OPT_ARG_DOUBLE :
544 case DK4_OPT_ARG_STRING : {
545 curptr++;
546 if (dkT('\0') == *curptr) {
547 curptr = NULL;
548 if (++i < argc) {
549 curptr = argv[i];
550 }
551 }
552 if (NULL != curptr) {
553 res = dk4opt_i_set_value(
554 &(optptr[j]), curptr, logstderr,
555 ((0 != progname) ? argv[0] : NULL)
556 );
557 if (0 == res) {
558 back = 0;
559 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
560 }
561 } else {
562 back = 0;
563 /* ERROR: Option requires argument */
564 dk4opt_complain_argument(
565 &(optptr[j]), NULL, argv[0], progname, logstderr
566 );
567 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
568 }
569 } break;
570 default : {
571 optptr[j].found = 1;
572 } break;
573 }
574 }
575 }
576 if (0 == found) {
577 back = 0;
578 /* ERROR: Option not found in specification */
579 dk4opt_log_3(
580 18, 19, ocurptr, ((0 != progname) ? argv[0] : NULL), logstderr
581 );
582 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
583 }
584 } else {
585 if ((NULL != filenames) && (NULL != nfilenames)) {
586 if (fnused < *nfilenames) {
587 filenames[fnused++] = ocurptr;
588 } else {
589 back = 0;
590 /* ERROR: Too many file names */
591 dk4opt_log_1(17,((0 != progname) ? argv[0] : NULL),logstderr);
592 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
593 }
594 } else {
595 back = 0;
596 /* ERROR: No file names expected */
597 dk4opt_log_1(16, ((0 != progname) ? argv[0] : NULL), logstderr);
598 dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
599 }
600 }
601 }
602 } else {
603 if ((NULL != filenames) && (NULL != nfilenames)) {
604 if (fnused < *nfilenames) {
605 filenames[fnused++] = curptr;
606 } else {
607 back = 0;
608 /* ERROR: Too many file names */
609 dk4opt_log_1(17, ((0 != progname) ? argv[0] : NULL), logstderr);
610 dk4error_set_simple_error_code(erp, DK4_E_BUFFER_TOO_SMALL);
611 }
612 } else {
613 back = 0;
614 /* ERROR: No file names expected */
615 dk4opt_log_1(16, ((0 != progname) ? argv[0] : NULL), logstderr);
616 dk4error_set_simple_error_code(erp, DK4_E_BUFFER_TOO_SMALL);
617 }
618 }
619 i++;
620 }
621 } else {
622 /* ERROR: Arguments */
623 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
624 }
625 } else {
626 /* ERROR: Arguments */
627 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
628 }
629 if (NULL != nfilenames) { *nfilenames = fnused; }
630
631 return back;
632 }
633
634