Commit 085ac306 authored by Ruben Undheim's avatar Ruben Undheim

Patch with new feature

parent e61d6832
Pipeline #41798 failed with stage
in 5 minutes and 46 seconds
From: Ruben Undheim <ruben.undheim@gmail.com>
Date: Sun, 31 Mar 2019 21:34:17 +0200
Subject: Use readline for interactive input. This adds 'command line
completion', search functionality etc
---
CMakeLists.txt | 5 ++
app/StaMain.cc | 142 ++++++++++++++++++++++++++++++++++++++-
cmake/modules/FindReadline.cmake | 47 +++++++++++++
3 files changed, 191 insertions(+), 3 deletions(-)
create mode 100644 cmake/modules/FindReadline.cmake
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8b16325..3ea605e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,6 +10,8 @@ cmake_minimum_required (VERSION 3.9)
project(STA VERSION 2.0.11)
+set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules CACHE STRING "CMake module path")
+
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@@ -540,6 +542,7 @@ get_filename_component(TCL_HEADER_DIR "${TCL_HEADER}" PATH)
find_package(FLEX)
find_package(BISON)
+find_package(Readline REQUIRED)
# LibertyExpr scan/parse.
bison_target(LibertyExprParser liberty/LibertyExprParse.yy ${STA_HOME}/liberty/LibertyExprParse.cc
@@ -683,6 +686,8 @@ if (ZLIB_FOUND)
target_link_libraries(sta ${ZLIB_LIBRARIES})
endif()
+target_link_libraries(sta ${Readline_LIBRARY})
+
message(STATUS "STA executable: ${STA_HOME}/app/sta")
diff --git a/app/StaMain.cc b/app/StaMain.cc
index 6cb5460..0f433fe 100644
--- a/app/StaMain.cc
+++ b/app/StaMain.cc
@@ -16,6 +16,8 @@
#include <tcl.h>
#include <stdlib.h>
+#include <readline/readline.h>
+#include <readline/history.h>
#include "Machine.hh"
#include "StringUtil.hh"
#include "Vector.hh"
@@ -26,6 +28,12 @@ namespace sta {
typedef sta::Vector<SwigInitFunc> SwigInitFuncSeq;
+char **extra_command_completion (const char *, int, int);
+char *extra_command_generator (const char *, int);
+int command_exit (ClientData, Tcl_Interp *, int, Tcl_Obj *const []);
+void save_history();
+void load_history();
+
// "Arguments" passed to staTclAppInit.
static int sta_argc;
static char **sta_argv;
@@ -38,12 +46,18 @@ static void
sourceTclFileEchoVerbose(const char *filename,
Tcl_Interp *interp);
+static bool ended = 0;
+
void
staMain(Sta *sta,
int argc,
char **argv,
SwigInitFunc swig_init)
{
+ char *buffer;
+ Tcl_Interp *myInterp;
+ int status;
+
initSta();
Sta::setSta(sta);
@@ -56,9 +70,31 @@ staMain(Sta *sta,
sta->setThreadCount(thread_count);
staSetupAppInit(argc, argv, swig_init);
- // Set argc to 1 so Tcl_Main doesn't source any files.
- // Tcl_Main never returns.
- Tcl_Main(1, argv, staTclAppInit);
+
+ myInterp = Tcl_CreateInterp();
+ Tcl_CreateObjCommand(myInterp, "exit", (Tcl_ObjCmdProc*)command_exit, 0, 0);
+
+ rl_attempted_completion_function = extra_command_completion;
+
+ staTclAppInit(myInterp);
+
+ load_history();
+
+ while((!ended) && (buffer = readline("OpenSTA> ")) != NULL) {
+ status = Tcl_Eval(myInterp, buffer);
+ if(status != TCL_OK) {
+ fprintf(stderr, "%s\n", Tcl_GetStringResult(myInterp));
+ }
+ if (buffer[0] != 0)
+ add_history(buffer);
+ free(buffer);
+ if(ended) break;
+ }
+
+ save_history();
+
+ Tcl_DeleteInterp(myInterp);
+ Tcl_Finalize();
}
void
@@ -204,6 +240,106 @@ evalTclInit(Tcl_Interp *interp,
delete [] unencoded;
}
+int command_exit(ClientData, Tcl_Interp *, int, Tcl_Obj *const [])
+{
+ ended = 1;
+ return 0;
+}
+
+char const *extra_commands[] = {
+ "all_clocks",
+ "all_inputs",
+ "all_outputs",
+ "all_registers",
+ "check_setup",
+ "create_clock",
+ "create_generated_clock",
+ "create_voltage_area",
+ "current_design",
+ "current_instance",
+ "define_corners",
+
+ "get_clocks",
+ "get_fanin",
+ "get_fanout",
+
+ "get_nets",
+ "get_pins",
+ "get_ports",
+ "read_liberty",
+ "read_parasitics",
+ "read_sdc",
+ "read_sdf",
+ "read_spef",
+ "read_verilog",
+ "report_annotated_delay",
+ "report_cell",
+ "report_checks",
+ "report_path",
+ "report_slack",
+ "set_input_delay",
+ "write_sdc",
+ "write_sdf",
+ NULL
+};
+
+char **extra_command_completion(const char *text, int, int)
+{
+ rl_attempted_completion_over = 0;
+ return rl_completion_matches(text, extra_command_generator);
+}
+
+char *extra_command_generator(const char *text, int state)
+{
+ static int list_index, len;
+ const char *name;
+
+ if (!state) {
+ list_index = 0;
+ len = strlen(text);
+ }
+
+ while ((name = extra_commands[list_index++])) {
+ if(strncmp(name, text, len) == 0) {
+ return strdup(name);
+ }
+ }
+
+ return NULL;
+}
+
+void load_history()
+{
+ FILE *histin = fopen(".history_sta", "r");
+ if(histin != NULL) {
+ char *line = NULL;
+ size_t len = 0;
+ ssize_t read;
+ while((read = getline(&line, &len, histin)) != -1) {
+ line[strlen(line)-1] = 0;
+ if (line[0] != 0) {
+ add_history(line);
+ }
+ }
+ fclose(histin);
+ }
+}
+
+void save_history()
+{
+ printf("Saving command history\n");
+ HIST_ENTRY **the_list;
+ the_list = history_list();
+ if(the_list){
+ FILE *histout = fopen(".history_sta", "w");
+ for(int i=0; the_list[i] ; i++) {
+ fprintf(histout, "%s\n", the_list[i]->line);
+ }
+ fclose(histout);
+ }
+}
+
+
void
showUseage(char *prog)
{
diff --git a/cmake/modules/FindReadline.cmake b/cmake/modules/FindReadline.cmake
new file mode 100644
index 0000000..4dcb649
--- /dev/null
+++ b/cmake/modules/FindReadline.cmake
@@ -0,0 +1,47 @@
+# - Try to find readline include dirs and libraries
+#
+# Usage of this module as follows:
+#
+# find_package(Readline)
+#
+# Variables used by this module, they can change the default behaviour and need
+# to be set before calling find_package:
+#
+# Readline_ROOT_DIR Set this variable to the root installation of
+# readline if the module has problems finding the
+# proper installation path.
+#
+# Variables defined by this module:
+#
+# READLINE_FOUND System has readline, include and lib dirs found
+# Readline_INCLUDE_PATH The readline include directories.
+# Readline_LIBRARY The readline library.
+
+find_path(Readline_ROOT_DIR
+ NAMES include/readline/readline.h
+)
+
+find_path(Readline_INCLUDE_PATH
+ NAMES readline/readline.h
+ HINTS ${Readline_ROOT_DIR}/include
+)
+
+find_library(Readline_LIBRARY
+ NAMES readline
+ HINTS ${Readline_ROOT_DIR}/lib
+)
+
+if(Readline_INCLUDE_PATH AND Readline_LIBRARY AND Ncurses_LIBRARY)
+ set(READLINE_FOUND TRUE)
+else(Readline_INCLUDE_PATH AND Readline_LIBRARY AND Ncurses_LIBRARY)
+ FIND_LIBRARY(Readline_LIBRARY NAMES readline)
+ include(FindPackageHandleStandardArgs)
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(Readline DEFAULT_MSG Readline_INCLUDE_PATH Readline_LIBRARY )
+ MARK_AS_ADVANCED(Readline_INCLUDE_PATH Readline_LIBRARY)
+endif(Readline_INCLUDE_PATH AND Readline_LIBRARY AND Ncurses_LIBRARY)
+
+mark_as_advanced(
+ Readline_ROOT_DIR
+ Readline_INCLUDE_PATH
+ Readline_LIBRARY
+)
0001-Fix-build-issue.patch
0002-Fix-spelling-error.patch
0003-Use-readline-for-interactive-input.-This-adds-comman.patch
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment