Finally got around to fixing the "logcommands" command, which has
been broken ever since moving to the Tcl/Tk wrapped version. Added some new features that allow background commands from the window handling (like pointer tracking) to be omitted from the log file via a suspend/resume function. Added a header file and a few commands at the top of the log file that align the log file contents with the screen and box state at the start of logging. This makes a log file which can be "played back" by sourcing it from the magic console prompt. Per request from Harald Pretl.
This commit is contained in:
parent
ca469510d5
commit
c8a2d06e08
|
|
@ -20,10 +20,20 @@
|
||||||
|
|
||||||
<H2>logcommands</H2>
|
<H2>logcommands</H2>
|
||||||
<HR>
|
<HR>
|
||||||
Log all commands into a file
|
Log all commands and mouse button actions into a file
|
||||||
<HR>
|
<HR>
|
||||||
|
|
||||||
<H3>Usage:</H3>
|
<H3>Usage:</H3>
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<B>logcommands</B> <I>option</I> [<I>file</I>] <BR><BR>
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
where <I>option</I> is one of: <B>start</B>, <B>stop</B>,
|
||||||
|
<B>update</B>, <B>suspend</B>, or <B>resume</B>, and
|
||||||
|
<I>file</I> is the name of the log file to write to.
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
or (legacy usage):
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<B>logcommands</B> [<I>file</I> [<B>update</B>]] <BR><BR>
|
<B>logcommands</B> [<I>file</I> [<B>update</B>]] <BR><BR>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
|
|
@ -33,10 +43,53 @@ Log all commands into a file
|
||||||
|
|
||||||
<H3>Summary:</H3>
|
<H3>Summary:</H3>
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
The <B>logcommands</B> command tells magic to write all
|
The <B>logcommands</B> command creates and manages a file
|
||||||
command-line commands and button pushes to the log file
|
containing all of the command-line commands and button actions
|
||||||
named <I>file</I>. If <B>update</B> is specified, a
|
as they occur while file writing is active. This creates a
|
||||||
screen update is generated after each command executes.
|
recording of the layout session which can be "played back" by
|
||||||
|
sourcing the log file. Behavior is controlled by one of the
|
||||||
|
command options, as follows:
|
||||||
|
<DL>
|
||||||
|
<DT><B>start</B> <I>filename</I>
|
||||||
|
<DD> This opens the log file named <I>filename</I>, writes
|
||||||
|
a header and issues a few rudimentary commands to
|
||||||
|
align the file with the current window size and zoom
|
||||||
|
factor, and the cursor box position. Then it starts
|
||||||
|
recording commands, not including the <B>logcommands</B>
|
||||||
|
command itself.
|
||||||
|
<DT><B>stop</B>
|
||||||
|
<DD> This command closes any open log file and stops recording
|
||||||
|
commands.
|
||||||
|
<DT><B>suspend</B>
|
||||||
|
<DD> This command stops recording commands until the
|
||||||
|
<B>logcommands resume</B> command is issued, without
|
||||||
|
ending or closing the file. This is used by the wrapper
|
||||||
|
script code to prevent some commands such as those that
|
||||||
|
track pointer movement from being added to the log file.
|
||||||
|
<DT><B>resume</B>
|
||||||
|
<DD> This command resumes recording after it has been suspended.
|
||||||
|
<DT><B>update</B>
|
||||||
|
<DD> This command sets a flag that issues a display update
|
||||||
|
command after every command recorded in the log file.
|
||||||
|
This usage is largely deprecated, since sourcing the
|
||||||
|
log file for playback will refresh the display as usual.
|
||||||
|
</DL>
|
||||||
|
|
||||||
|
The legacy syntax "<B>logcommands</B> [<I>file</I> [<B>update</B>]]"
|
||||||
|
will open a new command log file if <I>file</I> is given, optionally
|
||||||
|
with the "update" feature (see above) if the <B>update</B> keyword
|
||||||
|
is added. With no arguments, the log file is ended and closed.
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<H3>Caveats:</H3>
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
The initial header and setup in the log file is rudimentary. It
|
||||||
|
will not attempt to load a technology file, load a layout, or
|
||||||
|
edit some part of a layout to match what is in the layout window
|
||||||
|
at the time that the log file was created. The best usage is to
|
||||||
|
start the log file immediately after starting magic, and only
|
||||||
|
play back the log file in the tech file environment in which it
|
||||||
|
was created.
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
<H3>Implementation Notes:</H3>
|
<H3>Implementation Notes:</H3>
|
||||||
|
|
|
||||||
|
|
@ -243,10 +243,14 @@ proc magic::drcupdate { option } {
|
||||||
}
|
}
|
||||||
|
|
||||||
proc magic::drcstate { status } {
|
proc magic::drcstate { status } {
|
||||||
|
logcommands suspend
|
||||||
set winlist [*bypass windownames layout]
|
set winlist [*bypass windownames layout]
|
||||||
foreach lwin $winlist {
|
foreach lwin $winlist {
|
||||||
set framename [winfo parent $lwin]
|
set framename [winfo parent $lwin]
|
||||||
if {$framename == "."} {return}
|
if {$framename == "."} {
|
||||||
|
logcommands resume
|
||||||
|
return
|
||||||
|
}
|
||||||
switch $status {
|
switch $status {
|
||||||
idle {
|
idle {
|
||||||
set dct [*bypass drc list count total]
|
set dct [*bypass drc list count total]
|
||||||
|
|
@ -260,6 +264,7 @@ proc magic::drcstate { status } {
|
||||||
busy { ${framename}.titlebar.drcbutton configure -selectcolor yellow }
|
busy { ${framename}.titlebar.drcbutton configure -selectcolor yellow }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
logcommands resume
|
||||||
}
|
}
|
||||||
|
|
||||||
# Create the menu of windows. This is kept separate from the cell manager,
|
# Create the menu of windows. This is kept separate from the cell manager,
|
||||||
|
|
@ -502,6 +507,7 @@ proc magic::captions {{subcommand {}}} {
|
||||||
if {$subcommand != {} && $subcommand != "writeable" && $subcommand != "load"} {
|
if {$subcommand != {} && $subcommand != "writeable" && $subcommand != "load"} {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
logcommands suspend
|
||||||
set winlist [magic::windownames layout]
|
set winlist [magic::windownames layout]
|
||||||
foreach winpath $winlist {
|
foreach winpath $winlist {
|
||||||
set framename [winfo parent $winpath]
|
set framename [winfo parent $winpath]
|
||||||
|
|
@ -521,6 +527,7 @@ proc magic::captions {{subcommand {}}} {
|
||||||
"Loaded: ${subcaption1} Editing: ${subcaption2} Tool: $Opts(tool) \
|
"Loaded: ${subcaption1} Editing: ${subcaption2} Tool: $Opts(tool) \
|
||||||
Technology: ${techname}"
|
Technology: ${techname}"
|
||||||
}
|
}
|
||||||
|
logcommands resume
|
||||||
}
|
}
|
||||||
|
|
||||||
# Allow captioning in the title window by tagging the "load" and "edit" commands
|
# Allow captioning in the title window by tagging the "load" and "edit" commands
|
||||||
|
|
@ -655,8 +662,12 @@ proc magic::cursorview {win} {
|
||||||
if {$win == {}} {
|
if {$win == {}} {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
logcommands suspend
|
||||||
set framename [winfo parent $win]
|
set framename [winfo parent $win]
|
||||||
if {[catch {set cr [*bypass cif scale out]}]} {return}
|
if {[catch {set cr [*bypass cif scale out]}]} {
|
||||||
|
logcommands resume
|
||||||
|
return
|
||||||
|
}
|
||||||
if {$cr == 0} {return}
|
if {$cr == 0} {return}
|
||||||
set olst [${win} cursor internal]
|
set olst [${win} cursor internal]
|
||||||
|
|
||||||
|
|
@ -671,7 +682,10 @@ proc magic::cursorview {win} {
|
||||||
if {[catch {
|
if {[catch {
|
||||||
set olstx [expr {$olstx * $cr}]
|
set olstx [expr {$olstx * $cr}]
|
||||||
set olsty [expr {$olsty * $cr}]
|
set olsty [expr {$olsty * $cr}]
|
||||||
}]} {return}
|
}]} {
|
||||||
|
logcommands resume
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if {[${win} box exists]} {
|
if {[${win} box exists]} {
|
||||||
set dlst [${win} box position]
|
set dlst [${win} box position]
|
||||||
|
|
@ -685,20 +699,24 @@ proc magic::cursorview {win} {
|
||||||
set titletext [format "(%+g %+g) microns" $olstx $olsty]
|
set titletext [format "(%+g %+g) microns" $olstx $olsty]
|
||||||
${framename}.titlebar.pos configure -text $titletext
|
${framename}.titlebar.pos configure -text $titletext
|
||||||
}
|
}
|
||||||
|
logcommands resume
|
||||||
}
|
}
|
||||||
|
|
||||||
proc magic::toolupdate {win {yesno "yes"} {layerlist "none"}} {
|
proc magic::toolupdate {win {yesno "yes"} {layerlist "none"}} {
|
||||||
global Winopts
|
global Winopts
|
||||||
|
|
||||||
if {[magic::display] == "NULL"} {return}
|
if {[magic::display] == "NULL"} {return}
|
||||||
|
logcommands suspend
|
||||||
if {$win == {}} {
|
if {$win == {}} {
|
||||||
set win [magic::windownames]
|
set win [magic::windownames]
|
||||||
}
|
}
|
||||||
|
|
||||||
# Wind3d has a "see" function, so make sure this is not a 3d window
|
# Wind3d has a "see" function, so make sure this is not a 3d window
|
||||||
if {$win == [magic::windownames wind3d]} {
|
if {$win == [magic::windownames wind3d]} {
|
||||||
|
logcommands resume
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
logcommands resume
|
||||||
|
|
||||||
set topname [winfo toplevel $win]
|
set topname [winfo toplevel $win]
|
||||||
set framename [winfo parent $win]
|
set framename [winfo parent $win]
|
||||||
|
|
@ -939,11 +957,15 @@ proc magic::techrebuild {winpath {cmdstr ""}} {
|
||||||
proc magic::setscrollvalues {win} {
|
proc magic::setscrollvalues {win} {
|
||||||
global Opts
|
global Opts
|
||||||
|
|
||||||
|
logcommands suspend
|
||||||
set svalues [${win} view get]
|
set svalues [${win} view get]
|
||||||
set bvalues [${win} view bbox]
|
set bvalues [${win} view bbox]
|
||||||
|
|
||||||
set framename [winfo parent ${win}]
|
set framename [winfo parent ${win}]
|
||||||
if {$framename == "."} {return}
|
if {$framename == "."} {
|
||||||
|
logcommands resume
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
set bwidth [expr {[lindex $bvalues 2] - [lindex $bvalues 0]}]
|
set bwidth [expr {[lindex $bvalues 2] - [lindex $bvalues 0]}]
|
||||||
set bheight [expr {[lindex $bvalues 3] - [lindex $bvalues 1]}]
|
set bheight [expr {[lindex $bvalues 3] - [lindex $bvalues 1]}]
|
||||||
|
|
@ -985,6 +1007,7 @@ proc magic::setscrollvalues {win} {
|
||||||
|
|
||||||
proc magic::scrollupdate {win} {
|
proc magic::scrollupdate {win} {
|
||||||
|
|
||||||
|
logcommands suspend
|
||||||
if {[magic::display] == "NULL"} {return}
|
if {[magic::display] == "NULL"} {return}
|
||||||
if {[info level] <= 1} {
|
if {[info level] <= 1} {
|
||||||
|
|
||||||
|
|
@ -1001,6 +1024,7 @@ proc magic::scrollupdate {win} {
|
||||||
magic::setscrollvalues $win
|
magic::setscrollvalues $win
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
logcommands resume
|
||||||
}
|
}
|
||||||
|
|
||||||
# scrollview: update the magic display to match the
|
# scrollview: update the magic display to match the
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,9 @@ extern unsigned char TxInputRedirect;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define TX_LOG_UPDATE 1 /* Update display after every log command */
|
||||||
|
#define TX_LOG_SUSPEND 2 /* Suspend output logging */
|
||||||
|
|
||||||
extern int TxCurButtons;
|
extern int TxCurButtons;
|
||||||
|
|
||||||
/* These should really be defined by the application, not hard-coded */
|
/* These should really be defined by the application, not hard-coded */
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ static char rcsid[] __attribute__ ((unused)) ="$Header: /usr/cvsroot/magic-8.0/t
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "tcltk/tclmagic.h"
|
#include "tcltk/tclmagic.h"
|
||||||
#include "utils/magsgtty.h"
|
#include "utils/magsgtty.h"
|
||||||
|
|
@ -614,11 +615,11 @@ TxClearPoint()
|
||||||
}
|
}
|
||||||
|
|
||||||
static FILE *txLogFile = NULL;
|
static FILE *txLogFile = NULL;
|
||||||
bool txLogUpdate;
|
unsigned char txLogFlags;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
* TxLogCommands --
|
* TxLogStart --
|
||||||
*
|
*
|
||||||
* Log all further commands to the given file name. If the file is NULL,
|
* Log all further commands to the given file name. If the file is NULL,
|
||||||
* turn off logging.
|
* turn off logging.
|
||||||
|
|
@ -632,21 +633,165 @@ bool txLogUpdate;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
TxLogCommands(fileName, update)
|
TxLogStart(fileName, mw)
|
||||||
char *fileName;
|
char *fileName;
|
||||||
bool update; /* Request a screen update after each command */
|
MagWindow *mw; /* Window commands are logged from */
|
||||||
{
|
{
|
||||||
if (txLogFile != NULL)
|
if (txLogFile != NULL)
|
||||||
{
|
{
|
||||||
(void) fclose(txLogFile);
|
TxError("There is already a log file (%s) open!\n", txLogFile);
|
||||||
txLogFile = NULL;
|
return;
|
||||||
}
|
}
|
||||||
if (fileName == NULL) return;
|
|
||||||
|
|
||||||
txLogUpdate = update;
|
txLogFlags = 0;
|
||||||
txLogFile = fopen(fileName, "w");
|
txLogFile = fopen(fileName, "w");
|
||||||
if (txLogFile == NULL)
|
if (txLogFile == NULL)
|
||||||
TxError("Could not open file '%s' for writing.\n", fileName);
|
TxError("Could not open file '%s' for writing.\n", fileName);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
time_t t_stamp = time((time_t *)NULL);
|
||||||
|
struct tm *clock = localtime(&t_stamp);
|
||||||
|
char *now = ctime(&t_stamp);
|
||||||
|
|
||||||
|
TxPrintf("Logging commands to file \"%s\"\n", fileName);
|
||||||
|
/* Write comment line header into command file and log the current
|
||||||
|
* window view position so that cursor positions in the file match
|
||||||
|
* the layout. If the cursor box is defined, then issue a "box
|
||||||
|
* values" command so that relative box adjustments are correct.
|
||||||
|
*/
|
||||||
|
#ifdef MAGIC_WRAPPER
|
||||||
|
fprintf(txLogFile, "# Magic command log file\n");
|
||||||
|
fprintf(txLogFile, "# Using technology: %s\n", DBTechName);
|
||||||
|
if (mw != NULL)
|
||||||
|
fprintf(txLogFile, "# Title: %s\n", mw->w_caption);
|
||||||
|
fprintf(txLogFile, "# Date: %s", now);
|
||||||
|
#endif
|
||||||
|
if (mw != NULL)
|
||||||
|
{
|
||||||
|
CellDef *rootBoxDef;
|
||||||
|
Rect rootBox;
|
||||||
|
|
||||||
|
#ifndef MAGIC_WRAPPER
|
||||||
|
// Colon preceeds commands in the non-Tcl verson of the log file.
|
||||||
|
fprintf(txLogFile, ":");
|
||||||
|
#endif
|
||||||
|
fprintf(txLogFile, "view %di %di %di %di\n",
|
||||||
|
mw->w_surfaceArea.r_xbot, mw->w_surfaceArea.r_ybot,
|
||||||
|
mw->w_surfaceArea.r_xtop, mw->w_surfaceArea.r_ytop);
|
||||||
|
if (ToolGetBox(&rootBoxDef, &rootBox))
|
||||||
|
{
|
||||||
|
fprintf(txLogFile, "box values %di %di %di %di\n",
|
||||||
|
rootBox.r_xbot, rootBox.r_ybot,
|
||||||
|
rootBox.r_xtop, rootBox.r_ytop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* TxLogStop --
|
||||||
|
*
|
||||||
|
* Turn off logging.
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* None.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* File IO.
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
TxLogStop()
|
||||||
|
{
|
||||||
|
if (txLogFile != NULL)
|
||||||
|
{
|
||||||
|
TxPrintf("Ending command logging to file.\n");
|
||||||
|
fclose(txLogFile);
|
||||||
|
txLogFile = NULL;
|
||||||
|
txLogFlags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* TxLogUpdate --
|
||||||
|
*
|
||||||
|
* Set the log file flags to force a display refresh after logged commands
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* None.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* File IO.
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
TxLogUpdate()
|
||||||
|
{
|
||||||
|
if (txLogFile == NULL)
|
||||||
|
{
|
||||||
|
TxError("There is no log file to set an update flag on.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (txLogFlags & TX_LOG_UPDATE)
|
||||||
|
{
|
||||||
|
txLogFlags &= ~TX_LOG_UPDATE;
|
||||||
|
TxPrintf("No display refresh after logged commands.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
txLogFlags |= TX_LOG_UPDATE;
|
||||||
|
TxPrintf("Forcing display refresh after logged commands.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* TxLogSuspend --
|
||||||
|
*
|
||||||
|
* Suspend command logging
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* None.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* File IO.
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
TxLogSuspend()
|
||||||
|
{
|
||||||
|
if (txLogFile == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
txLogFlags |= TX_LOG_SUSPEND;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* TxLogResume --
|
||||||
|
*
|
||||||
|
* Resume command logging
|
||||||
|
*
|
||||||
|
* Results:
|
||||||
|
* None.
|
||||||
|
*
|
||||||
|
* Side effects:
|
||||||
|
* File IO.
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
TxLogResume()
|
||||||
|
{
|
||||||
|
if (txLogFile == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
txLogFlags &= ~TX_LOG_SUSPEND;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -681,25 +826,61 @@ txLogCommand(cmd)
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef MAGIC_WRAPPER
|
||||||
|
char *pfix = "";
|
||||||
|
#else
|
||||||
|
char *pfix = ":";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Do not do anything if there is no log file */
|
||||||
if (txLogFile == (FILE *) NULL) return;
|
if (txLogFile == (FILE *) NULL) return;
|
||||||
|
|
||||||
if (cmd->tx_wid >= 0) {
|
/* Do not write anything if the log file is suspended */
|
||||||
/* Command has a window associated with it. */
|
if (txLogFlags & TX_LOG_SUSPEND) return;
|
||||||
fprintf(txLogFile, ":setpoint %d %d %d\n",
|
|
||||||
cmd->tx_p.p_x, cmd->tx_p.p_y, cmd->tx_wid);
|
|
||||||
} else {
|
|
||||||
/* No window associated with the command. */
|
|
||||||
fprintf(txLogFile, ":setpoint %d %d\n",
|
|
||||||
cmd->tx_p.p_x, cmd->tx_p.p_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd->tx_argc > 0)
|
if (cmd->tx_argc > 0)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
fprintf(txLogFile, ":%s", cmd->tx_argv[0]);
|
char *postns;
|
||||||
|
|
||||||
|
/* Do not output "logcommand" commands to the log file.
|
||||||
|
* Do not output "*bypass" commands to the log file.
|
||||||
|
*/
|
||||||
|
postns = strstr(cmd->tx_argv[0], "::");
|
||||||
|
if (postns == NULL)
|
||||||
|
postns = cmd->tx_argv[0];
|
||||||
|
else
|
||||||
|
postns += 2;
|
||||||
|
|
||||||
|
if (!strncmp(postns, "logc", 4))
|
||||||
|
return;
|
||||||
|
else if (!strcmp(postns, "*bypass"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Commands ending in "cursor" should be preceeded by a set point */
|
||||||
|
/* to indicate where the pointer was at the time of the command. */
|
||||||
|
|
||||||
|
if (!strcmp(cmd->tx_argv[cmd->tx_argc - 1], "cursor"))
|
||||||
|
{
|
||||||
|
if (cmd->tx_wid >= 0)
|
||||||
|
{
|
||||||
|
/* Command has a window associated with it. */
|
||||||
|
fprintf(txLogFile, "%ssetpoint %d %d %d\n",
|
||||||
|
pfix, cmd->tx_p.p_x, cmd->tx_p.p_y, cmd->tx_wid);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* No window associated with the command. */
|
||||||
|
fprintf(txLogFile, "%ssetpoint %d %d\n",
|
||||||
|
pfix, cmd->tx_p.p_x, cmd->tx_p.p_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!strcmp(postns, "setpoint")) return;
|
||||||
|
|
||||||
|
fprintf(txLogFile, "%s%s", pfix, cmd->tx_argv[0]);
|
||||||
for (i = 1; i < cmd->tx_argc; i++)
|
for (i = 1; i < cmd->tx_argc; i++)
|
||||||
{
|
{
|
||||||
fprintf(txLogFile, " '%s'", cmd->tx_argv[i]);
|
fprintf(txLogFile, " %s", cmd->tx_argv[i]);
|
||||||
}
|
}
|
||||||
fprintf(txLogFile, "\n");
|
fprintf(txLogFile, "\n");
|
||||||
}
|
}
|
||||||
|
|
@ -722,12 +903,13 @@ txLogCommand(cmd)
|
||||||
default: {ASSERT(FALSE, "txLogCommand"); break; };
|
default: {ASSERT(FALSE, "txLogCommand"); break; };
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(txLogFile, ":pushbutton %s %s\n",
|
fprintf(txLogFile, "%spushbutton %s %s\n",
|
||||||
txButTable[but], txActTable[act]);
|
pfix, txButTable[but], txActTable[act]);
|
||||||
}
|
}
|
||||||
if (txLogUpdate)
|
if (txLogFlags & TX_LOG_UPDATE)
|
||||||
fprintf(txLogFile, ":updatedisplay\n");
|
fprintf(txLogFile, "%supdatedisplay\n", pfix);
|
||||||
(void) fflush(txLogFile);
|
|
||||||
|
fflush(txLogFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1183,6 +1365,8 @@ TxTclDispatch(clientData, argc, argv, quiet)
|
||||||
|
|
||||||
result = WindSendCommand((MagWindow *)clientData, tclcmd, quiet);
|
result = WindSendCommand((MagWindow *)clientData, tclcmd, quiet);
|
||||||
|
|
||||||
|
if (txLogFile != NULL) txLogCommand(tclcmd);
|
||||||
|
|
||||||
TxFreeCommand(tclcmd);
|
TxFreeCommand(tclcmd);
|
||||||
|
|
||||||
// Don't update the command number on bypass commands, or else
|
// Don't update the command number on bypass commands, or else
|
||||||
|
|
|
||||||
|
|
@ -130,9 +130,13 @@ extern void TxSetPoint();
|
||||||
extern int TxGetPoint();
|
extern int TxGetPoint();
|
||||||
extern void TxClearPoint();
|
extern void TxClearPoint();
|
||||||
|
|
||||||
/* Routine to set up command logging.
|
/* Routines to handle command logging.
|
||||||
*/
|
*/
|
||||||
extern void TxLogCommands();
|
extern void TxLogStart();
|
||||||
|
extern void TxLogStop();
|
||||||
|
extern void TxLogUpdate();
|
||||||
|
extern void TxLogSuspend();
|
||||||
|
extern void TxLogResume();
|
||||||
|
|
||||||
|
|
||||||
/* Routines for handling input events. A typical device driver in the
|
/* Routines for handling input events. A typical device driver in the
|
||||||
|
|
|
||||||
|
|
@ -863,18 +863,23 @@ windHelpCmd(w, cmd)
|
||||||
ASSERT(FALSE, windHelpCmd);
|
ASSERT(FALSE, windHelpCmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *logKeywords[] =
|
|
||||||
{
|
|
||||||
"update",
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
* windLogCommandsCmd --
|
* windLogCommandsCmd --
|
||||||
*
|
*
|
||||||
* Log the commands and button pushes in a file.
|
* Log the commands and button pushes in a file.
|
||||||
*
|
*
|
||||||
|
* Syntax:
|
||||||
|
* logcommands start <filename> Open and start a new command log file
|
||||||
|
* logcommands stop End and close a command log file
|
||||||
|
* logcommands update Refresh display after each log command
|
||||||
|
* logcommands suspend Suspend logging of commands
|
||||||
|
* logcommands resume Resume logging of commands
|
||||||
|
*
|
||||||
|
* Legacy syntax:
|
||||||
|
* logcommands <filename> [update] Start a new command log file with updating
|
||||||
|
* logcommands End and close a command log file
|
||||||
|
*
|
||||||
* Results:
|
* Results:
|
||||||
* None.
|
* None.
|
||||||
*
|
*
|
||||||
|
|
@ -883,35 +888,74 @@ static char *logKeywords[] =
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define LOG_CMD_START 0 // Create a new log file (default behavior)
|
||||||
|
#define LOG_CMD_STOP 1 // End a log file and stop logging.
|
||||||
|
#define LOG_CMD_UPDATE 2 // Update display after every logged command.
|
||||||
|
#define LOG_CMD_SUSPEND 3 // Suspend command logging.
|
||||||
|
#define LOG_CMD_RESUME 4 // Resume command logging.
|
||||||
|
|
||||||
void
|
void
|
||||||
windLogCommandsCmd(w, cmd)
|
windLogCommandsCmd(w, cmd)
|
||||||
MagWindow *w;
|
MagWindow *w;
|
||||||
TxCommand *cmd;
|
TxCommand *cmd;
|
||||||
{
|
{
|
||||||
char *fileName;
|
char *fileName = NULL;
|
||||||
bool update;
|
unsigned char flags = 0;
|
||||||
|
int idx = LOG_CMD_STOP;
|
||||||
|
|
||||||
|
static char *logKeywords[] = {"start", "stop", "update", "suspend", "resume", 0};
|
||||||
|
|
||||||
if ((cmd->tx_argc < 1) || (cmd->tx_argc > 3)) goto usage;
|
if ((cmd->tx_argc < 1) || (cmd->tx_argc > 3)) goto usage;
|
||||||
|
|
||||||
update = FALSE;
|
if (cmd->tx_argc > 1)
|
||||||
|
{
|
||||||
if (cmd->tx_argc == 1)
|
idx = Lookup(cmd->tx_argv[1], logKeywords);
|
||||||
fileName = NULL;
|
if (idx < 0) fileName = cmd->tx_argv[1];
|
||||||
else
|
|
||||||
fileName = cmd->tx_argv[1];
|
|
||||||
|
|
||||||
if (cmd->tx_argc == 3) {
|
|
||||||
int i;
|
|
||||||
i = Lookup(cmd->tx_argv[cmd->tx_argc - 1], logKeywords);
|
|
||||||
if (i != 0) goto usage;
|
|
||||||
update = TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TxLogCommands(fileName, update);
|
if (cmd->tx_argc == 3)
|
||||||
return;
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (fileName == NULL)
|
||||||
|
fileName = cmd->tx_argv[2];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Legacy behavior: Allow "logcommands <filename> update"
|
||||||
|
* to mean "logcommands start <filename> ; logcommands update"
|
||||||
|
*/
|
||||||
|
i = Lookup(cmd->tx_argv[2], logKeywords);
|
||||||
|
if (i != LOG_CMD_UPDATE) goto usage;
|
||||||
|
flags = TX_LOG_UPDATE;
|
||||||
|
idx = LOG_CMD_START;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (idx)
|
||||||
|
{
|
||||||
|
case LOG_CMD_START:
|
||||||
|
if (fileName == NULL) break;
|
||||||
|
TxLogStart(fileName, w);
|
||||||
|
if (flags & TX_LOG_UPDATE)
|
||||||
|
TxLogUpdate();
|
||||||
|
return;
|
||||||
|
case LOG_CMD_STOP:
|
||||||
|
TxLogStop();
|
||||||
|
return;
|
||||||
|
case LOG_CMD_UPDATE:
|
||||||
|
TxLogUpdate();
|
||||||
|
return;
|
||||||
|
case LOG_CMD_SUSPEND:
|
||||||
|
TxLogSuspend();
|
||||||
|
return;
|
||||||
|
case LOG_CMD_RESUME:
|
||||||
|
TxLogResume();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
usage:
|
usage:
|
||||||
TxError("Usage: %s [filename [update]]\n", cmd->tx_argv[0]);
|
TxError("Usage: %s [start|stop|update|suspend|resume [filename]]\n",
|
||||||
|
cmd->tx_argv[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -311,6 +311,24 @@ WindSendCommand(w, cmd, quiet)
|
||||||
if ((WindNewButtons == 0) && (windGrabber != (WindClient) NULL))
|
if ((WindNewButtons == 0) && (windGrabber != (WindClient) NULL))
|
||||||
WindReleaseInput((WindClient) rc);
|
WindReleaseInput((WindClient) rc);
|
||||||
|
|
||||||
|
/* This is a bit of a hack, because it shouldn't be done in so many
|
||||||
|
* places, but the command logging needs to regenerate the setpoint
|
||||||
|
* positions as commands, and it needs the command's Y value to be
|
||||||
|
* correct for the command. It is okay to modify the command's
|
||||||
|
* recorded position value, because logging the command is the only
|
||||||
|
* other thing done with the structure.
|
||||||
|
*/
|
||||||
|
if (w != NULL)
|
||||||
|
{
|
||||||
|
switch (WindPackageType)
|
||||||
|
{
|
||||||
|
case WIND_X_WINDOWS:
|
||||||
|
/* Windows have origin at lower-left corner */
|
||||||
|
cmd->tx_p.p_y = w->w_allArea.r_ytop - cmd->tx_p.p_y;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue