[med-svn] [SCM] aghermann branch, master, updated. 4b06a66467a52311d413e817136ece62c0e9c24a
Andrei Zavada
johnhommer at gmail.com
Sun Jul 21 19:56:38 UTC 2013
The following commit has been merged in the master branch:
commit 4b06a66467a52311d413e817136ece62c0e9c24a
Author: Andrei Zavada <johnhommer at gmail.com>
Date: Sun Jul 21 19:01:35 2013 +0300
support tsv files in aghermann, too
diff --git a/ChangeLog b/ChangeLog
index 2a2df4a..e56dab1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,9 +1,14 @@
-v.1.0 (2013-xx-xx)
+v.0.9.1 (2013-xx-xx)
* Reorg source tree around main executable, libs, & tools.
- * Properly use libsigfile.so.
+ * Properly use our own lib*.so (previously aghermann turned out
+ static despite libsigfile.so being installed).
* Plug a memory leak after early unique_ptr acquisition.
* SF: Move selection on montage (with Alt).
+ * SF: Artifact Detection dialog will now not get confused after
+ clicking outside it on other channels.
* New tool agh-profile-gen, a standalone profile generator.
+ * ascii (tsv) format support.
+ * Score assistant now uses delta and theta ranges as defined by user.
v.0.9.0.4 (2013-05-18)
* Remove stray AC_CHECK_FUNC(mremap).
diff --git a/data/mw-dialogs.glade b/data/mw-dialogs.glade
index 5e30fe4..c9bbe31 100644
--- a/data/mw-dialogs.glade
+++ b/data/mw-dialogs.glade
@@ -1053,6 +1053,7 @@ With bug reports, either send yours to <a href="mailto:aghermann-users at lists.
<property name="width_request">500</property>
<property name="can_focus">False</property>
<property name="border_width">10</property>
+ <property name="title" translatable="yes">Import EEG source</property>
<property name="icon">aghermann.png</property>
<property name="type_hint">normal</property>
<signal name="close" handler="gtk_widget_hide" swapped="no"/>
@@ -1133,7 +1134,6 @@ With bug reports, either send yours to <a href="mailto:aghermann-users at lists.
<property name="xalign">0</property>
<property name="xpad">5</property>
<property name="ypad">8</property>
- <property name="label" translatable="yes">(Identify new EDF source)</property>
<property name="use_markup">True</property>
<property name="ellipsize">middle</property>
</object>
@@ -1439,7 +1439,7 @@ With bug reports, either send yours to <a href="mailto:aghermann-users at lists.
<object class="GtkLabel" id="label14">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">EDF info</property>
+ <property name="label" translatable="yes">Details</property>
</object>
<packing>
<property name="position">1</property>
@@ -2524,6 +2524,7 @@ With bug reports, either send yours to <a href="mailto:aghermann-users at lists.
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="editable">False</property>
+ <property name="input_hints">GTK_INPUT_HINT_NO_SPELLCHECK | GTK_INPUT_HINT_NONE</property>
</object>
</child>
</object>
diff --git a/src/aghermann/expdesign/primaries.hh b/src/aghermann/expdesign/primaries.hh
index 80fbf6c..418b131 100644
--- a/src/aghermann/expdesign/primaries.hh
+++ b/src/aghermann/expdesign/primaries.hh
@@ -322,7 +322,7 @@ class CExpDesign {
string error_log_serialize() const;
size_t error_log_n_messages() const
{ return _error_log.size(); }
- void log_message( const char* fmt, ...);
+ void log_message( const char* fmt, ...) __attribute__ (( format (printf, 2, 3) ));
// contains
typedef map<string, CJGroup> TJGroups;
diff --git a/src/aghermann/expdesign/tree-scanner.cc b/src/aghermann/expdesign/tree-scanner.cc
index 30e4f62..56cc52d 100644
--- a/src/aghermann/expdesign/tree-scanner.cc
+++ b/src/aghermann/expdesign/tree-scanner.cc
@@ -142,8 +142,12 @@ register_intree_source( sigfile::CTypedSource&& F,
list<string>::iterator pe = broken_path.begin();
string& g_name = (pe = next(pe), *pe),
j_name = (pe = next(pe), *pe),
- d_name = (pe = next(pe), *pe),
- e_name = fs::make_fname_base(*next(pe), ".edf", false);
+ d_name = (pe = next(pe), *pe);
+ string e_name =
+ fs::make_fname_base(
+ *next(pe),
+ sigfile::supported_sigfile_extensions,
+ agh::fs::TMakeFnameOption::normal);
// take care of the case of episode-2.edf
{
auto subf = agh::str::tokens_trimmed(e_name, "-");
@@ -159,15 +163,17 @@ register_intree_source( sigfile::CTypedSource&& F,
// refuse to register sources of wrong subjects
if ( j_name != F().subject().id ) {
- log_message( "%s: file belongs to subject %s (\"%s\"), is misplaced here under subject \"%s\"",
- F().filename(), F().subject().id.c_str(), F().subject().name.c_str(), j_name.c_str());
+ log_message( "$$%s:", F().filename());
+ log_message( "file belongs to subject %s (\"%s\"), is misplaced here under subject \"%s\"",
+ F().subject().id.c_str(), F().subject().name.c_str(), j_name.c_str());
return -1;
}
try {
auto existing_group = group_of( F().subject().id.c_str());
if ( g_name != existing_group ) {
- log_message( "%s: subject %s (\"%s\") belongs to a different group (\"%s\")",
- F().filename(), F().subject().id.c_str(), F().subject().name.c_str(), existing_group);
+ log_message( "$$%s:", F().filename());
+ log_message( "subject %s (\"%s\") belongs to a different group (\"%s\")",
+ F().subject().id.c_str(), F().subject().name.c_str(), existing_group);
return -1;
}
} catch (invalid_argument) {
@@ -176,13 +182,14 @@ register_intree_source( sigfile::CTypedSource&& F,
// but correct session/episode fields
if ( d_name != F().session() ) {
- log_message( "%s: correcting embedded session \"%s\" to match placement in the tree (\"%s\")",
- F().filename(), F().session(), d_name.c_str());
+ log_message( "$$%s:", F().filename());
+ log_message( "correcting embedded session \"%s\" to match placement in the tree (\"%s\")",
+ F().session(), d_name.c_str());
F().set_session( d_name.c_str());
}
if ( e_name != F().episode() ) {
- log_message( "%s: correcting embedded episode \"%s\" to match file name",
- F().filename(), F().episode());
+ log_message( "correcting embedded episode \"%s\" to match file name",
+ F().episode());
F().set_episode( e_name.c_str());
}
@@ -225,7 +232,7 @@ register_intree_source( sigfile::CTypedSource&& F,
}
} catch (invalid_argument ex) {
- log_message( ex.what());
+ log_message( "%s", ex.what());
if ( reason_if_failed_p )
*reason_if_failed_p = ex.what();
return -1;
@@ -252,12 +259,12 @@ is_supported_source( sigfile::CTypedSource& F)
CTSVFile::TSubtype t;
} u;
return (F.type() == CTypedSource::TType::edf and
- (u.e = static_cast<CEDFFile*>(&F()) -> subtype(),
+ (u.e = F.obj<CEDFFile>().subtype(),
(u.e == CEDFFile::TSubtype::edf ||
u.e == CEDFFile::TSubtype::edfplus_c)))
or
(F.type() == CTypedSource::TType::ascii and
- (u.t = static_cast<CTSVFile*>(&F()) -> subtype(),
+ (u.t = F.obj<CTSVFile>().subtype(),
(u.t == CTSVFile::TSubtype::csv ||
u.t == CTSVFile::TSubtype::tsv)));
}
@@ -265,39 +272,39 @@ is_supported_source( sigfile::CTypedSource& F)
namespace {
size_t
- __cur_edf_file;
+ current_sigfile_source;
agh::CExpDesign
- *__expdesign;
+ *only_expdesign;
agh::CExpDesign::TMsmtCollectProgressIndicatorFun
only_progress_fun;
int
-edf_file_processor( const char *fname, const struct stat*, int flag, struct FTW *ftw)
+supported_sigfile_processor( const char *fname, const struct stat*, int flag, struct FTW *ftw)
{
if ( flag == FTW_F && ftw->level == 4 ) {
int fnlen = strlen(fname); // - ftw->base;
if ( fnlen < 5 )
return 0;
- if ( strcasecmp( &fname[fnlen-4], ".edf") == 0 ) {
- ++__cur_edf_file;
- only_progress_fun( fname, agh::fs::__n_edf_files, __cur_edf_file);
+ if ( sigfile::is_fname_ext_supported( fname) ) {
+ ++current_sigfile_source;
+ only_progress_fun( fname, agh::fs::total_supported_sigfiles, current_sigfile_source);
try {
using namespace sigfile;
- CTypedSource F {fname, (size_t)roundf(__expdesign->fft_params.pagesize)};
+ CTypedSource F {fname, (size_t)roundf(only_expdesign->fft_params.pagesize)};
string st = F().explain_status();
if ( not st.empty() ) {
- __expdesign->log_message( "$$%s:", fname);
- __expdesign->log_message( "%s", st.c_str());
+ only_expdesign->log_message( "$$%s:", fname);
+ only_expdesign->log_message( "%s", st.c_str());
}
// we only support edf and edfplus/edf_c
if ( agh::CExpDesign::is_supported_source(F) )
- __expdesign -> register_intree_source( move(F));
+ only_expdesign -> register_intree_source( move(F));
else
- __expdesign -> log_message( "File %s: unsupported format", fname);
+ only_expdesign -> log_message( "File %s: unsupported format", fname);
} catch ( invalid_argument ex) {
- __expdesign->log_message(ex.what());
+ only_expdesign->log_message( "%s", ex.what());
}
}
}
@@ -335,17 +342,17 @@ scan_tree( TMsmtCollectProgressIndicatorFun user_progress_fun)
groups.clear();
// glob it!
- agh::fs::__n_edf_files = 0;
- nftw( "./", agh::fs::edf_file_counter, 20, 0);
+ agh::fs::total_supported_sigfiles = 0;
+ nftw( "./", agh::fs::supported_sigfile_counter, 20, 0);
printf( "CExpDesign::scan_tree(\"%s\"): %zu edf file(s) found\n",
- session_dir().c_str(), agh::fs::__n_edf_files);
- if ( agh::fs::__n_edf_files == 0 )
+ session_dir().c_str(), agh::fs::total_supported_sigfiles);
+ if ( agh::fs::total_supported_sigfiles == 0 )
return;
- __cur_edf_file = 0;
+ current_sigfile_source = 0;
only_progress_fun = user_progress_fun;
- __expdesign = this;
- nftw( "./", edf_file_processor, 10, 0);
+ only_expdesign = this;
+ nftw( "./", supported_sigfile_processor, 10, 0);
printf( "CExpDesign::scan_tree(): recordings collected\n");
compute_profiles(); // in an SMP fashion
diff --git a/src/aghermann/ui/mw/admit-one.cc b/src/aghermann/ui/mw/admit-one.cc
index 5b94768..e2f29b9 100644
--- a/src/aghermann/ui/mw/admit-one.cc
+++ b/src/aghermann/ui/mw/admit-one.cc
@@ -22,153 +22,181 @@ int
aghui::SExpDesignUI::
dnd_maybe_admit_one( const char* fname)
{
- using namespace sigfile;
- CTypedSource *Fp = nullptr;
-
- string info;
try {
- Fp = new CTypedSource (fname, ED->fft_params.pagesize);
- switch ( Fp->type() ) {
- case CTypedSource::TType::edf:
+ string info;
+ sigfile::CTypedSource F_ (fname, ED->fft_params.pagesize);
+ switch ( F_.type() ) {
+ case sigfile::CTypedSource::TType::edf:
{
- CEDFFile& F = *static_cast<CEDFFile*> (&(*Fp)());
- if ( F.subtype() == CEDFFile::TSubtype::edfplus_d ) {
+ sigfile::CEDFFile& F = F_.obj<sigfile::CEDFFile>();
+ if ( F.subtype() == sigfile::CEDFFile::TSubtype::edfplus_d ) {
pop_ok_message(
- wMainWindow, "EDF+D Unsupported", "The file <b>%s</b> is in EDF+D format, which is not supported yet",
+ wMainWindow,
+ "EDF+D is unsupported",
+ "The file <b>%s</b> is in EDF+D format, which is not supported yet",
fname);
return 0;
}
- if ( F.status() & CEDFFile::TStatus::inoperable ) {
+ if ( F.status() & sigfile::CEDFFile::TStatus::inoperable ) {
pop_ok_message(
- wMainWindow, "Bad EDF file", "The file <b>%s</b> cannot be processed due to these issues:\n\n%s",
+ wMainWindow,
+ "Bad EDF file",
+ "The file <b>%s</b> cannot be processed due to these issues:\n\n%s",
fname, F.explain_status().c_str());
return 0;
}
+ }
+ break;
+
+ case sigfile::CTypedSource::TType::ascii:
+ break;
+
+ default:
+ pop_ok_message(
+ wMainWindow,
+ "Unsupported format",
+ "The file <b>%s</b> is in unrecognised format. Sorry.", fname);
+ return 0;
+ }
+
+ auto& F = F_();
+
+ info = F.details( 0|sigfile::CSource::TDetails::with_channels);
- info = (*Fp)().details( 0|sigfile::CEDFFile::with_channels);
+ {
+ char* mike;
+ mike = g_markup_escape_text(
+ agh::str::homedir2tilda( F.filename()).c_str(),
+ -1);
gtk_label_set_markup(
lEdfImportCaption,
- (snprintf_buf( "File: <i>%s</i>", fname),
- __buf__));
+ snprintf_buf( "File: <i>%s</i>", mike));
+ free( (void*)mike);
+
+ mike = g_markup_escape_text(
+ F.subject().name.empty() ? "<no name>" : F.subject().name.c_str(),
+ -1);
gtk_label_set_markup(
lEdfImportSubject,
- (snprintf_buf( "<b>%s</b> (%s)", F.subject().id.c_str(), F.subject().name.c_str()),
- __buf__));
- }
- break;
- default:
- pop_ok_message( wMainWindow, "Unsupported format", "The file <b>%s</b> is in unrecognised format. Sorry.", fname);
- return 0;
+ snprintf_buf(
+ "<b>%s</b> (%s)",
+ F.subject().id.c_str(),
+ mike));
+ free( (void*)mike);
}
- } catch ( exception& ex) {
- pop_ok_message( wMainWindow, "Corrupted EDF file", "File <b>%s</b> doesn't appear to have a valid header:\n\n%s",
- fname, (*Fp)().explain_status().c_str());
- return 0;
- }
- gtk_text_buffer_set_text( tEDFFileDetailsReport, info.c_str(), -1);
-
- GtkTreeIter iter;
- // populate and attach models
- GtkListStore
- *m_groups = gtk_list_store_new( 1, G_TYPE_STRING),
- *m_episodes = gtk_list_store_new( 1, G_TYPE_STRING),
- *m_sessions = gtk_list_store_new( 1, G_TYPE_STRING);
- // when adding a source for an already existing subject, disallow group selection
- try {
- gtk_entry_set_text(
- eEdfImportGroupEntry,
- ED->group_of( (*Fp)().subject().id.c_str()));
- gtk_widget_set_sensitive( (GtkWidget*)eEdfImportGroup, FALSE);
- } catch (invalid_argument ex) {
- for ( auto &i : AghGG ) {
- gtk_list_store_append( m_groups, &iter);
- gtk_list_store_set( m_groups, &iter, 0, i.c_str(), -1);
+ gtk_text_buffer_set_text( tEDFFileDetailsReport, info.c_str(), -1);
+
+ GtkTreeIter iter;
+ // populate and attach models
+ GtkListStore
+ *m_groups = gtk_list_store_new( 1, G_TYPE_STRING),
+ *m_episodes = gtk_list_store_new( 1, G_TYPE_STRING),
+ *m_sessions = gtk_list_store_new( 1, G_TYPE_STRING);
+ // when adding a source for an already existing subject, disallow group selection
+ try {
+ gtk_entry_set_text(
+ eEdfImportGroupEntry,
+ ED->group_of( F.subject().id.c_str()));
+ gtk_widget_set_sensitive( (GtkWidget*)eEdfImportGroup, FALSE);
+ } catch (invalid_argument ex) {
+ for ( auto &i : AghGG ) {
+ gtk_list_store_append( m_groups, &iter);
+ gtk_list_store_set( m_groups, &iter, 0, i.c_str(), -1);
+ }
+ gtk_combo_box_set_model(
+ eEdfImportGroup,
+ (GtkTreeModel*)m_groups);
+ gtk_combo_box_set_entry_text_column( eEdfImportGroup, 0);
+ // gtk_entry_set_text(
+ // (GtkEntry*)gtk_bin_get_child( (GtkBin*)eEdfImportGroup),
+ // "");
+ gtk_widget_set_sensitive( (GtkWidget*)eEdfImportGroup, TRUE);
}
- gtk_combo_box_set_model( eEdfImportGroup,
- (GtkTreeModel*)m_groups);
- gtk_combo_box_set_entry_text_column( eEdfImportGroup, 0);
- // gtk_entry_set_text(
- // (GtkEntry*)gtk_bin_get_child( (GtkBin*)eEdfImportGroup),
- // "");
- gtk_widget_set_sensitive( (GtkWidget*)eEdfImportGroup, TRUE);
- }
- for ( auto &i : AghEE ) {
- gtk_list_store_append( m_episodes, &iter);
- gtk_list_store_set( m_episodes, &iter, 0, i.c_str(), -1);
- }
- gtk_combo_box_set_model( eEdfImportEpisode,
- (GtkTreeModel*)m_episodes);
- gtk_combo_box_set_entry_text_column( eEdfImportEpisode, 0);
+ // enumerate known sessions and episodes
+ // suggest those from the file proper
+ for ( auto &i : AghEE ) {
+ gtk_list_store_append( m_episodes, &iter);
+ gtk_list_store_set( m_episodes, &iter, 0, i.c_str(), -1);
+ }
+ gtk_combo_box_set_model(
+ eEdfImportEpisode,
+ (GtkTreeModel*)m_episodes);
+ gtk_combo_box_set_entry_text_column(
+ eEdfImportEpisode, 0);
+ gtk_entry_set_text(
+ (GtkEntry*)gtk_bin_get_child( (GtkBin*)eEdfImportEpisode),
+ F.episode());
- for ( auto &i : AghDD ) {
- gtk_list_store_append( m_sessions, &iter);
- gtk_list_store_set( m_sessions, &iter, 0, i.c_str(), -1);
- }
- gtk_combo_box_set_model( eEdfImportSession,
- (GtkTreeModel*)m_sessions);
- gtk_combo_box_set_entry_text_column( eEdfImportSession, 0);
-
- // guess episode from fname
- char *fname2 = g_strdup( fname), *episode = strrchr( fname2, '/')+1;
- if ( g_str_has_suffix( episode, ".edf") || g_str_has_suffix( episode, ".EDF") )
- *strrchr( episode, '.') = '\0';
- gtk_entry_set_text( (GtkEntry*)gtk_bin_get_child( (GtkBin*)eEdfImportEpisode),
- episode);
-
- // display
- g_signal_emit_by_name( eEdfImportGroupEntry, "changed");
-
- gint response = gtk_dialog_run( (GtkDialog*)wEdfImport);
- const gchar
- *selected_group = gtk_entry_get_text( eEdfImportGroupEntry),
- *selected_session = gtk_entry_get_text( eEdfImportSessionEntry),
- *selected_episode = gtk_entry_get_text( eEdfImportEpisodeEntry);
- switch ( response ) {
- case GTK_RESPONSE_OK: // Admit
- {
- char *dest_path, *dest, *cmd;
- dest_path = g_strdup_printf( "%s/%s/%s/%s",
- ED->session_dir().c_str(),
- selected_group,
- (*Fp)().subject().id.c_str(),
- selected_session);
- dest = g_strdup_printf( "%s/%s.edf",
- dest_path,
- selected_episode);
- if ( gtk_toggle_button_get_active( (GtkToggleButton*)bEdfImportAttachCopy) )
- cmd = g_strdup_printf( "mkdir -p '%s' && cp -n '%s' '%s'", dest_path, fname, dest);
- else if ( gtk_toggle_button_get_active( (GtkToggleButton*)bEdfImportAttachMove) )
- cmd = g_strdup_printf( "mkdir -p '%s' && mv -n '%s' '%s'", dest_path, fname, dest);
- else
- cmd = g_strdup_printf( "mkdir -p '%s' && ln -s '%s' '%s'", dest_path, fname, dest);
- char* cmde = g_markup_escape_text( cmd, -1);
-
- int cmd_exit = system( cmd);
- if ( cmd_exit )
- pop_ok_message( wMainWindow,
+ for ( auto &i : AghDD ) {
+ gtk_list_store_append( m_sessions, &iter);
+ gtk_list_store_set( m_sessions, &iter, 0, i.c_str(), -1);
+ }
+ gtk_combo_box_set_model(
+ eEdfImportSession,
+ (GtkTreeModel*)m_sessions);
+ gtk_combo_box_set_entry_text_column(
+ eEdfImportSession, 0);
+ gtk_entry_set_text(
+ (GtkEntry*)gtk_bin_get_child( (GtkBin*)eEdfImportSession),
+ F.session());
+
+ // display
+ g_signal_emit_by_name( eEdfImportGroupEntry, "changed");
+
+ gint response = gtk_dialog_run( (GtkDialog*)wEdfImport);
+ const gchar
+ *selected_group = gtk_entry_get_text( eEdfImportGroupEntry),
+ *selected_session = gtk_entry_get_text( eEdfImportSessionEntry),
+ *selected_episode = gtk_entry_get_text( eEdfImportEpisodeEntry);
+ switch ( response ) {
+ case GTK_RESPONSE_OK: // Admit
+ {
+ string dest_path, dest, cmd;
+ using agh::str::sasprintf;
+ dest_path = sasprintf(
+ "%s/%s/%s/%s",
+ ED->session_dir().c_str(), selected_group,
+ F.subject().id.c_str(), selected_session);
+ dest = sasprintf(
+ "%s/%s.edf",
+ dest_path.c_str(), selected_episode);
+ if ( gtk_toggle_button_get_active( (GtkToggleButton*)bEdfImportAttachCopy) )
+ cmd = sasprintf( "mkdir -p '%s' && cp -n '%s' '%s'", dest_path.c_str(), fname, dest.c_str());
+ else if ( gtk_toggle_button_get_active( (GtkToggleButton*)bEdfImportAttachMove) )
+ cmd = sasprintf( "mkdir -p '%s' && mv -n '%s' '%s'", dest_path.c_str(), fname, dest.c_str());
+ else
+ cmd = sasprintf( "mkdir -p '%s' && ln -s '%s' '%s'", dest_path.c_str(), fname, dest.c_str());
+ char* cmde = g_markup_escape_text( cmd.c_str(), -1);
+
+ int cmd_exit = system( cmd.c_str());
+ if ( cmd_exit )
+ pop_ok_message(
+ wMainWindow,
"Failed to create recording path in experiment tree",
- "Command\n <span font=\"monospace\">%s</span>\nexited with code %d", cmde, cmd_exit);
-
- g_free( cmd);
- g_free( cmde);
- g_free( dest);
- g_free( dest_path);
- }
- break;
- case GTK_RESPONSE_CANCEL: // Drop
+ "Command\n <span font=\"monospace\">%s</span>\nexited with code %d",
+ cmde, cmd_exit);
+ g_free( cmde);
+ }
break;
- }
+ case GTK_RESPONSE_CANCEL: // Drop
+ break;
+ }
- // finalise
- g_free( fname2);
+ g_object_unref( m_groups);
+ g_object_unref( m_sessions);
+ g_object_unref( m_episodes);
- g_object_unref( m_groups);
- g_object_unref( m_sessions);
- g_object_unref( m_episodes);
+ return 0;
- return 0;
+ } catch ( exception& ex) {
+ pop_ok_message(
+ wMainWindow,
+ "Corrupted source file", "File <b>%s</b> could not be processed.",
+ fname);
+ return 0;
+ }
}
diff --git a/src/aghermann/ui/sf/sf.cc b/src/aghermann/ui/sf/sf.cc
index df281df..defd566 100644
--- a/src/aghermann/ui/sf/sf.cc
+++ b/src/aghermann/ui/sf/sf.cc
@@ -671,7 +671,11 @@ aghui::SScoringFacility::
load_montage()
{
libconfig::Config conf;
- string montage_file = (agh::fs::make_fname_base( channels.front().crecording.F().filename(), ".edf", true) + ".montage");
+ string montage_file =
+ agh::fs::make_fname_base(
+ channels.front().crecording.F().filename(),
+ sigfile::supported_sigfile_extensions,
+ agh::fs::TMakeFnameOption::hidden) + ".montage";
try {
conf.readFile (montage_file.c_str());
} catch (libconfig::ParseException ex) {
@@ -721,7 +725,12 @@ save_montage()
agh::confval::put( h.config_keys_g, conf);
}
try {
- conf.writeFile ((agh::fs::make_fname_base( channels.front().crecording.F().filename(), ".edf", true) + ".montage").c_str());
+ conf.writeFile (
+ (agh::fs::make_fname_base(
+ channels.front().crecording.F().filename(),
+ sigfile::supported_sigfile_extensions,
+ agh::fs::TMakeFnameOption::hidden)
+ + ".montage").c_str() );
} catch (...) {
;
}
diff --git a/src/aghermann/ui/sm/sm.cc b/src/aghermann/ui/sm/sm.cc
index 7aee9f2..74c7949 100644
--- a/src/aghermann/ui/sm/sm.cc
+++ b/src/aghermann/ui/sm/sm.cc
@@ -30,10 +30,10 @@ void
aghui::SSession::
get_session_stats()
{
- agh::fs::__n_edf_files = 0;
+ agh::fs::total_supported_sigfiles = 0;
string path = agh::str::tilda2homedir(c_str());
- nftw( path.c_str(), agh::fs::edf_file_counter, 20, 0);
- n_recordings = agh::fs::__n_edf_files;
+ nftw( path.c_str(), agh::fs::supported_sigfile_counter, 20, 0);
+ n_recordings = agh::fs::total_supported_sigfiles;
{
struct stat stat0;
diff --git a/src/common/fs.hh b/src/common/fs.hh
index faa2ca3..979bcfa 100644
--- a/src/common/fs.hh
+++ b/src/common/fs.hh
@@ -27,32 +27,18 @@ using namespace std;
namespace agh {
namespace fs {
-template<class T>
+enum class TMakeFnameOption { normal, hidden };
string
-make_fname_base( const T& _filename, const char *suffix, bool hidden)
-{
- string fname_ (_filename);
- auto slen = strlen( suffix);
- if ( fname_.size() > slen && strcasecmp( &fname_[fname_.size()-slen], suffix) == 0 )
- fname_.erase( fname_.size()-slen, slen);
- if ( hidden ) {
- size_t slash_at = fname_.rfind('/');
- if ( slash_at < fname_.size() )
- fname_.insert( slash_at+1, ".");
- }
- return fname_;
-}
+make_fname_base( const string& fname_, const string& suffices, TMakeFnameOption);
-template<class T>
-list<string>
-path_elements( const T& _filename)
+inline list<string>
+path_elements( const string& _filename)
{
return agh::str::tokens( _filename, "/");
}
-template<class T>
-string
-dirname( const T& _filename)
+inline string
+dirname( const string& _filename)
{
string pre = (_filename[0] == '/') ? "/" : "";
auto ee = agh::str::tokens( _filename, "/");
@@ -64,11 +50,9 @@ dirname( const T& _filename)
-template<class T>
-bool
-exists_and_is_writable( const T& _dir)
+inline bool
+exists_and_is_writable( const string& dir)
{
- string dir (_dir);
struct stat attr;
return stat( dir.c_str(), &attr) == 0 &&
S_ISDIR (attr.st_mode) &&
@@ -77,14 +61,13 @@ exists_and_is_writable( const T& _dir)
}
-template<class T>
-int
-mkdir_with_parents( const T& dir)
+inline int
+mkdir_with_parents( const string& dir)
{
return system(
agh::str::sasprintf(
"mkdir -p '%s'",
- string (dir).c_str())
+ dir.c_str())
.c_str());
}
@@ -94,8 +77,8 @@ mkdir_with_parents( const T& dir)
// this is another global
-int edf_file_counter( const char *fname, const struct stat*, int flag, struct FTW *ftw);
-extern size_t __n_edf_files;
+int supported_sigfile_counter( const char *fname, const struct stat*, int flag, struct FTW *ftw);
+extern size_t total_supported_sigfiles;
diff --git a/src/common/libcommon.cc b/src/common/libcommon.cc
index 1120884..f499057 100644
--- a/src/common/libcommon.cc
+++ b/src/common/libcommon.cc
@@ -123,6 +123,7 @@ decompose_double( double value, double *mantissa, int *exponent)
+
string&
agh::str::
homedir2tilda( string& inplace)
@@ -296,19 +297,45 @@ from_wstring( const wstring& in, const char* charset)
+
+// fs
+
+string
+agh::fs::
+make_fname_base( const string& fname_, const string& suffices, const TMakeFnameOption option)
+{
+ string fname (fname_);
+ for ( const auto& X : agh::str::tokens( suffices, ",; ") )
+ if ( fname.size() > X.size() &&
+ strcasecmp( &fname[fname.size()-X.size()], X.c_str()) == 0 ) {
+ fname.erase( fname.size()-X.size(), X.size());
+ break;
+ }
+
+ if ( option == TMakeFnameOption::hidden ) {
+ size_t slash_at = fname.rfind('/');
+ if ( slash_at < fname.size() )
+ fname.insert( slash_at+1, ".");
+ }
+ return move(fname);
+}
+
+
+
// found to be of use elsewhere
-size_t agh::fs::__n_edf_files;
+size_t agh::fs::total_supported_sigfiles;
+
int
agh::fs::
-edf_file_counter( const char *fname, const struct stat*, int flag, struct FTW *ftw)
+supported_sigfile_counter( const char *fname, const struct stat*, int flag, struct FTW *ftw)
{
if ( flag == FTW_F && ftw->level == 4 ) {
int fnlen = strlen(fname); // - ftw->base;
if ( fnlen < 5 )
return 0;
- if ( strcasecmp( &fname[fnlen-4], ".edf") == 0 ) {
- ++__n_edf_files;
- }
+ if ( strcasecmp( &fname[fnlen-4], ".edf") == 0 ||
+ strcasecmp( &fname[fnlen-4], ".tsv") == 0 )
+ ++total_supported_sigfiles;
}
return 0;
}
diff --git a/src/libmetrics/mc.cc b/src/libmetrics/mc.cc
index 70fa09d..e4ea16e 100644
--- a/src/libmetrics/mc.cc
+++ b/src/libmetrics/mc.cc
@@ -60,7 +60,7 @@ mirror_fname() const
"%s-%s-%lu"
":%g+%g-%g_%g" "_%g" "_%g_%g" "_%g_%g@%zu"
".mc",
- agh::fs::make_fname_base (_using_F().filename(), "", true).c_str(),
+ agh::fs::make_fname_base (_using_F().filename(), "", agh::fs::TMakeFnameOption::hidden).c_str(),
_using_F().channel_by_id(_using_sig_no).name(),
_using_F().dirty_signature( _using_sig_no),
Pp.pagesize, Pp.step,
diff --git a/src/libmetrics/psd.cc b/src/libmetrics/psd.cc
index 7eddf6c..21d0531 100644
--- a/src/libmetrics/psd.cc
+++ b/src/libmetrics/psd.cc
@@ -78,7 +78,7 @@ mirror_fname() const
"%s.%s-%lu"
":%g+%g-%g-%c%c@%zu"
".psd",
- agh::fs::make_fname_base (_using_F().filename(), "", true).c_str(),
+ agh::fs::make_fname_base (_using_F().filename(), "", agh::fs::TMakeFnameOption::hidden).c_str(),
_using_F().channel_by_id(_using_sig_no).name(),
_using_F().dirty_signature( _using_sig_no),
Pp.pagesize, Pp.step, Pp.binsize,
diff --git a/src/libmetrics/swu.cc b/src/libmetrics/swu.cc
index e1c123c..7be5570 100644
--- a/src/libmetrics/swu.cc
+++ b/src/libmetrics/swu.cc
@@ -57,7 +57,7 @@ mirror_fname() const
"%s.%s-%lu"
":%g+%g-%g@%zu"
".swu",
- agh::fs::make_fname_base (_using_F().filename(), "", true).c_str(),
+ agh::fs::make_fname_base (_using_F().filename(), "", agh::fs::TMakeFnameOption::hidden).c_str(),
_using_F().channel_by_id(_using_sig_no).name(),
_using_F().dirty_signature( _using_sig_no),
Pp.pagesize, Pp.step, Pp.min_upswing_duration,
diff --git a/src/libsigfile/edf.cc b/src/libsigfile/edf.cc
index 579b1c3..c966667 100644
--- a/src/libsigfile/edf.cc
+++ b/src/libsigfile/edf.cc
@@ -466,10 +466,10 @@ _parse_header()
_subtype =
(strncasecmp( header.reserved, "edf+c", 5) == 0)
- ? edfplus_c
+ ? TSubtype::edfplus_c
: (strncasecmp( header.reserved, "edf+d", 5) == 0)
- ? edfplus_d
- : edf;
+ ? TSubtype::edfplus_d
+ : TSubtype::edf;
size_t header_length;
@@ -771,7 +771,7 @@ details( const int which) const
" Record size\t: %g sec\n"
" # of discontinuities\t: %zu\n"
" # of embedded annotations\t: %zu\n",
- filename(),
+ agh::str::homedir2tilda( filename()).c_str(),
subtype_s(),
patient_id(),
trim( string (header.recording_id, 80)).c_str(),
diff --git a/src/libsigfile/edf.hh b/src/libsigfile/edf.hh
index 8d661ba..33861b1 100644
--- a/src/libsigfile/edf.hh
+++ b/src/libsigfile/edf.hh
@@ -45,7 +45,8 @@ class CEDFFile
public:
// subtype
- enum TSubtype {
+ enum class TSubtype {
+ invalid,
edf,
edfplus_c, // continuous
edfplus_d // discontinuous
@@ -56,9 +57,9 @@ class CEDFFile
subtype_s( TSubtype t)
{
switch (t) {
- case edf: return "edf";
- case edfplus_c: return "edf+c";
- case edfplus_d: return "edf+d";
+ case TSubtype::edf: return "edf";
+ case TSubtype::edfplus_c: return "edf+c";
+ case TSubtype::edfplus_d: return "edf+d";
default: return "(invalid)";
}
}
diff --git a/src/libsigfile/source-base.cc b/src/libsigfile/source-base.cc
index e9a7340..baa01c6 100644
--- a/src/libsigfile/source-base.cc
+++ b/src/libsigfile/source-base.cc
@@ -18,6 +18,25 @@
using namespace std;
using namespace sigfile;
+const char*
+ sigfile::supported_sigfile_extensions = ".edf .tsv .csv";
+
+bool
+sigfile::
+is_fname_ext_supported( const string& fname)
+{
+ for ( const auto& X : agh::str::tokens( supported_sigfile_extensions, " ") )
+ if ( fname.size() < X.size() )
+ continue;
+ else
+ if ( strcasecmp( &fname[fname.size()-4], X.c_str()) == 0 )
+ return true;
+ return false;
+}
+
+
+
+
void
SArtifacts::
mark_artifact( const double aa, const double az)
diff --git a/src/libsigfile/source-base.hh b/src/libsigfile/source-base.hh
index a96dd32..004b840 100644
--- a/src/libsigfile/source-base.hh
+++ b/src/libsigfile/source-base.hh
@@ -28,31 +28,46 @@ using namespace std;
namespace sigfile {
+extern const char* supported_sigfile_extensions;
+bool is_fname_ext_supported( const string&);
+
+
inline string
-make_fname_hypnogram( const string& _filename, size_t pagesize)
+make_fname_hypnogram( const string& filename, size_t pagesize)
{
- return agh::fs::make_fname_base( _filename, ".edf", true)
+ return agh::fs::make_fname_base(
+ filename,
+ supported_sigfile_extensions,
+ agh::fs::TMakeFnameOption::hidden)
+ "-" + to_string( (long long unsigned)pagesize) + ".hypnogram";
}
inline string
-make_fname_artifacts( const string& _filename, const SChannel& channel)
+make_fname_artifacts( const string& filename, const SChannel& channel)
{
- return agh::fs::make_fname_base( _filename, ".edf", true)
+ return agh::fs::make_fname_base(
+ filename,
+ supported_sigfile_extensions,
+ agh::fs::TMakeFnameOption::hidden)
+ "-" + channel.name() + ".af";
}
inline string
-make_fname_annotations( const string& _filename, const SChannel& channel)
+make_fname_annotations( const string& filename, const SChannel& channel)
{
- return agh::fs::make_fname_base( _filename, ".edf", true)
+ return agh::fs::make_fname_base(
+ filename,
+ supported_sigfile_extensions,
+ agh::fs::TMakeFnameOption::hidden)
+ "-" + channel.name() + ".annotations";
}
inline string
make_fname_filters( const string& _filename)
{
- return agh::fs::make_fname_base( _filename, ".edf", true)
+ return agh::fs::make_fname_base( _filename,
+ supported_sigfile_extensions,
+ agh::fs::TMakeFnameOption::hidden)
+ ".filters";
}
diff --git a/src/libsigfile/tsv.cc b/src/libsigfile/tsv.cc
index 176cde8..5fe877c 100644
--- a/src/libsigfile/tsv.cc
+++ b/src/libsigfile/tsv.cc
@@ -49,6 +49,11 @@ CTSVFile (const string& fname_, const int flags_)
_f = fopen( fname_.c_str(), "r");
if ( !_f )
throw invalid_argument (explain_status(_status |= sysfail));
+ _subtype =
+ (strcasecmp( &fname_[fname_.size()-4], ".csv") == 0)
+ ? TSubtype::csv
+ : (strcasecmp( &fname_[fname_.size()-4], ".tsv") == 0) ? TSubtype::tsv
+ : TSubtype::invalid;
// parse header
if ( _parse_header() ) { // creates channels list
@@ -189,6 +194,8 @@ _parse_header()
_status |= CSource::missing_patient_id;;
return -1;
}
+ _status |=
+ _subject.parse_recording_id_edf_style( metadata["patient_id"]);
if ( metadata.find( "recording_date") == metadata.end() ||
metadata.find( "recording_time") == metadata.end() ) {
@@ -259,7 +266,7 @@ _read_data()
do {
for ( r = 0; r < channels.size(); ++r ) {
double x;
- if ( 1 != fscanf( _f, "%lg", &x) )
+ if ( 1 != sscanf( _line0, "%lg%*[,\t]", &x) )
goto outer_break;
c2[r].push_back( x);
}
@@ -335,7 +342,7 @@ details( const int which) const
" Duration\t: %s\n"
" # of channels\t: %zu\n"
" Sample rate\t: %zu\n",
- filename(),
+ agh::str::homedir2tilda( filename()).c_str(),
subtype_s(),
patient_id(),
recording_id(),
diff --git a/src/libsigfile/tsv.hh b/src/libsigfile/tsv.hh
index 2a8b061..c3fea05 100644
--- a/src/libsigfile/tsv.hh
+++ b/src/libsigfile/tsv.hh
@@ -48,7 +48,8 @@ class CTSVFile
public:
// subtype
- enum TSubtype {
+ enum class TSubtype {
+ invalid,
csv,
tsv,
};
@@ -58,8 +59,8 @@ class CTSVFile
subtype_s( TSubtype t)
{
switch (t) {
- case csv: return "csv";
- case tsv: return "tsv";
+ case TSubtype::csv: return "csv";
+ case TSubtype::tsv: return "tsv";
default: return "(invalid)";
}
}
@@ -331,7 +332,7 @@ class CTSVFile
enum TStatus : int_least32_t {
- bad_channel_count = (1 << (COMMON_STATUS_BITS + 1)),
+ bad_channel_count = (1 << (COMMON_STATUS_BITS + 1)),
inoperable = (bad_header
| bad_numfld
| bad_datetime
diff --git a/src/libsigfile/typed-source.cc b/src/libsigfile/typed-source.cc
index 26049a2..6600df9 100644
--- a/src/libsigfile/typed-source.cc
+++ b/src/libsigfile/typed-source.cc
@@ -22,6 +22,7 @@ using sigfile::CTSVFile;
using sigfile::CEDFFile;
+
CTypedSource::
CTypedSource (const string& fname,
const size_t pagesize,
diff --git a/src/libsigfile/typed-source.hh b/src/libsigfile/typed-source.hh
index f372b92..88ca515 100644
--- a/src/libsigfile/typed-source.hh
+++ b/src/libsigfile/typed-source.hh
@@ -13,6 +13,7 @@
#define AGH_SIGFILE_SOURCE_H_
#include "source-base.hh"
+#include "forward-decls.hh"
#include "page.hh"
#if HAVE_CONFIG_H && !defined(VERSION)
@@ -61,6 +62,10 @@ class CTypedSource
const CSource& operator()() const
{ return *_obj; }
+ // specialisations for the two known sigfile types
+ template <class T> T& obj();
+ template <class T> const T& obj() const;
+
// filenames
string make_fname_hypnogram() const
{
@@ -71,6 +76,13 @@ class CTypedSource
};
+template <> inline CTSVFile& CTypedSource::obj() { return *(CTSVFile*)_obj; }
+template <> inline CEDFFile& CTypedSource::obj() { return *(CEDFFile*)_obj; }
+template <> inline const CTSVFile& CTypedSource::obj() const { return *(CTSVFile*)_obj; }
+template <> inline const CEDFFile& CTypedSource::obj() const { return *(CEDFFile*)_obj; }
+
+
+
template <typename T = int>
struct SNamedChannel {
CSource& source;
diff --git a/src/tools/edfcat.cc b/src/tools/edfcat.cc
index ad72592..3182f10 100644
--- a/src/tools/edfcat.cc
+++ b/src/tools/edfcat.cc
@@ -377,7 +377,7 @@ exec_prune( const SOperation::SObject& obj)
}
printf( "Keeping %zu channel(s)\n", selected_channels.size());
- sigfile::CEDFFile G ((agh::fs::make_fname_base( obj, ".edf", false) + "-mod.edf").c_str(),
+ sigfile::CEDFFile G ((agh::fs::make_fname_base( obj, ".edf", agh::fs::TMakeFnameOption::normal) + "-mod.edf").c_str(),
sigfile::CEDFFile::TSubtype::edf,
sigfile::CSource::no_ancillary_files,
selected_channels,
diff --git a/src/tools/edfhed.cc b/src/tools/edfhed.cc
index 1c96000..3c89d12 100644
--- a/src/tools/edfhed.cc
+++ b/src/tools/edfhed.cc
@@ -282,7 +282,7 @@ set_session_and_episode_from_tree( sigfile::CEDFFile& F)
// filename can be anything, including a symlink
bool is_path_absolute = (F.filename()[0] == '/');
list<string> pe = agh::fs::path_elements( string (is_path_absolute ? "" : "./") + F.filename());
- string episode = agh::fs::make_fname_base( pe.back(), ".edf", false);
+ string episode = agh::fs::make_fname_base( pe.back(), ".edf", agh::fs::TMakeFnameOption::normal);
string in_dir = string (is_path_absolute ? "/" : "") + agh::str::join( list<string> (pe.begin(), prev(pe.end())), "/") + "/.";
// a symlink from ./filename.edf would resolve somewhere else,
--
Sleep experiment manager
More information about the debian-med-commit
mailing list