OpenSTA/util/ReportTcl.cc

476 lines
11 KiB
C++
Raw Normal View History

2018-09-28 17:54:21 +02:00
// OpenSTA, Static Timing Analyzer
2020-03-07 03:50:37 +01:00
// Copyright (c) 2020, Parallax Software, Inc.
2020-04-13 04:19:22 +02:00
//
2018-09-28 17:54:21 +02:00
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
2020-04-13 04:19:22 +02:00
//
2018-09-28 17:54:21 +02:00
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
2020-04-13 04:19:22 +02:00
//
2018-09-28 17:54:21 +02:00
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2020-04-05 23:53:44 +02:00
#include "ReportTcl.hh"
2020-04-05 20:35:51 +02:00
2018-09-28 17:54:21 +02:00
#include <stdio.h>
2020-04-13 04:19:22 +02:00
#include <stdlib.h>
2018-09-28 17:54:21 +02:00
namespace sta {
2020-04-13 04:19:22 +02:00
using ::ClientData;
2018-09-28 17:54:21 +02:00
using ::Tcl_Channel;
2020-04-13 04:19:22 +02:00
using ::Tcl_ChannelOutputProc;
2018-09-28 17:54:21 +02:00
using ::Tcl_ChannelType;
using ::Tcl_DriverOutputProc;
2020-04-13 04:19:22 +02:00
using ::Tcl_GetChannelInstanceData;
using ::Tcl_GetChannelType;
2018-09-28 17:54:21 +02:00
extern "C" {
// Tcl8.4 adds const's to Tcl_ChannelType but earlier versions
// don't have them.
#ifndef CONST84
#define CONST84
#endif
static int
2020-04-13 04:19:22 +02:00
encapOutputProc(ClientData instanceData,
CONST84 char *buf,
int toWrite,
int *errorCodePtr);
2018-09-28 17:54:21 +02:00
static int
2020-04-13 04:19:22 +02:00
encapErrorOutputProc(ClientData instanceData,
CONST84 char *buf,
int toWrite,
int *errorCodePtr);
2018-09-28 17:54:21 +02:00
static int
encapCloseProc(ClientData instanceData, Tcl_Interp *interp);
static int
2020-04-13 04:19:22 +02:00
encapSetOptionProc(ClientData instanceData,
Tcl_Interp *interp,
CONST84 char *optionName,
CONST84 char *value);
2018-09-28 17:54:21 +02:00
static int
2020-04-13 04:19:22 +02:00
encapGetOptionProc(ClientData instanceData,
Tcl_Interp *interp,
CONST84 char *optionName,
Tcl_DString *dsPtr);
2018-09-28 17:54:21 +02:00
static int
2020-04-13 04:19:22 +02:00
encapInputProc(ClientData instanceData,
char *buf,
int bufSize,
int *errorCodePtr);
2018-09-28 17:54:21 +02:00
static int
2020-04-13 04:19:22 +02:00
encapSeekProc(ClientData instanceData,
long offset,
int seekMode,
int *errorCodePtr);
2018-09-28 17:54:21 +02:00
static void
encapWatchProc(ClientData instanceData, int mask);
static int
2020-04-13 04:19:22 +02:00
encapGetHandleProc(ClientData instanceData,
int direction,
ClientData *handlePtr);
2018-09-28 17:54:21 +02:00
static int
encapBlockModeProc(ClientData instanceData, int mode);
} // extern "C"
#ifdef TCL_CHANNEL_VERSION_5
Tcl_ChannelType tcl_encap_type_stdout = {
2020-04-13 04:19:22 +02:00
const_cast<char *>("file"),
TCL_CHANNEL_VERSION_4,
encapCloseProc,
encapInputProc,
encapOutputProc,
encapSeekProc,
encapSetOptionProc,
encapGetOptionProc,
encapWatchProc,
encapGetHandleProc,
nullptr, // close2Proc
encapBlockModeProc,
nullptr, // flushProc
nullptr, // handlerProc
nullptr, // wideSeekProc
nullptr, // threadActionProc
nullptr // truncateProc
2018-09-28 17:54:21 +02:00
};
Tcl_ChannelType tcl_encap_type_stderr = {
2020-04-13 04:19:22 +02:00
const_cast<char *>("file"),
TCL_CHANNEL_VERSION_4,
encapCloseProc,
encapInputProc,
encapErrorOutputProc,
encapSeekProc,
encapSetOptionProc,
encapGetOptionProc,
encapWatchProc,
encapGetHandleProc,
nullptr, // close2Proc
encapBlockModeProc,
nullptr, // flushProc
nullptr, // handlerProc
nullptr, // wideSeekProc
nullptr, // threadActionProc
nullptr // truncateProc
2018-09-28 17:54:21 +02:00
};
#else
#ifdef TCL_CHANNEL_VERSION_4
// Tcl 8.4.12
Tcl_ChannelType tcl_encap_type_stdout = {
2020-04-13 04:19:22 +02:00
const_cast<char *>("file"),
TCL_CHANNEL_VERSION_4,
encapCloseProc,
encapInputProc,
encapOutputProc,
encapSeekProc,
encapSetOptionProc,
encapGetOptionProc,
encapWatchProc,
encapGetHandleProc,
nullptr, // close2Proc
encapBlockModeProc,
nullptr, // flushProc
nullptr, // handlerProc
nullptr, // wideSeekProc
nullptr // threadActionProc
2018-09-28 17:54:21 +02:00
};
Tcl_ChannelType tcl_encap_type_stderr = {
2020-04-13 04:19:22 +02:00
const_cast<char *>("file"),
TCL_CHANNEL_VERSION_4,
encapCloseProc,
encapInputProc,
encapErrorOutputProc,
encapSeekProc,
encapSetOptionProc,
encapGetOptionProc,
encapWatchProc,
encapGetHandleProc,
nullptr, // close2Proc
encapBlockModeProc,
nullptr, // flushProc
nullptr, // handlerProc
nullptr, // wideSeekProc
nullptr // threadActionProc
2018-09-28 17:54:21 +02:00
};
#else
#ifdef TCL_CHANNEL_VERSION_3
// Tcl 8.4
Tcl_ChannelType tcl_encap_type_stdout = {
2020-04-13 04:19:22 +02:00
const_cast<char *>("file"),
TCL_CHANNEL_VERSION_3,
encapCloseProc,
encapInputProc,
encapOutputProc,
encapSeekProc,
encapSetOptionProc,
encapGetOptionProc,
encapWatchProc,
encapGetHandleProc,
nullptr, // close2Proc
encapBlockModeProc,
nullptr, // flushProc
nullptr, // handlerProc
nullptr // wideSeekProc
2018-09-28 17:54:21 +02:00
};
Tcl_ChannelType tcl_encap_type_stderr = {
2020-04-13 04:19:22 +02:00
const_cast<char *>("file"),
TCL_CHANNEL_VERSION_3,
encapCloseProc,
encapInputProc,
encapErrorOutputProc,
encapSeekProc,
encapSetOptionProc,
encapGetOptionProc,
encapWatchProc,
encapGetHandleProc,
nullptr, // close2Proc
encapBlockModeProc,
nullptr, // flushProc
nullptr, // handlerProc
nullptr // wideSeekProc
2018-09-28 17:54:21 +02:00
};
#else
#ifdef TCL_CHANNEL_VERSION_2
// Tcl 8.3.2
Tcl_ChannelType tcl_encap_type_stdout = {
2020-04-13 04:19:22 +02:00
const_cast<char *>("file"),
TCL_CHANNEL_VERSION_2,
encapCloseProc,
encapInputProc,
encapOutputProc,
encapSeekProc,
encapSetOptionProc,
encapGetOptionProc,
encapWatchProc,
encapGetHandleProc,
nullptr, // close2Proc
encapBlockModeProc,
nullptr, // flushProc
nullptr // handlerProc
2018-09-28 17:54:21 +02:00
};
Tcl_ChannelType tcl_encap_type_stderr = {
2020-04-13 04:19:22 +02:00
const_cast<char *>("file"),
TCL_CHANNEL_VERSION_2,
encapCloseProc,
encapInputProc,
encapErrorOutputProc,
encapSeekProc,
encapSetOptionProc,
encapGetOptionProc,
encapWatchProc,
encapGetHandleProc,
nullptr, // close2Proc
encapBlockModeProc,
nullptr, // flushProc
nullptr // handlerProc
2018-09-28 17:54:21 +02:00
};
#else
// Tcl 8.2
Tcl_ChannelType tcl_encap_type_stdout = {
2020-04-13 04:19:22 +02:00
const_cast<char *>("file"),
encapBlockModeProc,
encapCloseProc,
encapInputProc,
encapOutputProc,
encapSeekProc,
encapSetOptionProc,
encapGetOptionProc,
encapWatchProc,
encapGetHandleProc,
nullptr // close2Proc
2018-09-28 17:54:21 +02:00
};
Tcl_ChannelType tcl_encap_type_stderr = {
2020-04-13 04:19:22 +02:00
const_cast<char *>("file"),
encapBlockModeProc,
encapCloseProc,
encapInputProc,
encapErrorOutputProc,
encapSeekProc,
encapSetOptionProc,
encapGetOptionProc,
encapWatchProc,
encapGetHandleProc,
nullptr // close2Proc
2018-09-28 17:54:21 +02:00
};
#endif
#endif
#endif
#endif
////////////////////////////////////////////////////////////////
ReportTcl::ReportTcl() :
2020-04-13 04:19:22 +02:00
Report(), interp_(nullptr), tcl_stdout_(nullptr), tcl_stderr_(nullptr),
tcl_encap_stdout_(nullptr), tcl_encap_stderr_(nullptr)
2018-09-28 17:54:21 +02:00
{
}
ReportTcl::~ReportTcl()
{
2019-03-13 01:25:53 +01:00
tcl_encap_stdout_ = nullptr;
tcl_encap_stderr_ = nullptr;
2018-09-28 17:54:21 +02:00
Tcl_UnstackChannel(interp_, tcl_stdout_);
Tcl_UnstackChannel(interp_, tcl_stderr_);
}
// Encapsulate the Tcl stdout and stderr channels to print to the
// report object so that the output from Tcl puts and errors can be
// logged and redirected.
void
ReportTcl::setTclInterp(Tcl_Interp *interp)
{
interp_ = interp;
tcl_stdout_ = Tcl_GetStdChannel(TCL_STDOUT);
tcl_stderr_ = Tcl_GetStdChannel(TCL_STDERR);
2020-04-13 04:19:22 +02:00
tcl_encap_stdout_ = Tcl_StackChannel(interp,
&tcl_encap_type_stdout,
this,
TCL_WRITABLE,
tcl_stdout_);
tcl_encap_stderr_ = Tcl_StackChannel(interp,
&tcl_encap_type_stderr,
this,
TCL_WRITABLE,
tcl_stderr_);
2018-09-28 17:54:21 +02:00
}
size_t
ReportTcl::printConsole(const char *buffer, size_t length)
{
return printTcl(tcl_stdout_, buffer, length);
}
size_t
ReportTcl::printErrorConsole(const char *buffer, size_t length)
{
return printTcl(tcl_stderr_, buffer, length);
}
size_t
ReportTcl::printTcl(Tcl_Channel channel, const char *buffer, size_t length)
{
const Tcl_ChannelType *ch_type = Tcl_GetChannelType(channel);
Tcl_DriverOutputProc *output_proc = Tcl_ChannelOutputProc(ch_type);
int error_code;
ClientData clientData = Tcl_GetChannelInstanceData(channel);
2020-04-13 04:19:22 +02:00
return output_proc(clientData,
const_cast<char *>(buffer),
length,
&error_code);
2018-09-28 17:54:21 +02:00
}
// Tcl_Main can eval multiple commands before the flushing the command
// output, so the log/redirect commands must force a flush.
void
ReportTcl::logBegin(const char *filename)
{
Tcl_Flush(tcl_encap_stdout_);
Tcl_Flush(tcl_encap_stderr_);
Report::logBegin(filename);
}
void
ReportTcl::logEnd()
{
if (tcl_encap_stdout_)
Tcl_Flush(tcl_encap_stdout_);
if (tcl_encap_stderr_)
Tcl_Flush(tcl_encap_stderr_);
Report::logEnd();
}
void
ReportTcl::redirectFileBegin(const char *filename)
{
Tcl_Flush(tcl_encap_stdout_);
Tcl_Flush(tcl_encap_stderr_);
Report::redirectFileBegin(filename);
}
void
ReportTcl::redirectFileAppendBegin(const char *filename)
{
Tcl_Flush(tcl_encap_stdout_);
Tcl_Flush(tcl_encap_stderr_);
Report::redirectFileAppendBegin(filename);
}
void
ReportTcl::redirectFileEnd()
{
if (tcl_encap_stdout_)
Tcl_Flush(tcl_encap_stdout_);
if (tcl_encap_stderr_)
Tcl_Flush(tcl_encap_stderr_);
Report::redirectFileEnd();
}
void
ReportTcl::redirectStringBegin()
{
if (tcl_encap_stdout_)
Tcl_Flush(tcl_encap_stdout_);
if (tcl_encap_stderr_)
Tcl_Flush(tcl_encap_stderr_);
Report::redirectStringBegin();
}
const char *
ReportTcl::redirectStringEnd()
{
if (tcl_encap_stdout_)
Tcl_Flush(tcl_encap_stdout_);
if (tcl_encap_stderr_)
Tcl_Flush(tcl_encap_stderr_);
return Report::redirectStringEnd();
}
////////////////////////////////////////////////////////////////
static int
2020-04-13 04:19:22 +02:00
encapOutputProc(ClientData instanceData, CONST84 char *buf, int toWrite, int *)
2018-09-28 17:54:21 +02:00
{
2020-04-13 04:19:22 +02:00
ReportTcl *report = reinterpret_cast<ReportTcl *>(instanceData);
return report->printString(buf, toWrite);
2018-09-28 17:54:21 +02:00
}
static int
2020-04-13 04:19:22 +02:00
encapErrorOutputProc(ClientData instanceData,
CONST84 char *buf,
int toWrite,
int *)
2018-09-28 17:54:21 +02:00
{
2020-04-13 04:19:22 +02:00
ReportTcl *report = reinterpret_cast<ReportTcl *>(instanceData);
return report->printString(buf, toWrite);
2018-09-28 17:54:21 +02:00
}
static int
encapInputProc(ClientData, char *, int, int *)
{
return -1;
}
static int
encapCloseProc(ClientData instanceData, Tcl_Interp *)
{
2020-04-13 04:19:22 +02:00
ReportTcl *report = reinterpret_cast<ReportTcl *>(instanceData);
2018-09-28 17:54:21 +02:00
report->logEnd();
report->redirectFileEnd();
report->redirectStringEnd();
return 0;
}
static int
encapSetOptionProc(ClientData, Tcl_Interp *, CONST84 char *, CONST84 char *)
{
return 0;
}
static int
encapGetOptionProc(ClientData, Tcl_Interp *, CONST84 char *, Tcl_DString *)
{
return 0;
}
static int
encapSeekProc(ClientData, long, int, int *)
{
return -1;
}
static void
encapWatchProc(ClientData, int)
{
}
static int
encapGetHandleProc(ClientData, int, ClientData *)
{
return TCL_ERROR;
}
static int
encapBlockModeProc(ClientData, int)
{
return 0;
}
2020-04-13 04:19:22 +02:00
} // namespace sta