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