################################################################################ #*TSL-LIBRARY: EMOS_FRM_Lib ################################################################################ #*Copyright (C) 2000 EMOS Computer Consulting GmbH # #*This library is free software; 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.1 of the License, or (at your option) any later version. # #*This library 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 #*Lesser General Public License for more details. # #*You should have received a copy of the GNU Lesser General Public #*License along with this library; if not, write to the Free Software #*Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # #*For further information please contact: # #*Dean Rajovic #*EMOS Computer Consulting GmbH #*Oskar-Messter-Straße 25 #*85737 Ismaning #*Germany #*tel.: +49 89 608 765-0 #*mailto:drajovic@emos.de #*http://www.emos.de ################################################################################ #*$Revision: 1.7 $ #*$Author: drajovic $ #*$Date: 2005/01/24 09:30:36 $ #*$Archive: /MERCURY/TSL_PROJECTS/EMOS_GPL/FRM/emos_frm_lib/script $ #*$NoKeywords: $ ################################################################################ #**# #* This library provides the low-level interface to data tables. You can use the #* function from this library as replacement to standard ddt-functions even if #* you don't need other nice FRM feaures.<p> #* Here we implement our own ddt-interface and add plenty of other functions which #* make this interface very powerful. This library maintains a set of internal #* buffers which hold the table data and numerous other information. One of the #* "side-effects" (but since WR 6.0 one of the most important features) is the #* ability to use the same table from more than one main test within the same #* chain.<p> #* The most important feature of this interface is that you may also index table #* rows by some unique name (very much the same as you index columns by defining #* their names in the first row). For this to work the table MUST contain two #* columns named "IDX" and "Name". To index a row you need to define some name #* in the Name-column and place an "x" in the IDX-column.<p> #* For example imagine a table "Tab.xls" with the following content: #* <table border> #* <tr> <th>IDX</th> <th>Name</th><th>a</th><th>b</th><th>c</th><th>d</th> </tr> #* <tr> <td>x</td> <td>Block1</td> <td>1</td> <td>2</td> <td>3</td> <td>4</td> </tr> #* <tr> <td> </td> <td>1</td> <td>1x1</td> <td>1x2</td> <td>1x3</td> <td>1x4</td> </tr> #* <tr> <td> </td> <td>2</td> <td>1x1</td> <td>2x2</td> <td>3x3</td> <td>4x4</td> </tr> #* <tr> <td>x</td> <td>Block2</td> <td>x</td> <td>y</td> <td>z</td> <td> </td> </tr> #* <tr> <td> </td> <td>a</td> <td>ax</td> <td>ay</td> <td>az</td> <td> </td> </tr> #* <tr> <td> </td> <td>b</td> <td>bx</td> <td>by</td> <td>bz</td> <td> </td> </tr> #* <tr> <td> </td> <td>c</td> <td>cx</td> <td>cy</td> <td>cz</td> <td> </td> </tr> #* </table> #* You could use functions such as<p> #* <code>FRM_get_cell( "Tab.xls", "b", "Block1", val );</code><p> #* to retreive <code>"2"</code> in variable <code>val</code> no matter what row #* used to be active before.<p> #* From then on you could use<p> #* <code>FRM_get_next( "Tab.xls", "b", val );</code><p> #* to retreive <code>"1x2"</code> in variable <code>val</code> and so on. #*<p> PUBLIC VARIABLES #*<ul> #* <li><b>FRM_UNKNOWN</b> Indicates an unknown value.</li> #* <li><b>E_FRM_SKIP</b> Indicates an empty table cell.</li> #* <li><b>FRM_SET_MODE</b> Indicates the SET modus (test data is to be entered).</li> #* <li><b>FRM_CHK_MODE</b> Indicates the CHECK modus (test data is to be verified).</li> #* <li><b>FRM_GEN_MODE</b> Indicates the GENERATE modus (test data is to be generated).</li> #* <li><b>FRM_COL_IDX</b> The default title of the INDEX column.</li> #* <li><b>FRM_COL_NAME</b> The default title of the NAME column.</li> #*</ul> #*/ #** #* Indicates an unknown value. #*/ public const FRM_UNKNOWN = "???"; #** #* Indicates an empty table cell. #*/ public const E_FRM_SKIP = -66601; #** #* Initialization of a test block failed. #*/ public const E_FRM_INIT_BLOCK = -66602; #** #* Initialization of a test block failed. #*/ public const E_FRM_ILLEGAL_MODE = -66603; #** #* Test block not implemented. #*/ public const E_FRM_NOT_IMPLEMENTED = -66604; #** #* Test block unknown. #*/ public const E_FRM_UNKNOWN = -66605; #** #* Stop further execution of current test case. #*/ public const E_FRM_TEST_STOP = -66606; #** #* Stop further execution of current test set. #*/ public const E_FRM_SET_STOP = -66607; #** #* Stop further execution of current test suite. #*/ public const E_FRM_SUITE_STOP = -66608; #** #* Continue execution of the current test case. #*/ public const E_FRM_CONTINUE = -66609; #** #* Retry execution of the current test block. #*/ public const E_FRM_RETRY = -66610; #** #* Indicates the SET modus (test data is to be entered). #*/ public const FRM_SET_MODE = 1; #** #* Indicates the CHECK modus (test data is to be verified). #*/ public const FRM_CHK_MODE = 2; #** #* Indicates the GENERATE modus (test data is to be generated). #*/ public const FRM_GEN_MODE = 3; #** #* Indicates the ATTRIBTE check modus. #*/ public const FRM_ATR_MODE = 4; #** #* The title of the INDEX column. This column is used to mark (x) important rows #* in the data table which can be accessed through their logical name (content #* of OBJECT column). #*/ public const FRM_COL_IDX = "IDX"; #** #* The title of the NAME column. This column is used to define name of the #* particular row. It is used in conjunction with column IDX in the way that #* only the indexed rows must define the unique name. In all other rows (those #* not marked in IDX column) you can put anything you want (a comment, test #* data or nothing). #*/ public const FRM_COL_NAME = "Name"; #** #* Global variable containing return code of the codeb lock executed via #* <&...&> expression. #*/ public __evalRC; #____________________________________________________ #*local constans #____________________________________________________ static const IDX_CURROW = 0; static const IDX_ROWCOUNT = 1; static const IDX_MODE = 2; static const IDX_PARAMS = 3; static const IDX_MODIFIED = 4; #____________________________________________________ #*local variables #____________________________________________________ #*wird inkrementiert für jeden neuen FRM_open() static tabCount = 0; #*Eindimensional, d.h. [ table ] #*1. Dimension: #* - table: Tabellenname static tabs[]; #*Zweidimensional, d.h. [ table, info ] #*1. Dimension: #* - tabidx: Tabellenindex #*2. Dimension: #* - IDX_CURROW: aktive Zeile #* - IDX_ROWCOUNT: anzahl der Zeilen #* - IDX_MODE: Modus #* - IDX_PARAMS: Anzahl geladener Paramteres (d.h. Spalten) #* - IDX_MODIFIED: Indicates whether table was modified or not static tabInfo[]; #*Zweidimensional, d.h. [ table, info ] #*1. Dimension: #* - tabidx: Tabellenindex #*2. Dimension: #* - 0..n: Name des Paramters (Spalte) n=tabInfo[tid,IDX_PARAMS]-1 static tabParam[]; #*Dreidimensional, d.h. [ table, column, [0...n] ] #*1. Dimension: #* - tabidx: Tabellenindex #*2. Dimension: #* - column: Spaltenname #*3. Dimension: #* - 0..n: Inhalt der einzelne Zelle im Zeile 0..n static tabData[]; #*Zweidimensional, d.h. [ table, index ] #*1. Dimension: #* - tabidx: Tabellenindex #*2. Dimension: #* - index: Index ( Inhalt der Spalte "Objekt", #* makiert mit "x" in Spalte "IDX" static tabIdx[]; #*Zweidimensional, d.h. [ table, info ] #*1. Dimension: #* - tabidx: Tabellenindex #*2. Dimension: #* - libname: Name der geladener Bibliothek static tabLibs[]; #*Zweidimensional, d.h. [ tid, info ] #*1. Dimension: #* - tabidx: Tabellenindex #*2. Dimension: #* - GUIname: Name der geladener GUI Map static tabGuis[]; #*Zweidimensional, d.h. [ tid, info ] #*1. Dimension: #* - "": for global variables #* - tabidx: Tabellenindex #*2. Dimension: #* - VARname: Name der Variable static tabVars[]; #** #* Opens a data lt;table> and loads the desired <test>s (columns). #* <p>NOTE<p> #* This routine returns the <code>tid</code> (table ID). Unlike the ddt_ #* you have to use this id when calling other FRM functions. #* #*@param table (in) name of the data table #*@param tests (in) list of columns (comma-separated) #*@param tid (out) table ID #*@return #* E_OK: success #* !E_OK: failure #*/ public function FRM_open( in table, in tests, out tid, in nameSep ) { auto rc, par, val, i; auto name, nameArr[], count; auto params, rows; #auto t1, t2; count = split( table, nameArr, ddt_get_name_sep() ); switch (count) { case 1: nameArr[1] = tolower( nameArr[1] ); name = nameArr[1]; break; case 2: nameArr[1] = tolower( nameArr[1] ); name = nameArr[1] & ddt_get_name_sep() & nameArr[2]; break; default: return E_ILLEGAL_PARAMETER; } # close table if already opened FRM_close( FRM_get_tid( name ) ); rc = DDT_open_table( name ); if ( rc != E_OK ) return rc; # neue Tabelle registrieren tid = tabCount++; tabs[tid] = name; # Tabellenformat prüfen rc = build_params( tid, tests ); if ( rc != E_OK ) { DDT_close_table( name ); FRM_close( tid ); return rc; } # etwas Info speichern ddt_get_current_row( nameArr[1], val ); tabInfo[tid, IDX_CURROW] = val; ddt_get_row_count( nameArr[1], val ); tabInfo[tid, IDX_ROWCOUNT] = val; tabInfo[tid, IDX_MODE] = FRM_SET_MODE; tabInfo[tid, IDX_MODIFIED] = FALSE; # IDX aufbauen rc = build_idx( tid ); if ( rc != E_OK ) { DDT_close_table( name ); FRM_close( tid ); return rc; } params = tabInfo[tid,IDX_PARAMS]; rows = tabInfo[tid,IDX_ROWCOUNT]; #*t1=get_time(); # interne Tabelle aufbauen for( i=0; i < params; i++ ) load_column( tid, tabParam[tid,i], rows ); #*t2=get_time(); #*printf( "Tabelle %s bearbeitet in %s Sekundnen", name, t2-t1 ); DDT_close_table( name ); return E_OK; } #** #* Loads an individual column (test) into an already opened data table. #* #*@param tid (in) table ID #*@param test (in) column name to be loaded #*@return #* E_OK: success #* !E_OK: failure #*/ public function FRM_load_test( in tid, in test ) { auto rc, table, file, params; rc = FRM_is_parameter( tid, test ); if( rc != E_NOT_PARAMETER ) return rc; table = FRM_get_name( tid ); file = FRM_get_filename( tid ); rc = DDT_open_table( table ); if ( rc != E_OK ) return rc; rc = ddt_is_parameter( file, test ); if ( rc != E_OK ) { DDT_close_table( file ); return rc; } params = tabInfo[tid,IDX_PARAMS]; tabParam[tid,params] = test; tabInfo[tid,IDX_PARAMS] = params+1; rc = load_column( tid, test, tabInfo[tid,IDX_ROWCOUNT] ); DDT_close_table( file ); return rc; } #** #* Saves the given table. #* <p>NOTE! #* This funtion only works with WR 6.0 or higher. #* #*@param tid (in) table ID #*@return #* E_OK: success #* !E_OK: failure #*/ public function FRM_save( in tid ) { auto rc, table, file, params, par, rows, i; if ( !FRM_is_modified( tid ) ) return E_OK; table = FRM_get_name( tid ); file = FRM_get_filename( tid ); params = tabInfo[tid,IDX_PARAMS]; rows = tabInfo[tid,IDX_ROWCOUNT]; rc = DDT_open_table( table, DDT_MODE_READWRITE ); if ( rc != E_OK ) return rc; for( i=0; !rc && i < params; i++ ) { par = tabParam[tid,i]; if ( tabData[ tid, par, 0 ] ) rc = save_column( tid, par, rows ); } if ( rc == E_OK ) { rc = ddt_save( file ); for( i=0; i < params; i++ ) { par = tabParam[tid,i]; if ( tabData[ tid, par, 0 ] ) tabData[ tid, par, 0 ] = FALSE; } tabInfo[ tid, IDX_MODIFIED ] = FALSE; } DDT_close_table( file ); return rc; } #** #* Closes the given table and frees occupied memory. #* <p>NOTE! #* If table was modified, it is automatically saved before closing. #* #*@param tid (in) table ID #*@param drop (in) (optional) TRUE: do not save changes (default: FALSE) #*/ public function FRM_close( in tid, in drop ) { auto i, idx, rc = 0; if ( !FRM_is_open( tid ) ) return; if ( !drop ) FRM_save( tid ); idx = tid & ARRSEP; for ( i in tabInfo ) if ( match (i, idx) == 1 ) delete tabInfo[i]; for ( i in tabParam ) if ( match (i, idx) == 1 ) delete tabParam[i]; for ( i in tabData ) if ( match (i, idx) == 1 ) delete tabData[i]; for ( i in tabIdx ) if ( match (i, idx) == 1 ) delete tabIdx[i]; for ( i in tabLibs ) if ( match (i, idx) == 1 ) { unload( tabLibs[i] ); delete tabLibs[i]; } for ( i in tabGuis ) if ( match (i, idx) == 1 ) { rc = GUI_close( tabGuis[i] ); delete tabGuis[i]; } for ( i in tabVars ) if ( match (i, idx) == 1 ) delete tabVars[i]; delete tabs[ tid ]; } #** #* Closes all open tables. By default it automatically saves the changes. #* You can override this by setting <drop> to TRUE. #* #*@param drop (in) (optional) TRUE: do not save changes (default: FALSE) #*/ public function FRM_close_all( in drop ) { auto rc, i; if ( drop ) { # quick close for ( i in tabInfo ) delete tabInfo[i]; for ( i in tabParam ) delete tabParam[i]; for ( i in tabData ) delete tabData[i]; for ( i in tabIdx ) delete tabIdx[i]; for ( i in tabLibs ) { unload( tabLibs[i] ); delete tabLibs[i]; } for ( i in tabGuis ) { rc = GUI_close( tabGuis[i] ); delete tabGuis[i]; } for ( i in tabs ) delete tabs[i]; } else { for ( i in tabs ) FRM_close( i, drop ); } for ( i in tabVars ) delete tabVars[i]; } #** #* Closes all open tables except the specified ones. #* By default it automatically saves the changes. #* You can override this by setting <drop> to TRUE. #* #*@param xtabs[] (inout) array of table names which are NOT to be closed #*@param drop (in) (optional) TRUE: do not save changes (default: FALSE) #*/ public function FRM_close_all_except( inout xtabs[], in drop ) { auto i, j, x, xcount; auto count, nameArr[]; # make it case-insensitive + count xcount = 0; for ( j in xtabs ) { count = split( xtabs[j], nameArr, ddt_get_name_sep() ); switch (count) { case 1: xtabs[j] = tolower( nameArr[1] ); break; case 2: xtabs[j] = tolower( nameArr[1] ) & ddt_get_name_sep() & nameArr[2]; break; } xcount++; } for ( i in tabs ) { x = 0; for ( j in xtabs ) { #printf( "tabs[%s]=%s xtabs[%s]=%s", i, tabs[i], j, xtabs[j] ); if ( tabs[i] == xtabs[j] ) break; x++; } if ( x >= xcount ) # not found FRM_close( i, drop ); } } #** #* Reports whether a given table is open or not. #* #*@param table (in) table name #*@return #* TRUE: table is open #* FALSE: table is not open #*/ public function FRM_is_table_open( in table, out tid ) { auto i; for ( i in tabs ) { if ( tabs[i] == tolower( table ) ) { tid = i; return TRUE; } } return FALSE; } #** #* Reports whether a given table is open or not. #* #*@param tid (in) table ID #*@return #* TRUE: table is open #* FALSE: table is not open #*/ public function FRM_is_open( in tid ) { return ( tid in tabs ); } #** #* Returns the table ID of the corresponding table or empty string ("") if #* table unknown. #* #*@param table (in) table name #*@return table ID orempty string #*/ public function FRM_get_tid( in table ) { auto i, name; name = tolower( table ); for ( i in tabs ) { if ( name == tabs[i] ) return i; } return ""; } #** #* Returns the table name of the corresponding tid or empty string ("") if #* tid unknown. If sheet name was specified with FRM_open(), #* then the name returned includes the sheet name (e.g. c:\tab.xsl#sheet1). #* #*@param tid (in) table ID #*@return table name (including sheet name) or empty string #*/ public function FRM_get_name( in tid ) { if ( tid in tabs ) return tabs[ tid ]; return ""; } #** #* Returns the table name of the corresponding tid or empty string ("") if #* tid unknown. This function ensures that the sheet name is NOT returned. #* For example if FRM_open("c:\tab.xsl#sheet1") was specified, then #* only "c:\tab.xsl" is returned. #* #*@param tid (in) table ID #*@return table name (not including sheet name) or empty string #*/ public function FRM_get_filename( in tid ) { auto nameArr[]; if ( tid in tabs ) { split(tabs[ tid ], nameArr, ddt_get_name_sep() ); return nameArr[1]; } return ""; } #** #* Reports whether a given table is modified or not. #* #*@param tid (in) table ID #*@return #* TRUE: table is modified #* FALSE: table is not modified #*/ public function FRM_is_modified( in tid ) { if ( FRM_is_open( tid ) && tabInfo[ tid, IDX_MODIFIED ] ) return TRUE; return FALSE; } #** #* Positions the focus to the row specified by its name <idx>. If successful, #* the <row> number is returned. #* <p> NOTE! #* The row must be indexed. #* #*@param tid (in) table ID #*@param idx (in) row name/index #*@param row (out) row number #*@return #* E_OK: success #* !E_OK: failure #*/ public function FRM_idx( in tid, in idx, out row ) { if ( !FRM_is_open( tid ) ) return E_FILE_NOT_OPEN; if ( !((tid,idx) in tabIdx) ) return E_ILLEGAL_PARAMETER; row = tabIdx[tid, idx]; return E_OK; } #** #* Loads a library <lib> in scope of the specified <tid>. #* <p>NOTE! #* If table is closed, all libraries in its scope are automatically unloaded. #* #*@param tid (in) table ID #*@param lib (in) library name (full path) #*@param p1 (in) (optional) first parameter to underlying reload statement #*@param p2 (in) (optional) second parameter to underlying reload statement #*@return #* E_OK: success #* !E_OK: failure #*/ public function FRM_load_lib( in tid, in lib, in p1, in p2 ) { auto rc; if ( !FRM_is_open( tid ) ) return E_FILE_NOT_OPEN; if ( (tid,lib) in tabLibs ) return E_OK; # schon geladen rc = reload( lib, (p1==""?0:p1), (p2==""?0:p2) ); if ( rc ) return rc; tabLibs[tid,lib]=lib; return E_OK; } #** #* Loads a GUI map <gui> in scope of the specified <tid>. #* <p>NOTE! #* If table is closed, all GUI maps in its scope are automatically unloaded. #* #*@param tid (in) table ID #*@param gui (in) GUI map name (full path) #*@return #* E_OK: success #* !E_OK: failure #*/ public function FRM_load_gui( in tid, in gui ) { auto rc; if ( !FRM_is_open( tid ) ) return E_FILE_NOT_OPEN; if ( (tid,gui) in tabGuis ) return E_OK; # schon geladen rc = load_GUI( gui ); if ( rc ) return rc; tabGuis[tid,gui]=gui; return E_OK; } #** #* Allocates a new or overwrites an existing variable <var> #* with the initial value <val>. A scope of the variable depends on the #* given <tid> name. #* <p>NOTE! #* If it equals to "" the scope of the variable is is Frame-global. #* Otherwise the variable has table-scope. If table is closed, all variables in #* its scope are automatically unloaded. Global varables are unloaded only with #* FRM_close_all(). #* #*@param tid (in) table ID (scope) or "" for global variables #*@param var (in) variable name #*@param val (in) value to be saved #*@return #* E_OK: success #* !E_OK: failure #*/ public function FRM_setvar( in tid, in var, in val ) { auto rc; if ( tid == "" ) { tabVars[ "", var ] = val; return E_OK; } if ( !FRM_is_open( tid ) ) return E_FILE_NOT_OPEN; tabVars[tid,var] = val; return E_OK; } #** #* Retrieves the value of a given FRM variable <var>. #* A scope of the variable depends on the given <tid> name. #* <p>NOTE! #* If it equals to "" the scope of the variable is is Frame-global. #* Otherwise the variable has table-scope. If table is closed, all variables in #* its scope are automatically unloaded. Global varables are unloaded only with #* FRM_close_all(). #* #*@param tid (in) table ID (scope) or "" for global variables #*@param var (in) variable name #*@param val (out) value retrieved #*@return #* E_OK: success #* !E_OK: failure #*/ public function FRM_getvar( in tid, in var, out val ) { auto rc; if ( tid == "" ) { if ( ("",var) in tabVars ) { val = tabVars[ "", var ]; return E_OK; } return E_NOT_FOUND; } if ( !FRM_is_open( tid ) ) return E_FILE_NOT_OPEN; if ( (tid,var) in tabVars ) { val = tabVars[ tid, var ]; return E_OK; } return E_NOT_FOUND; } #** #* Returns the active frame mode. #* #*@param tid (in) table ID #*@return #* currently active mode (FRM_SET_MODE/FRM_CHK_MODE/FRM_ATR_MODE/FRM_GEN_MODE) or #* E_FILE_NOT_OPEN: table not open #*/ public function FRM_get_mode ( in tid ) { if ( !FRM_is_open( tid ) ) return E_FILE_NOT_OPEN; return tabInfo[ tid,IDX_MODE ]; } #** #* Sets the active frame mode. #* #*@param tid (in) table ID #*@param mode (in) either FRM_SET_MODE, FRM_CHK_MODE, FRM_ATR_MODE or FRM_GEN_MODE #*@return #* E_OK: mode successfully set #* E_FILE_NOT_OPEN: table not open #* E_ILLEGAL_PARAMETER: invalid mode (mode unchanged) #*/ public function FRM_set_mode ( in tid, in mode ) { if ( !FRM_is_open( tid ) ) return E_FILE_NOT_OPEN; switch ( mode ) { case FRM_SET_MODE: case FRM_CHK_MODE: case FRM_ATR_MODE: case FRM_GEN_MODE: tabInfo[ tid,IDX_MODE ] = mode; return E_OK; default: return E_ILLEGAL_PARAMETER; } } #** #* Convert the given <code>mode</code> from one representation to another #* (string2code and code2string). If none of the conversion succeeds, the #* the unchanged value is returned. #* @param mode (in) mode to be converted (either format) #* @return converted mode or unchanged value if no conversion possible #*/ public function FRM_convert_mode( in mode ) { auto m; switch ( toupper(mode) ) { case FRM_SET_MODE: m = "SET"; break; case FRM_CHK_MODE: m = "CHK"; break; case FRM_ATR_MODE: m = "ATR"; break; case FRM_GEN_MODE: m = "GEN"; break; case "SET": m = FRM_SET_MODE; break; case "CHK": m = FRM_CHK_MODE; break; case "ATR": m = FRM_ATR_MODE; break; case "GEN": m = FRM_GEN_MODE; break; default: m = mode; } return m; } #** #* Indicates whether the cell in the next row contains data or not. #* #*@param tid (in) table ID #*@param test (in) test (column) name #*@return #* TRUE: next row contains data #* FALSE: next row contains no data #*/ public function FRM_has_next ( in tid, in test ) { auto rc; auto row, val; rc = FRM_get_current_row ( tid, row ); if ( rc != E_OK ) return FALSE; rc = FRM_get( tid, test, val, row+1 ); if ( rc == E_OK ) return TRUE; return FALSE; } #** #* Returns the content of the cell from the given column (<code>test</code>) #* and the row following the currently active row. #* <p> #* A cell which is supposed to be ignored (an empy cell, a cell that contains no #* data), is indicated with E_FRM_SKIP. If an empty string ("") needs to be used #* as test data, then the cell must contain one of the following two strings #* <<cler>> or <<leer>> (including angle brackets). #* <p>NOTE! #* This routine modifies the currently active row. It does this before fetching #* the value. If an attemp is made to fatch the value beyond the last row, #* E_OUT_OF_RANGE is returned. #* #*@param tid (in) table ID #*@param test (in) test (column) name #*@param val (out) the fetched value #*@return #* E_OK: operation successful, value returned #* E_FRM_SKIP: operation successful, no value returned #* anything else: operation failed #*/ public function FRM_get_next ( in tid, in test, out val ) { auto rc; val = FRM_UNKNOWN; rc = FRM_next_row( tid ); if ( rc != E_OK ) { return FRM_rc( rc, "FRM_get_next", tid, test, val ); } return FRM_get( tid, test, val ); } #** #* Returns the content of the cell specified by the given row (<code>idx</code>) #* and column (<code>test</code>) names. #* <p> #* A cell which is supposed to be ignored (an empy cell, a cell that contains no #* data), is indicated with E_FRM_SKIP. If an empty string ("") needs to be used #* as test data, then the cell must contain one of the following two strings #* <<cler>> or <<leer>> (including angle brackets). #* <p>NOTE! #* For this to work the <idx> must be the content of some row in #* FRM_COL_NAME marked with "x" in FRM_COL_IDX. #* #*@param tid (in) table ID #*@param test (in) test (column) name #*@param idx (in) row name (index) #*@param val (out) the fetched value #*@return #* E_OK: operation successful, value returned #* E_FRM_SKIP: operation successful, no value returned #* anything else: operation failed #*/ public function FRM_get_cell ( in tid, in test, in idx, out val ) { auto rc, row; rc = FRM_idx( tid, idx, row ); if ( rc ) return rc; return FRM_get( tid, test, val, row ); } #** #* Returns the content of the cell specified by the given column name and, #* optionally, with the row number. #* <p> #* A cell which is supposed to be ignored (an empy cell, a cell that contains no #* data), is indicated with E_FRM_SKIP. If an empty string ("") needs to be used #* as test data, then the cell must contain one of the following two strings #* <<cler>> or <<leer>> (including angle brackets). #* <p>NOTE! #* If <code>row</code> is not defined, the current row is used. #* #*@param tid (in) table ID #*@param test (in) test (column) name #*@param val (out) the fetched value #*@param row (in) (optional) row number (default: current row) #*@return #* E_OK: operation successful, value returned #* E_FRM_SKIP: operation successful, no value returned #* anything else: operation failed #*/ public function FRM_get ( in tid, in test, out val, in row ) { auto rc; rc = FRM_is_parameter( tid, test ); if ( rc != E_OK ) return rc; if ( row*1 == 0 ) # parameter nicht vorhanden { val = tabData[tid, test, tabInfo[tid, IDX_CURROW]]; } else { rc = FRM_is_row( tid, row ); if ( rc != E_OK ) return rc; val = tabData[tid, test, row*1]; } return FRM_parse_val( tid, val ); } #/** #* Parses the given value and substitutes FRM keywords. #* If val is empty, then E_FRM_SKIP is returned and val is left unchanged. #* @param tid (in) table ID #* @param val (inout) value to be parsed; eventually modifiedd by parsing #* @return E_OK + val in case of succesful parsing; E_FRM_SKIP in case of #* empty val #*/ public function FRM_parse_val( in tid, inout val ) { extern __evalRC; extern RSTART, RLENGTH; auto t1, t2, t3; if ( val == "" ) { return E_FRM_SKIP; } if ( match( val, "<" ) ) { if ( match( val, "<<[Ll][Ee][Ee][Rr]>>" ) ) { val = ""; return E_OK; } if ( match( val, "<<[Cc][Ll][Ee][Aa][Rr]>>" ) ) { val = ""; return E_OK; } while( match( val, "<<[Tt][Aa][Bb]>>" ) ) # tabulator { t1 = (RSTART>1 ? substr( val, 1, RSTART-1 ) : "" ); t3 = substr( val, RSTART+RLENGTH ); val = t1 & "\t" & t3; } while( match( val, "<$..*$>" ) ) # FRM global-scope variable { t1 = (RSTART>1 ? substr( val, 1, RSTART-1 ) : "" ); FRM_getvar( "", substr( val, RSTART+2, RLENGTH-4 ), t2 ); t3 = substr( val, RSTART+RLENGTH ); val = t1 & t2 & t3; } while( match( val, "<#..*#>" ) ) # FRM table-scope variable { t1 = (RSTART>1 ? substr( val, 1, RSTART-1 ) : "" ); FRM_getvar( tid, substr( val, RSTART+2, RLENGTH-4 ), t2 ); t3 = substr( val, RSTART+RLENGTH ); val = t1 & t2 & t3; } while( match( val, "<%..*%>" ) ) # environment variable { t1 = (RSTART>1 ? substr( val, 1, RSTART-1 ) : "" ); t2 = getenv( substr( val, RSTART+2, RLENGTH-4 ) ); t3 = substr( val, RSTART+RLENGTH ); val = t1 & t2 & t3; } while( match( val, "<!..*!>" ) ) # WinRunner variable { t1 = (RSTART>1 ? substr( val, 1, RSTART-1 ) : "" ); t2 = getvar( substr( val, RSTART+2, RLENGTH-4 ) ); t3 = substr( val, RSTART+RLENGTH ); val = t1 & t2 & t3; } while( match( val, "<&..*&>" ) ) # arbitrary code (eval) { t1 = (RSTART>1 ? substr( val, 1, RSTART-1 ) : "" ); eval( "__evalRC = " & substr( val, RSTART+2, RLENGTH-4 ) & ";" ); t2 = __evalRC; t3 = substr( val, RSTART+RLENGTH ); val = t1 & t2 & t3; } } return E_OK; } #** #* Saves the given value (<code>val</code>) in the cell specified by the column #* name (<code>test</code>) and, optinally, the <code>row</code> number. #* <p>NOTE! #* The change is not made permanent yet. You must call FRM_save() in order #* to transfer your changes back to the Excel table. #* #*@param tid (in) table ID #*@param test (in) test name (column) #*@param val (in) value to be saved #*@param row (in) (optional) row number (default: current row) #*@return #*E_OK: operation successful #*!E_OK: operation failed #*/ public function FRM_set ( in tid, in test, in val, in row ) { auto rc, r; rc = FRM_is_parameter( tid, test ); if ( rc != E_OK ) return rc; if ( row*1 == 0 ) { r = tabInfo[tid, IDX_CURROW]; } else { rc = FRM_is_row( tid, row ); if ( rc != E_OK ) return rc; r=row*1; } tabData[tid, test, r] = val; # update modification flags tabInfo[tid, IDX_MODIFIED] = TRUE; # table-level tabData[tid, test, 0] = TRUE; # column-level return E_OK; } #** #* Returns a two-dimensional block from the table as array. #* <p> #* To define a block in the test table you must format it in a special way. #* An example of one such table follows. #* <table border> #* <tr> <th>IDX</th> <th>Name</th><th>a</th><th>b</th><th>c</th><th>d</th> </tr> #* <tr> <td>x</td> <td>Block1</td> <td>1</td> <td>2</td> <td>3</td> <td>4</td> </tr> #* <tr> <td> </td> <td>1</td> <td>1x1</td> <td>1x2</td> <td>1x3</td> <td>1x4</td> </tr> #* <tr> <td> </td> <td>2</td> <td>1x1</td> <td>2x2</td> <td>3x3</td> <td>4x4</td> </tr> #* <tr> <td> </td> <td><<END>></td> <td> </td> <td> </td> <td> </td> <td></td> </tr> #* <tr> <td>x</td> <td>Block2</td> <td>x</td> <td>y</td> <td>z</td> <td> </td> </tr> #* <tr> <td> </td> <td>a</td> <td>ax</td> <td>ay</td> <td>az</td> <td> </td> </tr> #* <tr> <td> </td> <td>b</td> <td>bx</td> <td>by</td> <td>bz</td> <td> </td> </tr> #* <tr> <td> </td> <td>c</td> <td>cx</td> <td>cy</td> <td>cz</td> <td> </td> </tr> #* <tr> <td> </td> <td><<END>></td> <td> </td> <td> </td> <td> </td> <td> </td> </tr> #* </table> #* #* #*@param tid (in) table ID #*@param idx (in) block index #*@param x (out) nomber of columns #*@param y (out) number of rows #*@param arr[] (out) values #*@return #* E_OK: operation succesfull, values returned #* !E_OK: operation failed #*/ public function FRM_get_block ( in tid, in idx, out x, out y, out arr[] ) { auto rc, row, params, param[], count, val, i; rc = FRM_idx( tid, idx, row ); if ( rc ) return rc; rc = FRM_get_parameters( tid, params, count ); if ( rc ) return rc; rc = FRM_get( tid, FRM_COL_NAME, val, row ); if ( rc ) return rc; arr[0,0] = val; count = split( params, param, "\t" ); for( x=1; x<=count; x++ ) { val = FRM_val_by_row( tid, row, param[x] ); if ( val == "" ) break; arr[0,x] = val; } y=1; while( 1 ) { row++; rc = FRM_get( tid, FRM_COL_NAME, val, row ); if ( rc != E_OK && rc != E_FRM_SKIP ) break; if ( rc == E_FRM_SKIP ) val = ""; if ( match( val, "<<[Ee][Nn][Dd][Ee]*>>" ) > 0 ) break; arr[y,0] = val; for( i=1; i<=count; i++ ) { val = FRM_val_by_row( tid, row, param[i] ); arr[y,i] = val; } y++; } return rc; } #** #* Executes the content of the next cell. #* #*@param tid (in) table ID #*@param rows (in) column name #*/ public function FRM_exec ( in tid, in test ) { auto val, cmd[], count, i; auto rc = FRM_get_next( tid, test, val ); switch ( rc ) { case E_OK: break; case E_FRM_SKIP: return E_OK; default: return rc; } count = split( val, cmd, ";" ); for( i=1; i<=count; i++ ) eval( cmd[i] & ";" ); } #** #* Skips the given number of rows. #* <p>NOTE! #* If <code>rows</code> is not given, one row is skipped. Therefore #* <code>FRM_skip( tab );</code> is equivalent to <code>FRM_skip( tab, 1 );</code>. #* <code>FRM_skip( tab, 0 );</code> also skips to next row because 0 is taken as #* the equivalent for "not given". #* <p> #* If <code>rows</code> is negative, the function skips backwards. Therefore #* <code>FRM_skip( tab, -3 );</code> jumps for example from row 15 to row 12. #* #*@param tid (in) table ID #*@param rows (in) (optional) number of rows to skip, negative skips backwards #*@return #* E_OK: success #* E_OUT_OF_RANGE: skip beyond table bounaries attempted #* !anything else: other failure #*/ public function FRM_skip ( in tid, in rows ) { switch ( FRM_get_mode( tid ) ) { case FRM_SET_MODE: case FRM_CHK_MODE: case FRM_ATR_MODE: case FRM_GEN_MODE: return FRM_SET_skip( tid, rows ); #*case FRM_GEN_MODE: #* return FRM_GEN_skip( tid, rows ); default: return !E_OK; } } static function FRM_SET_skip ( in tid, in rows ) { auto rc, curr_row; if ( rows*1 == 0 ) { return FRM_next_row( tid ); } rc = FRM_get_current_row( tid, curr_row ); if ( rc != E_OK ) return rc; else return FRM_set_row( tid, curr_row + rows ); } static function FRM_GEN_skip ( in tid, in rows ) { FRM_GEN_print( tid ); } #** #* Performs the initialisation for the given test block. #* <p>NOTE<br> #* Important change since version 6.02.01.00: mode sent as parameter to #* this function takes presedence over the mode of the test block header. #* #*@param tid (in) table ID #*@param test (in) column name #*@param idx (in) block name (row index) #*@param mode (in) (optional) frame mode (default: FRM_SET_MODE) #*@return #* E_OK: success #* E_FRM_SKIP: block schould be ignored (valid only for FRM_GEN_MODE) #* E_FRM_INIT_BLOCK: idx not found #* E_FRM_ILLEGAL_PARAMETER: idx found but mode could not be set #*/ public function FRM_init_block ( in tid, in test, in idx, inout mode ) { auto rc, row, block, m; if ( FRM_idx( tid, idx, row ) || FRM_set_row( tid, row ) || FRM_get( tid, FRM_COL_NAME, block ) ) { return E_FRM_INIT_BLOCK; } # if mode parameter unspecified, then try to determine # the mode from the header cell of the test block if ( mode == "" ) { rc = FRM_get( tid, test, m ); if ( rc != E_OK && rc != E_FRM_SKIP ) { return E_FRM_INIT_BLOCK; } # if mode unspecified in both the parameter and # test block header, then use SET mode as default if ( rc == E_FRM_SKIP ) { mode = FRM_SET_MODE; } # otherwise convert known modes to internal flags else { switch ( toupper( m ) ) { case "SET": mode = FRM_SET_MODE; break; case "CHK": mode = FRM_CHK_MODE; break; case "ATR": mode = FRM_ATR_MODE; break; case "GEN": mode = FRM_GEN_MODE; break; default: mode = m; } } } # GEN mode requires special treatment if ( mode == FRM_GEN_MODE ) { rc = pause_test( "Process block \"" & idx & "\" in GEN mode?", "&Yes", "&No" ); if ( rc == 1 ) return E_FRM_SKIP; } # now try to set the mode rc = FRM_set_mode( tid, mode ); wrlog_block_data( "MODE", FRM_convert_mode( mode ) ); tl_step( block, rc, "Block initialised in mode: " & FRM_convert_mode( mode ) ); return rc; } #** #* In case of <rc> != E_OK this function formats an <code>tl_step</code>-message #* from the given parameters. It automatically determines the current row number #* in the data table. #* #*@param rc (in) return code to be evaluated #*@param obj (in) logical name of the affected GUI-object #*@param tid (in) tid of the affected data table #*@param test (in) name of the test case from <tid> #*@param val (in) content of the affected cell from <tid> #*@return #* E_OK: success #* !E_OK: failure #*/ public function FRM_rc ( in rc, in func, in tid, in test, in val, in obj ) { auto row = ""; auto name = ""; auto mode = ""; auto msg; FRM_get_current_row( tid, row ); name = FRM_val( tid, FRM_COL_NAME ); mode = FRM_convert_mode( FRM_get_mode( tid ) ); msg = sprintf( "[%d] %s (%s) <%s>", row+1, name, mode, val ); report_msg( msg ); if ( rc == E_OK ) { # FRM_debug_obj_info( obj ); # FRM_debug_short_call_chain( 2 ); } else { tl_step( sprintf("ERROR=%s", rc), rc, msg ); if ( err_is_error( rc ) ) { err_perror( rc ); } # FRM_debug_obj_info( obj ); # FRM_debug_full_call_chain( 2 ); pause( sprintf( "ERROR=%s: %s", rc, msg ) ); } return rc; } #** #* In case of <rc> != E_OK this function formats an <code>tl_step</code>-message #* from the given parameters. It automatically determines the current row number #* in the data table. #* #*@param rc (in) return code to be evaluated #*@param msg (in) message content #*@param title (in) [optional] message title (default: "MSG") #*@return echoed input variable <code>rc</code> #*/ public function FRM_rc2 ( in rc, in msg, in title ) { auto func; auto tit = (title=="" ? "MSG" : title ); wrlog_prim_data( tit, msg ); if ( rc == E_OK ) { FRM_log_short_call_chain( 2 ); } else { call_chain_get_attr( "function", 1, func ); tl_step( func, rc, sprintf( "%s=[%s] rc=[%s]", tit, msg, rc ) ); if ( err_is_error( rc ) ) { wrlog_prim_data( "ERROR", err_perror( rc ) ); } if ( get_log_call_level() > 0 ) { FRM_log_full_call_chain( 2 ); } pause( sprintf( "ERROR rc=[%s] %s=%s", rc, tit, msg ) ); } return rc; } public function FRM_log_frm_info( in tid, in test, in val ) { auto row = ""; auto name = ""; auto mode = ""; auto msg; FRM_get_current_row( tid, row ); name = FRM_val( tid, FRM_COL_NAME ); mode = FRM_convert_mode( FRM_get_mode( tid ) ); wrlog_prim_frm_info( tid, test, row, name, mode, val ); debug_msg( sprintf( "[%d] %s (%s) <%s>", row+1, name, mode, val ) ); } public function FRM_log_obj_info( in obj ) { auto rc, msg; auto win, desc, file, class; if ( obj == "" ) return; win = GUI_get_window(); if ( obj == win ) { GUI_map_get_desc( win, "", desc, file ); GUI_buf_get_desc_attr( file, win, "", "class", class ); } else { GUI_map_get_desc( win, obj, desc, file ); GUI_buf_get_desc_attr( file, win, obj, "class", class ); } wrlog_prim_obj_info( win, obj, class, desc, file ); debug_msg2( sprintf("WIN=%s: OBJ=%s: CLASS=%s DESC=%s FILE=%s", win, obj, class, desc, file ) ); } #** #* Dumps the debug info for the 1 level deeper in the calling chain. #*/ public function FRM_log_short_call_chain( in level ) { auto rc, msg; auto test, type, func, line; call_chain_get_attr( "testname", level, test ); call_chain_get_attr( "type", level, type ); call_chain_get_attr( "function", level, func ); call_chain_get_attr( "line_no", level, line ); wrlog_debug_call_info( test, (type=="function" ? func : ""), line ); debug_msg2( sprintf("LINE=%d: FUNC=%s: FILE=%s", line, (type=="function" ? func : ""), test ) ); } #** #* Dumps the debug info for the calling chain starting with <code>depth_offset</code>. #* @param depth_offset (in) depth of the call chain to be dumped (0 = full chain, 1 = from the caller on, etc.) #*/ public function FRM_log_full_call_chain( in depth_offset ) { auto rc, i, msg; auto test, type, func, line; for (i = depth_offset; i < call_chain_get_depth(); i++) { call_chain_get_attr( "testname", i, test ); call_chain_get_attr( "type", i, type ); call_chain_get_attr( "function", i, func ); call_chain_get_attr( "line_no", i, line ); wrlog_debug_call_info( test, (type=="function" ? func : ""), line ); debug_msg2( sprintf("LINE=%d: FUNC=%s: FILE=%s", line, (type=="function" ? func : ""), test ) ); } } #** #* This function was used for generating test data in GEN mode. It appends the #* test data into a file named "gen.txt" located in the WR temp directory. #* <p>NOTE! #* Since implementing the save capability for FRM-tables (effectively modifying #* test date in place) this function is not used any more. #* #*@param tid (in) table ID #*@param gui_obj (in) name of the affected GUI object #*@param value (in) value contained in that object (test data) #*@param rc (in) return code received by retreiving the test date (if not #* E_OK, then a special message is formatted instead of the test data). #*/ public function FRM_GEN_print ( in tid, in gui_obj, in val, in rc ) { auto test_obj = FRM_UNKNOWN; auto row = FRM_UNKNOWN; auto tmpdir = getvar( "tempdir" ); auto file = join_path( tmpdir, "gen.txt" ); FRM_next_row( tid ); FRM_get_current_row( tid, row ); test_obj = FRM_val( tid, FRM_COL_NAME ); if ( rc != E_OK ) { val = "row=[" & row+1 & "] " & "obj=[" & test_obj & "] " & "GUI-obj=[" & gui_obj & "] " & "rc=[" & rc & "]"; } file_open( file, FO_MODE_APPEND ); file_printf( file, "%s\n", val ); file_close( file ); } #** #*#???# #* #*#???# #*@return #*#???# #*/ public function FRM_GEN_set ( in tid, in test, in gui_obj, in val, in rc ) { FRM_next_row( tid ); if ( rc != E_OK ) val = "obj=[" & gui_obj & "] " & "rc=[" & rc & "]"; FRM_set( tid, test, val ); } #** #* Indicates whether a given <row> exists in the given <tid>. #* #*@param tid (in) table ID #*@param row (in) row number to be evaluated #*@return #* E_OK: row number is valid #* E_OUT_OF_RANGE: row number is invalid #* else: other error #*/ public function FRM_is_row ( in tid, in row ) { auto rc, max; rc = FRM_get_row_count( tid, max ); if ( rc != E_OK ) return rc; if ( row*1 < 1 || row*1 > max ) return E_OUT_OF_RANGE; return E_OK; } ################################################################################ #* From here on the implementation of the ddt-interface follows ################################################################################ #** #*Returns whether a parameter in a data table is valid. #* #*@param tid (in) table ID #*@param param (in) The parameter name to check in the data table. #*@return #* E_OK: parameter is valid #* E_NOT_PARAMETER: parameter is invalid #* else: other error #*/ public function FRM_is_parameter( in tid, in param ) { auto i; if ( !FRM_is_open( tid ) ) return E_FILE_NOT_OPEN; for( i=0; i < tabInfo[tid,IDX_PARAMS]; i++) if ( tabParam[tid,i] == param ) return E_OK; return E_NOT_PARAMETER; } #** #* Returns a list of all loaded parameters in a FRM data table. #* <p>NOTE!<p> #* Does NOT return columns <code>IDX</code> and <code>name</code> because they #* are always there. For this reason the number returned is the number of all #* (loaded) parameters minus 2. #* #*@param tid (in) table ID #*@param params (out) column titles (tab-separated) #*@param count (out) nomber of loaded columns (excluding IDX and Name) #*@return #* E_OK: success; <code>params</code> and <code>count</code> provided #* !E_OK: faliure; <code>params</code> and <code>count</code> not provided #*/ public function FRM_get_parameters( in tid, out params, out count ) { auto i, param; if ( !FRM_is_open( tid ) ) return E_FILE_NOT_OPEN; count = 0; for( i=0; i < tabInfo[tid,IDX_PARAMS]; i++) { param = tabParam[tid,i]; if ( param == FRM_COL_IDX || param == FRM_COL_NAME ) continue; params = params & ((count)?"\t":"") & param; count++; } return E_OK; } #** #* Retrieves the active row of a data table. #* #*@param tid (in) table ID #*@param row (out) number of the active row (starting with 1) #*@return #* E_OK: success; active row returned #* !E_OK: failure; active row not returned #*/ public function FRM_get_current_row ( in tid, out row ) { if ( !FRM_is_open( tid ) ) return E_FILE_NOT_OPEN; row = tabInfo[ tid, IDX_CURROW ]; return E_OK; } #** #* Retrieves the number of rows in a data table. #* #*@param tid (in) table ID #*@param count (out) number of rows in the data table #*@return #* E_OK: success; <count> returned #* !E_OK: failure; <count> not returned #*/ public function FRM_get_row_count ( in tid, out count ) { if ( !FRM_is_open( tid ) ) return E_FILE_NOT_OPEN; count = tabInfo[ tid, IDX_ROWCOUNT ]; return E_OK; } #** #* Sets the active row in a data table. #* #*@param tid (in) table ID #*@param row (in) row to be set #*@return #* E_OK: success; <row> set #* !E_OK: failure; <row> not set #*/ public function FRM_set_row ( in tid, in row ) { auto rc, max; rc = FRM_is_row( tid, row ); if ( rc != E_OK ) return rc; tabInfo[ tid, IDX_CURROW ] = row*1; return E_OK; } #** #* Changes the active row in a data table to the next row. #* #*@param tid (in) table ID #*@return #* E_OK: success; active row changed #* !E_OK: failure; active row not changed #*/ public function FRM_next_row ( in tid ) { auto rc, row; rc = FRM_get_current_row( tid, row ); if ( rc != E_OK ) return rc; return FRM_set_row( tid, ++row ); } #** #* Returns the value of a parameter in the active row in a data table. #* #*@param tid (in) table ID #*@param param (in) column name #*@return #* E_NOT_PARAMETER: failure; invalid parameter (column) name #* else: value of the given cell #*/ public function FRM_val ( in tid, in param ) { auto rc; if ( FRM_is_parameter( tid, param ) != E_OK ) return E_NOT_PARAMETER; return tabData[tid, param, tabInfo[tid, IDX_CURROW]]; } #** #* Sets a value in the current row of the data table. #* #*@param tid (in) table ID #*@param val (in) value to be set #*@param param (in) column name #*@return #* E_OK: success; <code>val</code> set #* E_NOT_PARAMETER: failure; invalid parameter (column) name #* else: other error #*/ public function FRM_set_val ( in tid, in param, in val ) { auto rc; if ( FRM_is_parameter( tid, param ) != E_OK ) return E_NOT_PARAMETER; return FRM_set( tid, param, val ); } #** #* Returns the value of a parameter in the specified row in a data table. #* #*@param tid (in) table ID #*@param row (in) row number #*@param param (in) column name #*@return #* E_NOT_PARAMETER: failure; invalid parameter (column) name #* else: value of the given cell #*/ public function FRM_val_by_row ( in tid, in row, in param ) { auto rc; if ( FRM_is_parameter( tid, param ) != E_OK ) return E_NOT_PARAMETER; rc = FRM_is_row( tid, row ); if ( rc != E_OK ) return rc; return tabData[tid, param, row*1]; } #** #* Sets a value in a specified row of the data table. #* #*@param tid (in) table ID #*@param row (in) row number #*@param param (in) column name #*@param val (in) the value to be set #*@return #* E_OK: success; <code>val</code> set #* E_NOT_PARAMETER: failure; invalid parameter (column) name #* else: other error #*/ public function FRM_set_val_by_row ( in tid, in row, in param, in val ) { auto rc; if ( FRM_is_parameter( tid, param ) != E_OK ) return E_NOT_PARAMETER; rc = FRM_is_row( tid, row ); if ( rc != E_OK ) return rc; return FRM_set( tid, param, val, row*1 ); } #** #* Builds the internal data structure for (loaded) parameters (columns). #* #*@param tid (in) table ID #*@param tests (in) list of tests (columns/parameters) to be loaded #*@return #* E_OK: success #* !E_OK: failure #*/ static function build_params( in tid, in tests ) { auto rc, val, count, test, i, tmparr[], param[]; auto table, file; table = FRM_get_name( tid ); file = FRM_get_filename( tid ); rc = ddt_get_parameters( file, val, count ); if ( rc != E_OK ) return rc; count = split( val, tmparr, "\t" ); for ( i = 1; i <= count; i++ ) param[tmparr[i]] = 1; # check for Mandatory Params if ( !(FRM_COL_IDX in param) || !(FRM_COL_NAME in param) ) { rc = E_NOT_PARAMETER; tl_step( "FRM_open", rc, "invalid table format: " & "table=[" & table & "] " & "columns \"" & FRM_COL_IDX & "\" and/or \"" & FRM_COL_NAME & "\" missing!" ); return rc; } if ( tolower(tests) == "<<all>>" ) { for( i=1; i <= count; i++ ) tabParam[tid,i-1] = tmparr[i]; } else { count = 0; DDT_ACCESS_init( table, FRM_COL_IDX&","&FRM_COL_NAME&","&tests ); while ( DDT_ACCESS_has_more( table ) ) { test = DDT_ACCESS_get_next( table ); if ( test in param ) tabParam[tid,count++] = test; } DDT_ACCESS_clean( table ); } tabInfo[tid,IDX_PARAMS] = count; return E_OK; } #** #* Builds the internal index for marked rows. You can mark a row by placing an #* "x" in the IDX-column and defining the (uniquie!) name in the Name-column. #* #*@param tid (in) table ID #*@return #* E_OK: success #* !E_OK: failure #*/ static function build_idx ( in tid ) { auto rc, idx, obj, rows, i; auto table, file; table = FRM_get_name( tid ); file = FRM_get_filename( tid ); rows = tabInfo[tid, IDX_ROWCOUNT]; rc = ddt_set_row( file, 1 ); for ( i = 1; !rc && i <= rows; i++ ) { idx = ddt_val( file, FRM_COL_IDX ); if ( idx != "" ) { obj = ddt_val( file, FRM_COL_NAME ); if ( (tid, obj) in tabIdx ) { tl_step( "build_idx", 1, "index repeated: " & "table=[" & table & "] " & "column=[" & FRM_COL_NAME & "] " & "row=[" & i & "] " & "value=[" & obj & "] " & "rc=[" & rc & "] " ); return E_ILLEGAL_PARAMETER; } tabIdx[tid, obj] = i; } rc = ddt_next_row( file ); } if ( rc == E_OUT_OF_RANGE ) return E_OK; return rc; } #** #* Loads a given FRM-column from a data table. #* #*@param tid (in) table ID #*@param par (in) column name #*@param rows (in) number of rows in a table (performance) #*@return #* E_OK: operation succesfull #* !E_OK: operation failed #*/ static function load_column ( in tid, in par, in rows ) { auto rc, i, file; #*auto t1, t2; #*t1=get_time(); # first row indicates whether column has changed or not tabData[tid, par, 0] = FALSE; file = FRM_get_filename( tid ); rc = ddt_set_row( file, 1 ); for( i=1; !rc && i <= rows; i++ ) { tabData[tid, par, i] = ddt_val( file, par ); rc = ddt_next_row( file ); } #*t2=get_time(); #*printf( "Spalte %s bearbeitet in %s Sekundnen", par, t2-t1 ); return (rc==E_OUT_OF_RANGE) ? E_OK : rc; } #** #* Saves the FRM-column back to data table. #* #*@param tid (in) table ID #*@param par (in) column name #*@param rows (in) number of rows in a table (performance) #*@return #*E_OK: operation succesfull #*!E_OK: operation failed #*/ static function save_column ( in tid, in par, in rows ) { auto rc, i, file; #*auto t1, t2; #*t1=get_time(); file = FRM_get_filename( tid ); for( i=1; !rc && i <= rows; i++ ) { rc = ddt_set_val_by_row( file, i, par, tabData[tid, par, i] ); } #*t2=get_time(); #*printf( "Spalte %s bearbeitet in %s Sekundnen", par, t2-t1 ); return rc; } ################################################################################ #*TSL-LIBRARY: EMOS_FRM_Lib ################################################################################