trick/trick_source/sim_services/CommandLineArguments/CommandLineArguments.cpp
Hong Chen f666708374
Repurposed -OO for all sim run outputs including S_sie.resource being saved in the specified directory. (#1714)
* Repurposed -OO so all sim run outputs including S_sie.resource are saved to the specified folder. The files are placed in the sub-dir either RUN_xxx or DP_Product of the specified folder.

* Updated for repurposed -OO.

* Added quoting code markdown for such as in order to show <name> as is.

* Added quoting code for missing items.

* Updated to raise an error when the --read-only-sim flag is used without the -O or -OO. Also made updates to the related document accordingly.

* Fixed the error message to be more clear.
2024-07-16 10:31:52 -05:00

349 lines
11 KiB
C++

/*
PURPOSE: ( Handle the simulation command line args )
REFERENCE: ( Trick Simulation Environment )
ASSUMPTIONS AND LIMITATIONS: ( None )
CLASS: ( N/A )
LIBRARY DEPENDENCY: ( None )
PROGRAMMERS: ( Keith Vetter LinCom 6/2003 ) */
#include <iostream>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <cstring>
#include <cerrno>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include "trick/CommandLineArguments.hh"
#include "trick/memorymanager_c_intf.h"
Trick::CommandLineArguments * the_cmd_args ;
Trick::CommandLineArguments::CommandLineArguments() {
the_cmd_args = this ;
output_dir = std::string(".") ;
default_dir = std::string(".") ;
argc = 0;
argv = NULL;
}
int Trick::CommandLineArguments::get_argc() {
return(argc) ;
}
char ** Trick::CommandLineArguments::get_argv() {
return(argv) ;
}
std::string Trick::CommandLineArguments::get_output_dir() {
return(output_dir) ;
}
std::string & Trick::CommandLineArguments::get_output_dir_ref() {
return(output_dir) ;
}
std::string Trick::CommandLineArguments::get_user_output_dir() {
return(user_output_dir) ;
}
std::string & Trick::CommandLineArguments::get_user_output_dir_ref() {
return(user_output_dir) ;
}
std::string Trick::CommandLineArguments::get_input_file() {
return(input_file) ;
}
std::string & Trick::CommandLineArguments::get_input_file_ref() {
return(input_file) ;
}
std::string Trick::CommandLineArguments::get_default_dir() {
return(default_dir) ;
}
std::string & Trick::CommandLineArguments::get_default_dir_ref() {
return(default_dir) ;
}
std::string Trick::CommandLineArguments::get_cmdline_name() {
return(cmdline_name) ;
}
std::string & Trick::CommandLineArguments::get_cmdline_name_ref() {
return(cmdline_name) ;
}
// Helper function - create a full path with error checking along the way
int Trick::CommandLineArguments::create_path(const std::string& dirname) {
size_t cur_index = 0;
std::string full_dir (dirname);
// These syscalls don't seem to take care of home special character, so do it manually
// I think the shell should handle it before it gets here, but just in case check for it
if (dirname.at(0) == '~') {
struct passwd *pw = getpwuid(getuid());
full_dir = std::string(pw->pw_dir) + dirname.substr(1, dirname.size());
}
while (cur_index != full_dir.size()) {
cur_index = full_dir.find('/', cur_index+1);
if (cur_index == std::string::npos) {
cur_index = full_dir.size();
}
std::string cur_dir = full_dir.substr(0, cur_index);
struct stat info;
if(stat( cur_dir.c_str(), &info ) != 0) {
// does not exist - make it
if (mkdir(cur_dir.c_str(), 0775) == -1) {
std::cerr << "Error creating directory " << cur_dir << std::endl;
return 1;
}
} else {
// Does exist
if(info.st_mode & S_IFDIR) {
// Is a directory
if (info.st_mode & S_IWUSR) {
// Perfect, nothing to do here
} else {
// Not writeable
std::cerr << "Intermediate directory " << cur_dir << " is not writable, unable to create output directory." << std::endl;
return 1;
}
} else {
// Does exist, but is a file
std::cerr << "Intermediate directory " << cur_dir << " is not a directory, unable to create output directory." << std::endl;
return 1;
}
}
}
return 0;
}
/**
@details
-# Save the number of command line arguments.
-# Save the command line arguments.
-# Determine the directory and simulation executable name from the first
command line argument
-# If no directory is specified
-# Save the simulation executable name as the full first argument
-# Get the current working directory
-# Save the current working directory as the default input directory.
-# If a relative or full directory is present in the command line arguments
-# split the command line argument on the last "/" character
-# Save the back half of the split as the simulation executable name
-# Save the current working directory
-# Change the current working directory to the first half of the split
command line argument.
-# Get the current working directory
-# Save the current working directory as the default input directory.
-# Change the current working directory to the saved working directory
-# If present, the second argument will be the run directory and the input file.
-# Save the run input file name as the full second argument
-# Split the second argument on the last "/" character
-# If no directory is specified set the default output and current output
directories to the current directory
-# Else set the default and the current output directories to the first
half of the split
-# Search the remaining command line arguments for "-O" or "-OO"
-# If found set the output direcory to the following argument
-# Attempt to create the output directory if it does not exist.
-# Exit if the simulation cannot be created.
*/
int Trick::CommandLineArguments::process_sim_args(int nargs , char **args) {
char *buf, *buf2;
size_t found ;
argc = nargs ;
argv = (char **)TMM_declare_var_1d("char *", argc) ;
for (int ii = 0 ; ii < argc ; ii++ ) {
argv[ii] = TMM_strdup(args[ii]) ;
}
buf = (char *)malloc(4096) ;
buf2 = (char *)malloc(4096) ;
default_dir = argv[0] ;
found = default_dir.find_last_of("/") ;
if ( found == std::string::npos ) {
cmdline_name = default_dir ;
getcwd(buf, (size_t) 256);
default_dir = buf ;
} else {
cmdline_name = default_dir.substr(found + 1) ;
// save the current directory
getcwd(buf, (size_t) 256);
// change to the default directory
chdir(default_dir.substr(0,found).c_str());
// get the full path default directory
getcwd(buf2, (size_t) 256);
default_dir = buf2 ;
// change back to the current directory
chdir(buf);
}
free(buf) ;
free(buf2) ;
if ( argc > 1 ) {
/* First occurnance of "RUN_*" is the input file name: '<Run_dir>/<file_name>'.
If not found, defaults to first argument */
input_file = argv[1];
run_dir = argv[1];
for(int ii = 1; ii < argc; ii++) {
if(std::string(argv[ii]).find("RUN_") != std::string::npos) {
input_file = argv[ii];
run_dir = argv[ii];
break;
}
}
if (access(input_file.c_str(), F_OK) != 0) {
input_file = "";
if(strcmp(argv[1], "trick_version") && strcmp(argv[1], "sie") && strcmp(argv[1], "-help") && strcmp(argv[1], "--help") &&
strcmp(argv[1], "-h") && strcmp(argv[1], "help")) {
std::cerr << "\nERROR: Invalid input file or command line argument." << std::endl;
exit(1);
}
}
found = run_dir.find_last_of("/") ;
if ( found != std::string::npos ) {
run_dir.erase(found) ;
} else {
run_dir = "." ;
}
/* check existence of run directory */
if (access(run_dir.c_str(), F_OK) != 0) {
std::cerr << "\nERROR: while accessing input file directory \"" << run_dir << "\" : " << std::strerror(errno) << std::endl ;
exit(1);
}
output_dir = run_dir ;
for (int ii = 1; ii < argc; ii++) {
if (!strncmp("-OO", argv[ii], (size_t) 3) || !strncmp("-O", argv[ii], (size_t) 2)) {
if (ii == ( argc - 1 )) {
std::cerr << "\nERROR: No directory specified after -O or -OO argument" << std::endl ;
exit(1) ;
}
/* Output data directory */
output_dir = user_output_dir = argv[++ii];
if (!strncmp("-OO", argv[ii-1], (size_t) 3)) {
output_dir = output_dir + "/" + run_dir;
}
}
}
/* Create output directory if necessary. */
if (access(output_dir.c_str(), F_OK) != 0) {
if (create_path(output_dir) != 0) {
std::cerr << "\nERROR: While trying to create output directory \"" << output_dir << "\" : " << std::strerror(errno) << std::endl ;
exit(1) ;
}
} else {
/* check permissions on output directory */
if (access(output_dir.c_str(), (W_OK|X_OK) ) == -1) {
std::cerr << "\nERROR: while writing to output directory \"" << output_dir << "\" : " << std::strerror(errno) << std::endl ;
exit(2) ;
}
}
}
return(0) ;
}
/**
@design
-# Get the current system date and time.
-# Set the subdirectory within the current output directory to
DATA_<year>_<month>_<day>_<hour>_<minute>_<second>
-# Attempt to create the output directory if it does not exist.
-# Exit if the simulation cannot be created.
*/
int Trick::CommandLineArguments::output_dir_timestamped_on() {
time_t date ;
struct tm *curr_time ;
char temp_str[256] ;
date = time(NULL) ;
curr_time = localtime(&date) ;
snprintf(temp_str, sizeof(temp_str), "DATA_%4d_%02d_%02d_%02d_%02d_%02d",
curr_time->tm_year + 1900 , curr_time->tm_mon + 1 , curr_time->tm_mday,
curr_time->tm_hour , curr_time->tm_min , curr_time->tm_sec );
time_stamp_dir = std::string(temp_str) ;
if ( ! user_output_dir.empty() ) {
output_dir = user_output_dir + "/" + time_stamp_dir ;
} else {
output_dir = run_dir + "/" + time_stamp_dir ;
}
/* Create directories if necessary. */
if (access(output_dir.c_str(), F_OK) != 0) {
if (mkdir(output_dir.c_str(), 0775) == -1) {
std::cerr << "\nERROR: While trying to create dir \"" << output_dir << "\" Exiting!" << std::endl ;
exit(1) ;
}
}
output_dir_timestamped = 1 ;
return(0) ;
}
/**
@design
-# If the user had specified an output directory reset
the output directory to the user specified directory
-# Else set the output directory to the run directory.
*/
int Trick::CommandLineArguments::output_dir_timestamped_off() {
if ( ! user_output_dir.empty() ) {
output_dir = user_output_dir ;
} else {
output_dir = run_dir ;
}
output_dir_timestamped = 0 ;
return(0) ;
}
/**
@design
-# Sets the value of output_dir
*/
void Trick::CommandLineArguments::set_output_dir(std::string output_directory) {
output_dir = output_directory;
}