Showing posts with label tcl. Show all posts
Showing posts with label tcl. Show all posts

Friday, 7 October 2011

puts "# 20 != [expr pow($e,$pi)-$pi] http://xkcd.com/217/"

set pi [expr acos(-1)]
puts "# pi=$pi = acos(-1) == [expr atan(1)*4] = atan(1)*4"
# pi=3.141592653589793 = acos(-1) == 3.141592653589793 = atan(1)*4
set e [expr exp(1)]
puts "# e=$e"
# e=2.718281828459045
puts "# 20 != [expr pow($e,$pi)-$pi] http://xkcd.com/217/"
# 20 != 19.99909997918947 http://xkcd.com/217/

Friday, 16 April 2010

Howto tcl copy file and check for error

# is there a better way to check if file copy worked or not in tcl?
proc fileCopy {sFrom sTo} {
    set bUpdateFile 0
    if {[catch {file stat "$sFrom" aFromStat} r]} {
        FAIL "no 'from' file? $sFrom $::errorCode $::errorInfo"
        return
    }
    if {[catch {file stat "$sTo" aToStat} r]} {
        # no to file to compare with, do update
        set bUpdateFile 1
    }
    if {! $bUpdateFile} {
        # compare file stat info: mtime and size
        #log "stat from=[parray aFromStat] to=[parray aToStat] "
        if {$aFromStat(mtime) != $aToStat(mtime) || $aFromStat(size) != $aToStat(size)} {
            set bUpdateFile 1
            log "stat mtime from=$aFromStat(mtime) to=$aToStat(mtime)"
            log "stat size  from=$aFromStat(size)  to=$aToStat(size)"
        } else {
            log "no update needed. stat from=[parray aFromStat {mtime,size}] to=[parray aToStat {mtime,size}]"
            # did nothing
            PASS "update not needed to:$sTo"
        }
    }
    if {$bUpdateFile} {
        log "file copy -force $sFrom $sTo"
        if {[catch {file copy -force "$sFrom" "$sTo"} sError]} {
            FAIL "file copy failed: err:$sError to:$sTo"
    }
        # check for fail (mutters silly tcl manual!? how check success of file copy?)
        if {[catch {file stat "$sTo" aNewToStat} r]} {
            FAIL "cannot check file stat for copied file? to:$sTo"
        } else {
            if {$aFromStat(mtime) == $aNewToStat(mtime) && $aFromStat(size) == $aNewToStat(size)} {
                PASS "update done to:$sTo"
            } else {
                FAIL "update fstat doesn't match to:$sTo"
                parray aFromStat
                parray aNewToStat
            }
        }
    }
}

proc log {s} {
    puts "$s"
}

proc PASS {s} {
    log "PASS: $s"
}

proc FAIL {s} {
    log "FAIL: $s"
}

exec touch a.txt
fileCopy a.txt b.txt
exec rm -f ne.txt
fileCopy ne.txt b.txt

## OH! you must catch calls to file copy!
fileCopy a.txt notexistdir/fu/b.txt
fileCopy a.txt "K:/notexistdir/fu/b.txt"

log "test finish"


OUTPUT:

$ tclsh Tests/OLC/fileCopy.tcl
stat mtime from=1271431590 to=1271431430
stat size  from=0  to=0
file copy -force a.txt b.txt
PASS: update done to:b.txt
FAIL: no 'from' file? ne.txt POSIX ENOENT {no such file or directory} could not read "ne.txt": no such file or directory
    while executing
"file stat "$sFrom" aFromStat"
file copy -force a.txt notexistdir/fu/b.txt
FAIL: file copy failed: err:error copying "a.txt" to "notexistdir/fu/b.txt": no such file or directory to:notexistdir/fu/b.txt
FAIL: cannot check file stat for copied file? to:notexistdir/fu/b.txt
file copy -force a.txt K:/notexistdir/fu/b.txt
FAIL: file copy failed: err:error copying "a.txt" to "K:/notexistdir/fu/b.txt": no such file or directory to:K:/notexistdir/fu/b.txt
FAIL: cannot check file stat for copied file? to:K:/notexistdir/fu/b.txt
test finish


