lib_file/lib.rs
1
2//! # Functions for use in Managing File IO
3//! The functions in the modules below were written to help
4//! manage file paths, file names, and other file-based
5//! operations. I've used them in several different projects
6//! which is why I've kept them together in a separate crate.
7//! Their greatest weakness is poor error handling, so keep that
8//! in mind if you choose to use them. By the way, I need help getting
9//! those weaknesses corrected, so if you feel like taking that on,
10//! please check
11//! out the issues tab in this crate's repository.
12//!
13//!
14//! * VERSION = "0.0.5";
15//! * AUTHOR = "John T. Reagan";
16//! * LICENSE = "MIT";
17//! * LICENSE_URL = "<https://opensource.org/licenses/MIT>";
18//! * COPYRIGHT = "Copyright (c) 2025, John T. Reagan";
19//! * REPOSITORY = "<https://github.com/jtreagan/lib_file>";
20
21/// # Functions based on the fltk::dialog module.
22pub mod file_fltk {
23
24 use fltk::dialog;
25 use std::path::Path;
26
27 /// Browse to a desired directory, return a string to use as a path for saving.
28 pub fn file_browse_save(usedir: &String) -> String {
29
30 // region Convert the text of the starting directory into a PATH & check exists.
31 let strtpath = Path::new(usedir.as_str());
32 if !strtpath.exists() {
33 eprintln!("The path {} does not exist!", strtpath.display());
34 }
35 // endregion
36
37 // Set the dialog browser to the default directory.
38 let mut dialog = dialog::NativeFileChooser
39 ::new(dialog::NativeFileChooserType
40 ::BrowseSaveFile);
41
42 dialog.set_preset_file(usedir); // Set the suggested file name
43
44 let setrslt = dialog.set_directory(&strtpath);
45 if let Err(e) = setrslt {
46 eprintln!("Failed to set starting directory to: {}", e);
47 }
48
49 dialog.show();
50
51 let path = dialog.filename().to_str().unwrap().to_string();
52 path
53 }
54
55 /// Browse to a desired directory, filter the directory by the passed extension,
56 /// return a string to use as a path for saving.
57 ///
58 /// Examples:
59 ///
60 /// let path = file_browse_save_fltr("Text Files \t*.txt\nVariable Files \t*.vrbl\nAll Files");
61 ///
62 /// or use something like this:
63 ///
64 /// let path = file_browse_save_fltr("*.*");
65 ///
66 /// To show all files.
67 ///
68 pub fn file_browse_save_fltr(usedir: &String, extension: &str) -> String{
69 // Note that the `extension` value must have format "*.xxxxx"
70
71 // region Convert the text of the starting directory into a PATH.
72 let strtpath = Path::new(usedir.as_str());
73 if !strtpath.exists() {
74 eprintln!("The path {} does not exist!", strtpath.display());
75 }
76 // endregion
77
78 // Set the dialog browser to the default directory.
79 let mut dialog = dialog::NativeFileChooser
80 ::new(dialog::NativeFileChooserType
81 ::BrowseSaveFile);
82
83 dialog.set_preset_file(usedir); // Set the suggested file name
84
85 dialog.set_filter(extension);
86 let setrslt = dialog.set_directory(&strtpath);
87 if let Err(e) = setrslt {
88 eprintln!("Failed to set starting directory to: {}", e);
89 }
90
91 dialog.show();
92
93 let path = dialog.filename().to_str().unwrap().to_string();
94 path
95 }
96
97 /// Browse to a desired directory, return a string to use as a path.
98 /// Returned string includes both the path and the file name.
99 pub fn file_fullpath(usedir: &String) -> String {
100
101 // Convert the text of the starting directory into a PATH.
102 let strtpath = Path::new(usedir.as_str());
103 if !strtpath.exists() {
104 eprintln!("The path {} does not exist!", strtpath.display());
105 }
106
107 // Set the dialog browser to the default directory.
108 let mut dialog = dialog::NativeFileChooser::new(dialog
109 ::NativeFileChooserType::BrowseFile);
110 let setrslt = dialog.set_directory(&strtpath);
111 if let Err(e) = setrslt {
112 eprintln!("Failed to set starting directory to: {}", e);
113 }
114
115 dialog.show();
116
117 let path = dialog.filename().to_str().unwrap().to_string();
118
119 path
120 }
121
122 /// Browse to a desired directory, return a string to use as a path for saving.
123 /// Returned string includes both the path only, without the file name.
124 pub fn file_pathonly(usedir: &String) -> String {
125 // Convert the RefCell contents to a String.
126 //let rc_contents: String = usedir.borrow().clone();
127
128 // Convert the text of the starting directory into a PATH.
129 let strtpath = Path::new(usedir.as_str());
130 if !strtpath.exists() {
131 eprintln!("The path {} does not exist!", strtpath.display());
132 }
133
134 // Set the dialog browser to the default directory.
135 let mut dialog = dialog::NativeFileChooser::new(dialog
136 ::NativeFileChooserType::BrowseFile);
137 let setrslt = dialog.set_directory(&strtpath);
138 if let Err(e) = setrslt {
139 eprintln!("Failed to set starting directory to: {}", e);
140 }
141
142 dialog.show();
143
144 let path = dialog.filename();
145 let pathonly = path.parent().unwrap().to_str().unwrap().to_string();
146 pathonly
147 }
148
149 /// Browse to a desired directory, return the chosen file name only.
150 pub fn file_nameonly(usedir: &String) -> String {
151 // Convert the RefCell contents to a String.
152 //let rc_contents: String = usedir.borrow().clone();
153
154 // Convert the text of the starting directory into a PATH.
155 let strtpath = Path::new(usedir.as_str());
156 if !strtpath.exists() {
157 eprintln!("The path {} does not exist!", strtpath.display());
158 }
159
160 // Set the dialog browser to the default directory.
161 let mut dialog = dialog::NativeFileChooser::new(dialog
162 ::NativeFileChooserType::BrowseFile);
163 let setrslt = dialog.set_directory(&strtpath);
164 if let Err(e) = setrslt {
165 eprintln!("Failed to set starting directory to: {}", e);
166 }
167
168 dialog.show();
169
170 let path = dialog.filename();
171
172 let filename = path.file_name().expect("The path has no file available.");
173 let filename_str = filename.to_str().expect("The path is not valid UTF-8");
174 let filename_string: String = filename_str.to_string();
175
176 filename_string
177 }
178
179 /// Browse to a desired directory, filter the files by the passed extension.
180 /// The returned string includes both the path and the file name.
181 pub fn file_fullpath_fltr(usedir: &String, extension: &str) -> String {
182 // Note that the `extension` value must have format `*.xxxxx`.
183
184 // Convert the RefCell contents to a String.
185 //let rc_contents: String = usedir.borrow().clone();
186
187 // Convert the text of the starting directory into a PATH.
188 let strtpath = Path::new(usedir.as_str());
189 if !strtpath.exists() {
190 eprintln!("The path {} does not exist!", strtpath.display());
191 }
192
193 // Set the dialog browser to the default directory.
194 let mut dialog = dialog::NativeFileChooser::new(dialog
195 ::NativeFileChooserType::BrowseFile);
196 let setrslt = dialog.set_directory(&strtpath);
197 if let Err(e) = setrslt {
198 eprintln!("Failed to set starting directory to: {}", e);
199 }
200 dialog.set_filter(extension);
201
202 dialog.show();
203
204 let path = dialog.filename().to_str().unwrap().to_string();
205 path
206 }
207
208 /// Browse to a desired directory, filter the files by the passed extension.
209 /// The returned string includes both the path only.
210 pub fn file_pathonly_fltr(usedir: &String, extension: &str) -> String {
211 // Note that the `extension` value must have format `*.xxxxx`.
212
213 // Convert the RefCell contents to a String.
214 //let rc_contents: String = usedir.borrow().clone();
215
216 // Convert the text of the starting directory into a PATH.
217 let strtpath = Path::new(usedir.as_str());
218 if !strtpath.exists() {
219 eprintln!("The path {} does not exist!", strtpath.display());
220 }
221
222 // Set the dialog browser to the default directory.
223 let mut dialog = dialog::NativeFileChooser::new(dialog::NativeFileChooserType::BrowseFile);
224 dialog.set_filter(extension);
225 let setrslt = dialog.set_directory(&strtpath);
226 if let Err(e) = setrslt {
227 eprintln!("Failed to set starting directory to: {}", e);
228 }
229
230 dialog.show();
231
232 let path = dialog.filename();
233 let pathonly = path.parent().unwrap().to_str().unwrap().to_string();
234 pathonly
235 }
236
237 /// Browse to a desired directory, filter the files by the passed extension.
238 /// The returned string includes only the file name.
239 pub fn file_nameonly_fltr(usedir: &String, extension: &str) -> String {
240 // Note that the `extension` value must have format `*.xxxxx`.
241
242 // Convert the RefCell contents to a String.
243 //let rc_contents: String = usedir.borrow().clone();
244
245 // Convert the text of the starting directory into a PATH.
246 let strtpath = Path::new(usedir.as_str());
247 if !strtpath.exists() {
248 eprintln!("The path {} does not exist!", strtpath.display());
249 }
250
251 // Set the dialog browser to the default directory.
252 let mut dialog = dialog::NativeFileChooser::new(dialog::NativeFileChooserType::BrowseFile);
253 dialog.set_filter(extension);
254 let setrslt = dialog.set_directory(&strtpath);
255 if let Err(e) = setrslt {
256 eprintln!("Failed to set starting directory to: {}", e);
257 }
258
259 dialog.show();
260
261 let path = dialog.filename();
262
263 let filename = path.file_name().expect("The path has no file available.");
264 let filename_str = filename.to_str().expect("The path is not valid UTF-8");
265 let filename_string: String = filename_str.to_string();
266
267 filename_string
268 }
269
270
271}
272
273/// # Terminal-based file i/o functions.
274pub mod file_mngmnt {
275
276//! ### Note the following:
277//! 1) I wrote these functions early-on while I was still
278//! learning Rust and the code quality reflects that.
279//! 2) While the previous module -- file_fltk -- is
280//! dependent on the FLTK-RS crate, the functions in
281//! this module rely on the Rust standard crates along with
282//! some functions from `lib_utils`, another of my personal
283//! crates. These functions are all terminal-based.
284
285 use lib_utils::{input_utilities::*, misc::*};
286 use std::io::{BufRead, BufReader, Read, Write};
287 use std::{fmt::Debug, fs, fs::File, io, path::Path, str::FromStr};
288 use std::cell::RefCell;
289 use std::rc::Rc;
290
291 /// Read a file to a String and print that String to the terminal.
292 ///
293 pub fn file_read_print_to_term(fname: String) {
294 let mut file = File::open(fname.as_str()).expect("Can't open file!");
295 let mut contents = String::new();
296 file.read_to_string(&mut contents).expect("Oops! Cant read file...");
297
298 println!("{}", contents);
299 }
300
301 /// Read a file to a String with the file name passed
302 /// to the function as a RefCell.
303 pub fn file_read_file_to_string_refcell(fname: &Rc<RefCell<String>>) -> String {
304 let usefname = fname.borrow().clone();
305
306 let mut file = File::open(usefname.as_str()).expect("Can't open file!");
307 let mut contents = String::new();
308 file.read_to_string(&mut contents).expect("Oops! Cant read file...");
309 contents
310 }
311
312 /// Read a comma delimited file and collect its contents into a vector.
313 ///
314 /// Example:
315 ///
316 /// fn main() {
317 /// // Replace the path below with your own file path to
318 /// // a *.csv (comma separated values) file.
319 ///
320 /// let file_path = "/home/somebody/somewhere/rusty/nails.csv";
321 /// let vec = file_read_csv_to_vector(file_path);
322 ///
323 /// println!("\n {:?} \n", vec); // Print the resulting vector
324 /// }
325 pub fn file_read_csv_to_vector(file_path: &str) -> Vec<String> { // Comma delimited
326 // Read the file into a string
327 let content = fs::read_to_string(file_path).expect("Failed to read the file");
328
329 // Split the content by commas and collect into a vector
330 content.split(',')
331 .map(|s| s.trim().to_string()) // Trim whitespace off each element
332 .collect()
333 }
334
335 /// Read a file's contents into a String and return
336 /// it as a String.
337 ///
338 /// Example:
339 ///
340 /// fn main() {
341 /// let filename = "/home/jtreagan/programming/rust/mine/tr_rbld1/David_config.yaml";
342 ///
343 /// match file_read_to_string(filename) {
344 /// Ok(contents) => {
345 /// println!("\n The file contents is: \n{} \n", contents);
346 /// }
347 /// Err(err) => {
348 /// eprintln!("\n Error reading the file: {} \n", err);
349 /// }
350 /// }
351 /// }
352 ///
353 pub fn file_read_to_string(fname: &str) -> io::Result<String> {
354 // TODO: This needs better error handling.
355
356 // Attempt to open the file
357 let mut file = File::open(fname)?;
358
359 // Prepare a String to store the file's contents
360 let mut contents = String::new();
361
362 // Read the file's contents into the string
363 file.read_to_string(&mut contents)?;
364
365 // Return the contents
366 Ok(contents)
367 }
368
369 /// Pull the file name off of the end of a path and return it.
370 ///
371 pub fn file_path_to_fname(pathstr: &String) -> String {
372 // todo: This doesn't look right. Check it out.
373 let usepath = Path::new(pathstr);
374
375 match usepath.file_name() {
376 Some(filename_osstr) => {
377 match filename_osstr.to_str() {
378 Some(filename_str) => filename_str.to_string(),
379 None => "Error: Could not convert filename to UTF-8 string.".to_string(),
380 }
381 }
382 None => "Error: could not get filename".to_string()
383 }
384 }
385
386 /// Read a folder directory and collect the filenames into a vector.
387 /// Then return the vector.
388 ///
389 /// ******* Example for file_get_dir_list() ******
390 ///
391 /// fn main() {
392 /// let dirpath = "../qbnk_list";
393 /// let file_names = file_get_dir_list(dirpath);
394 ///
395 /// println!("\n In main() the list of files is \n {:?}", file_names);
396 /// }
397 pub fn file_get_dir_list(path: &str) -> Vec<String> {
398 let dir_entries = fs::read_dir(path).unwrap();
399
400 let file_names: Vec<String> = dir_entries
401 .filter_map(Result::ok)
402 .filter(|entry| entry.file_type().unwrap().is_file())
403 .map(|entry| entry.file_name().into_string().unwrap())
404 .collect();
405
406 file_names
407 }
408
409 /// Create a menu from a vector of file names. Returns the item chosen
410 /// by the user as a String.
411 ///
412 /// Example:
413 ///
414 /// fn main() {
415 /// let dirpath = "../qbnk_list";
416 /// let file_names = file_get_list(dirpath);
417 /// let chosen: String;
418 ///
419 /// chosen = file_namemenu(&file_names);
420 ///
421 /// println!("\n The chosen menu item is: {}", chosen);
422 /// }
423 ///
424 pub fn file_namemenu(fnames: &Vec<String>) -> String {
425 let choice = activity_menu(&fnames, "\n Please choose which file you want to use \n");
426 let chosen = &fnames[choice - 1];
427 chosen.to_string()
428 }
429
430 /// Given a list of file names, this functioncollects all extensions
431 /// into a vector
432 /// and returns the vector.
433 ///
434 /// Example:
435 ///
436 /// fn main() {
437 /// let mountains = vec!["Soldier.mtn".to_string(),
438 /// "Deer.low".to_string(),
439 /// "Buttercup.mtn".to_string(),
440 /// "Borah.hgher".to_string(),
441 /// "Newman.low".to_string(),
442 /// "Dollarhide.mtn".to_string()];
443 ///
444 /// let extns = file_extract_extensions(&mountains);
445 ///
446 /// println!("\n In main() the list of extensions is \n {:?}", extns);
447 /// }
448 ///
449 pub fn file_extract_extensions(filelist: &Vec<String>) -> Vec<String> {
450 let mut extensions: Vec<String> = Vec::new();
451
452 for item in filelist {
453 extensions.push(item.split('.').last().unwrap().to_string());
454 }
455 extensions
456 }
457
458 /// Removes the extension from a file name. Returns the modified file name.
459 ///
460 pub fn file_remove_extension(filename: &str) -> String {
461 let path = Path::new(filename);
462 match path.file_stem() {
463 Some(stem) => stem.to_string_lossy().into_owned(),
464 None => String::from(filename),
465 }
466 }
467
468 /// Sorts a vector of file names by their extensions.
469 ///
470 /// fn main() {
471 /// let dirpath = "../qbnk_list";
472 /// let mut file_names = file_get_list(dirpath);
473 ///
474 /// println!("\n Before: {:?}", file_names);
475 ///
476 /// file_sort_by_ext(&mut file_names);
477 ///
478 /// println!("\n After: {:?}", file_names);
479 /// }
480 ///
481 pub fn file_sort_by_ext(vctr: &mut Vec<String>) {
482 vctr.sort_by(|a, b| {
483 let ext_a = a.split('.').last().unwrap();
484 let ext_b = b.split('.').last().unwrap();
485 ext_a.cmp(ext_b)
486 });
487 }
488
489 /// Deletes all elements from the given vector that do not have an
490 /// extension that matches the passed extension.
491 ///
492 ///
493 /// fn main() {
494 /// let dirpath = "../qbnk_list";
495 /// let mut file_names = file_get_list(dirpath);
496 ///
497 /// println!("\n Before: {:?}", file_names);
498 ///
499 /// file_sort_by_ext(&mut file_names);
500 /// file_del_unwanted_names(&mut file_names, "lst");
501 ///
502 /// println!("\n After: {:?}", file_names);
503 /// }
504 ///
505 pub fn file_del_unwanted_names(vctr: &mut Vec<String>, keeper_ext: &str) {
506 vctr.retain(|item| (item.split('.').last().unwrap()) == keeper_ext);
507 }
508
509 /// Read the elements from a given file, storing them in a passed vector.
510 ///
511 pub fn file_read_to_vec<T: FromStr>(fname: &str, vctr: &mut Vec<T>)
512 where <T as FromStr>::Err: Debug {
513 let file = File::open(fname).unwrap();
514 let reader = BufReader::new(file);
515
516 for line in reader.lines() {
517 let line = line.unwrap();
518 let num = line.parse().unwrap();
519 vctr.push(num);
520 }
521 }
522
523 /// Saves a vector to a file.
524 ///
525 pub fn file_save_vec<T: std::fmt::Display>(fname: &str, vector: &[T]) ->
526 std::io::Result<()> {
527 let mut file = File::create(fname)?;
528 for num in vector {
529 let num_str = num.to_string();
530 file.write_all(num_str.as_bytes())?;
531 file.write_all(b"\n")?;
532 }
533 Ok(())
534 }
535
536 /// Lets the user input a path string, checks that path for validity, then
537 /// lets the user choose a file to work with. Returns both
538 /// the path and the chosen file name.
539 /// Example:
540 ///
541 /// fn main() {
542 /// let extension = "lst"; // Be sure to check using a non-existing extension.
543 /// let existing_fname = file_choose_from_existing(&extension);
544 /// if existing_fname == "".to_string() {
545 /// return
546 /// } else {
547 /// println!("\n You chose the name {} \n", existing_fname);
548 /// }
549 /// }
550 pub fn file_choose_from_existing(extsn: &str) -> (String, String) {
551 let dirpath = input_string_prompt("Please enter the path for the directory where this file has been saved: ");
552 let dirok = dir_checkexist_fix(&dirpath);
553 if dirok.0 == false {
554 println!("\n The path \n {} \n was not usable and was not corrected. \n", dirpath);
555 panic!("Invalid and uncorrected path entered.");
556 // Maybe eventually return a result that the main program can use to
557 // redirect user's activity.
558 }
559
560 let is_empty = dir_check_empty(&dirpath).unwrap();
561 if is_empty {
562 println!("\n That directory is empty.");
563 return (dirpath, "".to_string());
564 }
565 let mut file_names = file_get_dir_list(dirpath.as_str());
566
567 file_del_unwanted_names(&mut file_names, extsn);
568 if file_names.len() == 0 {
569 println!("\n There are no *.{} files in this directory.", extsn);
570 return (dirpath, "".to_string());
571 }
572
573 let chosen = file_namemenu(&file_names);
574 (dirpath, chosen)
575 }
576
577 /// Choose a name for your file from existing files in a given directory.
578 ///
579 /// Choose a file name to use for saving.
580 /// The function adds an extension to the file name and then
581 /// appends it to the path.
582 ///
583 /// Example:
584 ///
585 /// fn main() {
586 /// let dirpath = file_choose_new_fname("lst");
587 /// println!("\n In main() the new path & fname is: {}", dirpath);
588 ///
589 /// println!("\n All is okay!! :>) \n");
590 /// }
591 pub fn file_choose_new_fname(extnsn: &str, dirpath: &String) -> String {
592 let mut fname: String;
593 let mut usepath: String;
594 loop {
595 usepath = dirpath.clone();
596 fname = input_string_prompt("\n Please enter a name for your new file: ");
597 if fname.split('.').last().unwrap() != extnsn {
598 fname = fname + "." + extnsn;
599 }
600 usepath = usepath + "/" + fname.as_str(); // Try using format!() here.
601 let fullpath = Path::new(&usepath);
602 let exists = fullpath.try_exists()
603 .expect("Error when checking the existence of the file");
604 if exists {
605 println!("\n That file {} already exists.", &fname);
606 let choice = input_bool_prompt("\n Do you want to overwrite the file? ");
607 if choice { break; }
608 else { continue; }
609 }
610 break;
611 }
612 usepath
613 }
614
615 /// Input a file name and append an extension to it.
616 ///
617 pub fn file_getfname_addextsn(extnsn: &str) -> String {
618 let mut fname = input_string_prompt("\n Please enter a name for your new file: ");
619 if fname.split('.').last().unwrap() != extnsn {
620 fname = fname + "." + extnsn;
621 }
622 fname
623
624 }
625
626 /// Add an extension to a file name.
627 ///
628 pub fn file_addextsn(extnsn: &str, fname: &String) -> String {
629 let mut usename = fname.clone();
630 if usename.split('.').last().unwrap() != extnsn {
631 usename = usename + "." + extnsn;
632 }
633 usename
634 }
635
636 /// This function is not yet finished. Don't use it.
637 ///
638 pub fn file_chkfname( fname: &String, dirpath: &String) -> String {
639// This is not yet ready. What are you returning?
640
641 let mut usepath: String;
642 loop {
643 usepath = dirpath.clone();
644 usepath = usepath + "/" + fname.as_str();
645 let fullpath = Path::new(&usepath);
646 let exists = fullpath.try_exists()
647 .expect("Error when checking the existence of the file");
648 if exists {
649 println!("\n That file {} already exists.", &fname);
650 let choice = input_bool_prompt("\n Do you want to overwrite the file? ");
651 if choice {
652 break;
653 }
654 else { continue; }
655 }
656 break;
657 }
658 usepath
659 }
660
661 /// Check the validity of a directory path and correct it if necessary.
662 ///
663 /// Example:
664 ///
665 /// fn main() {
666 /// let mut dirpath: String = "kjhkjhjkh/home/camascounty/programming/rust/mine/file_lib".to_string();
667 ///
668 /// let dirchecked = dir_checkexist_fix(&dirpath);
669 /// if dirchecked.0 == false {
670 /// println!("\n The path \n {} \n was not usable and was not corrected. \n", dirpath);
671 /// } else {
672 /// println!("\n The correct path is: {}", dirchecked.1);
673 /// println!("\n All is okay!! :>) \n");
674 /// }
675 /// }
676 pub fn dir_checkexist_fix(dirpath: &String) -> (bool, String) {
677 let mut fullpath = Path::new(dirpath.as_str());
678 let mut newpath: String = dirpath.to_string().clone();
679
680 loop {
681 let exists = fullpath.try_exists()
682 .expect("Error when checking the existence of the directory");
683
684 if exists {
685 return (true, newpath);
686 } else {
687 println!("\n The directory \n {} \n does not exist and may not be used.", newpath);
688 newpath = input_string_prompt(
689 "\n Please enter a corrected path for the directory in which you wish to save this file. \n\
690 (Do not include the file name): "); // Eventually add ability to edit the existing string.
691 if newpath == "" {
692 return (false, "".to_string());
693 } else {
694 fullpath = Path::new(newpath.as_str());
695 }
696 }
697 }
698 }
699
700 /// Check to see if a directory is empty.
701 ///
702 /// Example:
703 ///
704 /// fn main() {
705 /// let directory = "/home/camascounty/programming/rust/mine/empty";
706 /// match dir_check_empty(directory) {
707 /// Ok(is_empty) => {
708 /// if is_empty {
709 /// println!("\n The path {} is empty.", directory);
710 /// } else {
711 /// println!("\n The path {} is not empty.", directory);
712 /// }
713 /// }
714 /// Err(err) => {
715 /// println!("Error when checking if directory is empty: {}", err);
716 /// }
717 /// }
718 /// }
719 ///
720 pub fn dir_check_empty(dirpath: &str) -> io::Result<bool> {
721 let mut entries = fs::read_dir(dirpath)?;
722 let first_entry = entries.next();
723 Ok(first_entry.is_none())
724 }
725
726 /// Check a user-entered path for validity.
727 ///
728 pub fn dir_get_path() -> (bool, String) {
729 let dirpath = input_string_prompt(
730 "\n Please enter a path for the directory in which you wish to save this file. \n\
731 (Do not include the file name): ");
732
733 let dirok = dir_checkexist_fix(&dirpath);
734 if dirok.0 == false {
735 println!("\n The path \n {} \n was not usable and was not corrected. \n", dirpath);
736 panic!("Invalid and uncorrected path entered.");
737 // todo: Maybe eventually return an error that the main program can use to
738 // redirect the user's activity.
739 }
740 (true, dirpath)
741 }
742
743 /// Same as `dir_get_path` except that one can pass whatever prompt
744 /// you like to the function.
745 pub fn dir_get_path_prompt(prompt: &str) -> (bool, String) {
746 let dirpath = input_string_prompt( prompt);
747 let dirok = dir_checkexist_fix(&dirpath);
748 if dirok.0 == false {
749 println!("\n The path \n {} \n was not usable and was not corrected. \n", dirpath);
750 panic!("Invalid and uncorrected path entered.");
751 // todo: Maybe eventually return an error that the main program can use to
752 // redirect user's activity.
753 }
754 (true, dirpath)
755 }
756
757
758
759}
760