1 /*
2  * Project    : ipv6calc
3  * File       : ipv6calchelp.c
4  * Version    : $Id: 50128046d35b1cc796bdc470c9c6cacaa87940bd $
5  * Copyright  : 2002-2020 by Peter Bieringer <pb (at) bieringer.de>
6  *
7  * Information:
8  *  Help library
9  */
10 
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include "libipv6calc.h"
15 #include "libipv6calcdebug.h"
16 #include "ipv6calctypes.h"
17 #include "ipv6calcoptions.h"
18 #include "ipv6calchelp.h"
19 #include "config.h"
20 
21 #include "libieee.h"
22 #include "databases/lib/libipv6calc_db_wrapper.h"
23 #include "databases/lib/libipv6calc_db_wrapper_GeoIP2.h"
24 #include "databases/lib/libipv6calc_db_wrapper_IP2Location.h"
25 #include "databases/lib/libipv6calc_db_wrapper_DBIP2.h"
26 #include "databases/lib/libipv6calc_db_wrapper_BuiltIn.h"
27 #include "databases/lib/libipv6calc_db_wrapper_External.h"
28 
29 
30 /* to be defined in each application */
31 extern void printversion(void);
32 extern void printcopyright(void);
33 
34 
35 /* format option arguments */
printhelp_print(void)36 void printhelp_print(void) {
37 	fprintf(stderr, "   --printprefix        : print only prefix of IPv6 address\n");
38         fprintf(stderr, "   --printsuffix        : print only suffix of IPv6 address\n");
39 };
40 
printhelp_mask(void)41 void printhelp_mask(void) {
42 	fprintf(stderr, "   --maskprefix         : mask IPv6 address with prefix length (clears suffix bits)\n");
43         fprintf(stderr, "   --masksuffix         : mask IPv6 address with suffix length (clears prefix bits)\n");
44 };
45 
printhelp_case(void)46 void printhelp_case(void) {
47 	fprintf(stderr, "   --uppercase|-u       : print chars of IPv6 address in upper case\n");
48         fprintf(stderr, "   --lowercase|-l       : print chars of IPv6 address in lower case [default]\n");
49 };
50 
printhelp_printstartend(void)51 void printhelp_printstartend(void) {
52 	fprintf(stderr, "   --printstart <1-128> : print part of IPv6 address start from given number\n");
53 	fprintf(stderr, "   --printend   <1-128> : print part of IPv6 address end at given number\n");
54 };
55 
printhelp_doublecommands(void)56 void printhelp_doublecommands(void) {
57 	printversion();
58 	printcopyright();
59 	fprintf(stderr, "   Only one command may be specified!\n");
60 };
61 
printhelp_missinginputdata(void)62 void printhelp_missinginputdata(void) {
63 	printversion();
64 	printcopyright();
65 	fprintf(stderr, "   Missing or too few input data given!\n");
66 };
67 
68 /* list of input types */
printhelp_inputtypes(const uint32_t formatoptions)69 void printhelp_inputtypes(const uint32_t formatoptions) {
70 	int i, j;
71 	size_t maxlen = 0;
72 	char printformatstring[20];
73 
74 	if ((formatoptions & FORMATOPTION_machinereadable) == 0) {
75 		printversion();
76 		printcopyright();
77 	};
78 
79 	/* look for longest type definition */
80 	for (j = 0; j < MAXENTRIES_ARRAY(ipv6calc_formatstrings); j++) {
81 		if (strlen(ipv6calc_formatstrings[j].token) > maxlen) {
82 			maxlen = strlen(ipv6calc_formatstrings[j].token);
83 		};
84 	};
85 
86 	if (maxlen > 999) {
87 		fprintf(stderr, " Something going wrong with array 'ipv6calc_formatstrings'!\n");
88 		exit(EXIT_FAILURE);
89 	};
90 
91 	if ((formatoptions & FORMATOPTION_machinereadable) == 0) {
92 		snprintf(printformatstring, sizeof(printformatstring), "  %%-%ds : %%s\n", (int) maxlen);
93 	} else {
94 		snprintf(printformatstring, sizeof(printformatstring), "%%-%ds\n", (int) maxlen);
95 	}
96 
97 	DEBUGPRINT_WA(DEBUG_ipv6calcoptions, "Format string: %s", printformatstring);
98 
99 	if ((formatoptions & FORMATOPTION_machinereadable) == 0) fprintf(stderr, "\n Available input types:\n");
100 
101 	/* run through matrix */
102 	for (i = 0; i < MAXENTRIES_ARRAY(ipv6calc_formatmatrix); i++) {
103 		DEBUGPRINT_WA(DEBUG_ipv6calcoptions, "Row %d: %08x - %08x", i, (unsigned int) ipv6calc_formatmatrix[i][0], (unsigned int) ipv6calc_formatmatrix[i][1]);
104 		if (ipv6calc_formatmatrix[i][1] != 0) {
105 			/* available for input, look for name now */
106 			for (j = 0; j < MAXENTRIES_ARRAY(ipv6calc_formatstrings); j++) {
107 				DEBUGPRINT_WA(DEBUG_ipv6calcoptions, "Format-Row %d: %08x - %s - %s", j, (unsigned int) ipv6calc_formatstrings[j].number, ipv6calc_formatstrings[j].token, ipv6calc_formatstrings[j].explanation);
108 				if (ipv6calc_formatstrings[j].number == ipv6calc_formatmatrix[i][0]) {
109 					if ((formatoptions & FORMATOPTION_machinereadable) == 0) {
110 						fprintf(stderr, printformatstring, ipv6calc_formatstrings[j].token, ipv6calc_formatstrings[j].explanation);
111 					} else {
112 						fprintf(stdout, printformatstring, ipv6calc_formatstrings[j].token);
113 					};
114 				};
115 			};
116 		};
117 	};
118 
119 	if ((formatoptions & FORMATOPTION_machinereadable) == 0) fprintf(stderr, "\n");
120 };
121 
122 
123 /* list of output types */
printhelp_outputtypes(const uint32_t inputtype,const uint32_t formatoptions)124 void printhelp_outputtypes(const uint32_t inputtype, const uint32_t formatoptions) {
125 	int i, j;
126 	size_t maxlen = 0;
127 	char printformatstring[20];
128 
129 	if ((formatoptions & FORMATOPTION_machinereadable) == 0) {
130 		printversion();
131 		printcopyright();
132 	};
133 
134 	/* look for longest type definition */
135 	for (j = 0; j < MAXENTRIES_ARRAY(ipv6calc_formatstrings); j++) {
136 		if (strlen(ipv6calc_formatstrings[j].token) > maxlen) {
137 			maxlen = strlen(ipv6calc_formatstrings[j].token);
138 		};
139 	};
140 
141 	if (maxlen > 999) {
142 		fprintf(stderr, " Something going wrong with array 'ipv6calc_formatstrings'!\n");
143 		exit(EXIT_FAILURE);
144 	};
145 
146 	if ((formatoptions & FORMATOPTION_machinereadable) == 0) {
147 		snprintf(printformatstring, sizeof(printformatstring), "  %%-%ds : %%s\n", (int) maxlen);
148 	} else {
149 		snprintf(printformatstring, sizeof(printformatstring), "%%-%ds\n", (int) maxlen);
150 	};
151 
152 	DEBUGPRINT_WA(DEBUG_ipv6calcoptions, "Format string: %s", printformatstring);
153 
154 	if ((formatoptions & FORMATOPTION_machinereadable) == 0) {
155 		if ( (inputtype & ~ (FORMAT_auto | FORMAT_any) ) != 0 ) {
156 			fprintf(stderr, "\n Available output types filtered by input type:\n");
157 		} else {
158 			fprintf(stderr, "\n Available output types:\n");
159 		};
160 	};
161 
162 	/* run through matrix */
163 	for (j = 0; j < MAXENTRIES_ARRAY(ipv6calc_formatstrings); j++) {
164 		DEBUGPRINT_WA(DEBUG_ipv6calcoptions, "Format-Row %d: %08x - %s - %s", j, (unsigned int) ipv6calc_formatstrings[j].number, ipv6calc_formatstrings[j].token, ipv6calc_formatstrings[j].explanation);
165 
166 		for (i = 0; i < MAXENTRIES_ARRAY(ipv6calc_formatmatrix); i++) {
167 			if ( (inputtype & ~ (FORMAT_auto | FORMAT_any) ) != 0 ) {
168 				if (ipv6calc_formatmatrix[i][0] != inputtype) {
169 					/* skip */
170 					continue;
171 				};
172 			};
173 
174 			DEBUGPRINT_WA(DEBUG_ipv6calcoptions, "Row %d: %08x - %08x", i, (unsigned int) ipv6calc_formatmatrix[i][0], (unsigned int) ipv6calc_formatmatrix[i][1]);
175 
176 			if ((ipv6calc_formatmatrix[i][1] & ipv6calc_formatstrings[j].number) != 0) {
177 				/* available for output, look for name now */
178 				if (strlen(ipv6calc_formatstrings[j].explanation) > 0) {
179 					fprintf(stderr, printformatstring, ipv6calc_formatstrings[j].token, ipv6calc_formatstrings[j].explanation);
180 				} else {
181 					fprintf(stdout, printformatstring, ipv6calc_formatstrings[j].token, "(empty)");
182 				};
183 				break;
184 			};
185 		};
186 	};
187 
188 	if ((formatoptions & FORMATOPTION_machinereadable) == 0) {
189 		fprintf(stderr, "\n For examples and available format options use:\n");
190 		fprintf(stderr, "    -O|--out <type> --examples\n");
191 		fprintf(stderr, "\n");
192 	};
193 };
194 
195 
196 /* list of action types */
printhelp_actiontypes(const uint32_t formatoptions,const struct option longopts[])197 void printhelp_actiontypes(const uint32_t formatoptions, const struct option longopts[]) {
198 	int i, j, o, test, has_options;
199 	size_t maxlen = 0;
200 	char printformatstring[20], printformatstring2[20], printformatstring3[20];
201 
202 	if ((formatoptions & FORMATOPTION_machinereadable) == 0) {
203 		printversion();
204 		printcopyright();
205 	};
206 
207 	/* look for longest type definition */
208 	for (j = 0; j < MAXENTRIES_ARRAY(ipv6calc_actionstrings); j++) {
209 		if (strlen(ipv6calc_actionstrings[j].token) > maxlen) {
210 			maxlen = strlen(ipv6calc_actionstrings[j].token);
211 		};
212 	};
213 
214 	if (maxlen > 999) {
215 		fprintf(stderr, " Something going wrong with array 'ipv6calc_actionstrings'!\n");
216 		exit (EXIT_FAILURE);
217 	};
218 
219 	if ((formatoptions & FORMATOPTION_machinereadable) == 0) {
220 		snprintf(printformatstring, sizeof(printformatstring), "  %%-%ds : %%s\n", (int) maxlen);
221 	} else {
222 		snprintf(printformatstring, sizeof(printformatstring), "%%-%ds\n", (int) maxlen);
223 	};
224 
225 	snprintf(printformatstring2, sizeof(printformatstring2), "  %%-%ds%%s\n", (int) maxlen + 4);
226 	snprintf(printformatstring3, sizeof(printformatstring3), "  %%-%ds--%%s", (int) maxlen + 5);
227 
228 	DEBUGPRINT_WA(DEBUG_ipv6calcoptions, "Action string: %s", printformatstring);
229 
230 	if ((formatoptions & FORMATOPTION_machinereadable) == 0) fprintf(stderr, "\n Available action types:\n");
231 
232 	for (j = 0; j < MAXENTRIES_ARRAY(ipv6calc_actionstrings); j++) {
233 		DEBUGPRINT_WA(DEBUG_ipv6calcoptions, "Action-Row %d: %08x - %s - %s", j, (unsigned int) ipv6calc_actionstrings[j].number, ipv6calc_actionstrings[j].token, ipv6calc_actionstrings[j].explanation);
234 
235 		if ((formatoptions & FORMATOPTION_machinereadable) == 0) {
236 			fprintf(stderr, printformatstring, ipv6calc_actionstrings[j].token, ipv6calc_actionstrings[j].explanation);
237 
238 			test = 2;
239 			has_options = 0;
240 			while (test != 0) {
241 				if (test == 1) {
242 					fprintf(stderr, printformatstring2, "", "Options:");
243 				};
244 
245 				/* search for defined options */
246 				for (i = 0; i < MAXENTRIES_ARRAY(ipv6calc_actionoptionmap); i++) {
247 					DEBUGPRINT_WA(DEBUG_ipv6calcoptions, "Option %d", i)
248 
249 					if (ipv6calc_actionstrings[j].number == ipv6calc_actionoptionmap[i][0]) {
250 						if (ipv6calc_actionoptionmap[i][1] == 0) {
251 							/* no options supported */
252 							break;
253 						};
254 
255 						DEBUGPRINT_WA(DEBUG_ipv6calcoptions, "Option value: %08x", (unsigned int) ipv6calc_actionoptionmap[i][1]);
256 
257 						/* run through options */
258 						o = 0;
259 						while(longopts[o].name != NULL) {
260 							if ((ipv6calc_actionoptionmap[i][1] == (uint32_t) longopts[o].val)) {
261 								has_options = 1;
262 								if (test == 1) {
263 									fprintf(stderr, printformatstring3, "", longopts[o].name);
264 									if (longopts[o].has_arg > 0) {
265 										fprintf(stderr, " ...");
266 									};
267 									if (ipv6calc_actionoptionmap[i][2] > 0) {
268 										fprintf(stderr, " (optional)");
269 									} else {
270 										fprintf(stderr, " (required)");
271 									};
272 									fprintf(stderr, "\n");
273 								};
274 							};
275 							o++;
276 						};
277 					};
278 				};
279 				if (has_options == 0) {
280 					break;
281 				};
282 				test--;
283 			};
284 		} else {
285 			fprintf(stdout, printformatstring, ipv6calc_actionstrings[j].token);
286 		};
287 	};
288 	if ((formatoptions & FORMATOPTION_machinereadable) == 0) fprintf(stderr, "\n");
289 };
290 
291 
292 /* print global common help */
printhelp_common(const uint32_t help_features)293 void printhelp_common(const uint32_t help_features) {
294 	fprintf(stderr, "\n");
295 
296 	fprintf(stderr, "  [-d|--debug <debug value>] : debug value (bitwise like)\n");
297 	fprintf(stderr, "                                can also be set by IPV6CALC_DEBUG environment value\n");
298 	fprintf(stderr, "  [-v|--version [-v [-v]]]   : version information (2 optional detail levels)\n");
299 	fprintf(stderr, "  [-v|--version -h]          : explanation of feature tokens\n");
300 	fprintf(stderr, "  [-V|--verbose]             : be more verbose\n");
301 	fprintf(stderr, "  [-h|--help|-?]             : this online help\n");
302 
303 	if ((help_features & IPV6CALC_HELP_QUIET) != 0) {
304 		fprintf(stderr, "  [-q|--quiet]               : be more quiet\n");
305 	};
306 
307 	if ((help_features & IPV6CALC_HELP_IP2LOCATION) != 0) {
308 #ifdef SUPPORT_IP2LOCATION
309 		fprintf(stderr, "\n");
310 		fprintf(stderr, "  [--disable-ip2location           ] : IP2Location support disabled\n");
311 		fprintf(stderr, "  [--db-ip2location-disable        ] : IP2Location support disabled\n");
312 		fprintf(stderr, "  [--db-ip2location-dir <directory>] : IP2Location database directory (default: %s)\n", ip2location_db_dir);
313 #ifdef SUPPORT_IP2LOCATION_DYN
314 		fprintf(stderr, "  [--db-ip2location-lib <file>     ] : IP2Location library file (default: %s)\n", ip2location_lib_file);
315 #endif
316 		fprintf(stderr, "  [--db-ip2location-only-type <TYPE>]: IP2Location database only selected type (1-%d)\n", IP2LOCATION_DB_MAX);
317 		fprintf(stderr, "  [--db-ip2location-allow-softlinks] : IP2Location database softlinks allowed\n");
318 		fprintf(stderr, "     by default they are ignored because it is hard to autodetect COMM/LITE/SAMPLE\n");
319 		fprintf(stderr, "  [--db-ip2location-lite-to-sample-autoswitch-max-delta-months <MONTHS>]:\n");
320 		fprintf(stderr, "     autoswitch from LITE to SAMPLE databases if possible and delta is not more than %d months (0=disabled)\n", ip2location_db_lite_to_sample_autoswitch_max_delta_months);
321 		fprintf(stderr, "  [--db-ip2location-comm-to-lite-switch-min-delta-months <MONTHS>]:\n");
322 		fprintf(stderr, "     switch from COMM to LITE databases if possible and delta more than %d months (0=disabled)\n", ip2location_db_comm_to_lite_switch_min_delta_months);
323 #endif
324 	};
325 
326 	if ((help_features & IPV6CALC_HELP_GEOIP) != 0) {
327 #ifdef SUPPORT_GEOIP
328 		fprintf(stderr, "\n");
329 		fprintf(stderr, "  [--disable-geoip                 ] : GeoIP support disabled\n");
330 		fprintf(stderr, "  [--db-geoip-disable              ] : GeoIP support disabled\n");
331 		fprintf(stderr, "  [--db-geoip-dir       <directory>] : GeoIP database directory (default: %s)\n", geoip_db_dir);
332 #ifdef SUPPORT_GEOIP_DYN
333 		fprintf(stderr, "  [--db-geoip-lib       <file>     ] : GeoIP library file (default: %s)\n", geoip_lib_file);
334 #endif
335 #endif
336 	};
337 
338 	if ((help_features & IPV6CALC_HELP_MMDB) != 0) {
339 #ifdef SUPPORT_MMDB_DYN
340 		fprintf(stderr, "\n");
341 		fprintf(stderr, "  [--db-mmdb-lib       <file>      ] : MaxMindDB library file (default: %s)\n", mmdb_lib_file);
342 #endif
343 
344 #ifdef SUPPORT_GEOIP2
345 		fprintf(stderr, "\n");
346 		fprintf(stderr, "  [--disable-geoip2                ] : GeoIP(MaxMindDB) support disabled\n");
347 		fprintf(stderr, "  [--db-geoip2-disable             ] : GeoIP(MaxMindDB) support disabled\n");
348 		fprintf(stderr, "  [--db-geoip2-dir      <directory>] : GeoIP(MaxMindDB) database directory (default: %s)\n", geoip2_db_dir);
349 #endif
350 
351 #ifdef SUPPORT_DBIP2
352 		fprintf(stderr, "\n");
353 		fprintf(stderr, "  [--disable-dbip2                 ] : db-ip.com(MaxMindDB) support disabled\n");
354 		fprintf(stderr, "  [--db-dbip2-disable              ] : db-ip.com(MaxMindDB) support disabled\n");
355 		fprintf(stderr, "  [--db-dbip2-dir       <directory>] : db-ip.com(MaxMindDB) database directory (default: %s)\n", dbip2_db_dir);
356 		fprintf(stderr, "  [--db-dbip2-only-type <TYPE>]      : db-ip.com(MaxMindDB) database only selected type (1-%d)\n", DBIP2_DB_MAX);
357 		fprintf(stderr, "  [--db-dbip2-comm-to-free-switch-min-delta-months <MONTHS>]:\n");
358 		fprintf(stderr, "     switch from COMM to FREE databases if possible and delta more than %d months (0=disabled)\n", dbip2_db_comm_to_free_switch_min_delta_months);
359 #endif
360 	};
361 
362 	if ((help_features & IPV6CALC_HELP_EXTERNAL) != 0) {
363 #ifdef SUPPORT_EXTERNAL
364 		fprintf(stderr, "\n");
365 		fprintf(stderr, "  [--disable-external              ] : External support disabled\n");
366 		fprintf(stderr, "  [--db-external-disable           ] : External support disabled\n");
367 		fprintf(stderr, "  [--db-external-dir    <directory>] : External database directory (default: %s)\n", external_db_dir);
368 #endif
369 	};
370 
371 	if ((help_features & IPV6CALC_HELP_BUILTIN) != 0) {
372 #ifdef SUPPORT_BUILTIN
373 		fprintf(stderr, "\n");
374 		fprintf(stderr, "  [--disable-builtin               ] : BuiltIn support disabled\n");
375 		fprintf(stderr, "  [--db-builtin-disable            ] : BuiltIn support disabled\n");
376 #endif
377 
378 #if defined SUPPORT_EXTERNAL || defined SUPPORT_DBIP2 || defined SUPPORT_GEOIP2 || SUPPORT_IP2LOCATION
379 		fprintf(stderr, "\n");
380 		fprintf(stderr, "  [--db-priorization <entry1>[:...]] : Database priorization order list (overwrites default)\n");
381 		fprintf(stderr, "                                         colon separated:");
382 		int i;
383 		for (i = 0; i < MAXENTRIES_ARRAY(data_sources); i++) {
384 			fprintf(stderr, " %s", data_sources[i].shortname);
385 		};
386 		fprintf(stderr, "\n");
387 #endif
388 	};
389 
390 	fprintf(stderr, "\n");
391 	fprintf(stderr, " Hint: all long options can be predefined from environment by using\n");
392 	fprintf(stderr, "  prefix: IPV6CALC_ and  conversion: '-' -> '_' and lowercase -> uppercase\n");
393 	fprintf(stderr, "  example for options with values   : --db-dbip2-dir=<DIR>  ->  environment: IPV6CALC_DB_DBIP2_DIR=<DIR>\n");
394 	fprintf(stderr, "  example for options without values: --db-dbip2-disable    ->  environment: IPV6CALC_DB_DBIP2_DISABLE=1\n");
395 	fprintf(stderr, "                                                                              on|off|0|1 is supported\n");
396 
397 	fprintf(stderr, "\n");
398 	return;
399 };
400 
printhelp_shortcut_options(const struct option longopts[],const s_ipv6calc_longopts_shortopts_map longopts_shortopts_map[])401 void printhelp_shortcut_options(const struct option longopts[], const s_ipv6calc_longopts_shortopts_map longopts_shortopts_map[]) {
402 	int i = 0;
403 	int j;
404 	char c;
405 	const char *info;
406 
407 	fprintf(stderr, "\n");
408 	fprintf(stderr, " Usage with shortcut options: <shortcut option> [<format option> ...] <input data>\n");
409 	fprintf(stderr, "  for more information and available format options use: <shortcut option> -?|-h|--help\n");
410 	fprintf(stderr, "\n");
411 
412 	while(longopts[i].name != NULL) {
413 		if (longopts[i].val >= CMD_shortcut_start && longopts[i].val <= CMD_shortcut_end) {
414 			c = '\0';
415 			info = NULL;
416 
417 			if (longopts_shortopts_map != NULL) {
418 				DEBUGPRINT_WA(DEBUG_ipv6calcoptions, "Search in longopts_shortopts_map for %08x", longopts[i].val);
419 				j = 0;
420 				while (longopts_shortopts_map[j].val > 0) {
421 					DEBUGPRINT_WA(DEBUG_ipv6calcoptions, "Check against longopts_shortopts_map entry %d:%08x", j, longopts_shortopts_map[j].val);
422 					if (longopts[i].val == longopts_shortopts_map[j].val) {
423 						c = longopts_shortopts_map[j].c;
424 						info = longopts_shortopts_map[j].info;
425 						break;
426 					};
427 					j++;
428 				};
429 			};
430 
431 			if (c != '\0') {
432 				fprintf(stderr, "  -%c|--%s", c, longopts[i].name);
433 			} else {
434 				fprintf(stderr, "     --%s", longopts[i].name);
435 			};
436 
437 			if (info != NULL) {
438 				fprintf(stderr, " (%s)", info);
439 			};
440 
441 			fprintf(stderr, "\n");
442 		};
443 		i++;
444 	};
445 
446 	fprintf(stderr, "\n");
447 	return;
448 };
449 
450 
451 /* print help for output type examples */
452 
453 
printhelp_output_base85(void)454 static void printhelp_output_base85(void) {
455 	fprintf(stderr, " Print a given IPv6 address in base85 format (RFC 1924), e.g.\n");
456 	fprintf(stderr, "  1080:0:0:0:8:800:200c:417a -> 4)+k&C#VzJ4br>0wv%%Yp\n");
457 };
458 
printhelp_output_bitstring(void)459 static void printhelp_output_bitstring(void) {
460 	fprintf(stderr, " Print a given IPv6 address as a bitstring label for use with DNS, e.g.\n");
461 	fprintf(stderr, "  3ffe:ffff::1    -> \\[x3ffeffff000000000000000000000001/128].ip6.arpa.\n");
462 	fprintf(stderr, "  3ffe:ffff::1/64 -> \\[x3ffeffff000000000000000000000001/64].ip6.arpa.\n");
463 	fprintf(stderr, "  --printsuffix 3ffe:ffff::1/64 -> \\[x0000000000000001/64]\n");
464 	fprintf(stderr, "  --printprefix 3ffe:ffff::1/64 -> \\[x3ffeffff00000000/64]\n");
465 };
466 
printhelp_output_ipv6addr(void)467 static void printhelp_output_ipv6addr(void) {
468 	fprintf(stderr, " Print a given IPv6 address depending on format options:\n");
469 	fprintf(stderr, "  Uncompressed, e.g.\n");
470 	fprintf(stderr, "   3ffe:ffff:100:f101::1    -> 3ffe:ffff:100:f101:0:0:0:1\n");
471 	fprintf(stderr, "   3ffe:ffff:100:f101::1/64 -> 3ffe:ffff:100:f101:0:0:0:1/64\n");
472 	fprintf(stderr, "  Full uncompressed, e.g.\n");
473 	fprintf(stderr, "   3ffe:ffff:100:f101::1 -> 3ffe:ffff:0100:f101:0000:0000:0000:0001\n");
474 	fprintf(stderr, "  Compressed, e.g.\n");
475 	fprintf(stderr, "   3ffe:ffff:0100:f101:0000:0000:0000:0001 -> 3ffe:ffff:100:f101::1\n");
476 };
477 
printhelp_output_ipv6literal(void)478 static void printhelp_output_ipv6literal(void) {
479 	fprintf(stderr, " Print a given IPv6 address in literal format depending on format options:\n");
480 	fprintf(stderr, "  Uncompressed, e.g.\n");
481 	fprintf(stderr, "   2001:db8::1 -> 2001-db8-0-0-0-0-0-1.ipv6-literal.net\n");
482 	fprintf(stderr, "  Full uncompressed, e.g.\n");
483 	fprintf(stderr, "   2001:db8::1 -> 2001-0db8-0000-0000-0000-0000-0000-0001.ipv6-literal.net\n");
484 	fprintf(stderr, "  Compressed (default), e.g.\n");
485 	fprintf(stderr, "   2001:db8::1 -> 2001-db8--1.ipv6-literal.net\n");
486 	fprintf(stderr, "  With Scope ID, e.g.\n");
487 	fprintf(stderr, "   fe80::1%%0    -> fe80--1s0.ipv6-literal.net\n");
488 };
489 
printhelp_output_hex(void)490 static void printhelp_output_hex(void) {
491 	fprintf(stderr, " Print a given IPv4/v6 address in hex format depending on format options:\n");
492 	fprintf(stderr, "  without any format option, e.g.\n");
493 	fprintf(stderr, "   0123:4567:89ab:cdef:0000:1111:2222:3333 -> 0123456789abcdef0000111122223333\n");
494 	fprintf(stderr, "   1.2.3.4                                 -> 01020304\n");
495 };
496 
printhelp_output_eui64(void)497 static void printhelp_output_eui64(void) {
498 	fprintf(stderr, " Print a generated EUI-64 identifier, e.g.:\n");
499 	fprintf(stderr, "  00:50:BF:06:B4:F5 -> 0250:bfff:fe06:b4f5\n");
500 };
501 
printhelp_output_iid_token(void)502 static void printhelp_output_iid_token(void) {
503 	fprintf(stderr, " Print generated interface identifier and token, e.g.:\n");
504 	fprintf(stderr, "  -> 4462:bdea:8654:776d 486072ff7074945e\n");
505 };
506 
printhelp_output_revnibble_int(void)507 static void printhelp_output_revnibble_int(void) {
508 	fprintf(stderr, " Print a given IPv6 address in dot separated reverse nibble format for use with DNS, e.g.\n");
509 	fprintf(stderr, "  3ffe:ffff:100:f101::1\n    -> 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.1.f.0.0.1.0.0.0.4.0.e.f.f.3.ip6.int.\n");
510 	fprintf(stderr, "  3ffe:ffff:100:f101::1/64\n    -> 1.0.1.f.0.0.1.0.0.0.4.0.e.f.f.3.ip6.int.\n");
511 };
512 
printhelp_output_revnibble_arpa(void)513 static void printhelp_output_revnibble_arpa(void) {
514 	fprintf(stderr, " Print a given IPv6 address in dot separated reverse nibble format for use with DNS, e.g.\n");
515 	fprintf(stderr, "  3ffe:ffff:100:f101::1\n    -> 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.1.f.0.0.1.0.0.0.4.0.e.f.f.3.ip6.arpa.\n");
516 	fprintf(stderr, "  3ffe:ffff:100:f101::1/64\n    -> 1.0.1.f.0.0.1.0.0.0.4.0.e.f.f.3.ip6.arpa.\n");
517 };
518 
printhelp_input_revnibbles(void)519 static void printhelp_input_revnibbles(void) {
520 	fprintf(stderr, " Print reverse nibble format (used in DNS) as IPv6 address, e.g.\n");
521 	fprintf(stderr, "  1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.\n    -> 2001:db8::1/128\n");
522 	fprintf(stderr, "  8.b.d.0.1.0.0.2.ip6.arpa.\n    -> 2001:db8::/32\n");
523 	fprintf(stderr, "  8.b.d.0.1.0.0.2.ip6.arpa. --printprefix\n    -> 2001:db8\n");
524 	fprintf(stderr, "  1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0\n    -> ::1/64\n");
525 	fprintf(stderr, "  1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 --printsuffix\n    -> 0:0:0:1\n");
526 };
527 
528 
printhelp_output_ifinet6void(void)529 static void printhelp_output_ifinet6void(void) {
530 	fprintf(stderr, " Print a given IPv6 address to same format shown in Linux /proc/net/if_inet6:\n");
531 	fprintf(stderr, "  3ffe:ffff:100:f101::1    -> 3ffeffff0100f1010000000000000001 00\n");
532 	fprintf(stderr, "  3ffe:ffff:100:f101::1/64 -> 3ffeffff0100f1010000000000000001 00 40\n");
533 };
534 
printhelp_output_ipv4addr(void)535 static void printhelp_output_ipv4addr(void) {
536 	fprintf(stderr, " Print an IPv4 address, depending on format options:\n");
537 	fprintf(stderr, "  Uncompressed, e.g.\n");
538 	fprintf(stderr, "   1.2.0.0 -> 1.2.0.0\n");
539 	fprintf(stderr, "   1.2.0.  -> 1.2.0.0\n");
540 	fprintf(stderr, "   1.2     -> 1.2.0.0\n");
541 	fprintf(stderr, "  Compressed, e.g.\n");
542 	fprintf(stderr, "   1.2.0.0 -> 1.2\n");
543 };
544 
printhelp_output_revipv4(void)545 static void printhelp_output_revipv4(void) {
546 	fprintf(stderr, " Print an IPv4 address in reverse format for PTR/DNS\n");
547 	fprintf(stderr, "  1.2.3.4  -> 4.3.2.1.in-addr.arpa\n");
548 };
549 
printhelp_output_addrtype(void)550 static void printhelp_output_addrtype(void) {
551 	fprintf(stderr, " Print type of a given IPv4/IPv6 address:\n");
552 	fprintf(stderr, "  IPv4 address  -> ipv4-addr.addrtype.ipv6calc\n");
553 	fprintf(stderr, "  IPv6 address  -> ipv6-addr.addrtype.ipv6calc\n");
554 };
555 
printhelp_output_ipv6addrtype(void)556 static void printhelp_output_ipv6addrtype(void) {
557 	fprintf(stderr, " Print type of a given IPv6 address:\n");
558 	fprintf(stderr, "  3ffe::/16         -> 6bone-global.ipv6addrtype.ipv6calc\n");
559 	fprintf(stderr, "  2002::/16         -> 6to4-global.ipv6addrtype.ipv6calc\n");
560 	fprintf(stderr, "  2001::/16         -> productive-global.ipv6addrtype.ipv6calc\n");
561 	fprintf(stderr, "  fe80::/10         -> link-local.ipv6addrtype.ipv6calc\n");
562 	fprintf(stderr, "  fec0::/10         -> site-local.ipv6addrtype.ipv6calc\n");
563 	fprintf(stderr, "  ::ffff:0:0:0:0/96 -> mapped-ipv4.ipv6addrtype.ipv6calc\n");
564 	fprintf(stderr, "  ::0:0:0:0/96      -> compat-ipv4.ipv6addrtype.ipv6calc\n");
565 };
566 
printhelp_output_ouitype(void)567 static void printhelp_output_ouitype(void) {
568 	fprintf(stderr, " Print OUI name of a given IPv6 address:\n");
569 	fprintf(stderr, "  IID local scope   -> local-scoppe.ouitype.ipv6calc\n");
570 	fprintf(stderr, "  IID global scope  -> vendorname.ouitype.ipv6calc\n");
571 };
572 
printhelp_output_octal(void)573 static void printhelp_output_octal(void) {
574 	fprintf(stderr, " Print octal representation of a given IPv6 address:\n");
575 	fprintf(stderr, "  (useful for djbdns/tinydns)\n");
576 	fprintf(stderr, "  3ffe:ffff::1 ->\n    \\77\\376\\377\\377\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\1\n");
577 	fprintf(stderr, "  --printfulluncompressed 3ffe:ffff::1 ->\n    \\077\\376\\377\\377\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\001\n");
578 };
579 
printhelp_output_dispatcher(const uint32_t outputtype,const uint32_t inputtype)580 void printhelp_output_dispatcher(const uint32_t outputtype, const uint32_t inputtype) {
581 	int i, j;
582 
583 	printversion();
584 
585 	fprintf(stderr, "\n");
586 
587 	switch (outputtype) {
588 		case FORMAT_base85:
589 			printhelp_output_base85();
590 			break;
591 
592 		case FORMAT_bitstring:
593 			printhelp_output_bitstring();
594 			break;
595 
596 		case FORMAT_ipv6addr:
597 			printhelp_output_ipv6addr();
598 			break;
599 
600 		case FORMAT_ipv6literal:
601 			printhelp_output_ipv6literal();
602 			break;
603 
604 		case FORMAT_eui64:
605 			printhelp_output_eui64();
606 			break;
607 
608 		case FORMAT_revnibbles_int:
609 			printhelp_output_revnibble_int();
610 			break;
611 
612 		case FORMAT_revnibbles_arpa:
613 			printhelp_output_revnibble_arpa();
614 			break;
615 
616 		case FORMAT_ifinet6:
617 			printhelp_output_ifinet6void();
618 			break;
619 
620 		case FORMAT_iid_token:
621 			printhelp_output_iid_token();
622 			break;
623 
624 		case FORMAT_ipv4addr:
625 			printhelp_output_ipv4addr();
626 			break;
627 
628 		case FORMAT_addrtype:
629 			printhelp_output_addrtype();
630 			break;
631 
632 		case FORMAT_ipv6addrtype:
633 			printhelp_output_ipv6addrtype();
634 			break;
635 
636 		case FORMAT_ouitype:
637 			printhelp_output_ouitype();
638 			break;
639 
640 		case FORMAT_revipv4:
641 			printhelp_output_revipv4();
642 			break;
643 
644 		case FORMAT_octal:
645 			printhelp_output_octal();
646 			break;
647 
648 		case FORMAT_hex:
649 			printhelp_output_hex();
650 			break;
651 
652 		default:
653 			switch (inputtype) {
654 				case FORMAT_revnibbles_int:
655 				case FORMAT_revnibbles_arpa:
656 					printhelp_input_revnibbles();
657 					break;
658 
659 				default:
660 					fprintf(stderr, " Examples currently missing... (output type)!\n");
661 					break;
662 			};
663 			break;
664 	};
665 
666 	/* looking for outtype */
667 	for (i = 0; i < MAXENTRIES_ARRAY(ipv6calc_outputformatoptionmap); i++) {
668 		if (outputtype == ipv6calc_outputformatoptionmap[i][0]) {
669 			if (ipv6calc_outputformatoptionmap[i][1] == 0) {
670 				fprintf(stderr, " No format options supported\n");
671 				break;
672 			};
673 
674 			DEBUGPRINT_WA(DEBUG_ipv6calcoptions, "Format value: %08x", (unsigned int) ipv6calc_outputformatoptionmap[i][1]);
675 
676 			fprintf(stderr, "\n");
677 			fprintf(stderr, " Available format options:\n");
678 
679 			/* run through format options */
680 			for (j = 0; j < MAXENTRIES_ARRAY(ipv6calc_formatoptionstrings); j++) {
681 				if ((ipv6calc_outputformatoptionmap[i][1] & ipv6calc_formatoptionstrings[j].number) != 0) {
682 					fprintf(stderr, "  %s: %s\n", ipv6calc_formatoptionstrings[j].token, ipv6calc_formatoptionstrings[j].explanation);
683 				};
684 			};
685 			break;
686 		};
687 	};
688 	fprintf(stderr, "\n");
689 };
690 
691 /* help regarding action command */
692 /* in: embedded = 1 : do not show version and command */
printhelp_action_dispatcher(const uint32_t action,const int embedded)693 void printhelp_action_dispatcher(const uint32_t action, const int embedded) {
694 	int i, j;
695 	char method_name[32];
696 
697 	if (embedded != 1) {
698 		printversion();
699 	};
700 
701 	fprintf(stderr, "\n");
702 
703 	switch (action) {
704 		case ACTION_mac_to_eui64:
705 			fprintf(stderr, " help still missing - sorry.\n");
706 			break;
707 
708 		case ACTION_ipv4_to_6to4addr:
709 			fprintf(stderr, "  Convert IPv4 to 6to4 prefix / extract IPv4 from 6to4 prefix\n");
710 			fprintf(stderr, "   ipv6calc -A conv6to4 192.0.2.1\n");
711 			fprintf(stderr, "    2002:c000:201::\n");
712 			fprintf(stderr, "   ipv6calc -A conv6to4 2002:c000:201::\n");
713 			fprintf(stderr, "    192.0.2.1\n");
714 			break;
715 
716 		case ACTION_ipv4_to_nat64:
717 			fprintf(stderr, "  Convert IPv4 to NAT64 address / extract IPv4 from NAT64 address\n");
718 			fprintf(stderr, "   ipv6calc -A convnat64 192.0.2.1\n");
719 			fprintf(stderr, "    64:ff9b::c000:201\n");
720 			fprintf(stderr, "   ipv6calc -A convnat64 64:ff9b::c000:201\n");
721 			fprintf(stderr, "    192.0.2.1\n");
722 			break;
723 
724 		case ACTION_anonymize:
725 			if (embedded != 1) {
726 				fprintf(stderr, " Anonymize given address according to preset or custom values, e.g.\n");
727 				fprintf(stderr, "  ipv6calc -A anonymize 2001:db8:2280:6901:224:21ff:fe01:2345 --anonymize-preset zeroize-standard\n");
728 				fprintf(stderr, "   2001:db8:2280:6900:224:21ff:fe00:0\n");
729 				fprintf(stderr, "  ipv6calc -A anonymize 2001:db8:2280:6901:224:21ff:fe01:2345 --anonymize-preset anonymize-standard\n");
730 				fprintf(stderr, "   2001:db8:2280:6909:a929:4291:4022:4217\n");
731 				fprintf(stderr, "\n");
732 			};
733 
734 			fprintf(stderr, "  Shortcut for anonymization presets:\n");
735 			fprintf(stderr, "   --anonymize-standard (default)\n");
736 			fprintf(stderr, "   --anonymize-careful\n");
737 			fprintf(stderr, "   --anonymize-paranoid\n");
738 			fprintf(stderr, "\n");
739 			fprintf(stderr, "  Supported methods [--anonymize-method METHOD]:\n");
740 			for (i = 0; i < MAXENTRIES_ARRAY(ipv6calc_anon_methods); i++) {
741 				fprintf(stderr, "   %-10s: %s\n", ipv6calc_anon_methods[i].name, ipv6calc_anon_methods[i].description);
742 			};
743 			fprintf(stderr, "\n");
744 
745 			fprintf(stderr, "  Available presets (shortcut names) [--anonymize-preset|ap PRESET-NAME]:\n");
746 
747 			for (i = 0; i < MAXENTRIES_ARRAY(ipv6calc_anon_set_list); i++) {
748 				snprintf(method_name, sizeof(method_name), "%s", "unknown"); // default
749 
750 				for (j = 0; j < MAXENTRIES_ARRAY(ipv6calc_anon_methods); j++) {
751 					if (ipv6calc_anon_methods[j].method == ipv6calc_anon_set_list[i].method) {
752 						snprintf(method_name, sizeof(method_name), "%s", ipv6calc_anon_methods[j].name);
753 						break;
754 					};
755 				};
756 
757 				fprintf(stderr, "   %-20s (%2s): mask-ipv6=%3d mask-ipv4=%2d mask-eui64=%2d mask-mac=%2d mask-autoadjust=%-3s method=%s\n", ipv6calc_anon_set_list[i].name, ipv6calc_anon_set_list[i].name_short, ipv6calc_anon_set_list[i].mask_ipv6, ipv6calc_anon_set_list[i].mask_ipv4, ipv6calc_anon_set_list[i].mask_eui64, ipv6calc_anon_set_list[i].mask_mac, (ipv6calc_anon_set_list[i].mask_autoadjust == 1) ? "yes" : "no", method_name);
758 			};
759 			fprintf(stderr, "\n");
760 
761 			fprintf(stderr, "  Custom control:\n");
762 			fprintf(stderr, "  --mask-ipv4  <bits>     : mask IPv4 address [0-32] (even if occurs in IPv6 address)\n");
763 			fprintf(stderr, "  --mask-ipv6  <bits>     : mask IPv6 prefix [0-64] (only applied to related address types)\n");
764 			fprintf(stderr, "  --mask-eui64 <bits>     : mask EUI-64 address or IPv6 interface identifier [0-64]\n");
765 			fprintf(stderr, "  --mask-mac   <bits>     : mask MAC address [0-48]\n");
766 			fprintf(stderr, "  --mask-autoadjust yes|no: autoadjust mask to keep type/vendor information regardless of less given mask\n");
767 
768 			break;
769 
770 		case ACTION_iid_token_to_privacy:
771 			fprintf(stderr, " help still missing - sorry.\n");
772 			break;
773 
774 		case ACTION_prefix_mac_to_ipv6:
775 			fprintf(stderr, " help still missing - sorry.\n");
776 			break;
777 
778 		case ACTION_6rd_local_prefix:
779 			fprintf(stderr, " help still missing - sorry.\n");
780 			break;
781 
782 		case ACTION_filter:
783 			fprintf(stderr, " Filter given addresses from stdin by filter expression, e.g.\n");
784 			fprintf(stderr, "  echo '2001:db8::1' | ipv6calc [-A filter] -E iid-local\n");
785 			fprintf(stderr, "  echo '2001:db8::1' | ipv6calc [-A filter] -E iid-local,global-unicast\n");
786 			fprintf(stderr, "  echo '2001:db8::1' | ipv6calc [-A filter] -E ^iid-random\n");
787 			fprintf(stderr, "\n");
788 			fprintf(stderr, " (note: since version 0.95.0 '-A filter' is autoselected if option '-E <filter expression>' is given)\n");
789 			fprintf(stderr, "\n");
790 			fprintf(stderr, " negation of filter expression with prefix: ^\n");
791 			fprintf(stderr, "\n");
792 			fprintf(stderr, "  IPv6 address filter tokens:\n");
793 			fprintf(stderr, "   ipv6 ");
794 			for (i = 0; i < MAXENTRIES_ARRAY(ipv6calc_ipv6addrtypestrings); i++ ) {
795 				fprintf(stderr, " %s", ipv6calc_ipv6addrtypestrings[i].token);
796 			};
797 			fprintf(stderr, "\n");
798 			fprintf(stderr, "\n");
799 			fprintf(stderr, "  IPv4 address filter tokens:\n");
800 			fprintf(stderr, "   ipv4 ");
801 			for (i = 0; i < MAXENTRIES_ARRAY(ipv6calc_ipv4addrtypestrings); i++ ) {
802 				fprintf(stderr, " %s", ipv6calc_ipv4addrtypestrings[i].token);
803 			};
804 			fprintf(stderr, "\n");
805 			fprintf(stderr, "\n");
806 			fprintf(stderr, "  IPv4/v6 address filter tokens based on databases:\n");
807 			fprintf(stderr, "   [^][ipv4.|ipv6.]db.cc=<CC>|unknown (Country Code [2 chars])\n");
808 			fprintf(stderr, "   [^][ipv4.|ipv6.]db.asn=<ASN>|unknown (Autonomous System Number)\n");
809 			fprintf(stderr, "   [^][ipv4.|ipv6.]db.reg=<REGISTRY>\n");
810 			fprintf(stderr, "    Registry tokens:");
811 			for (i = 0; i < MAXENTRIES_ARRAY(ipv6calc_registries); i++ ) {
812 				fprintf(stderr, " %s", ipv6calc_registries[i].token);
813 			};
814 			fprintf(stderr, "\n");
815 			fprintf(stderr, "\n");
816 			fprintf(stderr, "  IPv4/v6 address filter tokens based on address/mask:\n");
817 			fprintf(stderr, "   [^]ipv4.addr=<IPV4-ADDRESS>[<PREFIX-LENGTH>]\n");
818 			fprintf(stderr, "   [^]ipv6.addr=<IPV6-ADDRESS>[<PREFIX-LENGTH>]\n");
819 			fprintf(stderr, "\n");
820 			fprintf(stderr, "  IPv4/v6 address filter tokens based on address ranges (<=|<|>|>=):\n");
821 			fprintf(stderr, "   [^]ipv4.addr(<=|<|>|>=)<IPV4-ADDRESS>\n");
822 			fprintf(stderr, "   [^]ipv6.addr(<=|<|>|>=)<IPV6-ADDRESS>\n");
823 			fprintf(stderr, "\n");
824 			fprintf(stderr, "   as alternative in case <|> creating problems also supported: =(le|lt|gt|ge)=:\n");
825 			fprintf(stderr, "   [^]ipv4.addr=(le|lt|gt|ge)=<IPV4-ADDRESS>\n");
826 			fprintf(stderr, "   [^]ipv6.addr=(le|lt|gt|ge)=<IPV6-ADDRESS>\n");
827 			fprintf(stderr, "\n");
828 			fprintf(stderr, "  EUI-48/MAC address filter tokens:\n");
829 			fprintf(stderr, "   ");
830 			fprintf(stderr, " IMPLEMENTATION MISSING");
831 			fprintf(stderr, "\n");
832 			fprintf(stderr, "\n");
833 			fprintf(stderr, "  EUI-64 address filter tokens:\n");
834 			fprintf(stderr, "   ");
835 			fprintf(stderr, " IMPLEMENTATION MISSING");
836 			fprintf(stderr, "\n");
837 			break;
838 
839 		case ACTION_test:
840 			fprintf(stderr, " Test given address(es) against supported tests:\n");
841 			fprintf(stderr, "  --test_prefix <PREFIX>       : inside a prefix\n");
842 			fprintf(stderr, "  --test_gt|--test_ge <ADDRESS>: greater(/equal) than an address\n");
843 			fprintf(stderr, "  --test_lt|--test_le <ADDRESS>: less(/equal) than an address\n");
844 			fprintf(stderr, "\n");
845 			fprintf(stderr, " Test given address(es) from stdin, e.g.\n");
846 			fprintf(stderr, "  echo '2001:db8::1' | ipv6calc [-A test] --test_prefix 2001:db8::/32\n");
847 			fprintf(stderr, "  echo '2001:db8::1' | ipv6calc [-A test] --test_prefix 2001:db9::/32\n");
848 			fprintf(stderr, "\n");
849 			fprintf(stderr, " Single address test, return code: 0=inside/matching 1=outside/not-matching 2=uncomparable\n");
850 			fprintf(stderr, "  ipv6calc [-A test] --test_prefix 2001:db8::/32 2001:db8::1\n");
851 			fprintf(stderr, "  ipv6calc [-A test] --test_prefix 2001:db9::/32 2001:db8::1\n");
852 			fprintf(stderr, "  ipv6calc [-A test] --test_ge 2001:db8:: --test_le 2001:db8:ffff:ffff:ffff:ffff:ffff:ffff 2001:db8::1\n");
853 			fprintf(stderr, "  ipv6calc [-A test] --test_ge 2001:db9:: --test_le 2001:db9:ffff:ffff:ffff:ffff:ffff:ffff 2001:db8::1\n");
854 			fprintf(stderr, "  ipv6calc [-A test] --test_ge 2001:db9:: --test_lt 2001:dba:: 2001:db8::1\n");
855 			fprintf(stderr, "  ipv6calc [-A test] --test_ge 2001:db8:: --test_lt 2001:db9:: 2001:db8::1\n");
856 			fprintf(stderr, "\n");
857 			break;
858 
859 		case ACTION_addr_to_countrycode:
860 			fprintf(stderr, " Convert given IPv4/IPv6 address to country code\n");
861 			fprintf(stderr, "  --addr2cc|-A addr2cc <ADDRESS>\n");
862 			fprintf(stderr, "\n");
863 			fprintf(stderr, " Examples:\n");
864 			fprintf(stderr, "  ipv6calc -A addr2cc 50.60.70.80\n");
865 			fprintf(stderr, "  US\n");
866 			fprintf(stderr, "\n");
867 			fprintf(stderr, " Example for address which has no country code:\n");
868 			fprintf(stderr, " (reason is only displayed in non-quiet mode)\n");
869 			fprintf(stderr, "  ipv6calc -A addr2cc 2001:db8::1\n");
870 			fprintf(stderr, "  -- (unknown)\n");
871 			fprintf(stderr, "\n");
872 			fprintf(stderr, " Example in case no related database is available:\n");
873 			fprintf(stderr, " (reason is only displayed in non-quiet mode)\n");
874 			fprintf(stderr, "  ipv6calc -A addr2cc 50.60.70.80\n");
875 			fprintf(stderr, "  -- (no-usable-database)\n");
876 			fprintf(stderr, "\n");
877 			break;
878 	};
879 };
880 
881 
882 /***************************
883  * verbose feature information
884  * *************************/
885 
886 /* display features in verbose mode */
ipv6calc_print_features_verbose(const int level_verbose)887 void ipv6calc_print_features_verbose(const int level_verbose) {
888 	char string[IPV6CALC_STRING_MAX] = "";
889 
890 	libipv6calc_db_wrapper_capabilities(string, sizeof(string));
891 	fprintf(stderr, "Capabilities: %s\n\n", string);
892 
893 	fprintf(stderr, "Internal main     library version: %s  API: %s  (%s)\n"
894 		, libipv6calc_lib_version_string()
895 		, libipv6calc_api_version_string()
896 #ifdef SHARED_LIBRARY
897 		, "shared"
898 #else  // SHARED_LIBRARY
899 		, "built-in"
900 #endif // SHARED_LIBRARY
901 	);
902 
903 	fprintf(stderr, "Internal database library version: %s  API: %s  (%s)\n\n"
904 		, libipv6calc_db_lib_version_string()
905 		, libipv6calc_db_api_version_string()
906 #ifdef SHARED_LIBRARY
907 		, "shared"
908 #else  // SHARED_LIBRARY
909 		, "built-in"
910 #endif // SHARED_LIBRARY
911 	);
912 
913 #if defined ENABLE_BUNDLED_MD5 || defined ENABLE_BUNDLED_GETOPT
914 	fprintf(stderr, "Bundled with:");
915 #ifdef ENABLE_BUNDLED_MD5
916 	fprintf(stderr, " MD5");
917 #endif
918 #ifdef ENABLE_BUNDLED_GETOPT
919 	fprintf(stderr, " GETOPT");
920 #endif
921 	fprintf(stderr, "\n\n");
922 #endif
923 
924 	fprintf(stderr, "Compiled: %s  %s\n\n", __DATE__, __TIME__);
925 
926 	libipv6calc_db_wrapper_print_features_verbose(level_verbose);
927 };
928