1 // ----------------------------------------------------------------------------
2 // flarqenv.cxx
3 //
4 // Copyright (C) 2009
5 // Stelios Bounanos, M0GLD
6 // ----------------------------------------------------------------------------
7 // Copyright (C) 2014
8 // David Freese, W1HKJ
9 //
10 // This file is part of fldigi
11 //
12 // fldigi is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 3 of the License, or
15 // (at your option) any later version.
16 //
17 // fldigi is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this program. If not, see <http://www.gnu.org/licenses/>.
24 // ----------------------------------------------------------------------------
25
26 #include <config.h>
27
28 #include <iostream>
29 #include <string>
30 #include <sstream>
31
32 #include <cstdlib>
33 #include <cstring>
34 #include <cerrno>
35
36 #ifdef __MINGW32__
37 # include "compat.h"
38 #endif
39
40 #if HAVE_SYS_UTSNAME_H
41 # include <sys/utsname.h>
42 #endif
43
44 #include <signal.h>
45 #include <getopt.h>
46
47 #include <FL/Fl.H>
48
49 #include "stacktrace.h"
50 #include "flarq.h"
51
52 using namespace std;
53
54 string option_help, version_text, build_text;
55 extern string arq_address, arq_port;
56 extern bool ioMPSK;
57 extern bool SHOWDEBUG;
58
generate_option_help(void)59 void generate_option_help(void)
60 {
61 ostringstream help;
62 help << "Usage:\n"
63 << " " << PACKAGE_NAME << " [option...]\n\n";
64
65 help << PACKAGE_NAME << " options:\n\n"
66 << " --arq-protocol TYPE\n"
67 << " Set the ARQ protocol\n"
68 << " May be either ``fldigi'' or ``multipsk''\n"
69 << " The default is: " << (ioMPSK ? "multipsk" : "fldigi") << "\n\n"
70
71 << " --arq-server-address HOSTNAME\n"
72 << " Set the ARQ TCP server address\n"
73 << " The default is: " << arq_address << "\n\n"
74
75 << " --arq-server-port PORT\n"
76 << " Set the ARQ TCP server port\n"
77 << " The default is: " << arq_port << "\n\n"
78
79 << " --version\n"
80 << " Print version information\n\n"
81
82 << " --build-info\n"
83 << " Print build information\n\n"
84
85 << " --help\n"
86 << " Print this option help\n\n";
87
88 // Fl::help looks ugly so we'll write our own
89
90 help << "Standard FLTK options:\n\n"
91
92 << " -bg COLOR, -background COLOR\n"
93 << " Set the background color\n"
94
95 << " -bg2 COLOR, -background2 COLOR\n"
96 << " Set the secondary (text) background color\n\n"
97
98 << " -di DISPLAY, -display DISPLAY\n"
99 << " Set the X display to use DISPLAY,\n"
100 << " format is ``host:n.n''\n\n"
101
102 << " -dn, -dnd or -nodn, -nodnd\n"
103 << " Enable or disable drag and drop copy and paste in text fields\n\n"
104
105 << " -fg COLOR, -foreground COLOR\n"
106 << " Set the foreground color\n\n"
107
108 << " -g GEOMETRY, -geometry GEOMETRY\n"
109 << " Set the initial window size and position\n"
110 << " GEOMETRY format is ``WxH+X+Y''\n"
111 << " ** " << PACKAGE_NAME << " may override this setting **\n\n"
112
113 << " -i, -iconic\n"
114 << " Start " << PACKAGE_NAME << " in iconified state\n\n"
115
116 << " -k, -kbd or -nok, -nokbd\n"
117 << " Enable or disable visible keyboard focus in non-text widgets\n\n"
118
119 << " -na CLASSNAME, -name CLASSNAME\n"
120 << " Set the window class to CLASSNAME\n\n"
121
122 << " -ti WINDOWTITLE, -title WINDOWTITLE\n"
123 << " Set the window title\n\n";
124
125 help << "Additional UI options:\n\n"
126
127 << " --font FONT[:SIZE]\n"
128 << " Set the widget font and (optionally) size\n"
129 << " The default is: " << Fl::get_font(FL_HELVETICA)
130 << ':' << FL_NORMAL_SIZE << "\n\n";
131
132 option_help = help.str();
133 }
134
parse_args(int argc,char ** argv,int & idx)135 int parse_args(int argc, char** argv, int& idx)
136 {
137 // Only handle long options
138 if ( !(strlen(argv[idx]) >= 2 && strncmp(argv[idx], "--", 2) == 0) )
139 return 0;
140
141 enum { OPT_ZERO,
142 #ifndef __WOE32__
143 OPT_RX_IPC_KEY, OPT_TX_IPC_KEY,
144 #endif
145 OPT_ARQ_PROTOCOL, OPT_ARQ_ADDRESS, OPT_ARQ_PORT,
146
147 OPT_FONT,
148
149 OPT_DEBUG, OPT_DEPRECATED, OPT_HELP, OPT_VERSION, OPT_BUILD_INFO
150 };
151
152 const char shortopts[] = "+";
153 struct option longopts[] = {
154 #ifndef __WOE32__
155 { "rx-ipc-key", 1, 0, OPT_RX_IPC_KEY },
156 { "tx-ipc-key", 1, 0, OPT_TX_IPC_KEY },
157 #endif
158 { "arq-protocol", 1, 0, OPT_ARQ_PROTOCOL },
159 { "arq-server-address", 1, 0, OPT_ARQ_ADDRESS },
160 { "arq-server-port", 1, 0, OPT_ARQ_PORT },
161
162 { "font", 1, 0, OPT_FONT },
163
164 { "help", 0, 0, OPT_HELP },
165 { "version", 0, 0, OPT_VERSION },
166 { "build-info", 0, 0, OPT_BUILD_INFO },
167 { 0 }
168 };
169
170 int longindex;
171 optind = idx;
172 int c = getopt_long(argc, argv, shortopts, longopts, &longindex);
173
174 switch (c) {
175 case -1:
176 return 0;
177 case 0:
178 // handle options with non-0 flag here
179 return 0;
180
181 case OPT_ARQ_PROTOCOL:
182 if (!strcmp(optarg, "fldigi"))
183 ioMPSK = false;
184 else if (!strcmp(optarg, "multipsk"))
185 ioMPSK = true;
186 else {
187 cerr << "E: unknown protocol type\n";
188 exit(EXIT_FAILURE);
189 }
190 break;
191 case OPT_ARQ_ADDRESS:
192 arq_address = optarg;
193 break;
194 case OPT_ARQ_PORT:
195 arq_port = optarg;
196 break;
197
198 case OPT_FONT: {
199 char *p;
200 if ((p = strchr(optarg, ':'))) {
201 *p = '\0';
202 FL_NORMAL_SIZE = strtol(p + 1, 0, 10);
203 }
204
205 Fl::set_font(FL_HELVETICA, optarg);
206 break;
207 }
208
209 case OPT_DEBUG:
210 SHOWDEBUG = true;
211 break;
212
213 case OPT_DEPRECATED:
214 cerr << "W: the --" << longopts[longindex].name
215 << " option has been deprecated and will be removed in a future version\n";
216 break;
217
218 case OPT_HELP:
219 cout << option_help;
220 exit(EXIT_SUCCESS);
221
222 case OPT_VERSION:
223 cout << version_text;
224 exit(EXIT_SUCCESS);
225
226 case OPT_BUILD_INFO:
227 cout << build_text;
228 exit(EXIT_SUCCESS);
229
230 case '?': default:
231 cerr << "Try `" << PACKAGE_NAME << " --help' for more information.\n";
232 exit(EXIT_FAILURE);
233
234 }
235
236 // Increment idx by the number of args we used and return that number.
237 // We must check whether the option argument is in the same argv element
238 // as the option name itself, i.e., --opt=arg.
239 c = longopts[longindex].has_arg ? 2 : 1;
240 if (c == 2) {
241 string arg = argv[idx];
242 string::size_type p;
243 if ((p = arg.rfind(optarg)) != string::npos && arg[p-1] == '=')
244 c = 1;
245 }
246 idx += c;
247 return c;
248 }
249
set_platform_ui(void)250 void set_platform_ui(void)
251 {
252 #if defined(__APPLE__)
253 FL_NORMAL_SIZE = 12;
254 #elif defined(__WOE32__)
255 Fl::set_font(FL_HELVETICA, "Tahoma");
256 FL_NORMAL_SIZE = 11;
257 #else
258 FL_NORMAL_SIZE = 12;
259 #endif
260 }
261
generate_version_text(void)262 void generate_version_text(void)
263 {
264 version_text.assign(PACKAGE_STRING "\nCopyright (C) 2008, 2009 " PACKAGE_AUTHORS ".\n");
265 version_text.append("License GPLv3+: GNU GPL version 3 or later "
266 "<http://www.gnu.org/licenses/gpl.html>\n"
267 "This is free software: you are free to change and redistribute it.\n"
268 "There is NO WARRANTY, to the extent permitted by law.\n");
269
270 ostringstream s;
271 s << "Build information:\n";
272 s << " built : " << BUILD_DATE << " by " << BUILD_USER
273 << '@' << BUILD_HOST << " on " << BUILD_BUILD_PLATFORM
274 << " for " << BUILD_TARGET_PLATFORM << "\n\n"
275 << " configure flags: " << BUILD_CONFIGURE_ARGS << "\n\n"
276 << " compiler : " << BUILD_COMPILER << "\n\n"
277 << " compiler flags : " << FLARQ_BUILD_CXXFLAGS << "\n\n"
278 << " linker flags : " << FLARQ_BUILD_LDFLAGS << "\n\n"
279
280 << " libraries : " "FLTK " FLTK_BUILD_VERSION "\n";
281
282 s << "\nRuntime information:\n";
283 struct utsname u;
284 if (uname(&u) != -1) {
285 s << " system : " << u.sysname << ' ' << u.nodename
286 << ' ' << u.release << ' ' << u.version << ' ' << u.machine << "\n\n";
287 }
288
289 build_text = s.str();
290 }
291
setup_signal_handlers(void)292 void setup_signal_handlers(void)
293 {
294 #ifndef __WOE32__
295 struct sigaction action;
296 memset(&action, 0, sizeof(struct sigaction));
297
298 // no child stopped notifications, no zombies
299 action.sa_handler = SIG_DFL;
300 action.sa_flags = SA_NOCLDSTOP;
301 #ifdef SA_NOCLDWAIT
302 action.sa_flags |= SA_NOCLDWAIT;
303 #endif
304 sigaction(SIGCHLD, &action, NULL);
305 action.sa_flags = 0;
306
307 action.sa_handler = handle_signal;
308 sigaction(SIGSEGV, &action, NULL);
309 sigaction(SIGILL, &action, NULL);
310 sigaction(SIGABRT, &action, NULL);
311 sigaction(SIGUSR2, &action, NULL);
312
313 action.sa_handler = SIG_IGN;
314 sigaction(SIGPIPE, &action, NULL);
315
316 sigemptyset(&action.sa_mask);
317 sigaddset(&action.sa_mask, SIGUSR2);
318 pthread_sigmask(SIG_BLOCK, &action.sa_mask, NULL);
319 #else
320 signal(SIGSEGV, handle_signal);
321 signal(SIGILL, handle_signal);
322 signal(SIGABRT, handle_signal);
323 #endif
324 }
325