cleanup
This commit is contained in:
26
dsviewer/CMakeLists.backup
Normal file
26
dsviewer/CMakeLists.backup
Normal file
@@ -0,0 +1,26 @@
|
||||
set(TOOL_NAME dsviewer)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
|
||||
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_search_module(EDITLINE REQUIRED libeditline)
|
||||
include_directories(${EDITLINE_INCLUDE_DIRS})
|
||||
link_directories(${EDITLINE_LIBRARY_DIRS})
|
||||
|
||||
aux_source_directory(. TOOL_SRC)
|
||||
add_executable(${TOOL_NAME} ${TOOL_SRC})
|
||||
|
||||
set_target_properties(${TOOL_NAME} PROPERTIES INSTALL_RPATH /usr/local/lib)
|
||||
set_target_properties(${TOOL_NAME} PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
target_link_libraries(${TOOL_NAME} PRIVATE gctl)
|
||||
target_link_libraries(${TOOL_NAME} PRIVATE ${EDITLINE_LIBRARIES})
|
||||
|
||||
install(TARGETS ${TOOL_NAME} RUNTIME DESTINATION sbin)
|
||||
|
||||
file(GLOB HELP_DOC *.md)
|
||||
install(FILES ${HELP_DOC} DESTINATION sbin/share)
|
614
dsviewer/dsviewer.cpp
Normal file
614
dsviewer/dsviewer.cpp
Normal file
@@ -0,0 +1,614 @@
|
||||
/********************************************************
|
||||
* ██████╗ ██████╗████████╗██╗
|
||||
* ██╔════╝ ██╔════╝╚══██╔══╝██║
|
||||
* ██║ ███╗██║ ██║ ██║
|
||||
* ██║ ██║██║ ██║ ██║
|
||||
* ╚██████╔╝╚██████╗ ██║ ███████╗
|
||||
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
|
||||
* Geophysical Computational Tools & Library (GCTL)
|
||||
*
|
||||
* Copyright (c) 2023 Yi Zhang (yizhang-geo@zju.edu.cn)
|
||||
*
|
||||
* GCTL is distributed under a dual licensing scheme. You can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation, either version 2
|
||||
* of the License, or (at your option) any later version. You should have
|
||||
* received a copy of the GNU Lesser General Public License along with this
|
||||
* program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* If the terms and conditions of the LGPL v.2. would prevent you from using
|
||||
* the GCTL, please consider the option to obtain a commercial license for a
|
||||
* fee. These licenses are offered by the GCTL's original author. As a rule,
|
||||
* licenses are provided "as-is", unlimited in time for a one time fee. Please
|
||||
* send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget
|
||||
* to include some description of your company and the realm of its activities.
|
||||
* Also add information on how to contact you by electronic and paper mail.
|
||||
******************************************************/
|
||||
|
||||
#include "dsviewer.h"
|
||||
// We use the editline library to handle all inputs
|
||||
#include "editline.h"
|
||||
// install configuration
|
||||
#include "../gctl_toolkits_config.h"
|
||||
|
||||
cmd_pair curr_cmd; // Executing command
|
||||
gctl::dsv_io tc; // Grid object
|
||||
|
||||
extern "C" {
|
||||
|
||||
/*
|
||||
* Strip whitespace from the start and end of STRING. Return a pointer
|
||||
* into STRING.
|
||||
*/
|
||||
char *stripwhite(char *string)
|
||||
{
|
||||
char *s, *t;
|
||||
|
||||
for (s = string; isspace(*s); s++) ;
|
||||
|
||||
if (*s == 0)
|
||||
return s;
|
||||
|
||||
t = s + strlen(s) - 1;
|
||||
while (t > s && isspace(*t))
|
||||
t--;
|
||||
*++t = '\0';
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Generator function for command completion. STATE lets us
|
||||
know whether to start from scratch; without any state
|
||||
(i.e. STATE == 0), then we start at the top of the list. */
|
||||
char *command_generator(const char *text, int state)
|
||||
{
|
||||
static int list_index, len;
|
||||
|
||||
/* If this is a new word to complete, initialize now. This
|
||||
includes saving the length of TEXT for efficiency, and
|
||||
initializing the index variable to 0. */
|
||||
if (!state)
|
||||
{
|
||||
list_index = 0;
|
||||
len = strlen(text);
|
||||
}
|
||||
|
||||
/* Return the next name which partially matches from the command list. */
|
||||
while (list_index < CMD_NUM)
|
||||
{
|
||||
if (std::string(text) == commands[list_index].name.substr(0, len))
|
||||
{
|
||||
//const char* name = commands[list_index].name.data();
|
||||
return strdup(commands[list_index].name.data());
|
||||
}
|
||||
else list_index++;
|
||||
}
|
||||
|
||||
/* If no names matched, then return NULL. */
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to complete on the contents of TEXT. START and END
|
||||
* bound the region of rl_line_buffer that contains the word to
|
||||
* complete. TEXT is the word to complete. We can use the entire
|
||||
* contents of rl_line_buffer in case we want to do some simple
|
||||
* parsing. Return the array of matches, or NULL if there aren't any.
|
||||
*/
|
||||
char **dsviewer_completion(const char *text, int start, int end)
|
||||
{
|
||||
char **matches = nullptr;
|
||||
|
||||
/* If this word is at the start of the line, then it is a command
|
||||
to complete. Otherwise it is the name of a file in the current
|
||||
directory. */
|
||||
if (start == 0) matches = rl_completion_matches(text, command_generator);
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
void initialize_readline(void)
|
||||
{
|
||||
/* Allow conditional parsing of the ~/.inputrc file. */
|
||||
rl_readline_name = "dsviewer";
|
||||
|
||||
/* Tell the completer that we want a crack first. */
|
||||
rl_attempted_completion_function = dsviewer_completion;
|
||||
}
|
||||
|
||||
} // End C section
|
||||
|
||||
void display_cmds()
|
||||
{
|
||||
std::clog << "Command:\n";
|
||||
for (size_t i = 0; i < CMD_NUM - 1; i++)
|
||||
{
|
||||
std::clog << std::setw(12) << commands[i].name << ":\t" << commands[i].brief << "\n";
|
||||
}
|
||||
|
||||
std::clog << "\nEnter \"<command>?\" to see detailed instructions.\n";
|
||||
|
||||
std::clog << "\nCmdFile:\n";
|
||||
std::clog << "Each line of the input file(s) will be parsed as a command.\nEmpty lines and lines start with '#' will be skipped.\n";
|
||||
|
||||
std::clog << "\nHereDoc:\n";
|
||||
std::clog << "You can use HereDoc to input commands. A simple example is:\n";
|
||||
std::clog << "dsviewer << EOF\n";
|
||||
std::clog << "open file1.csv\n";
|
||||
std::clog << "info\n";
|
||||
std::clog << "EOF\n";
|
||||
return;
|
||||
}
|
||||
|
||||
void display_help(std::string input_cmd)
|
||||
{
|
||||
std::string install_dir = GCTL_TOOLKITS_INSTALL_PREFIX;
|
||||
std::ifstream helpin;
|
||||
open_infile(helpin, install_dir + "/sbin/share/dsviewer", ".md");
|
||||
|
||||
std::string tmp_l, tmp_help;
|
||||
std::vector<std::string> cmds;
|
||||
std::vector<std::string> helps;
|
||||
while (getline(helpin, tmp_l))
|
||||
{
|
||||
if (tmp_l.substr(0, 4) == "####")
|
||||
{
|
||||
cmds.push_back(tmp_l.substr(5));
|
||||
tmp_help = "";
|
||||
while (getline(helpin, tmp_l))
|
||||
{
|
||||
if (tmp_l == "") break;
|
||||
else tmp_help += tmp_l + "\n";
|
||||
}
|
||||
helps.push_back(tmp_help);
|
||||
}
|
||||
}
|
||||
helpin.close();
|
||||
|
||||
std::string cmd_str;
|
||||
for (size_t j = 0; j < cmds.size(); j++)
|
||||
{
|
||||
parse_string_to_value(cmds[j], ' ', true, cmd_str);
|
||||
if (input_cmd == cmd_str)
|
||||
{
|
||||
replace_all(tmp_l, cmds[j], "\\", "");
|
||||
std::cout << GCTL_BOLDGREEN << tmp_l << GCTL_RESET << "\n";
|
||||
std::cout << helps[j] << "\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void exec_cmd(std::string cmd)
|
||||
{
|
||||
std::string cmd_name;
|
||||
parse_string_to_value(cmd, ' ', true, cmd_name);
|
||||
|
||||
// show instruction if there is a question mark at end of the command
|
||||
if (cmd_name.back() == '?')
|
||||
{
|
||||
cmd_name = cmd_name.substr(0, cmd_name.length() - 1);
|
||||
display_help(cmd_name);
|
||||
return;
|
||||
}
|
||||
|
||||
// set default command to null
|
||||
curr_cmd = commands[CMD_NUM - 1];
|
||||
for (size_t i = 0; i < CMD_NUM - 1; i++)
|
||||
{
|
||||
if (cmd_name == commands[i].name)
|
||||
{
|
||||
curr_cmd = commands[i]; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (curr_cmd.func_p == nullptr) throw gctl::runtime_error("Invalid command: " + cmd_name);
|
||||
|
||||
std::vector<std::string> cmd_units;
|
||||
parse_string_with_quotes(cmd, cmd_units);
|
||||
|
||||
return curr_cmd.func_p(cmd_units);
|
||||
}
|
||||
|
||||
// This function is defined to avoid potential breakdown while running in script mode.
|
||||
void quit(const std::vector<std::string> &cmd_units)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void info(const std::vector<std::string> &cmd_units)
|
||||
{
|
||||
std::smatch ret;
|
||||
std::regex pata("att"), patt("tag"), patc("col"), patr("row"), path("hdr");
|
||||
|
||||
// info [att|tag|hdr|col|row]
|
||||
int info_code = 0;
|
||||
if (cmd_units.size() > 1)
|
||||
{
|
||||
if (regex_search(cmd_units[1], ret, pata)) info_code = AttInfo;
|
||||
if (regex_search(cmd_units[1], ret, patt)) info_code = info_code|TagInfo;
|
||||
if (regex_search(cmd_units[1], ret, patc)) info_code = info_code|ColInfo;
|
||||
if (regex_search(cmd_units[1], ret, patr)) info_code = info_code|RowInfo;
|
||||
if (regex_search(cmd_units[1], ret, path)) info_code = info_code|HeadInfo;
|
||||
tc.info(info_code);
|
||||
}
|
||||
else tc.info(ColInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
void head(const std::vector<std::string> &cmd_units)
|
||||
{
|
||||
// head [number]
|
||||
int h = 10;
|
||||
if (cmd_units.size() > 1) h = atoi(cmd_units[1].c_str());
|
||||
if (h <= 0) throw std::runtime_error("head: invalid number.");
|
||||
|
||||
_1s_vector cnames = tc.column_names();
|
||||
display_vector(cnames, std::cout, tc.delimeter());
|
||||
|
||||
_1s_array line;
|
||||
for (size_t i = 1; i <= h; i++)
|
||||
{
|
||||
tc.get_row(line, i);
|
||||
line.show(std::cout, tc.delimeter());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void tail(const std::vector<std::string> &cmd_units)
|
||||
{
|
||||
// tail [number]
|
||||
int h = 10;
|
||||
if (cmd_units.size() > 1) h = atoi(cmd_units[1].c_str());
|
||||
if (h <= 0) throw std::runtime_error("tail: invalid number.");
|
||||
|
||||
_1s_vector cnames = tc.column_names();
|
||||
display_vector(cnames, std::cout, tc.delimeter());
|
||||
|
||||
_1s_array line;
|
||||
for (size_t i = tc.row_number() - h + 1; i <= tc.row_number(); i++)
|
||||
{
|
||||
tc.get_row(line, i);
|
||||
line.show(std::cout, tc.delimeter());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void set_enable(const std::vector<std::string> &cmd_units)
|
||||
{
|
||||
// enable table|column|row [<name1>,<name2>...]
|
||||
if (cmd_units.size() < 2) throw std::runtime_error("enable: insufficient parameters.");
|
||||
|
||||
if (cmd_units[1] == "table") tc.table_output(Enable);
|
||||
else if (cmd_units[1] == "column")
|
||||
{
|
||||
for (size_t i = 2; i < cmd_units.size(); i++)
|
||||
{
|
||||
tc.column_output(cmd_units[i], Enable);
|
||||
}
|
||||
}
|
||||
else if (cmd_units[1] == "row")
|
||||
{
|
||||
for (size_t i = 2; i < cmd_units.size(); i++)
|
||||
{
|
||||
tc.row_output(cmd_units[i], Enable);
|
||||
}
|
||||
}
|
||||
else throw std::runtime_error("enable: invalid parameters.");
|
||||
return;
|
||||
}
|
||||
|
||||
void set_disable(const std::vector<std::string> &cmd_units)
|
||||
{
|
||||
// disable table|column|row [<name1>,<name2>...]
|
||||
if (cmd_units.size() < 2) throw std::runtime_error("disable: insufficient parameters.");
|
||||
|
||||
if (cmd_units[1] == "table") tc.table_output(Disable);
|
||||
else if (cmd_units[1] == "column")
|
||||
{
|
||||
for (size_t i = 2; i < cmd_units.size(); i++)
|
||||
{
|
||||
tc.column_output(cmd_units[i], Disable);
|
||||
}
|
||||
}
|
||||
else if (cmd_units[1] == "row")
|
||||
{
|
||||
for (size_t i = 2; i < cmd_units.size(); i++)
|
||||
{
|
||||
tc.row_output(cmd_units[i], Disable);
|
||||
}
|
||||
}
|
||||
else throw std::runtime_error("disable: invalid parameters.");
|
||||
return;
|
||||
}
|
||||
|
||||
void load_file(const std::vector<std::string> &cmd_units)
|
||||
{
|
||||
// load <file> [nohead|column|row|both] [head_num] [<delimeter>] [att_sym] [tag_sym]
|
||||
if (cmd_units.size() < 2) throw std::runtime_error("open: insufficient parameters.");
|
||||
|
||||
gctl::array<std::string> copy_str(5, "null");
|
||||
for (size_t i = 0; i < GCTL_MIN(cmd_units.size() - 2, 5); i++)
|
||||
{
|
||||
copy_str[i] = cmd_units[i + 2];
|
||||
}
|
||||
|
||||
int ht = NoHead;
|
||||
if (copy_str[0] == "nohead") ht = NoHead;
|
||||
else if (copy_str[0] == "column") ht = ColHead;
|
||||
else if (copy_str[0] == "row") ht = RowHead;
|
||||
else if (copy_str[0] == "both") ht = RowHead|ColHead;
|
||||
|
||||
int hnum = 0;
|
||||
if (copy_str[1] != "null") hnum = atoi(copy_str[1].c_str());
|
||||
if (hnum != 0) tc.head_number(hnum);
|
||||
|
||||
if (copy_str[2] != "null") tc.delimeter(copy_str[2][0]);
|
||||
if (copy_str[3] != "null") tc.annotation_symbol(copy_str[3][0]);
|
||||
if (copy_str[4] != "null") tc.tag_symbol(copy_str[4][0]);
|
||||
|
||||
std::string naked_name, exten_name;
|
||||
parse_filename(cmd_units[1], naked_name, exten_name);
|
||||
|
||||
if (exten_name == ".csv") tc.load_csv(naked_name);
|
||||
else tc.load_text(naked_name, exten_name, ht);
|
||||
return;
|
||||
}
|
||||
|
||||
void save_file(const std::vector<std::string> &cmd_units)
|
||||
{
|
||||
// save <file> [<delimeter>] [att_sym] [tag_sym]
|
||||
if (cmd_units.size() < 2) throw std::runtime_error("save: insufficient parameters.");
|
||||
|
||||
gctl::array<std::string> copy_str(3, "null");
|
||||
for (size_t i = 0; i < GCTL_MIN(cmd_units.size() - 2, 3); i++)
|
||||
{
|
||||
copy_str[i] = cmd_units[i + 2];
|
||||
}
|
||||
|
||||
if (copy_str[0] != "null") tc.delimeter(copy_str[0][0]);
|
||||
if (copy_str[1] != "null") tc.annotation_symbol(copy_str[1][0]);
|
||||
if (copy_str[2] != "null") tc.tag_symbol(copy_str[2][0]);
|
||||
|
||||
std::string naked_name, exten_name;
|
||||
parse_filename(cmd_units[1], naked_name, exten_name);
|
||||
|
||||
if (exten_name == ".csv") tc.save_csv(naked_name);
|
||||
else tc.save_text(naked_name, exten_name);
|
||||
return;
|
||||
}
|
||||
|
||||
void statistic(const std::vector<std::string> &cmd_units)
|
||||
{
|
||||
// stats <column> <column>...
|
||||
if (cmd_units.size() < 2) throw std::runtime_error("stats: insufficient parameters.");
|
||||
|
||||
_1d_array data;
|
||||
for (size_t i = 1; i < cmd_units.size(); i++)
|
||||
{
|
||||
tc.get_column(data, cmd_units[i]);
|
||||
std::clog << "column: " << cmd_units[i]
|
||||
<< " | " << data.min() << "/" << data.mean() << "/" << data.max()
|
||||
<< " | STD: " << data.std() << "\n";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void set_type(const std::vector<std::string> &cmd_units)
|
||||
{
|
||||
// type row|col int|float|string <name>
|
||||
if (cmd_units.size() < 4) throw std::runtime_error("type: insufficient parameters.");
|
||||
if (cmd_units[1] == "row")
|
||||
{
|
||||
if (cmd_units[2] == "int") tc.row_type(Int, cmd_units[3]);
|
||||
else if (cmd_units[2] == "float") tc.row_type(Float, cmd_units[3]);
|
||||
else if (cmd_units[2] == "string") tc.row_type(String, cmd_units[3]);
|
||||
else throw std::runtime_error("type: invalid parameters.");
|
||||
}
|
||||
else if (cmd_units[1] == "col")
|
||||
{
|
||||
if (cmd_units[2] == "int") tc.column_type(Int, cmd_units[3]);
|
||||
else if (cmd_units[2] == "float") tc.column_type(Float, cmd_units[3]);
|
||||
else if (cmd_units[2] == "string") tc.column_type(String, cmd_units[3]);
|
||||
else throw std::runtime_error("type: invalid parameters.");
|
||||
}
|
||||
else throw std::runtime_error("type: invalid parameters.");
|
||||
return;
|
||||
}
|
||||
|
||||
void set_titles(const std::vector<std::string> &cmd_units)
|
||||
{
|
||||
// title <row|col> <t1>,<t2>,<t3>,... [<id1>,<id2>,<id3>,...]
|
||||
if (cmd_units.size() < 3) throw std::runtime_error("title: insufficient parameters.");
|
||||
if (cmd_units[1] == "row")
|
||||
{
|
||||
std::vector<std::string> row_titles;
|
||||
std::vector<int> row_ids;
|
||||
parse_string_to_vector(cmd_units[2], ',', row_titles);
|
||||
if (cmd_units.size() >= 4)
|
||||
{
|
||||
parse_string_to_vector(cmd_units[3], ',', row_ids);
|
||||
if (row_titles.size() != row_ids.size()) throw std::runtime_error("title: invalid parameters.");
|
||||
tc.row_names(row_titles, row_ids);
|
||||
}
|
||||
else tc.row_names(row_titles);
|
||||
}
|
||||
else if (cmd_units[1] == "col")
|
||||
{
|
||||
std::vector<std::string> col_titles;
|
||||
std::vector<int> col_ids;
|
||||
parse_string_to_vector(cmd_units[2], ',', col_titles);
|
||||
if (cmd_units.size() >= 4)
|
||||
{
|
||||
parse_string_to_vector(cmd_units[3], ',', col_ids);
|
||||
if (col_titles.size()!= col_ids.size()) throw std::runtime_error("title: invalid parameters.");
|
||||
tc.column_names(col_titles, col_ids);
|
||||
}
|
||||
else tc.column_names(col_titles);
|
||||
}
|
||||
else throw std::runtime_error("title: invalid parameters.");
|
||||
return;
|
||||
}
|
||||
|
||||
void math_func(const std::vector<std::string> &cmd_units)
|
||||
{
|
||||
// math <func> <col1>,<col2>,<col3>...
|
||||
if (cmd_units.size() < 3) throw std::runtime_error("math: insufficient parameters.");
|
||||
|
||||
std::vector<std::string> col_names;
|
||||
parse_string_to_vector(cmd_units[2], ',', col_names);
|
||||
|
||||
tc.cal_column(cmd_units[1], col_names, 12);
|
||||
return;
|
||||
}
|
||||
|
||||
void rand_data(const std::vector<std::string> &cmd_units)
|
||||
{
|
||||
// random normal|uniform <p1> <p2> [<colname>]
|
||||
if (cmd_units.size() < 4) throw std::runtime_error("random: insufficient parameters.");
|
||||
|
||||
random_type_e rd_type = RdNormal;
|
||||
if (cmd_units[1] == "normal") rd_type = RdNormal;
|
||||
else if (cmd_units[1] == "uniform") rd_type = RdUniform;
|
||||
else throw std::runtime_error("random: invalid parameters.");
|
||||
|
||||
double p1 = atof(cmd_units[2].c_str());
|
||||
double p2 = atof(cmd_units[3].c_str());
|
||||
array<double> rd_data(tc.row_number());
|
||||
rd_data.random_float(p1, p2, rd_type);
|
||||
|
||||
if (cmd_units.size() >= 5) tc.fill_column(rd_data, cmd_units[4], 12);
|
||||
else
|
||||
{
|
||||
std::string col_name = "RdData";
|
||||
tc.add_column(col_name);
|
||||
tc.fill_column(rd_data, col_name, 12);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void filt_data(const std::vector<std::string> &cmd_units)
|
||||
{
|
||||
// filter row|col regex|math <expression> <name1>,<name2>,<name3>...
|
||||
if (cmd_units.size() < 5) throw std::runtime_error("filter: insufficient parameters.");
|
||||
std::vector<std::string> tar_names;
|
||||
parse_string_to_vector(cmd_units[4], ',', tar_names);
|
||||
|
||||
table_headtype_e thead;
|
||||
if (cmd_units[1] == "row") thead = RowHead;
|
||||
else if (cmd_units[1] == "col") thead = ColHead;
|
||||
else throw std::runtime_error("filter: invalid parameters.");
|
||||
|
||||
if (cmd_units[2] == "regex") tc.filter(cmd_units[3], tar_names[0], thead);
|
||||
else if (cmd_units[2] == "math") tc.filter(cmd_units[3], tar_names, thead);
|
||||
else throw std::runtime_error("filter: invalid parameters.");
|
||||
return;
|
||||
}
|
||||
|
||||
void insert_data(const std::vector<std::string> &cmd_units)
|
||||
{
|
||||
// insert row|col [<new-name>] [<insert-name>]
|
||||
if (cmd_units.size() < 2) throw std::runtime_error("insert: insufficient parameters.");
|
||||
|
||||
if (cmd_units[1] == "row")
|
||||
{
|
||||
if (cmd_units.size() == 2) tc.add_row();
|
||||
else if (cmd_units.size() == 3) tc.add_row(cmd_units[2]);
|
||||
else if (cmd_units.size() == 4) tc.add_row(cmd_units[2], cmd_units[3]);
|
||||
}
|
||||
else if (cmd_units[1] == "col")
|
||||
{
|
||||
if (cmd_units.size() == 2) tc.add_column();
|
||||
else if (cmd_units.size() == 3) tc.add_column(cmd_units[2]);
|
||||
else if (cmd_units.size() == 4) tc.add_column(cmd_units[2], cmd_units[3]);
|
||||
}
|
||||
else throw std::runtime_error("insert: invalid parameters.");
|
||||
return;
|
||||
}
|
||||
|
||||
void set_data(const std::vector<std::string> &cmd_units)
|
||||
{
|
||||
// set row|col \<name\> \<value\>
|
||||
if (cmd_units.size() < 4) throw std::runtime_error("set: insufficient parameters.");
|
||||
|
||||
if (cmd_units[1] == "row")
|
||||
{
|
||||
_1s_array row_data(tc.row_number(), cmd_units[3]);
|
||||
tc.fill_row(row_data, cmd_units[2]);
|
||||
}
|
||||
else if (cmd_units[1] == "col")
|
||||
{
|
||||
_1s_array col_data(tc.col_number(), cmd_units[3]);
|
||||
tc.fill_column(col_data, cmd_units[2]);
|
||||
}
|
||||
else throw std::runtime_error("set: invalid parameters.");
|
||||
return;
|
||||
}
|
||||
|
||||
void display_table(const std::vector<std::string> &cmd_units)
|
||||
{
|
||||
// view
|
||||
tc.display();
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc >= 2)
|
||||
{
|
||||
std::string tmp_l;
|
||||
std::ifstream cmdin;
|
||||
|
||||
// Run commands from files. Each line is a command.
|
||||
// You can give more than one file
|
||||
for (size_t i = 1; i < argc; i++) try
|
||||
{
|
||||
open_infile(cmdin, argv[i]);
|
||||
while (getline(cmdin, tmp_l) && tmp_l != "" && tmp_l[0] != '#')
|
||||
{
|
||||
exec_cmd(tmp_l);
|
||||
}
|
||||
cmdin.close();
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
GCTL_ShowWhatError(e.what(), GCTL_ERROR_ERROR, 0, "run dsviewer in the interactive mode for instructions.", 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
setlocale(LC_CTYPE, "");
|
||||
initialize_readline(); /* Bind our completer. */
|
||||
|
||||
display_logo();
|
||||
std::clog << "dsviewer - read, manipulate and write dsv/csv files.\n";
|
||||
std::clog << "Usage: dsviewer [<cmdfile1> <cmdfile2>...]\n";
|
||||
std::clog << "Enter '?' to see all available commands.\n";
|
||||
|
||||
std::string cmd_str;
|
||||
char *c_line = (char *)NULL;
|
||||
char *c_line_s = (char *)NULL;
|
||||
bool quit = false;
|
||||
|
||||
while (!quit) try
|
||||
{
|
||||
c_line = readline(">> ");
|
||||
if (!c_line) break;
|
||||
|
||||
c_line_s = stripwhite(c_line);
|
||||
cmd_str = c_line_s;
|
||||
|
||||
if (cmd_str == "quit") quit = true;
|
||||
else if (cmd_str == "?") display_cmds();
|
||||
else exec_cmd(cmd_str);
|
||||
|
||||
free(c_line);
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
GCTL_ShowWhatError(e.what(), GCTL_ERROR_ERROR, 0, "Enter 'help' for instructions.", 0);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
86
dsviewer/dsviewer.h
Normal file
86
dsviewer/dsviewer.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/********************************************************
|
||||
* ██████╗ ██████╗████████╗██╗
|
||||
* ██╔════╝ ██╔════╝╚══██╔══╝██║
|
||||
* ██║ ███╗██║ ██║ ██║
|
||||
* ██║ ██║██║ ██║ ██║
|
||||
* ╚██████╔╝╚██████╗ ██║ ███████╗
|
||||
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
|
||||
* Geophysical Computational Tools & Library (GCTL)
|
||||
*
|
||||
* Copyright (c) 2023 Yi Zhang (yizhang-geo@zju.edu.cn)
|
||||
*
|
||||
* GCTL is distributed under a dual licensing scheme. You can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation, either version 2
|
||||
* of the License, or (at your option) any later version. You should have
|
||||
* received a copy of the GNU Lesser General Public License along with this
|
||||
* program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* If the terms and conditions of the LGPL v.2. would prevent you from using
|
||||
* the GCTL, please consider the option to obtain a commercial license for a
|
||||
* fee. These licenses are offered by the GCTL's original author. As a rule,
|
||||
* licenses are provided "as-is", unlimited in time for a one time fee. Please
|
||||
* send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget
|
||||
* to include some description of your company and the realm of its activities.
|
||||
* Also add information on how to contact you by electronic and paper mail.
|
||||
******************************************************/
|
||||
|
||||
#ifndef GCTL_DSVIEWER_H
|
||||
#define GCTL_DSVIEWER_H
|
||||
|
||||
#include <regex>
|
||||
#include "gctl/io.h"
|
||||
|
||||
using namespace gctl;
|
||||
|
||||
// Function pointer for commands
|
||||
typedef void (*cmd_func_ptr)(const std::vector<std::string> &cmd_units);
|
||||
|
||||
struct cmd_pair
|
||||
{
|
||||
std::string name;
|
||||
cmd_func_ptr func_p;
|
||||
std::string brief;
|
||||
};
|
||||
|
||||
void quit(const std::vector<std::string> &cmd_units);
|
||||
void info(const std::vector<std::string> &cmd_units);
|
||||
void head(const std::vector<std::string> &cmd_units);
|
||||
void tail(const std::vector<std::string> &cmd_units);
|
||||
void load_file(const std::vector<std::string> &cmd_units);
|
||||
void save_file(const std::vector<std::string> &cmd_units);
|
||||
void statistic(const std::vector<std::string> &cmd_units);
|
||||
void set_enable(const std::vector<std::string> &cmd_units);
|
||||
void set_disable(const std::vector<std::string> &cmd_units);
|
||||
void set_type(const std::vector<std::string> &cmd_units);
|
||||
void set_titles(const std::vector<std::string> &cmd_units);
|
||||
void math_func(const std::vector<std::string> &cmd_units);
|
||||
void rand_data(const std::vector<std::string> &cmd_units);
|
||||
void filt_data(const std::vector<std::string> &cmd_units);
|
||||
void insert_data(const std::vector<std::string> &cmd_units);
|
||||
void set_data(const std::vector<std::string> &cmd_units);
|
||||
void display_table(const std::vector<std::string> &cmd_units);
|
||||
|
||||
#define CMD_NUM 18
|
||||
const cmd_pair commands[CMD_NUM] = {
|
||||
{"quit", quit, "Quit the program."},
|
||||
{"view", display_table, "Display valid cells."},
|
||||
{"info", info, "Show the table information."},
|
||||
{"head", head, "Show head line(s) of the table."},
|
||||
{"tail", tail, "Show tail line(s) of the table."},
|
||||
{"open", load_file, "Open a dsv/csv file."},
|
||||
{"save", save_file, "Save the table to a file."},
|
||||
{"stats", statistic, "Calculate statistics of the selected columns."},
|
||||
{"enable", set_enable, "Enable column/row outputs by name or index."},
|
||||
{"disable", set_disable, "Disable column/row outputs by name or index."},
|
||||
{"insert", insert_data, "Insert a new column/row data."},
|
||||
{"set", set_data, "Set a column/row data."},
|
||||
{"type", set_type, "Set column/row data types."},
|
||||
{"title", set_titles, "Set row and column titles."},
|
||||
{"math", math_func, "Preform mathematic operations of column data."},
|
||||
{"random", rand_data, "Generate random column data."},
|
||||
{"filter", filt_data, "Filter row and column data using regex and mathematic expressions."},
|
||||
{"null", nullptr, "null"}
|
||||
};
|
||||
|
||||
#endif // GCTL_DSVIEWER_H
|
47
dsviewer/dsviewer.md
Normal file
47
dsviewer/dsviewer.md
Normal file
@@ -0,0 +1,47 @@
|
||||
#### quit
|
||||
Does what it says.
|
||||
|
||||
#### info [att|tag|hdr|col|row]
|
||||
Show the table information. 'att' shows the annotations, 'tag' shows the tag lines, 'hdr' shows the head lines, 'col' shows the columns' summary, and 'row' shows the rows' summary. Use '|' to separate multiple options.
|
||||
|
||||
#### head
|
||||
Show the first `n` (the default is 10) rows of the table.
|
||||
|
||||
#### tail
|
||||
Show the last `n` (the default is 10) rows of the table.
|
||||
|
||||
#### open \<file\> [nohead|column|row|both] [\<head_num\>] [\<deli-sym\>] [\<att-sym\>] [\<tag-sym\>]
|
||||
Open a dsv/csv file. The default setups are 'nohead', space for delimeter, '#' for annotations, and '!' for tags. If the file name ends with '.csv', the default delimeter is ','.
|
||||
|
||||
#### save \<file\> [\<delimeter\>] [\<att-sym\>] [\<tag-sym\>]
|
||||
Save table to a dsv/csv file. The default setups are space for delimeter, '#' for annotations, and '!' for tags. If the file name ends with '.csv', the default delimeter is ','.
|
||||
|
||||
#### stats \<colname1\> \<colname2\> ...
|
||||
Show statistics of a data column or columns. If the input file has no column names, use inbuilt names `C<id>` to select the columns.
|
||||
|
||||
#### enable table|column|row [\<name1\> \<name2\> ...]
|
||||
Enable table outputs. If the input file has no row or column names, use inbuilt names `R<id>` and `C<id>` to select the rows and columns.
|
||||
|
||||
#### disable table|column|row [\<name1\> \<name2\> ...]
|
||||
Disable table outputs. If the input file has no row or column names, use inbuilt names `R<id>` and `C<id>` to select the rows and columns.
|
||||
|
||||
#### insert row|col [\<new-name\>] [\<insert-name\>]
|
||||
Insert a new row or column. The new row or column will be attached to the end of the table by default. A `new-name` can be provided if the user wants to rename the new row or column. Provide the `insert-name` to insert the new row or column at the specified row or column. The remaining columns or rows will be moved one step right or down accordingly. If the input file has no row or column names, use inbuilt names `R<id>` and `C<id>` to select the rows and columns.
|
||||
|
||||
#### set row|col \<name\> \<value\>
|
||||
Set a row or column's value to the given one. If the input file has no row or column names, use inbuilt names `R<id>` and `C<id>` to select the rows and columns.
|
||||
|
||||
#### type row|col int|float|string \<name\>
|
||||
Set the data type of a row or column. If the input file has no row or column names, use inbuilt names `R<id>` and `C<id>` to select the rows and columns.
|
||||
|
||||
#### title row|col \<t1\>,\<t2\>,\<t3\>,... [\<id1\>,\<id2\>,\<id3\>,...]
|
||||
Set row and column titles. The titles will be assigned sequentially if no index is specified.
|
||||
|
||||
#### math \<func\> \<col1\>,\<col2\>,\<col3\>...
|
||||
Preform mathematic operations of column data. The user needs to write a mathematical expression using the column names as variables. Then provide the column names as the arguments, in which the resultant column's name must be placed at the beginning. For example, to calculate the sum of column `C1` and `C2`, and store the result in column `C3`, the command is: `math C3=C1+C2 C3,C1,C2`.
|
||||
|
||||
#### random normal|uniform \<p1\> \<p2\> [\<colname\>]
|
||||
Generate random data using normal or uniform distribution. The first parameter is the mean or the lower bound, and the second parameter is the standard deviation or the upper bound. If no column name is provided, a new column will be created (titled "RdData").
|
||||
|
||||
#### filter row|col regex|math \<expression\> \<name1\>,\<name2\>,\<name3\>...
|
||||
Filter row and column data using regex and mathematic expressions. The first parameter is the expression, and the following parameters are the column names. For example, to filter rows whose column `C1` is greater than 0, the command is: `filter col math C1>0 C1`. Regex expression can be used to filter rows whose column `C1` contains the string "abc", the command is: `filter col regex abc C1`.
|
11
dsviewer/example.csv
Normal file
11
dsviewer/example.csv
Normal file
@@ -0,0 +1,11 @@
|
||||
Name,Age,Gender,Occupation,City,Phone Number,Email,Annual Income,Company,Position
|
||||
John Doe,28,Male,Engineer,New York,123-456-7890,john.doe@example.com,$75000,ABC Tech,Senior Software Engineer
|
||||
Jane Smith,34,Female,Teacher,Los Angeles,234-567-8901,jane.smith@example.com,$55000,XYZ School,Math Teacher
|
||||
Michael Brown,22,Male,Student,Toronto,345-678-9012,michael.brown@example.com,$18000,University of Toronto,Undergraduate Student
|
||||
Emily Davis,45,Female,Doctor,Chicago,456-789-0123,emily.davis@example.com,$180000,Chicago Medical Center,Cardiologist
|
||||
David Wilson,30,Male,Designer,San Francisco,567-890-1234,david.wilson@example.com,$90000,DesignWorks,Senior Graphic Designer
|
||||
Sarah Johnson,29,Female,Marketing Specialist,Seattle,678-901-2345,sarah.johnson@example.com,$85000,MarketingPro,Marketing Manager
|
||||
Robert Lee,36,Male,Software Developer,Boston,789-012-3456,robert.lee@example.com,$120000,SoftDev Solutions,Lead Developer
|
||||
Laura Miller,25,Female,Graphic Designer,Denver,890-123-4567,laura.miller@example.com,$60000,Creative Arts,Junior Designer
|
||||
William Clark,40,Male,Consultant,Atlanta,901-234-5678,william.clark@example.com,$110000,ConsultPro,Business Consultant
|
||||
Olivia Turner,33,Female,Researcher,Phoenix,012-345-6789,olivia.turner@example.com,$70000,ResearchInnovate,Research Scientist
|
|
Reference in New Issue
Block a user