http://wiki.tcl.tk/10068
http://tmml.sourceforge.net/doc/tcl/file.html
http://www.beedub.com/book/2nd/unix.doc.html

HELP! How to get tcl expect session to not wrap lines at 80 columns?

Is it possible to get Windows + tcl + tcl expect session to not wrap lines at 80 columns?
I've spent a couple of days over past few months blipping into try and investigate and solve this but for a simple/stupid thing it's proving troublesome.

Somewhere in a tcl + tcl expect function which telnet's into qnx hardware cards or VMs:

    # I had a big argument trying to get tcl+expect to set it's session to not t
    # runcate columns at 80 chars (which causes various annoying parsing difficu
    # lties). No matter what teminal tcl script was invoked from or what termina
    # l environment/settings were used the expect session negotiated at telnet p
    # rotocol level a terminal with 80 chars width. Also could not solve problem
    # with sttying and setting terminal environment on qnx after login.
    # If anyone can solve this please send info.






Wrapping at 80 chars is very annoying isn't it! But more annoying for trying to parse command-line interaction in a reliable way. Surely this has been solved by someone before? But after googling and grepping web it appears it might not have been ever solved + published on teh hinternet (in keeping with the tcl philosophy of hack it and get it working messily and move on).

    # Wherever tcl is invoked from terminal then settings are passed through int
    # o tcl process (environment set, terminal escapes, stty), and THESE are pas
    # sed into telnet process invoked by tcl. BUT tcl + expect + telnet windows
    # telnet sends NegotiateWindowSize 80x25 no matter what else is done.
    # If a telnet session running in windows terminal or putty has window resize
    # then telnet option messages are sent again. For now I can't find how to te
    # ll that telnet session to set column width. Setting stty rows/cols or send
    # ing ansi escape sequences doesn't seem to have an effect.




I have some wireshark logs with the telnet negotiation packets captured. I suppose we also have tcl expect source code ... but it is the telnet invoked which queries the environment it has and decides column setting to use.   

    # This causes Invalid telnet packet sent:
    # sent telnetSuboptionBegin Negotiate about window size
    # width \x02\x00 height \x00\x35
    #olc::sendCli "\xff\xfa\x1f\x02\x00\x00\x35\xff\xf0"
 

stty-ing (or changing terminal program used) before tcl called or inside tcl before expect session started or sending ansi/other ESC sequences didn't work for me.

    # stty rows 52 columns 512 < $spawn_out(slave,name)
    # log::logarray expect_out
    # log::logarray spawn_out
    #LOG: log::logarray:spawn_out(slave,name) = ExpectInjector_pid8148
    #?×?×?×8L?×ÐÝ: redirection not supported on Windows NT
    #(ù8ùHùàmXùhùÀn: redirection not supported on Windows NT


Tried lots of different things but need to collect information on what works and how it works:

[Windows application] - [tclsh - [tcl expect - [spawn telnet]]] - [QNX VM or hardware]

Try Windows application =
 cygwin rxvt
 windows shell
 eclipse (running tcl with DLTK plugin)

Try outside tcl telnet in from each application, then  each of these:
 * resizing window possible? + results in line wrapping? Negotiated at telnet level?
 * stty settings before telnet
 * stty settings on qnx after telnet in
 * control using ansi ESC codes: disable line wrap OR set terminal width (OR other settings)

Try inside tcl invoked from each application and try each of the above and add:
 * in tcl set stty things
 * in tcl set environment things
 * in tcl expect set things


Last thing: try all of the above from a linux machine with equivalent linux applications (terminal tool, xterm, eclipse).

Too many variants affect the problem!
It comes down to what qnx's bash does with it's output SO would be good if we could start there.
So ansi ESC codes / environment settings?


Tuesday, 23 February 2010

Questions about tcl for job interviews, thoughts on tcl quirks

