3434#define KSEQ_INIT_READY
3535KSEQ_INIT (gzFile, gzread)
3636#endif
37+
38+ // Create directories recursively if they don't exist (exiting if not possible)
39+ // C++17 and above only
40+ #if SPLITCODE_CPP_VERSION < 201703L
41+ void ensure_parent_directories (const std::string& filepath) { } // Empty
42+ #else
43+ #include < filesystem>
44+ #include < system_error>
45+ inline void ensure_parent_directories (const std::string& filepath) {
46+ if (filepath.length () == 0 ) return ;
47+ namespace fs = std::filesystem;
48+ fs::path p (filepath);
49+ fs::path parent = p.parent_path ();
50+ // No parent (e.g. "out.txt") → nothing to do
51+ if (parent.empty ()) {
52+ return ;
53+ }
54+ std::error_code ec;
55+ fs::create_directories (parent, ec); // creates all missing parents; no-op if they exist
56+ if (ec) {
57+ std::fprintf (stderr,
58+ " Error: Failed to create directory '%s': %s\n " ,
59+ parent.string ().c_str (),
60+ ec.message ().c_str ());
61+ std::exit (1 );
62+ }
63+ }
64+ #endif
65+
3766
3867class MasterProcessor ;
3968
@@ -130,13 +159,15 @@ class MasterProcessor {
130159 std::string compress_level_str = " wb" + std::to_string (opt.compress_level );
131160 const char * gz_out_str = compress_level_str.c_str ();
132161 for (auto f : opt.output_files ) {
162+ ensure_parent_directories (f);
133163 if (opt.gzip ) {
134164 out_gz.push_back (gzopen (f.c_str (), gz_out_str));
135165 } else {
136166 out.push_back (fopen (f.c_str (), " wb" ));
137167 }
138168 }
139169 for (auto f : opt.unassigned_files ) {
170+ ensure_parent_directories (f);
140171 if (opt.gzip ) {
141172 if (f.length () == 0 ) outu_gz.push_back (nullptr );
142173 else outu_gz.push_back (gzopen (f.c_str (), gz_out_str));
@@ -147,6 +178,7 @@ class MasterProcessor {
147178 }
148179 if (!opt.pipe && !opt.no_x_out && !opt.no_output ) {
149180 for (auto f : sc.get_umi_names ()) {
181+ ensure_parent_directories (f+suffix);
150182 if (opt.gzip ) {
151183 outumi_gz.push_back (gzopen ((f+suffix_gz).c_str (), gz_out_str));
152184 } else {
@@ -182,6 +214,7 @@ class MasterProcessor {
182214 out_keep_name = v[i-1 ];
183215 }
184216 }
217+ ensure_parent_directories (out_keep_name+suffix_gz);
185218 out_keep_gz[f.second ].push_back (gzopen ((out_keep_name + suffix_gz).c_str (), gz_out_str));
186219 }
187220 }
@@ -207,6 +240,7 @@ class MasterProcessor {
207240 out_keep_name = v[i-1 ];
208241 }
209242 }
243+ ensure_parent_directories (out_keep_name+suffix);
210244 out_keep[f.second ].push_back (fopen ((out_keep_name + suffix).c_str (), " wb" ));
211245 }
212246 }
@@ -238,6 +272,7 @@ class MasterProcessor {
238272 out_keep_name = v[i-1 ];
239273 }
240274 }
275+ ensure_parent_directories (out_keep_name+suffix_gz);
241276 out_keep_gz[f.second ].push_back (gzopen ((out_keep_name + suffix_gz).c_str (), gz_out_str));
242277 }
243278 }
@@ -263,14 +298,18 @@ class MasterProcessor {
263298 out_keep_name = v[i-1 ];
264299 }
265300 }
266- else out_keep[f.second ].push_back (fopen ((out_keep_name + suffix).c_str (), " wb" ));
301+ else {
302+ ensure_parent_directories (out_keep_name+suffix);
303+ out_keep[f.second ].push_back (fopen ((out_keep_name + suffix).c_str (), " wb" ));
304+ }
267305 }
268306 }
269307 }
270308 }
271309 write_output_fastq = opt.output_fastq_specified || opt.pipe || opt.x_only ;
272310 write_unassigned_fastq = outu.size () > 0 || outu_gz.size () > 0 ;
273311 if (write_barcode_separate_fastq) {
312+ ensure_parent_directories (opt.outputb_file );
274313 if (opt.gzip ) {
275314 outb_gz = gzopen (opt.outputb_file .c_str (), gz_out_str);
276315 } else {
0 commit comments