dl-fldigi/src/main.cxx

1375 wiersze
37 KiB
C++
Czysty Zwykły widok Historia

// ----------------------------------------------------------------------------
2007-06-22 22:10:49 +00:00
// Digital Modem Program for the Fast Light Toolkit
//
// Copyright 2006-2010, Dave Freese, W1HKJ
// Copyright 2007-2010, Stelios Bounanos, M0GLD
2007-06-22 22:10:49 +00:00
//
// This file is part of fldigi.
2007-06-22 22:10:49 +00:00
//
// Fldigi is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
2007-06-22 22:10:49 +00:00
//
// Fldigi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
2007-06-22 22:10:49 +00:00
//
// You should have received a copy of the GNU General Public License
// along with fldigi. If not, see <http://www.gnu.org/licenses/>.
2007-06-22 22:10:49 +00:00
//
// Please report all bugs and problems to fldigi-devel@lists.berlios.de.
// ----------------------------------------------------------------------------
2007-07-21 12:15:41 +00:00
2007-11-28 22:32:50 +00:00
#include <config.h>
2007-10-08 06:59:57 +00:00
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cstdlib>
#include <getopt.h>
2007-07-21 12:15:41 +00:00
#include <sys/types.h>
2009-04-17 18:17:55 +00:00
#if !defined(__WOE32__) && !defined(__APPLE__)
2008-03-30 13:38:05 +00:00
# include <sys/ipc.h>
# include <sys/msg.h>
#endif
2009-04-17 18:17:55 +00:00
#ifdef __MINGW32__
# include "compat.h"
#endif
2009-04-12 22:57:17 +00:00
#include <sys/stat.h>
2009-04-17 18:17:55 +00:00
#if HAVE_SYS_UTSNAME_H
# include <sys/utsname.h>
#endif
2007-11-01 03:22:20 +00:00
#include <unistd.h>
2007-12-11 03:36:51 +00:00
#include <exception>
#include <signal.h>
2007-12-20 08:21:04 +00:00
#include <locale.h>
2007-07-21 12:15:41 +00:00
2008-04-01 17:47:24 +00:00
#include <FL/Fl.H>
#include <FL/Enumerations.H>
#include <FL/Fl_Window.H>
2007-06-22 22:10:49 +00:00
#include <FL/Fl_Shared_Image.H>
2008-04-01 17:47:24 +00:00
#include <FL/x.H>
2009-04-17 18:17:55 +00:00
#ifdef __MINGW32__
# define dirent fl_dirent_no_thanks
#endif
2009-04-12 22:57:17 +00:00
#include <FL/filename.H>
#ifdef __WOE32__
# if FLDIGI_FLTK_API_MAJOR == 1 && FLDIGI_FLTK_API_MINOR < 3
# undef dirent
# include <dirent.h>
# endif
#else
# include <dirent.h>
2009-04-17 18:17:55 +00:00
#endif
2008-01-09 04:19:08 +00:00
#include "gettext.h"
2007-06-22 22:04:50 +00:00
#include "main.h"
#include "waterfall.h"
2009-04-12 22:57:17 +00:00
#include "trx.h"
2008-03-30 13:38:05 +00:00
#include "soundconf.h"
2007-06-22 22:04:50 +00:00
#include "fl_digi.h"
#include "rigio.h"
#include "globals.h"
2008-02-15 19:36:53 +00:00
#include "confdialog.h"
2008-11-29 19:20:54 +00:00
#include "colorsfonts.h"
2007-06-22 22:04:50 +00:00
#include "configuration.h"
#include "macros.h"
#include "status.h"
2008-05-17 03:24:15 +00:00
#include "fileselect.h"
2008-06-30 00:20:03 +00:00
#include "timeops.h"
2008-08-26 22:33:34 +00:00
#include "debug.h"
2008-11-22 01:32:17 +00:00
#include "pskrep.h"
2009-06-30 15:26:08 +00:00
#include "notify.h"
2008-11-26 05:21:34 +00:00
#include "logbook.h"
2008-12-10 22:48:53 +00:00
#include "dxcc.h"
#include "newinstall.h"
#include "Viewer.h"
2007-06-22 22:04:50 +00:00
2007-11-28 22:32:50 +00:00
#if USE_HAMLIB
2007-06-22 22:04:50 +00:00
#include "rigclass.h"
#endif
#include "rigsupport.h"
#include "log.h"
2007-09-19 00:45:42 +00:00
#include "qrunner.h"
2007-12-11 03:36:51 +00:00
#include "stacktrace.h"
2007-09-19 00:45:42 +00:00
2008-05-17 03:24:15 +00:00
#if USE_XMLRPC
#include "xmlrpc.h"
#endif
#if BENCHMARK_MODE
#include "benchmark.h"
#endif
#include "icons.h"
2007-06-22 22:04:50 +00:00
using namespace std;
2008-05-10 23:59:51 +00:00
string appname;
2008-02-27 02:58:09 +00:00
string scDevice[2];
2007-11-07 17:42:47 +00:00
bool NBEMSapps_dir = false;
string BaseDir = "";
string HomeDir = "";
string RigsDir = "";
string ScriptsDir = "";
string PalettesDir = "";
string LogsDir = "";
string PicsDir = "";
string HelpDir = "";
string MacrosDir = "";
string WrapDir = "";
string TalkDir = "";
string TempDir = "";
string PskMailDir = "";
string NBEMS_dir = "";
string ARQ_dir = "";
string ARQ_files_dir = "";
string ARQ_recv_dir = "";
string ARQ_send = "";
string WRAP_dir = "";
string WRAP_recv_dir = "";
string WRAP_send_dir = "";
string WRAP_auto_dir = "";
string ICS_dir = "";
string ICS_msg_dir = "";
string ICS_tmp_dir = "";
string FLMSG_dir = "";
string FLMSG_dir_default = "";
string FLMSG_WRAP_dir = "";
string FLMSG_WRAP_recv_dir = "";
string FLMSG_WRAP_send_dir = "";
string FLMSG_WRAP_auto_dir = "";
string FLMSG_ICS_dir = "";
string FLMSG_ICS_msg_dir = "";
string FLMSG_ICS_tmp_dir = "";
2007-06-22 22:10:49 +00:00
string PskMailFile;
2007-07-21 12:15:41 +00:00
string ArqFilename;
2007-06-22 22:04:50 +00:00
string xmlfname;
PTT *push2talk = (PTT *)0;
2007-11-28 22:32:50 +00:00
#if USE_HAMLIB
2007-06-22 22:04:50 +00:00
Rig *xcvr = (Rig *)0;
#endif
2008-09-14 14:00:49 +00:00
bool tlfio = false;
2008-11-26 05:21:34 +00:00
cLogfile *logfile = 0;
2007-06-22 22:04:50 +00:00
cLogfile *Maillogfile = (cLogfile *)0;
FILE *server;
FILE *client;
2007-07-21 12:15:41 +00:00
bool mailserver = false, mailclient = false, arqmode = false;
static bool show_cpucheck = false;
static bool iconified = false;
2007-06-22 22:04:50 +00:00
2007-07-21 12:15:41 +00:00
RXMSGSTRUC rxmsgst;
int rxmsgid = -1;
2007-06-22 22:04:50 +00:00
2007-07-21 12:15:41 +00:00
TXMSGSTRUC txmsgst;
int txmsgid = -1;
2007-06-22 22:25:46 +00:00
2009-04-17 18:17:56 +00:00
string option_help, version_text, build_text;
2007-06-22 22:04:50 +00:00
2007-11-28 22:32:50 +00:00
qrunner *cbq[NUM_QRUNNER_THREADS];
2007-08-14 13:44:14 +00:00
2007-10-08 06:59:57 +00:00
void arqchecks(void);
void generate_option_help(void);
int parse_args(int argc, char **argv, int& idx);
2008-01-25 23:11:48 +00:00
void generate_version_text(void);
2008-01-15 03:16:59 +00:00
void debug_exec(char** argv);
2008-06-30 00:20:03 +00:00
void set_platform_ui(void);
double speed_test(int converter, unsigned repeat);
2008-10-12 06:35:04 +00:00
static void setup_signal_handlers(void);
static void checkdirectories(void);
static void arg_error(const char* name, const char* arg, bool missing) noreturn__;
2007-07-21 12:15:41 +00:00
// TODO: find out why fldigi crashes on OS X if the wizard window is
// shown before fldigi_main.
#ifndef __APPLE__
# define SHOW_WIZARD_BEFORE_MAIN_WINDOW 1
#else
# define SHOW_WIZARD_BEFORE_MAIN_WINDOW 0
#endif
2010-01-11 16:58:17 +00:00
// these functions are all started after Fl::run() is executing
void delayed_startup(void *)
{
connect_to_log_server();
arq_init();
#ifdef __WIN32__
if (progdefaults.auto_talk) open_talker();
#else
grpTalker->hide();
#endif
#if USE_XMLRPC
XML_RPC_Server::start(progdefaults.xmlrpc_address.c_str(), progdefaults.xmlrpc_port.c_str());
#endif
notify_start();
if (progdefaults.usepskrep)
if (!pskrep_start())
LOG_ERROR("Could not start PSK reporter: %s", pskrep_error());
if (progdefaults.check_for_updates)
cb_mnuCheckUpdate((Fl_Widget *)0, NULL);
}
2007-09-19 00:45:42 +00:00
int main(int argc, char ** argv)
{
2008-05-10 23:59:51 +00:00
appname = argv[0];
{
string appdir;
char apptemp[FL_PATH_MAX];
fl_filename_expand(apptemp, sizeof(apptemp), appname.c_str());
appdir.assign(apptemp);
#ifdef __WOE32__
size_t p = appdir.rfind("fldigi.exe");
appdir.erase(p);
#else
size_t p = appdir.rfind("fldigi");
if (appdir.find("./fldigi") != std::string::npos) {
if (getcwd(apptemp, sizeof(apptemp)))
appdir.assign(apptemp).append("/");
} else
appdir.erase(p);
#endif
if (p != std::string::npos) {
string testfile;
testfile.assign(appdir).append("NBEMS.DIR");
FILE *testdir = fopen(testfile.c_str(),"r");
if (testdir) {
fclose(testdir);
BaseDir = appdir;
NBEMSapps_dir = true;
}
}
}
2008-01-15 03:16:59 +00:00
debug_exec(argv);
2007-09-19 00:45:42 +00:00
CREATE_THREAD_ID(); // only call this once
SET_THREAD_ID(FLMAIN_TID);
2007-10-06 15:04:10 +00:00
for (int i = 0; i < NUM_QRUNNER_THREADS; i++) {
2008-06-12 22:15:17 +00:00
cbq[i] = new qrunner;
2007-09-19 00:45:42 +00:00
cbq[i]->attach();
}
2007-07-21 12:15:41 +00:00
2007-12-11 03:36:51 +00:00
set_unexpected(handle_unexpected);
set_terminate(diediedie);
2008-09-26 19:17:45 +00:00
setup_signal_handlers();
2007-12-11 03:36:51 +00:00
#ifndef ENABLE_NLS
2008-01-10 18:02:24 +00:00
setlocale(LC_TIME, "");
#endif
2007-12-20 08:21:04 +00:00
set_platform_ui();
generate_version_text();
{
char dirbuf[FL_PATH_MAX + 1];
2009-04-17 18:17:55 +00:00
#ifdef __WOE32__
if (BaseDir.empty()) {
fl_filename_expand(dirbuf, sizeof(dirbuf) -1, "$USERPROFILE/");
BaseDir = dirbuf;
}
2008-07-24 12:22:53 +00:00
#else
if (BaseDir.empty()) {
fl_filename_expand(dirbuf, sizeof(dirbuf) -1, "$HOME/");
BaseDir = dirbuf;
}
#endif
}
{
#ifdef __WOE32__
if (HomeDir.empty()) HomeDir.assign(BaseDir).append("fldigi.files/");
if (PskMailDir.empty()) PskMailDir = BaseDir;
if (NBEMS_dir.empty()) NBEMS_dir.assign(BaseDir).append("NBEMS.files/");
if (FLMSG_dir.empty()) FLMSG_dir_default = NBEMS_dir;
#else
if (HomeDir.empty()) HomeDir.assign(BaseDir).append(".fldigi/");
if (PskMailDir.empty()) PskMailDir = BaseDir;
if (NBEMS_dir.empty()) NBEMS_dir.assign(BaseDir).append(".nbems/");
if (FLMSG_dir.empty()) FLMSG_dir_default = NBEMS_dir;
#endif
}
generate_option_help();
int arg_idx;
if (Fl::args(argc, argv, arg_idx, parse_args) != argc)
arg_error(argv[0], NULL, false);
if (main_window_title.empty())
main_window_title = PACKAGE_TARNAME;
2007-10-27 14:57:10 +00:00
{
char dirbuf[FL_PATH_MAX + 1];
if (FLMSG_dir_default[FLMSG_dir_default.length()-1] != '/')
FLMSG_dir_default += '/';
fl_filename_expand(dirbuf, sizeof(dirbuf) - 1, FLMSG_dir_default.c_str());
FLMSG_dir = dirbuf;
}
checkdirectories();
check_nbems_dirs();
2008-08-26 22:33:34 +00:00
try {
debug::start(string(HomeDir).append("status_log.txt").c_str());
time_t t = time(NULL);
2009-01-05 16:00:01 +00:00
LOG(debug::QUIET_LEVEL, debug::LOG_OTHER, _("%s log started on %s"), PACKAGE_STRING, ctime(&t));
2009-05-26 18:57:44 +00:00
LOG_THREAD_ID();
2008-08-26 22:33:34 +00:00
}
catch (const char* error) {
cerr << error << '\n';
debug::stop();
}
LOG_INFO("appname: %s", appname.c_str());
LOG_INFO("HomeDir: %s", HomeDir.c_str());
LOG_INFO("RigsDir: %s", RigsDir.c_str());
LOG_INFO("ScriptsDir: %s", ScriptsDir.c_str());
LOG_INFO("PalettesDir: %s", PalettesDir.c_str());
LOG_INFO("LogsDir: %s", LogsDir.c_str());
LOG_INFO("PicsDir: %s", PicsDir.c_str());
LOG_INFO("HelpDir: %s", HelpDir.c_str());
LOG_INFO("MacrosDir: %s", MacrosDir.c_str());
LOG_INFO("WrapDir: %s", WrapDir.c_str());
LOG_INFO("TalkDir: %s", TalkDir.c_str());
LOG_INFO("TempDir: %s", TempDir.c_str());
LOG_INFO("PskMailDir: %s", PskMailDir.c_str());
LOG_INFO("NBEMS_dir: %s", NBEMS_dir.c_str());
LOG_INFO("ARQ_dir: %s", ARQ_dir.c_str());
LOG_INFO("ARQ_files_dir: %s", ARQ_files_dir.c_str());
LOG_INFO("ARQ_recv_dir: %s", ARQ_recv_dir.c_str());
LOG_INFO("ARQ_send: %s", ARQ_send.c_str());
LOG_INFO("WRAP_dir: %s", WRAP_dir.c_str());
LOG_INFO("WRAP_recv_dir: %s", WRAP_recv_dir.c_str());
LOG_INFO("WRAP_send_dir: %s", WRAP_send_dir.c_str());
LOG_INFO("WRAP_auto_dir: %s", WRAP_auto_dir.c_str());
LOG_INFO("ICS_dir: %s", ICS_dir.c_str());
LOG_INFO("ICS_msg_dir: %s", ICS_msg_dir.c_str());
LOG_INFO("ICS_tmp_dir: %s", ICS_tmp_dir.c_str());
LOG_INFO("FLMSG_dir: %s", FLMSG_dir.c_str());
LOG_INFO("FLMSG_dir_default: %s", FLMSG_dir_default.c_str());
LOG_INFO("FLMSG_WRAP_dir: %s", FLMSG_WRAP_dir.c_str());
LOG_INFO("FLMSG_WRAP_recv_dir: %s", FLMSG_WRAP_recv_dir.c_str());
LOG_INFO("FLMSG_WRAP_send_dir: %s", FLMSG_WRAP_send_dir.c_str());
LOG_INFO("FLMSG_WRAP_auto_dir: %s", FLMSG_WRAP_auto_dir.c_str());
LOG_INFO("FLMSG_ICS_dir: %s", FLMSG_ICS_dir.c_str());
LOG_INFO("FLMSG_ICS_msg_dir: %s", FLMSG_ICS_msg_dir.c_str());
LOG_INFO("FLMSG_ICS_tmp_dir: %s", FLMSG_ICS_tmp_dir.c_str());
bool have_config = progdefaults.readDefaultsXML();
xmlfname = HomeDir;
2007-07-21 12:15:41 +00:00
xmlfname.append("rig.xml");
2009-04-06 20:59:27 +00:00
2009-04-17 18:17:55 +00:00
#if !defined(__WOE32__) && !defined(__APPLE__)
2007-10-29 03:15:22 +00:00
txmsgid = msgget( (key_t) progdefaults.tx_msgid, 0666 );
2008-03-30 13:38:05 +00:00
#else
txmsgid = -1;
#endif
2008-09-14 14:00:49 +00:00
checkTLF();
2007-10-29 03:15:22 +00:00
Fl::lock(); // start the gui thread!!
2007-08-14 01:18:58 +00:00
Fl::visual(FL_RGB); // insure 24 bit color operation
2007-06-22 22:04:50 +00:00
fl_register_images();
2007-06-22 22:19:01 +00:00
Fl::set_fonts(0);
Fl::scheme(progdefaults.ui_scheme.c_str());
progdefaults.initFonts();
if (progdefaults.cty_dat_pathname.empty())
progdefaults.cty_dat_pathname = HomeDir;
dxcc_open(string(progdefaults.cty_dat_pathname).append("cty.dat").c_str());
qsl_open(string(progdefaults.cty_dat_pathname).append("lotw1.txt").c_str(), QSL_LOTW);
if (!qsl_open(string(progdefaults.cty_dat_pathname).append("eqsl.txt").c_str(), QSL_EQSL))
qsl_open(string(progdefaults.cty_dat_pathname).append("AGMemberList.txt").c_str(), QSL_EQSL);
progStatus.loadLastState();
create_fl_digi_main(argc, argv);
2008-06-30 00:20:03 +00:00
if (!have_config || show_cpucheck) {
2008-06-30 00:20:03 +00:00
double speed = speed_test(SRC_SINC_FASTEST, 8);
2008-08-26 22:33:34 +00:00
2008-06-30 00:20:03 +00:00
if (speed > 150.0) { // fast
progdefaults.slowcpu = false;
progdefaults.sample_converter = SRC_SINC_BEST_QUALITY;
}
else if (speed > 60.0) { // ok
progdefaults.slowcpu = false;
progdefaults.sample_converter = SRC_SINC_MEDIUM_QUALITY;
}
else if (speed > 15.0) { // slow
2008-06-30 00:20:03 +00:00
progdefaults.slowcpu = true;
progdefaults.sample_converter = SRC_SINC_FASTEST;
}
else { // recycle me
progdefaults.slowcpu = true;
progdefaults.sample_converter = SRC_LINEAR;
}
2008-08-26 22:33:34 +00:00
LOG_INFO("CPU speed factor=%f: setting slowcpu=%s, sample_converter=\"%s\"", speed,
progdefaults.slowcpu ? "true" : "false",
src_get_name(progdefaults.sample_converter));
2008-06-30 00:20:03 +00:00
}
2008-10-25 01:11:49 +00:00
if (progdefaults.XmlRigFilename.empty())
progdefaults.XmlRigFilename = xmlfname;
2008-06-30 00:20:03 +00:00
#if BENCHMARK_MODE
return setup_benchmark();
#endif
2008-05-17 03:24:15 +00:00
FSEL::create();
2007-06-22 22:24:50 +00:00
2008-11-29 19:20:54 +00:00
make_colorsfonts();
UTF-8 overhaul * Refactor get_tx_char() * Reset to stock version, call byte_at() The class Fl_Text_Buffer_mod (borrowed from FLTK) contained a modified version of the method char_at() that effectively made it behave as byte_at(). Silently modifying a library-provided method not only disables the access to a certain functionality of the library, but can also cause other unforeseen consequences. The method was thus reverted to the stock version and the code that previously called the modified version was changed to call byte_at() instead. * Remove unneeded code in FTextTX::nextChar() * Libtiniconv - Added libtiniconv (charset conversion library) - Library Version 1.0.1 fetched from http://tiniconv.sf.net A small fix made to change a misspelled macro name. Build system adapted to fit into the fldigi build model. * Added CharsetDistiller class - Sanitize input data and convert it into UTF-8 - CharsetDistiller receives input data one byte at a time and converts this data stream from a particular character set into UTF-8. Invalid input data is treated as if it was encoded in CP1252. Character set conversion is performed as soon as possible, i.e., when enough input is received to constitute a valid character in the input character set, this character is immediatly converted into UTF-8 and made available at the output. * Make put_rx_char_flmain() use charsetDistiller * Make put_echo_char() use CharsetDistiller * Make pskBrowser use CharsetDistiller * Added OutputEncoder class - Used for encoding transmitted data - OutputEncoder accepts UTF-8 strings at input, converts them to the selected encoding and outputs them one byte at a time. * TX character set conversion using OutputEncoder * Fix backspace for >2byte UTF-8 characters * Cleanup modem UTF-8 code - PSK, Olivia, MT63 and MFSK modems: cleanup of unneeded UTF-8 handling code - Everything that deals with output character set conversion and data sequencing is now done using OutputEncoder, so the modems can become completely agnostic about the character set used. As far as they are concerned, everything is just byte-sized data. * Added an array of character set names and identifiers * UTF-8 code cleanup - Cleanup of unneeded UTF-8 handling code in add_rxtx_char() and family * Character set selection menu - Add menu button to select the active TX/RX charset to the colors-fonts configure dialog. The setting defaults to UTF-8 (selected at program startup). The selection is saved to the program defaults configuration file when "Config/Save" is executed.
2012-10-29 17:24:49 +00:00
populate_charset_menu();
set_default_charset();
2008-11-29 19:20:54 +00:00
setTabColors();
2008-11-26 05:21:34 +00:00
2008-09-08 16:48:25 +00:00
progdefaults.testCommPorts();
2007-06-22 22:04:50 +00:00
macros.loadDefault();
2007-11-28 22:32:50 +00:00
#if USE_HAMLIB
2007-06-22 22:04:50 +00:00
xcvr = new Rig();
#endif
2007-06-22 22:04:50 +00:00
push2talk = new PTT();
2008-03-08 23:19:46 +00:00
progdefaults.setDefaults();
2008-02-09 23:07:10 +00:00
2008-03-30 13:38:05 +00:00
atexit(sound_close);
2008-02-09 23:07:10 +00:00
sound_init();
2008-04-01 17:47:24 +00:00
progdefaults.initInterface();
trx_start();
2008-04-14 22:18:15 +00:00
2010-01-11 16:58:17 +00:00
#if SHOW_WIZARD_BEFORE_MAIN_WINDOW
if (!have_config) {
show_wizard(argc, argv);
Fl_Window* w;
while ((w = Fl::first_window()) && w->visible())
Fl::wait();
}
#endif
dlgViewer = createViewer();
create_logbook_dialogs();
LOGBOOK_colors_font();
2008-10-31 03:47:24 +00:00
// OS X will prevent the main window from being resized if we change its
// size *after* it has been shown. With some X11 window managers, OTOH,
// the main window will not be restored at its exact saved position if
// we move it *after* it has been shown.
#ifndef __APPLE__
2008-02-09 23:07:10 +00:00
fl_digi_main->show(argc, argv);
progStatus.initLastState();
2008-10-31 03:47:24 +00:00
#else
progStatus.initLastState();
fl_digi_main->show(argc, argv);
#endif
if (iconified)
for (Fl_Window* w = Fl::first_window(); w; w = Fl::next_window(w))
w->iconize();
update_main_title();
2008-10-31 03:47:24 +00:00
mode_browser = new Mode_Browser;
2008-12-10 22:48:53 +00:00
2010-01-11 16:58:17 +00:00
#if !SHOW_WIZARD_BEFORE_MAIN_WINDOW
if (!have_config)
show_wizard();
#endif
Fl::add_timeout(.05, delayed_startup);
2008-02-09 23:07:10 +00:00
int ret = Fl::run();
2008-05-17 03:24:15 +00:00
2008-08-13 15:41:18 +00:00
arq_close();
2008-05-17 03:24:15 +00:00
#if USE_XMLRPC
XML_RPC_Server::stop();
#endif
2008-11-23 06:20:16 +00:00
if (progdefaults.usepskrep)
pskrep_stop();
2008-11-22 01:32:17 +00:00
2008-04-29 21:07:44 +00:00
for (int i = 0; i < NUM_QRUNNER_THREADS; i++) {
2008-02-09 23:07:10 +00:00
cbq[i]->detach();
2008-04-29 21:07:44 +00:00
delete cbq[i];
}
2008-05-17 03:24:15 +00:00
FSEL::destroy();
2008-02-09 23:07:10 +00:00
return ret;
}
2007-10-08 06:59:57 +00:00
void generate_option_help(void) {
ostringstream help;
string disp_base_dir = BaseDir;
#ifdef __WOE32__
size_t p = 0;
while ((p = disp_base_dir.find("/")) != string::npos)
disp_base_dir[p] = '\\';
#endif
2008-01-29 15:58:15 +00:00
help << "Usage:\n"
2008-01-25 23:11:48 +00:00
<< " " << PACKAGE_NAME << " [option...]\n\n";
help << PACKAGE_NAME << " options:\n\n"
#if !defined(__WOE32__)
<< " --home-dir DIRECTORY\n"
<< " Set the home directory to full pathname of DIRECTORY\n"
<< " fldigi will put the file stores\n"
<< " .fldigi.files, and .nbems.files\n"
<< " in this directory\n"
<< " The default is: " << disp_base_dir << "\n\n"
2008-01-29 15:58:15 +00:00
<< " --config-dir DIRECTORY\n"
2008-01-25 23:11:48 +00:00
<< " Look for configuration files in DIRECTORY\n"
<< " The default is: " << disp_base_dir << ".fldigi/\n\n"
#else
<< " --home-dir FOLDER\n"
<< " Set the home folder to full pathname of FOLDER\n"
<< " fldigi will put the file stores\n"
<< " fldigi.files, and nbems.files\n"
<< " in this folder\n"
<< " The default is: " << disp_base_dir << "\n\n"
<< " --config-dir FOLDER\n"
<< " Look for configuration files in FOLDER\n"
<< " The default is: " << disp_base_dir << "fldigi.files\\\n\n"
#endif
2008-01-29 15:58:15 +00:00
2009-04-17 18:17:55 +00:00
#if !defined(__WOE32__) && !defined(__APPLE__)
2008-01-29 15:58:15 +00:00
<< " --rx-ipc-key KEY\n"
<< " Set the receive message queue key\n"
2008-01-25 23:11:48 +00:00
<< " May be given in hex if prefixed with \"0x\"\n"
<< " The default is: " << progdefaults.rx_msgid
<< " or 0x" << hex << progdefaults.rx_msgid << dec << "\n\n"
2008-01-29 15:58:15 +00:00
<< " --tx-ipc-key KEY\n"
<< " Set the transmit message queue key\n"
2008-01-25 23:11:48 +00:00
<< " May be given in hex if prefixed with \"0x\"\n"
<< " The default is: " << progdefaults.tx_msgid
<< " or 0x" << hex << progdefaults.tx_msgid << dec << "\n\n"
2008-03-30 13:38:05 +00:00
#endif
2008-01-25 23:11:48 +00:00
2008-08-13 15:41:18 +00:00
<< " --arq-server-address HOSTNAME\n"
<< " Set the ARQ TCP server address\n"
<< " The default is: " << progdefaults.arq_address << "\n\n"
<< " --arq-server-port PORT\n"
<< " Set the ARQ TCP server port\n"
<< " The default is: " << progdefaults.arq_port << "\n\n"
<< " --flmsg-dir DIRECTORY\n"
<< " Look for flmsg files in DIRECTORY\n"
<< " The default is " << FLMSG_dir_default << "\n\n"
<< " --auto-dir DIRECTORY\n"
<< " Look for auto-send files in DIRECTORY\n"
<< " The default is " << HomeDir << "/autosend" << "\n\n"
2008-08-13 15:41:18 +00:00
2008-06-13 13:23:46 +00:00
#if USE_XMLRPC
2008-05-17 03:24:15 +00:00
<< " --xmlrpc-server-address HOSTNAME\n"
<< " Set the XML-RPC server address\n"
<< " The default is: " << progdefaults.xmlrpc_address << "\n\n"
<< " --xmlrpc-server-port PORT\n"
<< " Set the XML-RPC server port\n"
<< " The default is: " << progdefaults.xmlrpc_port << "\n\n"
2008-09-26 19:17:45 +00:00
<< " --xmlrpc-allow REGEX\n"
<< " Allow only the methods whose names match REGEX\n\n"
<< " --xmlrpc-deny REGEX\n"
<< " Allow only the methods whose names don't match REGEX\n\n"
<< " --xmlrpc-list\n"
<< " List all available methods\n\n"
2008-06-13 13:23:46 +00:00
#endif
2008-05-17 03:24:15 +00:00
#if BENCHMARK_MODE
<< " --benchmark-modem ID\n"
<< " Specify the modem\n"
<< " Default: " << mode_info[benchmark.modem].sname << "\n\n"
<< " --benchmark-frequency FREQ\n"
<< " Specify the modem frequency\n"
<< " Default: " << benchmark.freq << "\n\n"
<< " --benchmark-afc BOOLEAN\n"
<< " Set modem AFC\n"
<< " Default: " << benchmark.afc
<< " (" << boolalpha << benchmark.afc << noboolalpha << ")\n\n"
<< " --benchmark-squelch BOOLEAN\n"
<< " Set modem squelch\n"
<< " Default: " << benchmark.sql
<< " (" << boolalpha << benchmark.sql << noboolalpha << ")\n\n"
<< " --benchmark-squelch-level LEVEL\n"
<< " Set modem squelch level\n"
<< " Default: " << benchmark.sqlevel << " (%)\n\n"
<< " --benchmark-input INPUT\n"
<< " Specify the input\n"
<< " Must be a positive integer indicating the number of samples\n"
" of silence to generate as the input"
# if USE_SNDFILE
", or a filename containing\n"
" non-digit characters"
#endif
"\n\n"
<< " --benchmark-output FILE\n"
<< " Specify the output data file\n"
<< " Default: decoder output is discarded\n\n"
<< " --benchmark-src-ratio RATIO\n"
<< " Specify the sample rate conversion ratio\n"
<< " Default: 1.0 (input is not resampled)\n\n"
<< " --benchmark-src-type TYPE\n"
<< " Specify the sample rate conversion type\n"
<< " Default: " << benchmark.src_type << " (" << src_get_name(benchmark.src_type) << ")\n\n"
#endif
<< " --cpu-speed-test\n"
<< " Perform the CPU speed test, show results in the event log\n"
<< " and possibly change options.\n\n"
<< " --noise\n"
<< " Unhide controls for noise tests\n\n"
<< " --wfall-only\n"
<< " Hide all controls but the waterfall\n\n"
2008-08-26 22:33:34 +00:00
<< " --debug-level LEVEL\n"
<< " Set the event log verbosity\n\n"
2008-01-29 15:58:15 +00:00
<< " --version\n"
2008-01-25 23:11:48 +00:00
<< " Print version information\n\n"
2009-04-17 18:17:56 +00:00
<< " --build-info\n"
<< " Print build information\n\n"
2008-01-29 15:58:15 +00:00
<< " --help\n"
2008-01-25 23:11:48 +00:00
<< " Print this option help\n\n";
// Fl::help looks ugly so we'll write our own
help << "Standard FLTK options:\n\n"
<< " -bg COLOR, -background COLOR\n"
<< " Set the background color\n"
<< " -bg2 COLOR, -background2 COLOR\n"
<< " Set the secondary (text) background color\n\n"
<< " -di DISPLAY, -display DISPLAY\n"
<< " Set the X display to use DISPLAY,\n"
<< " format is ``host:n.n''\n\n"
<< " -dn, -dnd or -nodn, -nodnd\n"
2008-01-29 15:58:15 +00:00
<< " Enable or disable drag and drop copy and paste in text fields\n\n"
2008-01-25 23:11:48 +00:00
<< " -fg COLOR, -foreground COLOR\n"
<< " Set the foreground color\n\n"
<< " -g GEOMETRY, -geometry GEOMETRY\n"
<< " Set the initial window size and position\n"
<< " GEOMETRY format is ``WxH+X+Y''\n"
2008-11-19 20:17:40 +00:00
<< " ** " << PACKAGE_NAME << " may override this setting **\n\n"
2008-01-25 23:11:48 +00:00
<< " -i, -iconic\n"
<< " Start " << PACKAGE_NAME << " in iconified state\n\n"
<< " -k, -kbd or -nok, -nokbd\n"
<< " Enable or disable visible keyboard focus in non-text widgets\n\n"
<< " -na CLASSNAME, -name CLASSNAME\n"
<< " Set the window class to CLASSNAME\n\n"
<< " -ti WINDOWTITLE, -title WINDOWTITLE\n"
2008-11-19 20:17:40 +00:00
<< " Set the window title\n\n";
2008-01-25 23:11:48 +00:00
help << "Additional UI options:\n\n"
2007-10-16 17:18:03 +00:00
2008-01-25 23:11:48 +00:00
<< " --font FONT[:SIZE]\n"
<< " Set the widget font and (optionally) size\n"
<< " The default is: " << Fl::get_font(FL_HELVETICA)
<< ':' << FL_NORMAL_SIZE << "\n\n"
2007-10-12 23:15:06 +00:00
2008-10-16 10:11:28 +00:00
;
2007-10-12 09:14:02 +00:00
2007-10-08 06:59:57 +00:00
option_help = help.str();
}
2008-06-11 17:36:06 +00:00
void exit_cb(void*) { fl_digi_main->do_callback(); }
2008-02-09 23:07:10 +00:00
2007-10-08 06:59:57 +00:00
int parse_args(int argc, char **argv, int& idx)
{
2007-10-12 09:14:02 +00:00
// Only handle long options
if (!(strlen(argv[idx]) >= 2 && strncmp(argv[idx], "--", 2) == 0)) {
// Store the window title. We may need this early in the initialisation
// process, before FLTK uses it to set the main window title.
if (main_window_title.empty() && argc > idx &&
(!strcmp(argv[idx], "-ti") || !strcmp(argv[idx], "-title")))
main_window_title = argv[idx + 1];
else if (!strcmp(argv[idx], "-i") || !strcmp(argv[idx], "-iconic"))
iconified = true;
2007-10-08 06:59:57 +00:00
return 0;
}
2007-10-08 06:59:57 +00:00
2008-03-30 13:38:05 +00:00
enum { OPT_ZERO,
2009-04-17 18:17:55 +00:00
#ifndef __WOE32__
2008-03-30 13:38:05 +00:00
OPT_RX_IPC_KEY, OPT_TX_IPC_KEY,
#endif
OPT_HOME_DIR,
2008-10-12 06:35:04 +00:00
OPT_CONFIG_DIR,
OPT_ARQ_ADDRESS, OPT_ARQ_PORT,
OPT_SHOW_CPU_CHECK,
OPT_FLMSG_DIR,
OPT_AUTOSEND_DIR,
2008-05-17 03:24:15 +00:00
#if USE_XMLRPC
2008-10-12 06:35:04 +00:00
OPT_CONFIG_XMLRPC_ADDRESS, OPT_CONFIG_XMLRPC_PORT,
2008-09-26 19:17:45 +00:00
OPT_CONFIG_XMLRPC_ALLOW, OPT_CONFIG_XMLRPC_DENY, OPT_CONFIG_XMLRPC_LIST,
2008-05-17 03:24:15 +00:00
#endif
#if BENCHMARK_MODE
OPT_BENCHMARK_MODEM, OPT_BENCHMARK_AFC, OPT_BENCHMARK_SQL, OPT_BENCHMARK_SQLEVEL,
OPT_BENCHMARK_FREQ, OPT_BENCHMARK_INPUT, OPT_BENCHMARK_OUTPUT,
OPT_BENCHMARK_SRC_RATIO, OPT_BENCHMARK_SRC_TYPE,
#endif
OPT_FONT, OPT_WFALL_HEIGHT,
OPT_WINDOW_WIDTH, OPT_WINDOW_HEIGHT, OPT_WFALL_ONLY,
2007-11-28 22:32:50 +00:00
#if USE_PORTAUDIO
2008-03-01 07:03:03 +00:00
OPT_FRAMES_PER_BUFFER,
2007-11-28 22:32:50 +00:00
#endif
OPT_NOISE, OPT_DEBUG_LEVEL,
2008-02-09 23:07:10 +00:00
OPT_EXIT_AFTER,
2009-04-17 18:17:56 +00:00
OPT_DEPRECATED, OPT_HELP, OPT_VERSION, OPT_BUILD_INFO };
2007-10-12 23:15:06 +00:00
const char shortopts[] = ":";
2007-10-08 06:59:57 +00:00
static struct option longopts[] = {
2009-04-17 18:17:55 +00:00
#ifndef __WOE32__
2007-11-28 22:32:50 +00:00
{ "rx-ipc-key", 1, 0, OPT_RX_IPC_KEY },
{ "tx-ipc-key", 1, 0, OPT_TX_IPC_KEY },
2008-03-30 13:38:05 +00:00
#endif
{ "home-dir", 1, 0, OPT_HOME_DIR },
2007-11-28 22:32:50 +00:00
{ "config-dir", 1, 0, OPT_CONFIG_DIR },
2008-05-17 03:24:15 +00:00
2008-08-13 15:41:18 +00:00
{ "arq-server-address", 1, 0, OPT_ARQ_ADDRESS },
{ "arq-server-port", 1, 0, OPT_ARQ_PORT },
{ "flmsg-dir", 1, 0, OPT_FLMSG_DIR },
{ "auto-dir", 1, 0, OPT_AUTOSEND_DIR },
2008-08-13 15:41:18 +00:00
{ "cpu-speed-test", 0, 0, OPT_SHOW_CPU_CHECK },
2008-05-17 03:24:15 +00:00
#if USE_XMLRPC
{ "xmlrpc-server-address", 1, 0, OPT_CONFIG_XMLRPC_ADDRESS },
{ "xmlrpc-server-port", 1, 0, OPT_CONFIG_XMLRPC_PORT },
2008-09-26 19:17:45 +00:00
{ "xmlrpc-allow", 1, 0, OPT_CONFIG_XMLRPC_ALLOW },
{ "xmlrpc-deny", 1, 0, OPT_CONFIG_XMLRPC_DENY },
{ "xmlrpc-list", 0, 0, OPT_CONFIG_XMLRPC_LIST },
2008-05-17 03:24:15 +00:00
#endif
#if BENCHMARK_MODE
{ "benchmark-modem", 1, 0, OPT_BENCHMARK_MODEM },
{ "benchmark-frequency", 1, 0, OPT_BENCHMARK_FREQ },
{ "benchmark-afc", 1, 0, OPT_BENCHMARK_AFC },
{ "benchmark-squelch", 1, 0, OPT_BENCHMARK_SQL },
{ "benchmark-squelch-level", 1, 0, OPT_BENCHMARK_SQLEVEL },
{ "benchmark-input", 1, 0, OPT_BENCHMARK_INPUT },
{ "benchmark-output", 1, 0, OPT_BENCHMARK_OUTPUT },
{ "benchmark-src-ratio", 1, 0, OPT_BENCHMARK_SRC_RATIO },
{ "benchmark-src-type", 1, 0, OPT_BENCHMARK_SRC_TYPE },
#endif
2007-11-28 22:32:50 +00:00
{ "font", 1, 0, OPT_FONT },
{ "wfall-height", 1, 0, OPT_WFALL_HEIGHT },
{ "window-width", 1, 0, OPT_WINDOW_WIDTH },
{ "window-height", 1, 0, OPT_WINDOW_HEIGHT },
{ "wfall-only", 0, 0, OPT_WFALL_ONLY },
{ "wo", 0, 0, OPT_WFALL_ONLY },
2008-02-20 20:10:25 +00:00
2007-11-28 22:32:50 +00:00
#if USE_PORTAUDIO
{ "frames-per-buffer",1, 0, OPT_FRAMES_PER_BUFFER },
2007-11-28 22:32:50 +00:00
#endif
2008-02-09 23:07:10 +00:00
{ "exit-after", 1, 0, OPT_EXIT_AFTER },
{ "noise", 0, 0, OPT_NOISE },
2008-08-26 22:33:34 +00:00
{ "debug-level", 1, 0, OPT_DEBUG_LEVEL },
2007-11-28 22:32:50 +00:00
{ "help", 0, 0, OPT_HELP },
{ "version", 0, 0, OPT_VERSION },
2009-04-17 18:17:56 +00:00
{ "build-info", 0, 0, OPT_BUILD_INFO },
2007-10-08 06:59:57 +00:00
{ 0 }
};
2007-10-18 07:49:27 +00:00
2007-10-08 06:59:57 +00:00
int longindex;
2008-02-09 23:07:10 +00:00
optind = idx;
opterr = 0;
2008-02-09 23:07:10 +00:00
int c = getopt_long(argc, argv, shortopts, longopts, &longindex);
2007-10-08 06:59:57 +00:00
switch (c) {
2007-10-18 07:49:27 +00:00
case -1:
return 0;
case 0:
// handle options with non-0 flag here
return 0;
2009-04-17 18:17:55 +00:00
#if !defined(__WOE32__) && !defined(__APPLE__)
2007-11-28 22:32:50 +00:00
case OPT_RX_IPC_KEY: case OPT_TX_IPC_KEY:
2007-10-18 07:49:27 +00:00
{
errno = 0;
int key = strtol(optarg, NULL, (strncasecmp(optarg, "0x", 2) ? 10 : 16));
if (errno || key <= 0)
cerr << "Hmm, " << key << " doesn't look like a valid IPC key\n";
2007-11-28 22:32:50 +00:00
if (c == OPT_RX_IPC_KEY)
2007-10-18 07:49:27 +00:00
progdefaults.rx_msgid = key;
else
progdefaults.tx_msgid = key;
2007-10-12 09:14:02 +00:00
}
2008-02-09 23:07:10 +00:00
break;
2008-03-30 13:38:05 +00:00
#endif
2007-10-18 07:49:27 +00:00
case OPT_HOME_DIR: {
char buf[FL_PATH_MAX + 1];
fl_filename_absolute(buf, sizeof(buf) - 1, optarg);
BaseDir = buf;
}
if (*BaseDir.rbegin() != '/')
BaseDir += '/';
break;
case OPT_CONFIG_DIR: {
char buf[FL_PATH_MAX + 1];
fl_filename_absolute(buf, sizeof(buf) - 1, optarg);
HomeDir = buf;
}
2007-10-18 07:49:27 +00:00
if (*HomeDir.rbegin() != '/')
HomeDir += '/';
2008-02-09 23:07:10 +00:00
break;
2007-10-18 07:49:27 +00:00
2008-08-13 15:41:18 +00:00
case OPT_ARQ_ADDRESS:
progdefaults.arq_address = optarg;
break;
case OPT_ARQ_PORT:
progdefaults.arq_port = optarg;
break;
case OPT_FLMSG_DIR:
FLMSG_dir_default = optarg;
break;
case OPT_AUTOSEND_DIR:
FLMSG_WRAP_auto_dir = optarg;
break;
2008-05-17 03:24:15 +00:00
#if USE_XMLRPC
case OPT_CONFIG_XMLRPC_ADDRESS:
progdefaults.xmlrpc_address = optarg;
break;
case OPT_CONFIG_XMLRPC_PORT:
progdefaults.xmlrpc_port = optarg;
break;
2008-09-26 19:17:45 +00:00
case OPT_CONFIG_XMLRPC_ALLOW:
progdefaults.xmlrpc_allow = optarg;
break;
case OPT_CONFIG_XMLRPC_DENY:
if (!progdefaults.xmlrpc_allow.empty())
cerr << "W: --" << longopts[longindex].name
<< " cannot be used together with --"
<< longopts[OPT_CONFIG_XMLRPC_ALLOW-1].name
<< " and will be ignored\n";
else
progdefaults.xmlrpc_deny = optarg;
break;
case OPT_CONFIG_XMLRPC_LIST:
XML_RPC_Server::list_methods(cout);
exit(EXIT_SUCCESS);
2008-05-17 03:24:15 +00:00
#endif
#if BENCHMARK_MODE
case OPT_BENCHMARK_MODEM:
benchmark.modem = strtol(optarg, NULL, 10);
if (!(benchmark.modem >= 0 && benchmark.modem < NUM_MODES)) {
cerr << "Bad modem id\n";
exit(EXIT_FAILURE);
}
break;
case OPT_BENCHMARK_FREQ:
benchmark.freq = strtol(optarg, NULL, 10);
if (benchmark.freq < 0) {
cerr << "Bad frequency\n";
exit(EXIT_FAILURE);
}
break;
case OPT_BENCHMARK_AFC:
benchmark.afc = strtol(optarg, NULL, 10);
break;
case OPT_BENCHMARK_SQL:
benchmark.sql = strtol(optarg, NULL, 10);
break;
case OPT_BENCHMARK_SQLEVEL:
benchmark.sqlevel = strtod(optarg, NULL);
break;
case OPT_BENCHMARK_INPUT:
benchmark.input = optarg;
break;
case OPT_BENCHMARK_OUTPUT:
benchmark.output = optarg;
break;
case OPT_BENCHMARK_SRC_RATIO:
benchmark.src_ratio = strtod(optarg, NULL);
break;
case OPT_BENCHMARK_SRC_TYPE:
benchmark.src_type = strtol(optarg, NULL, 10);
break;
#endif
2007-11-28 22:32:50 +00:00
case OPT_FONT:
2007-10-18 07:49:27 +00:00
{
char *p;
if ((p = strchr(optarg, ':'))) {
*p = '\0';
FL_NORMAL_SIZE = strtol(p + 1, 0, 10);
}
2007-10-12 23:15:06 +00:00
}
2007-10-18 07:49:27 +00:00
Fl::set_font(FL_HELVETICA, optarg);
2008-02-09 23:07:10 +00:00
break;
2007-10-18 07:49:27 +00:00
2007-11-28 22:32:50 +00:00
case OPT_WFALL_HEIGHT:
2008-10-16 10:11:28 +00:00
progdefaults.wfheight = strtol(optarg, NULL, 10);
2008-02-09 23:07:10 +00:00
break;
2007-10-18 07:49:27 +00:00
2007-11-28 22:32:50 +00:00
case OPT_WINDOW_WIDTH:
2007-10-18 07:49:27 +00:00
WNOM = strtol(optarg, NULL, 10);
2008-02-09 23:07:10 +00:00
break;
2007-10-18 07:49:27 +00:00
2007-11-28 22:32:50 +00:00
case OPT_WINDOW_HEIGHT:
2007-10-18 07:49:27 +00:00
HNOM = strtol(optarg, NULL, 10);
2008-02-09 23:07:10 +00:00
break;
2007-10-18 07:49:27 +00:00
2007-11-28 22:32:50 +00:00
#if USE_PORTAUDIO
case OPT_FRAMES_PER_BUFFER:
2008-04-18 00:36:53 +00:00
progdefaults.PortFramesPerBuffer = strtol(optarg, 0, 10);
2008-02-09 23:07:10 +00:00
break;
2007-11-28 22:32:50 +00:00
#endif // USE_PORTAUDIO
2008-02-09 23:07:10 +00:00
case OPT_EXIT_AFTER:
Fl::add_timeout(strtod(optarg, 0), exit_cb);
break;
case OPT_WFALL_ONLY:
bWF_only = true;
break;
case OPT_NOISE:
withnoise = true;
break;
case OPT_SHOW_CPU_CHECK:
show_cpucheck = true;
break;
2008-08-26 22:33:34 +00:00
case OPT_DEBUG_LEVEL:
{
int v = strtol(optarg, 0, 10);
2008-08-30 03:02:24 +00:00
debug::level = (debug::level_e)CLAMP(v, 0, debug::LOG_NLEVELS-1);
2008-08-26 22:33:34 +00:00
}
break;
2008-10-12 06:35:04 +00:00
case OPT_DEPRECATED:
cerr << "W: the --" << longopts[longindex].name
<< " option has been deprecated and will be removed in a future version\n";
break;
2007-11-28 22:32:50 +00:00
case OPT_HELP:
2008-01-29 15:58:15 +00:00
cout << option_help;
2007-10-18 07:49:27 +00:00
exit(EXIT_SUCCESS);
2007-11-28 22:32:50 +00:00
case OPT_VERSION:
2008-01-29 15:58:15 +00:00
cout << version_text;
2007-10-18 07:49:27 +00:00
exit(EXIT_SUCCESS);
2009-04-17 18:17:56 +00:00
case OPT_BUILD_INFO:
cout << build_text;
exit(EXIT_SUCCESS);
case '?': case ':': default:
arg_error(argv[0], argv[idx], (c == ':'));
2008-02-09 23:07:10 +00:00
}
// Increment idx by the number of args we used and return that number.
// We must check whether the option argument is in the same argv element
// as the option name itself, i.e., --opt=arg.
2008-03-02 08:22:41 +00:00
c = longopts[longindex].has_arg ? 2 : 1;
if (c == 2) {
string arg = argv[idx];
string::size_type p;
2008-06-11 17:36:06 +00:00
if ((p = arg.rfind(optarg)) != string::npos && arg[p-1] == '=')
2008-03-02 08:22:41 +00:00
c = 1;
}
2008-02-09 23:07:10 +00:00
idx += c;
return c;
2007-10-08 06:59:57 +00:00
}
2007-10-16 17:18:03 +00:00
2008-01-25 23:11:48 +00:00
void generate_version_text(void)
2007-10-16 17:18:03 +00:00
{
version_text.assign(PACKAGE_STRING "\nCopyright (C) 2007-2010 " PACKAGE_AUTHORS ".\n");
version_text.append(_("License GPLv3+: GNU GPL version 3 or later "
"<http://www.gnu.org/licenses/gpl-3.0.html>\n"
2009-04-17 18:17:56 +00:00
"This is free software: you are free to change and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.\n"));
2008-01-25 23:11:48 +00:00
ostringstream s;
2009-04-17 18:17:56 +00:00
s << "Build information:\n";
s << " built : " << BUILD_DATE << " by " << BUILD_USER
<< '@' << BUILD_HOST << " on " << BUILD_BUILD_PLATFORM
<< " for " << BUILD_TARGET_PLATFORM << "\n\n"
<< " configure flags: " << BUILD_CONFIGURE_ARGS << "\n\n"
<< " compiler : " << BUILD_COMPILER << "\n\n"
<< " compiler flags : " << FLDIGI_BUILD_CXXFLAGS << "\n\n"
<< " linker flags : " << FLDIGI_BUILD_LDFLAGS << "\n\n"
2009-04-17 18:17:56 +00:00
<< " libraries : " "FLTK " FLTK_BUILD_VERSION "\n"
<< " " "libsamplerate " << SAMPLERATE_BUILD_VERSION "\n";
#if USE_SNDFILE
s << " " "libsndfile " << SNDFILE_BUILD_VERSION "\n";
#endif
#if USE_PORTAUDIO
s << " " "PortAudio " << PORTAUDIO_BUILD_VERSION "\n";
#endif
#if USE_PULSEAUDIO
s << " " "PulseAudio " << PULSEAUDIO_BUILD_VERSION "\n";
#endif
#if USE_HAMLIB
s << " " "Hamlib " << HAMLIB_BUILD_VERSION "\n";
#endif
#if USE_XMLRPC
s << " " "XMLRPC-C " << XMLRPC_BUILD_VERSION "\n\n";
#endif
2008-10-12 06:35:04 +00:00
2009-04-17 18:17:56 +00:00
s << "\nRuntime information:\n";
2007-10-16 17:18:03 +00:00
struct utsname u;
if (uname(&u) != -1) {
2009-04-17 18:17:56 +00:00
s << " system : " << u.sysname << ' ' << u.nodename
<< ' ' << u.release << ' ' << u.version << ' ' << u.machine << "\n\n";
2007-12-11 03:36:51 +00:00
}
2007-10-16 17:18:03 +00:00
2009-04-17 18:17:56 +00:00
s << " libraries : " << src_get_version() << '\n';
2007-11-28 22:32:50 +00:00
#if USE_SNDFILE
2007-12-11 03:36:51 +00:00
char sndfile_version[32];
sf_command(NULL, SFC_GET_LIB_VERSION, sndfile_version, sizeof(sndfile_version));
2009-04-17 18:17:56 +00:00
s << " " << sndfile_version << '\n';
#endif
#if USE_PORTAUDIO
s << " " << Pa_GetVersionText() << ' ' << Pa_GetVersion() << '\n';
#endif
#if USE_PULSEAUDIO
s << " " << "Pulseaudio " << pa_get_library_version() << '\n';
#endif
#if USE_HAMLIB
s << " " << hamlib_version << '\n';
2007-11-28 22:32:50 +00:00
#endif
2009-04-17 18:17:56 +00:00
build_text = s.str();
2007-10-16 17:18:03 +00:00
}
2008-01-15 03:16:59 +00:00
// When debugging is enabled, reexec with malloc debugging hooks enabled, unless
2008-02-09 23:07:10 +00:00
// the env var FLDIGI_NO_EXEC is set, or our parent process is gdb.
2008-01-15 03:16:59 +00:00
void debug_exec(char** argv)
{
2009-04-17 18:17:55 +00:00
#if !defined(NDEBUG) && defined(__GLIBC__)
2008-01-15 03:16:59 +00:00
if (getenv("FLDIGI_NO_EXEC"))
return;
char ppath[32], lname[32];
ssize_t n;
snprintf(ppath, sizeof(ppath), "/proc/%u/exe", getppid());
if ((n = readlink(ppath, lname, sizeof(lname))) > 0) {
lname[n] = '\0';
if (strstr(lname, "gdb")) {
cerr << "Not using malloc debugging hooks\n";
return;
}
}
setenv("FLDIGI_NO_EXEC", "1", 0);
setenv("MALLOC_CHECK_", "3", 0);
setenv("MALLOC_PERTURB_", "42", 0);
if (execvp(*argv, argv) == -1)
perror("execvp");
#endif
}
2008-01-25 23:11:48 +00:00
2008-06-30 00:20:03 +00:00
void set_platform_ui(void)
2008-06-16 02:17:11 +00:00
{
#if defined(__APPLE__)
2008-08-30 03:02:24 +00:00
FL_NORMAL_SIZE = 12;
progdefaults.WaterfallFontsize = 12;
progdefaults.RxFontsize = 12;
progdefaults.TxFontsize = 12;
2009-04-17 18:17:55 +00:00
#elif defined(__WOE32__)
2008-06-16 02:17:11 +00:00
Fl::set_font(FL_HELVETICA, "Tahoma");
FL_NORMAL_SIZE = 11;
progdefaults.WaterfallFontnbr = FL_HELVETICA;
progdefaults.WaterfallFontsize = 12;
2008-06-30 00:20:03 +00:00
progdefaults.RxFontsize = 12;
progdefaults.TxFontsize = 12;
#else
FL_NORMAL_SIZE = 12;
2008-06-16 02:17:11 +00:00
#endif
}
2008-06-30 00:20:03 +00:00
// Convert 1 second of 1-channel silence from IN_RATE Hz to OUT_RATE Hz,
// Repeat test "repeat" times. Return (repeat / elapsed_time),
// the faster-than-realtime factor averaged over "repeat" runs.
// Some figures for SRC_SINC_FASTEST:
// Pentium 4 2.8GHz: 70
// Pentium 3 550MHz: 13
// UltraSparc II 270MHz: 3.5
// Atom N280 1.66GHz: 17.7
2008-06-30 00:20:03 +00:00
#define IN_RATE 48000
#define OUT_RATE 8000
double speed_test(int converter, unsigned repeat)
{
SRC_DATA src;
src.src_ratio = (double)OUT_RATE / IN_RATE;
src.input_frames = IN_RATE;
src.output_frames = OUT_RATE;
src.data_in = new float[src.input_frames];
src.data_out = new float[src.output_frames];
memset(src.data_in, 0, src.input_frames * sizeof(float));
// warm up
2008-09-11 01:35:48 +00:00
src_simple(&src, converter, 1);
2008-06-30 00:20:03 +00:00
struct timespec t0, t1;
2008-07-24 12:22:53 +00:00
#ifdef _POSIX_MONOTONIC_CLOCK
clock_gettime(CLOCK_MONOTONIC, &t0);
#else
2008-06-30 00:20:03 +00:00
clock_gettime(CLOCK_REALTIME, &t0);
2008-07-24 12:22:53 +00:00
#endif
2008-06-30 00:20:03 +00:00
for (unsigned i = 0; i < repeat; i++)
2008-09-11 01:35:48 +00:00
src_simple(&src, converter, 1);
2008-07-24 12:22:53 +00:00
#ifdef _POSIX_MONOTONIC_CLOCK
clock_gettime(CLOCK_MONOTONIC, &t1);
#else
2008-06-30 00:20:03 +00:00
clock_gettime(CLOCK_REALTIME, &t1);
2008-07-24 12:22:53 +00:00
#endif
2008-06-30 00:20:03 +00:00
delete [] src.data_in;
delete [] src.data_out;
t0 = t1 - t0;
return repeat / (t0.tv_sec + t0.tv_nsec/1e9);
}
2008-09-26 19:17:45 +00:00
2008-10-12 06:35:04 +00:00
static void setup_signal_handlers(void)
2008-09-26 19:17:45 +00:00
{
2009-04-17 18:17:55 +00:00
#ifndef __WOE32__
2008-09-26 19:17:45 +00:00
struct sigaction action;
memset(&action, 0, sizeof(struct sigaction));
// no child stopped notifications, no zombies
2008-10-12 06:35:04 +00:00
action.sa_handler = SIG_DFL;
action.sa_flags = SA_NOCLDSTOP;
#ifdef SA_NOCLDWAIT
action.sa_flags |= SA_NOCLDWAIT;
#endif
2008-09-26 19:17:45 +00:00
sigaction(SIGCHLD, &action, NULL);
action.sa_flags = 0;
action.sa_handler = handle_signal;
sigaction(SIGSEGV, &action, NULL);
sigaction(SIGILL, &action, NULL);
sigaction(SIGABRT, &action, NULL);
sigaction(SIGUSR2, &action, NULL);
action.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &action, NULL);
sigemptyset(&action.sa_mask);
sigaddset(&action.sa_mask, SIGUSR2);
2008-10-12 06:35:04 +00:00
pthread_sigmask(SIG_BLOCK, &action.sa_mask, NULL);
#else
signal(SIGSEGV, handle_signal);
signal(SIGILL, handle_signal);
signal(SIGABRT, handle_signal);
#endif
2008-09-26 19:17:45 +00:00
}
static void checkdirectories(void)
{
struct DIRS {
string& dir;
const char* suffix;
void (*new_dir_func)(void);
};
DIRS fldigi_dirs[] = {
{ HomeDir, 0, 0 },
{ RigsDir, "rigs", 0 },
{ ScriptsDir, "scripts", 0 },
{ PalettesDir, "palettes", create_new_palettes },
{ LogsDir, "logs", 0 },
{ PicsDir, "images", 0 },
{ HelpDir, "help", 0 },
{ MacrosDir, "macros", create_new_macros },
{ WrapDir, "wrap", 0 },
{ TalkDir, "talk", 0 },
{ TempDir, "temp", 0 },
};
int r;
for (size_t i = 0; i < sizeof(fldigi_dirs)/sizeof(*fldigi_dirs); i++) {
if (fldigi_dirs[i].suffix)
fldigi_dirs[i].dir.assign(HomeDir).append(fldigi_dirs[i].suffix).append(PATH_SEP);
if ((r = mkdir(fldigi_dirs[i].dir.c_str(), 0777)) == -1 && errno != EEXIST) {
cerr << _("Could not make directory") << ' ' << fldigi_dirs[i].dir
<< ": " << strerror(errno) << '\n';
exit(EXIT_FAILURE);
}
else if (r == 0 && fldigi_dirs[i].new_dir_func)
fldigi_dirs[i].new_dir_func();
}
}
bool nbems_dirs_checked = false;
void check_nbems_dirs(void)
{
if (nbems_dirs_checked) return;
struct DIRS {
string& dir;
const char* suffix;
void (*new_dir_func)(void);
};
DIRS NBEMS_dirs[] = {
{ NBEMS_dir, 0, 0 },
{ ARQ_dir, "ARQ", 0 },
{ ARQ_files_dir, "ARQ/files", 0 },
{ ARQ_recv_dir, "ARQ/recv", 0 },
{ ARQ_send, "ARQ/send", 0 },
{ WRAP_dir, "WRAP", 0 },
{ WRAP_recv_dir, "WRAP/recv", 0 },
{ WRAP_send_dir, "WRAP/send", 0 },
{ WRAP_auto_dir, "WRAP/auto", 0 },
{ ICS_dir, "ICS", 0 },
{ ICS_msg_dir, "ICS/messages", 0 },
{ ICS_tmp_dir, "ICS/templates", 0 },
};
int r;
for (size_t i = 0; i < sizeof(NBEMS_dirs)/sizeof(*NBEMS_dirs); i++) {
if (NBEMS_dirs[i].suffix)
NBEMS_dirs[i].dir.assign(NBEMS_dir).append(NBEMS_dirs[i].suffix).append(PATH_SEP);
if ((r = mkdir(NBEMS_dirs[i].dir.c_str(), 0777)) == -1 && errno != EEXIST) {
cerr << _("Could not make directory") << ' ' << NBEMS_dirs[i].dir
<< ": " << strerror(errno) << '\n';
exit(EXIT_FAILURE);
}
else if (r == 0 && NBEMS_dirs[i].new_dir_func)
NBEMS_dirs[i].new_dir_func();
}
DIRS FLMSG_dirs[] = {
{ FLMSG_dir, 0, 0 },
{ FLMSG_WRAP_dir, "WRAP", 0 },
{ FLMSG_WRAP_recv_dir, "WRAP/recv", 0 },
{ FLMSG_WRAP_send_dir, "WRAP/send", 0 },
{ FLMSG_WRAP_auto_dir, "WRAP/auto", 0 },
{ FLMSG_ICS_dir, "ICS", 0 },
{ FLMSG_ICS_msg_dir, "ICS/messages", 0 },
{ FLMSG_ICS_tmp_dir, "ICS/templates", 0 },
};
for (size_t i = 0; i < sizeof(FLMSG_dirs)/sizeof(*FLMSG_dirs); i++) {
if (FLMSG_dirs[i].dir.empty() && FLMSG_dirs[i].suffix)
FLMSG_dirs[i].dir.assign(FLMSG_dir).append(FLMSG_dirs[i].suffix).append("/");
if ((r = mkdir(FLMSG_dirs[i].dir.c_str(), 0777)) == -1 && errno != EEXIST) {
cerr << _("Could not make directory") << ' ' << FLMSG_dirs[i].dir
<< ": " << strerror(errno) << '\n';
exit(EXIT_FAILURE);
}
else if (r == 0 && FLMSG_dirs[i].new_dir_func)
FLMSG_dirs[i].new_dir_func();
}
nbems_dirs_checked = true;
}
// Print an error message and exit. If stderr is not a terminal
// show an error dialog instead. On win32 we always use Fl::fatal,
// which displays its own error window.
static void arg_error(const char* name, const char* arg, bool missing)
{
ostringstream msg;
msg << name << ": ";
if (arg && *arg) {
if (missing)
msg << "option '" << arg << "' requires an argument\n";
else
msg << "unrecognized option '" << arg << "'\n";
}
else
msg << "error while parsing command line\n";
#ifdef __WOE32__
bool woe32 = true;
#else
bool woe32 = false;
#endif
bool tty = isatty(STDERR_FILENO);
if (tty && !woe32)
msg << "Try `" << name << " --help' for more information.";
else
msg << "See command line help for more information.";
if (tty || woe32)
Fl::fatal("%s", msg.str().c_str());
else {
fl_message_font(FL_HELVETICA, FL_NORMAL_SIZE);
fl_alert2("%s", msg.str().c_str());
}
exit(EXIT_FAILURE);
}