3
# LSB Test Execution Framework
4
# Tests Execution Module (tests_exec.pl)
6
# Copyright (C) 2007-2009 The Linux Foundation. All rights reserved.
8
# This program has been developed by ISP RAS for LF.
9
# The ptyshell tool is originally written by Jiri Dluhos <jdluhos@suse.cz>
10
# Copyright (C) 2005-2007 SuSE Linux Products GmbH
12
# This program is free software; you can redistribute it and/or
13
# modify it under the terms of the GNU General Public License
14
# version 2 as published by the Free Software Foundation.
16
# This program is distributed in the hope that it will be useful,
17
# but WITHOUT ANY WARRANTY; without even the implied warranty of
18
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
# GNU General Public License for more details.
21
# You should have received a copy of the GNU General Public License
22
# along with this program; if not, write to the Free Software
23
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
30
# Check if we need to run manual tests only
31
if ($_COOKIE{'profile'} and open(PROFILE, $SERVER_PARAM{'APP_DATA'}.'/profiles/'.$_COOKIE{'profile'})) {
32
my $manual_present = 0;
33
my $automatic_present = 0;
36
if (m/^MANUAL_TESTS:\s*(.*)$/) {
39
if (m/^AUTOMATIC_TESTS:\s*(.*)$/) {
40
$automatic_present = $1;
44
if ($manual_present and not $automatic_present) {
45
# User selected the manual tests only.
46
my $profile_path = $SERVER_PARAM{'APP_DATA'}.'/profiles/'.$_COOKIE{'profile'};
47
system($CONFIG{'TESTS_DIR'}."/lsb-tef.pl -f \"$profile_path\" > /dev/null 2>&1");
49
if (open(FILE_HIST, $CONFIG{'RESULTS_DIR'}.'/HISTORY')) {
50
flock(FILE_HIST, LOCK_SH);
54
flock(FILE_HIST, LOCK_UN);
58
print "HTTP/1.0 302 Moved" . CRLF;
59
print "Location: tests_appbat.pl?test_run=$tmp" . CRLF;
60
print "Set-Cookie: profile=; path=/;" . CRLF . CRLF;
66
if ($_COOKIE{'profile'}) {
67
# Start tests via AJAX
68
$js_init = "startTests('$_COOKIE{'profile'}');\n";
71
my $status = read_status();
72
if ($status->{'IS_RUNNING'}) {
73
$js_init = "cert = '".($status->{'CERTIFICATION'} ? 'certification' : 'custom')."';\nstartTestsPrepareGUI();\nstartRefresh();\n";
77
print "HTTP/1.0 200 OK" . CRLF;
78
print "Content-type: text/html" . CRLF;
79
print "Set-Cookie: profile=; path=/;" . CRLF . CRLF;
81
print_header('Test Execution Console Page', 'exec');
83
print show_error_dlg('');
87
<div id="ajax_loading" style="display: none;"></div>
89
<h1>Test Execution</h1>
90
Please, select the user profile to run:
94
my $profiles_list = '';
95
if (opendir(DIR, $SERVER_PARAM{'APP_DATA'}.'/profiles')) {
96
my @files = sort grep !/^[\.~]/, readdir(DIR);
97
$found = scalar(@files);
99
if ($_COOKIE{'profile'} and ($_COOKIE{'profile'} eq $_)) {
100
$profiles_list .= " <option value=\"$_\" selected=\"selected\">$_</option>\n";
103
$profiles_list .= " <option value=\"$_\">$_</option>\n";
111
<select name="test_profile" id="test_profile" style="width: 12em;">
112
$profiles_list </select>
113
<input type="button" name="Start" id="start_button" value="Start" style="width: 6em;" onclick="javascript:startTests('');" />
114
<input type="button" name="Stop" id="stop_button" value="Stop" style="width: 6em;" onclick="javascript:stopTests();" disabled="disabled" />
119
<select name="test_profile_no" id="test_profile_no" style="width: 12em;" disabled="disabled">
120
<option value=""><No profiles present></option>
122
<input type="button" name="Start" id="start_button_no" value="Start" style="width: 6em;" disabled="disabled" />
123
<input type="button" name="Stop" id="stop_button" value="Stop" style="width: 6em;" onclick="javascript:stopTests();" disabled="disabled" />
129
<table border="0" cellpadding="0" cellspacing="0" style="width: 60em;"><tr><td align="left">
130
<b><font color="blue"><span id="exec_info">Nothing started</span></font> <span id="exec_status"></span></b> <b><a id="go_to_manual" style="display: none;" href="tests_appbat.pl">Run manual tests</a></b>
131
</td><td align="right">
132
<b><a id="view_report" style="display: none;" href="tests_results.pl">View test report</a></b>
135
<pre id="cmdlog" style="height: 400px; width: 60em; overflow: auto; text-wrap: none; border: 1px solid black; background-color: black; color: lightgreen;">Execute output will go here…</pre>
137
<div id="progress_table" style="border-bottom: solid 1px #aaaaaa; position: absolute; top: 250px; left: 850px; opacity: 1.0; filter: alpha(opacity=100);" onmouseover="javascript:setOpacity(this, 1.0);" onmouseout="javascript:setOpacity(this, 0.7);">
140
<script language="javascript" type="text/javascript">
142
// Preload images for shadow, various icons, buttons, etc.
143
preload_images(new Array('ajax_progress.gif', 'install_progress.gif', 'test_finished.png', 'test_manual.png', 'test_crashed.png', 'progress.png', 'progress_finished.png', 'progress_crashed.png', 'progress_divider.png'));
145
var cmdlog = document.getElementById('cmdlog');
146
var exec_status = document.getElementById('exec_status');
147
var exec_info = document.getElementById('exec_info');
148
var go_to_manual = document.getElementById('go_to_manual');
149
var view_report = document.getElementById('view_report');
150
var progress_table = document.getElementById('progress_table');
151
if (!cmdlog || !exec_status || !exec_info || !go_to_manual || !view_report || !progress_table)
152
alert('Internal error: Cannot find essential form fields! JavaScript will not work correctly.\\nPlease, contact the authors.');
154
var start_button = document.getElementById('start_button');
155
var stop_button = document.getElementById('stop_button');
156
var test_profile = document.getElementById('test_profile');
159
if (navigator.appName.indexOf('Opera') != -1)
160
cmdlog_height = cmdlog.style.pixelHeight;
162
cmdlog_height = cmdlog.clientHeight;
165
var log_contents = '';
168
// If the element intersects the console log, the function changes its opacity as requested
169
function setOpacity(elem, opacity_value) {
170
var pos_elem = getPosition(elem);
171
var drag_rect = {l: pos_elem.x, r: pos_elem.x + elem.offsetWidth, t: pos_elem.y, b: pos_elem.y + elem.offsetHeight};
172
var pos_cmdlog = getPosition(cmdlog);
173
var cons_rect = {l: pos_cmdlog.x, r: pos_cmdlog.x + cmdlog.offsetWidth, t: pos_cmdlog.y, b: pos_cmdlog.y + cmdlog.offsetHeight};
174
if ((cons_rect.l <= drag_rect.r) && (drag_rect.l <= cons_rect.r) && (cons_rect.t <= drag_rect.b) && (drag_rect.t <= cons_rect.b)) {
175
elem.style.opacity = opacity_value;
176
// IE opacity support
177
elem.style.filter = 'alpha(opacity=' + (opacity_value * 100) + ')';
181
function format_time(tm) {
182
var h = Math.floor(tm / 3600);
183
var m = Math.floor(tm / 60 - h * 60);
184
var s = tm - h * 3600 - m * 60;
185
return h + ':' + ((m < 10) ? '0' + m : m) + ':' + ((s < 10) ? '0' + s : s);
189
var refresh_delay = 1000;
190
timeout_show_progress = -1;
194
var progress_table_present = false;
195
var current_test_id = '';
196
var current_test_time = 0;
197
var server_time_estimated = 0;
199
function updateTestTimer() {
200
var next_call_period = 1000;
201
if (current_test_id) {
202
var elem = document.getElementById(current_test_id + '-elapsed-time');
205
++server_time_estimated;
206
elem.innerHTML = format_time(current_test_time);
207
// Correct the speed of internal time counter to catch up the server time
208
var dt = server_time_estimated - current_test_time;
209
// Heuristic function for adjusting timer speed.
210
// Time to the next timer call is F(dt) seconds, where:
211
// F(x) = 2 , if x in (-oo, -4);
212
// F(x) = 1 - 3*|x|*x/64 + x^4/1024 , if x in [-4, 4];
213
// F(x) = 0.5 , if x in (4, +oo).
215
next_call_period = 2000;
218
next_call_period = 500;
221
var z = Math.abs(dt) * dt / 16;
222
next_call_period = Math.round((4 - 3 * z + z * z) * 250);
226
test_timer_var = setTimeout('updateTestTimer()', next_call_period);
229
function startTestsPrepareGUI() {
231
start_button.disabled = true;
233
stop_button.disabled = false;
235
test_profile.disabled = true;
236
exec_info.innerHTML = 'Preparing to run the tests…';
237
exec_status.innerHTML = ' <img src="images/ajax_progress.gif" width="16" height="16" alt="" />';
238
cmdlog.innerHTML = '';
241
current_test_time = 0;
242
server_time_estimated = 0;
243
current_test_id = '';
246
function startTests(profile_name) {
248
var profile = document.getElementById('test_profile');
251
profile_name = profile.value;
254
alert('Profile is not specified!');
259
alert("Internal error: Cannot find 'profile' form field!\\nPlease, contact the authors.!");
263
startTestsPrepareGUI();
264
ajax_call_get('action=run_tests&profile=' + encodeURIComponent(profile_name));
267
function stopTestsPrepareGUI() {
269
start_button.disabled = false;
271
stop_button.disabled = true;
273
test_profile.disabled = false;
276
function stopTests() {
277
if (confirm('Are you sure you want to terminate test execution?')) {
279
stop_button.disabled = true;
280
exec_info.innerHTML = 'Tests are stopping…';
281
ajax_call_get('action=stop_tests&tree=tests');
285
function startRefresh() {
286
exec_info.innerHTML = 'Tests are running (' + cert + ')…';
287
exec_status.innerHTML = ' <img src="images/ajax_progress.gif" width="16" height="16" alt="" />';
288
cmdlog.innerHTML = '';
291
ajax_call_get('action=get_test_log&start=0');
295
function stopRefresh() {
296
clearTimeout(timeout_var);
298
clearTimeout(test_timer_var);
299
test_timer_var = null;
300
stopTestsPrepareGUI();
301
progress_table_present = false;
302
current_test_id = '';
305
function onAjaxError() {
306
clearTimeout(timeout_var);
308
clearTimeout(test_timer_var);
309
test_timer_var = null;
310
stopTestsPrepareGUI();
311
exec_info.innerHTML = 'Nothing started';
312
exec_status.innerHTML = '';
315
var test_progress_data;
317
var status_images = new Array();
318
status_images['Not started'] = 'images/environment-spacer.gif';
319
status_images['Preparing'] = 'images/install_progress.gif';
320
status_images['Running'] = 'images/ajax_progress.gif';
321
status_images['Finished'] = 'images/test_finished.png';
322
status_images['FinishedM'] = 'images/test_manual.png';
323
status_images['Crashed'] = 'images/test_crashed.png';
325
var progress_images = new Array();
326
progress_images['Not started'] = 'images/progress.png';
327
progress_images['Preparing'] = 'images/progress.png';
328
progress_images['Running'] = 'images/progress.png';
329
progress_images['Finished'] = 'images/progress_finished.png';
330
progress_images['FinishedM'] = 'images/progress_finished.png';
331
progress_images['Crashed'] = 'images/progress_crashed.png';
333
var time_colors = new Array();
334
time_colors['Not started'] = 'gray';
335
time_colors['Preparing'] = 'blue';
336
time_colors['Running'] = 'blue';
337
time_colors['Finished'] = 'black';
338
time_colors['FinishedM'] = 'black';
339
time_colors['Crashed'] = 'darkred';
341
function ajaxProcessResult(responseXML) {
343
if (responseXML.getElementsByTagName('cert').length > 0) {
344
cert = ((responseXML.getElementsByTagName('cert')[0].childNodes[0].nodeValue == '0') ? 'custom' : 'certification');
346
if (responseXML.getElementsByTagName('progress').length > 0) {
347
var progress_data = responseXML.getElementsByTagName('progress')[0];
348
var testsuites_data = progress_data.getElementsByTagName('testsuite');
349
if (!progress_table_present) {
350
// Build the progress table HTML code
351
test_progress_data = new Array();
352
var html_data = '<table class="progress-table" cellpadding="0" cellspacing="0" style="width: 26em; background: #f2f2f2;" onmousedown="javascript:dragStart(event, progress_table, true);" onmouseup="javascript:dragStop(event);">\\n <tr>\\n <th style="width: 26px; padding: 0; text-align: center;"><img src="images/environment-spacer.gif" alt="" width="16" height="16" /></th>\\n <th style="width: 13em;">Test Suite</th>\\n <th style="width: 5em;">Elapsed</th>\\n <th style="width: 5em;">Estimated</th>\\n </tr>\\n</table>\\n<div style="max-height: 400px; overflow: auto;">\\n <table class="progress-table" cellpadding="0" cellspacing="0" style="width: 26em; background: #f9f9f9; border-top: none; border-bottom: none;" onmousedown="javascript:dragStart(event, progress_table, true);" onmouseup="javascript:dragStop(event);">';
353
if (testsuites_data.length == 0) {
354
html_data += ' <tr>\\n <td colspan="4" style="border-top: none; color: gray; text-align: center;">Nothing started</td>\\n </tr>\\n';
357
for (var i = 0; i < testsuites_data.length; ++i) {
358
var id = testsuites_data[i].getAttribute('id');
359
var name = testsuites_data[i].getElementsByTagName('name')[0].childNodes[0].nodeValue;
360
var status = testsuites_data[i].getElementsByTagName('status')[0].childNodes[0].nodeValue;
361
var elapsed = testsuites_data[i].getElementsByTagName('elapsed')[0].childNodes[0].nodeValue;
362
var total = testsuites_data[i].getElementsByTagName('total')[0].childNodes[0].nodeValue;
363
var prepare_percent = testsuites_data[i].getElementsByTagName('prep_percent')[0].childNodes[0].nodeValue;
364
var percent = testsuites_data[i].getElementsByTagName('percent')[0].childNodes[0].nodeValue;
366
var total_time = '-:--:--';
367
var elapsed_time = '-:--:--';
370
if (status == 'Not started') {
373
total_time = format_time(total);
375
else if ((status == 'Running') || (status == 'Preparing')) {
376
current_test_id = id;
377
server_time_estimated = elapsed;
378
current_test_time = elapsed;
379
elapsed_time = format_time(elapsed);
381
total_time = format_time(total);
382
name_style = ' style="font-weight: bold; color: blue;"';
384
else if ((status == 'Finished') || (status == 'FinishedM')) {
385
if (current_test_id == id)
386
current_test_id = '';
388
elapsed_time = format_time(elapsed);
390
total_time = elapsed_time;
392
else if (status == 'Crashed') {
393
if (current_test_id == id)
394
current_test_id = '';
395
elapsed_time = format_time(elapsed);
396
total_time = format_time(total);
399
test_progress_data[id] = new Array();
400
test_progress_data[id]['name'] = name;
401
test_progress_data[id]['status'] = status;
402
test_progress_data[id]['elapsed'] = elapsed;
403
test_progress_data[id]['total'] = total;
404
test_progress_data[id]['prepare_percent'] = prepare_percent;
405
test_progress_data[id]['percent'] = percent;
407
var prep_progress_width = Math.round(prepare_percent * 1.5);
408
var progress_width = Math.round(percent * 1.5);
409
var progress_img = '';
410
if (prep_progress_width) {
411
progress_img += '<img id="' + id + '-prep-progress-bar" src="' + progress_images[status] + '" alt="' + prepare_percent + '%" width="' + prep_progress_width + '" height="5" /><img id="' + id + '-div-progress-bar" src="images/progress_divider.png" alt="" width="1" height="5" />';
412
progress_width -= prep_progress_width + 1;
413
if (progress_width < 0)
417
progress_img += '<img id="' + id + '-prep-progress-bar" src="' + progress_images[status] + '" alt="0%" width="0" height="5" style="display: none;" /><img id="' + id + '-div-progress-bar" src="images/progress_divider.png" alt="" width="0" height="5" style="display: none;" />';
419
if (progress_width) {
420
progress_img += '<img id="' + id + '-progress-bar" src="' + progress_images[status] + '" alt="' + percent + '%" width="' + progress_width + '" height="5" />';
423
progress_img += '<img id="' + id + '-progress-bar" src="' + progress_images[status] + '" alt="0%" width="0" height="5" style="display: none;" />';
428
border += ' border-top: none;';
429
if (i == testsuites_data.length - 1)
430
border += ' border-bottom: none;';
431
html_data += ' <tr>\\n <td style="width: 26px; padding: 0; text-align: center;' + border + '"><img id="' + id + '-img" src="' + status_images[status] + '" alt="' + status + '" width="16" height="16" /></td>\\n <td id="' + id + '" style="width: 13em;' + border + '">\\n <span id="' + id + '-name"' + name_style + '>' + name + '</span>\\n <div style="width: 150px; height: 5px; border: 1px solid #004000; text-align: left;">' + progress_img + '</div>\\n </td>\\n <td style="width: 5em;' + border + ' white-space: nowrap; text-align: right;"><span id="' + id + '-elapsed-time" style="color: ' + time_colors[status] + '; font-family: monospace;">' + elapsed_time + '</span></td>\\n <td style="width: 5em;' + border + ' white-space: nowrap; text-align: right;"><span id="' + id + '-total-time" style="color: ' + time_colors[status] + '; font-family: monospace;">' + total_time + '</span></td>\\n </tr>\\n';
434
html_data += ' </table>\\n</div>';
435
progress_table.innerHTML = html_data;
436
var pos_str = getCookie('pos_progress_table');
438
var comma_idx = pos_str.indexOf(',');
439
progress_table.style.left = pos_str.substr(0, comma_idx);
440
progress_table.style.top = pos_str.substr(comma_idx + 1);
442
progress_table.style.display = '';
443
// If the list is long enough, the scrollbar is shown.
444
// In this case we increase the width so that the scrollbar was outside the table
445
if (progress_table.offsetHeight >= 400)
446
progress_table.style.width = (progress_table.offsetWidth + 17) + 'px';
447
setOpacity(progress_table, 0.7); // Set opacity, if the table intersects with cmdlog area
448
progress_table_present = true;
451
// Update the progress table data
452
for (var i = 0; i < testsuites_data.length; ++i) {
453
var id = testsuites_data[i].getAttribute('id');
454
var status = testsuites_data[i].getElementsByTagName('status')[0].childNodes[0].nodeValue;
455
var elapsed = testsuites_data[i].getElementsByTagName('elapsed')[0].childNodes[0].nodeValue;
456
var total = testsuites_data[i].getElementsByTagName('total')[0].childNodes[0].nodeValue;
457
var prepare_percent = testsuites_data[i].getElementsByTagName('prep_percent')[0].childNodes[0].nodeValue;
458
var percent = testsuites_data[i].getElementsByTagName('percent')[0].childNodes[0].nodeValue;
460
var total_time = '-:--:--';
461
var elapsed_time = '-:--:--';
463
var name_elem = document.getElementById(id + '-name');
464
var img_elem = document.getElementById(id + '-img');
465
var prep_percent_elem = document.getElementById(id + '-prep-progress-bar');
466
var div_percent_elem = document.getElementById(id + '-div-progress-bar');
467
var percent_elem = document.getElementById(id + '-progress-bar');
468
var elapsed_time_elem = document.getElementById(id + '-elapsed-time');
469
var total_time_elem = document.getElementById(id + '-total-time');
470
if (!name_elem || !img_elem || !prep_percent_elem || !div_percent_elem || !percent_elem || !elapsed_time_elem || !total_time_elem)
473
// Avoid flickering from unnecessary refreshes
474
if (test_progress_data[id]['status'] != status) {
475
img_elem.setAttribute('src', status_images[status]);
476
img_elem.setAttribute('alt', status);
477
elapsed_time_elem.style.color = time_colors[status];
478
total_time_elem.style.color = time_colors[status];
479
if ((status == 'Running') || (status == 'Preparing')) {
480
current_test_id = id;
481
server_time_estimated = elapsed;
482
current_test_time = elapsed;
483
name_elem.style.fontWeight = 'bold';
484
name_elem.style.color = 'blue';
487
name_elem.style.fontWeight = 'normal';
488
name_elem.style.color = 'black';
492
if (status == 'Not started') {
495
total_time = format_time(total);
497
else if ((status == 'Running') || (status == 'Preparing')) {
498
elapsed_time = format_time(elapsed);
500
total_time = format_time(total);
502
else if ((status == 'Finished') || (status == 'FinishedM')) {
503
if (current_test_id == id)
504
current_test_id = '';
506
elapsed_time = format_time(elapsed);
508
total_time = elapsed_time;
510
else if (status == 'Crashed') {
511
if (current_test_id == id)
512
current_test_id = '';
513
elapsed_time = format_time(elapsed);
514
total_time = format_time(total);
517
test_progress_data[id]['status'] = status;
518
test_progress_data[id]['elapsed'] = elapsed;
519
test_progress_data[id]['total'] = total;
520
test_progress_data[id]['prepare_percent'] = prepare_percent;
521
test_progress_data[id]['percent'] = percent;
523
var prep_progress_width = Math.round(prepare_percent * 1.5);
524
var progress_width = Math.round(percent * 1.5);
526
prep_percent_elem.setAttribute('src', progress_images[status]);
527
prep_percent_elem.setAttribute('alt', prepare_percent + '%');
528
prep_percent_elem.width = prep_progress_width;
529
if (prep_progress_width) {
530
prep_percent_elem.style.display = '';
531
div_percent_elem.width = 1;
532
div_percent_elem.style.display = '';
533
progress_width -= prep_progress_width + 1;
534
if (progress_width < 0)
538
prep_percent_elem.style.display = 'none';
539
div_percent_elem.width = 0;
540
div_percent_elem.style.display = 'none';
543
percent_elem.setAttribute('src', progress_images[status]);
544
percent_elem.setAttribute('alt', percent + '%');
545
percent_elem.width = progress_width;
546
percent_elem.style.display = ((progress_width == 0) ? 'none' : '');
547
if ((status != 'Running') && (status != 'Preparing'))
548
elapsed_time_elem.innerHTML = elapsed_time;
549
total_time_elem.innerHTML = total_time;
553
if (responseXML.getElementsByTagName('started').length > 0) {
554
setTimeout('startRefresh()', 100);
557
if (responseXML.getElementsByTagName('output').length > 0) {
559
for (var i=0; i<responseXML.getElementsByTagName('output').length; ++i) {
560
for (var j=0; j<responseXML.getElementsByTagName('output')[i].childNodes.length; ++j)
561
output += responseXML.getElementsByTagName('output')[i].childNodes[j].nodeValue;
563
updateCmdLog(output);
565
if (responseXML.getElementsByTagName('tid').length > 0) {
566
tid = responseXML.getElementsByTagName('tid')[0].childNodes[0].nodeValue;
568
if (responseXML.getElementsByTagName('size').length > 0) {
569
var sz = responseXML.getElementsByTagName('size')[0].childNodes[0].nodeValue;
570
timeout_var = setTimeout("ajax_call_get('action=get_test_log&start=" + sz + "&tid=" + tid + "')", refresh_delay);
573
if (responseXML.getElementsByTagName('tr_status').length > 0) {
574
exec_info.innerHTML = 'Tests are finished (' + cert + ').';
575
exec_status.innerHTML = responseXML.getElementsByTagName('tr_status')[0].childNodes[0].nodeValue;
578
if (responseXML.getElementsByTagName('redirect').length > 0) {
579
document.location = 'tests_results.pl?details=' + responseXML.getElementsByTagName('redirect')[0].childNodes[0].nodeValue + '&summary=1';
585
var re_x0d = new RegExp();
586
re_x0d.compile('^[^\\x0d]*\\x0d', 'g');
588
function make_merge(line) {
590
// Make every ^M control character (\\x0d) erase all from the beginning of line
592
re_x0d.lastIndex = 0;
593
tmp = line.replace(re_x0d, '');
602
function updateCmdLog(txt) {
603
var scroll_top = cmdlog.scrollTop;
604
var scroll_height = cmdlog.scrollHeight;
605
var auto_scroll = (scroll_height - cmdlog_height - scroll_top < 10);
607
var fnewln_pos = last_line.indexOf('\\n');
608
var lnewln_pos = last_line.lastIndexOf('\\n');
610
if (fnewln_pos == -1) {
611
// merge and make new last_line
612
last_line = make_merge(last_line);
615
// block1 (till first '\\n'): for merging and adding to log_contents
616
// block2 (from first till last '\\n'): for adding to log_contents (no merging needed)
617
// block3 (after last '\\n'): to be the new last_line (no merging needed)
618
log_contents += make_merge(last_line.substring(0, fnewln_pos + 1)) + last_line.substring(fnewln_pos + 1, lnewln_pos + 1);
619
last_line = last_line.substring(lnewln_pos + 1);
621
if (typeof(cmdlog.innerText) == 'undefined')
622
cmdlog.textContent = log_contents + last_line;
624
cmdlog.innerText = log_contents + last_line;
626
cmdlog.scrollTop = cmdlog.scrollHeight;
627
cmdlog.scrollTop = cmdlog.scrollHeight; // IE fix