Tricky question. "What is a simple question and answer that would give us confidence that they knew TCL?"

Try and set up interview so your candidate can write code. You can’t determine it with one question I think but you can if you get them to write a function. Incidentally The Gureilla Guide to Interviewing by Joel Spolsky FogCreek is very good on technical/software interviews.

One question might be what kinds of different data types are available by default in tcl?
Answer1: in tcl, “everything is a string” (but lots of people who know tcl mightn’t get this!)
Answer2: There is default support for list and array. And normal var types would be considered integers/floats/strings.
“everything is a string” means there is no type protection
Data types are supported by the way they are treated in procedures.


Write a procedure (that would require a while or for loop) to calculate something.
Show how this can be called and print the answer.
e.g. calculate the sum of a list

# my answer
proc calc_sum_of_list { list } {
set sum 0
foreach a $list {
# OR if you're a real tcler here use: incr sum $a
set sum [expr $sum + $a]
}
return $sum
}

# how this is called
set mList [list 1 2 3 4]
puts “sum of list result: [calc_sum_of_list $mList]”

# OR
set mList [list 1 2 3 4]
set result [calc_sum_of_list $mList]
puts “sum of list result: $result”


Simpler questions:

How do you set a variable?
Answer: set a 40

How do you increment an integer variable?
Answer: incr a

How do you decrement?
Answer: incr a -1

How to you print a variable?
Answer: puts $a
OR puts “a is $a”
OR puts [format “a is %d = 0x%08x, string %s” $a $a “string”]
OR ...



A fundamental tcl question: Are spaces needed in tcl in for/while/if loops?
Answer: YES tcl has a couple of really awkward quirks.

e.g. valid tcl:
set a 20
if {$a > 4} {
puts “$a is bigger than 4”
}

Invalid:
set a 20
if{$a > 4} {
puts “$a is bigger than 4”
}

invalid command name "if{20"

Invalid:
set a 20
if {$a > 4}
{
puts “$a is bigger than 4”
}

wrong # args: no script following "{$a > 4}" argument
invalid command name "
puts "$a is bigger than 4"
"



Another fundamental question: In tcl what brackets in comments might cause problems (especially if they’re not balanced in comments)?
Answer: Curley brackets {} cause problems. parenthesis () or square [] or anything else don’t cause problems in comments.

Pure and even very impure software people who haven't encountered tcl before have probably already WTFed several times and swooned away by now. Must be because tcl syntax was defined by one of those hardware people! :-P i.e. Possibly a very practical person who has made a very gluey language with a few glaring hairy things remaining in the syntax (possibly on purpose to scare/annoy computer science philosophers).
Please excuse me hardware and software people alike :)
Tcl language syntax overview
Why is tcl syntax so weird?on wiki.tcl.tk
syntax related pages on wiki.tcl.tk
Ousterhout
John Ousterhout on tcl history
wikipedia.org:Tcl

Friday, 11 September 2009

a tcl launcher for XQual XStudio ...

It was trivial to modify the XQual XStudio launcher for perl to work for tcl (ActiveTcl).
It is working for very simple tcl scripts with ActiveTcl 8.5 (and with modification with 8.4).

Change the perl CLauncherImpl.java thusly:
s/perl/tcl/gi; s/\.pl/\.tcl/g;
Tcl interpreter: C:/Tcl/bin/tclsh85.exe

It implements the same test interface as XStudio perl (and other):
* Test generates log.txt with lines including [Success] or [Failure] or [Log].
* Test is deemed complete when a file test_completed.txt is created.

