1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
/* SPDX-License-Identifier: MIT-0 */
#include <argp.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "opendeco-cli.h"
#include "toml/LICENSE.h"
#include "minunit/LICENSE.h"
#define print_xxd_arr(name, arrname) \
do { \
wprintf(L"--------\n\n"); \
wprintf(L"License for: %s\n\n", name); \
for (int i = 0; i < arrname##_len; i++) \
putwchar(arrname[i]); \
wprintf(L"\n"); \
} while (0)
static char args_doc[] = "";
static char doc[] = "Implementation of Buhlmann ZH-L16 with Gradient Factors:"
"\vExamples:\n\n"
" ./opendeco -d 18 -t 60 -g Air\n"
" ./opendeco -d 30 -t 60 -g EAN32\n"
" ./opendeco -d 40 -t 120 -g 21/35 -L 20 -H 80 --decogasses Oxygen,EAN50\n";
const char *argp_program_bug_address = "<~tsegers/opendeco@lists.sr.ht> or https://todo.sr.ht/~tsegers/opendeco";
const char *argp_program_version = "opendeco " VERSION;
static struct argp_option options[] = {
{0, 0, 0, 0, "Dive options:", 0 },
{"depth", 'd', "NUMBER", 0, "Set the depth of the dive in meters", 0 },
{"time", 't', "NUMBER", 0, "Set the time of the dive in minutes", 1 },
{"gas", 'g', "STRING", 0, "Set the bottom gas used during the dive, defaults to Air", 2 },
{"pressure", 'p', "NUMBER", 0, "Set the surface air pressure, defaults to 1.01325bar or 1atm", 3 },
{"rmv", 'r', "NUMBER", 0, "Set the RMV during the dive portion of the dive, defaults to 20", 4 },
{0, 0, 0, 0, "Deco options:", 0 },
{"gflow", 'L', "NUMBER", 0, "Set the gradient factor at the first stop, defaults to 30", 5 },
{"gfhigh", 'H', "NUMBER", 0, "Set the gradient factor at the surface, defaults to 75", 6 },
{"decogasses", 'G', "LIST", 0, "Set the gasses available for deco", 7 },
{0, 'S', 0, OPTION_ARG_OPTIONAL, "Only switch gas at deco stops", 8 },
{0, '6', 0, OPTION_ARG_OPTIONAL, "Perform last deco stop at 6m", 9 },
{"decormv", 'R', "NUMBER", 0, "Set the RMV during the deco portion of the dive, defaults to 15", 10},
{"showtravel", 'T', 0, 0, "Show travel segments in deco plan", 11},
{0, 0, 0, 0, "Informational options:", 0 },
{"licenses", -1, 0, 0, "Show third-party licenses", 0 },
{0, 0, 0, 0, 0, 0 }
};
static void print_licenses()
{
wprintf(L"THIRD-PARTY LICENSES:\n\n");
print_xxd_arr("cktan/tomlc99", toml_LICENSE);
print_xxd_arr("siu/minunit", minunit_LICENSE);
}
static error_t parse_opt(int key, char *arg, struct argp_state *state)
{
struct arguments *arguments = state->input;
switch (key) {
case 'd':
arguments->depth = arg ? atof(arg) : -1;
break;
case 't':
arguments->time = arg ? atof(arg) : -1;
break;
case 'g':
if (arguments->gas)
free(arguments->gas);
arguments->gas = strdup(arg);
break;
case 'p':
arguments->SURFACE_PRESSURE = arg ? atof(arg) : -1;
break;
case 'r':
arguments->RMV_DIVE = arg ? atof(arg) : -1;
break;
case 'L':
arguments->gflow = arg ? atoi(arg) : -1;
break;
case 'H':
arguments->gfhigh = arg ? atoi(arg) : -1;
break;
case 'G':
if (arguments->decogasses)
free(arguments->decogasses);
arguments->decogasses = strdup(arg);
break;
case 'S':
arguments->SWITCH_INTERMEDIATE = 0;
break;
case '6':
arguments->LAST_STOP_AT_SIX = 1;
break;
case 'R':
arguments->RMV_DECO = arg ? atof(arg) : -1;
break;
case 'T':
arguments->SHOW_TRAVEL = 1;
break;
case -1:
print_licenses();
exit(ARGP_ERR_UNKNOWN);
case ARGP_KEY_END:
if (arguments->depth < 0 || arguments->time < 0) {
argp_state_help(state, stderr, ARGP_HELP_USAGE);
argp_failure(state, 1, 0, "Options -d and -t are required. See --help for more information");
exit(ARGP_ERR_UNKNOWN);
}
if (arguments->SURFACE_PRESSURE <= 0) {
argp_failure(state, 1, 0, "Surface air pressure must be positive");
exit(ARGP_ERR_UNKNOWN);
}
if (arguments->gflow <= 0) {
argp_failure(state, 1, 0, "GF Low invalid");
exit(ARGP_ERR_UNKNOWN);
}
if (arguments->gfhigh <= 0) {
argp_failure(state, 1, 0, "GF High invalid");
exit(ARGP_ERR_UNKNOWN);
}
if (arguments->gflow > arguments->gfhigh) {
argp_failure(state, 1, 0, "GF Low must not be greater than GF High");
exit(ARGP_ERR_UNKNOWN);
}
if (arguments->RMV_DIVE <= 0) {
argp_failure(state, 1, 0, "Dive RMV must be greater than 0");
exit(ARGP_ERR_UNKNOWN);
}
if (arguments->RMV_DECO <= 0) {
argp_failure(state, 1, 0, "Deco RMV must be greater than 0");
exit(ARGP_ERR_UNKNOWN);
}
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
void opendeco_argp_parse(int argc, char *argv[], struct arguments *arguments)
{
static struct argp argp = {options, parse_opt, args_doc, doc, 0, 0, 0};
argp_parse(&argp, argc, argv, 0, 0, arguments);
}
|