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