Note for XQual XStudio:
* tools seems very nice to use, developer good - closed source though ...
* source code for test launchers is provided in XAgent and XStudio dir trees.
* there doesn't seem to be a Developers Guide though it is referred to (there are javadocs)
* a launcher has 4 files (e.g. for tcl) tcl.jar and tcl.xml in launchers/, tcl/CLauncherImpl.java and buildTclLauncher.bat in src/*/ and build/

I've been evaluating using XQual XStudio as a test invoking tool. As opposed to Salome_tmf.
http://www.xqual.com/
http://xqual.freeforums.org/evaluating-test-tools-xqual-xstudio-salome-tmf-t349.html


Files here:
http://www.dspsrv.com/~jamesc/torture/work/tool_xqual_xstudio/

/*
+----------------------------------------------------------------------+
| Class: CLauncher |
| |
| Developer: Eric Gavaldo (egavaldo@xqual.com) |
| Jumbo |
| James Coleman (jamesc@dspsrv.com) |
| |
+----------------------------------------------------------------------+
*/

/*
This file was created by changing the perl CLauncherImpl.java
s/perl/tcl/gi; s/\.pl/\.tcl/g;
It has been tested with ActiveTcl, tcl interpreter: C:/Tcl/bin/tclsh85.exe

It implements the same test interface as XStudio perl (and other).
Test generates log.txt with lines including [Success] or [Failure]
or [Log]. Test is deemed complete when a file test_completed.txt is created.
*/

package com.xqual.xlauncher.tcl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.Vector;

import com.xqual.xagent.launcher.CExecutionStep;
import com.xqual.xagent.launcher.CLauncher;
import com.xqual.xagent.launcher.CParamParsingException;
import com.xqual.xagent.launcher.CReturnStatus;
import com.xqual.xagent.launcher.runner.CRunner;
import com.xqual.xagent.launcher.runner.IRunner;
import com.xqual.xcommon.CAttribute;
import com.xqual.xcommon.IConstantsResults;
import com.xqual.xlauncher.CTimeoutListener;

/**
* The CLauncherImpl implementation of ILauncher for Tcl.
* @author egavaldo & jumbo & jamesc
*/
public class CLauncherImpl extends CLauncher implements IConstantsResults {

// +==============================================================+
// | Attributes |
// +==============================================================+

static final String TRACE_HEADER = "{tcl } ";

// parameters impacting executing at run time set by the test operator
private String testRootPath;
private int timeout = 600;
private String tclInstallPath;
private File tclInterpreter;

private File workingDir;

private static final String TCL_INTERPRETER_EXE = "tclsh85.exe";

// +==============================================================+
// | Constructors |
// +==============================================================+

public CLauncherImpl() {
super(TRACE_HEADER);
}

// +==============================================================+
// | Methods |
// +==============================================================+

public CReturnStatus initialize(int sutId, String sutName, String sutVersion) {
setSutDetails(sutId, sutName, sutVersion);

// check the configuration sent by the manager
printConfiguration();

Vector executionSteps = new Vector();
try {
// retrieve the parameters we need
testRootPath = getStringParamValue("General", "Test root path");
timeout = getIntegerParamValue("General", "Asynchronous timeout (in seconds)");

tclInstallPath = getStringParamValue("Tcl", "Tcl install path");
tclInterpreter = new File(tclInstallPath + "\\" + TCL_INTERPRETER_EXE);
} catch (CParamParsingException e) {
traceln(LOG_PRIORITY_SEVERE, "parsing error during initialization");
executionSteps.add(new CExecutionStep(RESULT_FAILURE, "Exception during initialize: " + e.getMessage()));
return new CReturnStatus(RESULT_FAILURE, executionSteps);
}
return new CReturnStatus(RESULT_SUCCESS, executionSteps);
}

public CReturnStatus preRun(int testId, String testPath, String testName, Vector attributes) {
traceln(LOG_PRIORITY_INFO, "preRun testId=" + testId + " testPath=" + testPath + ":" + testName + "...");
Vector executionSteps = new Vector();
return new CReturnStatus(RESULT_SUCCESS, executionSteps);
}

public CReturnStatus run(int testId, String testPath, String testName, int testcaseIndex) {
traceln(LOG_PRIORITY_INFO, "run testId=" + testId + " testPath=" + testRootPath + "/" + testPath + "/" + testName + " testcaseIndex=" + testcaseIndex + "...");
Vector executionSteps = new Vector();

String scriptParentFolderPath = testRootPath + "/" + testPath + "/";
workingDir = new File(scriptParentFolderPath);

// +------------------------------------+
// | Interpret the script
// +------------------------------------+
CRunner tclRunner = new CRunner("[" + testId + "] "+ testPath + ":" + testName + "." + testcaseIndex,
tclInterpreter.toString() + " " + testRootPath + "/" + testPath + "/" + testName + ".tcl " +
"/debug " +
"/testcaseIndex=" + testcaseIndex,
workingDir);
short result = tclRunner.requestAction(IRunner.START_PROCESS, IRunner.DO_NOT_WAIT_END_OF_EXECUTION);
if (result == RESULT_FAILURE) {
executionSteps.add(new CExecutionStep(RESULT_FAILURE, "script interpretation failed"));
return new CReturnStatus(RESULT_FAILURE, executionSteps);
}

// to check if the execution completed correctly, we need to check if the "test_completed.txt" has been created
short resultTimeout = CTimeoutListener.waitForFile(new File(workingDir + "/test_completed.txt"), timeout);
if (resultTimeout != RESULT_SUCCESS) {
executionSteps.add(new CExecutionStep(RESULT_SUCCESS, "timeout of " + timeout + " seconds to execute the test case expired"));
return new CReturnStatus(RESULT_FAILURE, executionSteps);
}

return parseResultFile(executionSteps);
}

public CReturnStatus postRun(int testId, String testPath, String testName) {
traceln(LOG_PRIORITY_INFO, "postRun testId=" + testId + " testPath=" + testPath + ":" + testName + "...");
Vector executionSteps = new Vector();
executionSteps.add(new CExecutionStep(RESULT_SUCCESS, "postRun: succeeded"));
return new CReturnStatus(RESULT_SUCCESS, null);
}

public CReturnStatus terminate() {
Vector executionSteps = new Vector();
executionSteps.add(new CExecutionStep(RESULT_SUCCESS, "Terminate"));
return new CReturnStatus(RESULT_SUCCESS, executionSteps);
}

// +--------------------------+
// ¦ Utilities ¦
// +--------------------------+

private CReturnStatus parseResultFile(Vector executionSteps) {
// parse the result file to get the result and the execution steps
File resultFile = new File(workingDir + "/log.txt");
if (!resultFile.exists()) {
traceln(LOG_PRIORITY_SEVERE, "Result file not found!");
executionSteps.add(new CExecutionStep(RESULT_FAILURE, "run: result file not found!"));
return new CReturnStatus(RESULT_FAILURE, executionSteps);
} else {
executionSteps.add(new CExecutionStep(RESULT_SUCCESS, "run: result file found"));
}

String line, message;
boolean errorDetected = false;

try {
FileInputStream fileInputStream = new FileInputStream(resultFile);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));

while ((line = bufferedReader.readLine()) != null) {
line = line.trim();
System.out.println(">" + line);
if (line.indexOf("[Success]")>=0) {
message = line.substring(10, line.length()); // [Success] length = 9
executionSteps.add(new CExecutionStep(RESULT_SUCCESS, message));

} else if (line.indexOf("[Failure]")>=0) {
message = line.substring(10, line.length());
executionSteps.add(new CExecutionStep(RESULT_FAILURE, message));
errorDetected = true;

} else if (line.indexOf("[Log]")>=0) {
message = line.substring(6, line.length());
executionSteps.add(new CExecutionStep(RESULT_UNKNOWN, message));

} else {
//traceln(LOG_PRIORITY_SEVERE, "unknown tag!");
}
}

} catch (Exception e) {
traceln(LOG_PRIORITY_SEVERE, "exception whle parsing the result file: " + e);
executionSteps.add(new CExecutionStep(RESULT_FAILURE, "Exception whle parsing the result file: " + e));
errorDetected = true;
}

if (errorDetected) {
return new CReturnStatus(RESULT_FAILURE, executionSteps);
} else {
return new CReturnStatus(RESULT_SUCCESS, executionSteps);
}
}
}