[SCM] BOINC packaging branch, master, updated. debian/7.0.33+dfsg-1-86-g699e2cb
Gianfranco Costamagna
costamagnagianfranco at yahoo.it
Mon Nov 5 00:18:32 UTC 2012
The following commit has been merged in the master branch:
commit 699e2cbfb61730eec0f9d4a300a9b3077366fb52
Author: Gianfranco Costamagna <costamagnagianfranco at yahoo.it>
Date: Mon Nov 5 01:17:56 2012 +0100
Added missing test files
diff --git a/debian/patches/add-missing-test-files.patch b/debian/patches/add-missing-test-files.patch
new file mode 100644
index 0000000..dad5074
--- /dev/null
+++ b/debian/patches/add-missing-test-files.patch
@@ -0,0 +1,8187 @@
+Cherry picking commit 2c7b2a0 in order to add missing test files (boinc ftbfs without them)
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_loop.php
+@@ -0,0 +1,47 @@
++#! /usr/local/bin/php
++<?php
++ // This tests whether the most basic mechanisms are working
++ // Also whether stderr output is reported correctly
++
++ include_once("test.inc");
++
++ $project = new Project;
++ $user = new User();
++ $host = new Host($user);
++ $app = new App("upper_case");
++ $app_version = new App_Version($app);
++
++ $project->add_user($user);
++ $project->add_app($app);
++ $project->add_app_version($app_version);
++ $project->start_feeder = true;
++ $project->start_make_work = true;
++ $project->start_validate = true;
++ $project->start_file_delete = true;
++ $project->start_assimilator = true;
++ $project->install(); // must install projects before adding to hosts
++
++ $host->log_flags = "log_flags.xml";
++ $host->add_user($user,$project);
++ $host->install();
++
++ echo "adding work\n";
++
++ $work = new Work($app);
++ $work->wu_template = "uc_wu";
++ $work->result_template = "uc_result";
++ $work->redundancy = 3;
++
++ array_push($work->input_files, "input");
++ $work->install($project);
++
++ $project->start_feeder();
++ $project->start_make_work($work);
++ $project->start_validate($app, 3);
++ $project->start_file_delete();
++ $project->start_assimilator($app);
++ $project->start_stripchart();
++ //$project->start_servers();
++ $host->run();
++ $project->stop();
++?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_pers.php
+@@ -0,0 +1,149 @@
++#! /usr/local/bin/php
++<?php
++
++//This tests the persistent file transfers for download and upload. It interrupts them in the middle and makes sure that the filesize never decreases along interrupted transfers.
++
++include_once("test.inc");
++set_time_limit(10000000000);
++
++$project = new Project;
++$user = new User();
++$host = new Host($user);
++$app = new App("upper_case");
++$app_version = new App_Version($app);
++
++$project->add_user($user);
++$project->add_app($app);
++$project->add_app_version($app_version);
++$project->install(); // must install projects before adding to hosts
++
++$host->log_flags = "log_flags.xml";
++$host->add_project($project);
++$host->install();
++
++echo "adding work\n";
++
++$work = new Work($app);
++$work->wu_template = "uc_wu";
++$work->result_template = "uc_result";
++$work->redundancy = 2;
++array_push($work->input_files, "input");
++$work->install($project);
++$project->start_feeder();
++
++//get the path for checking download
++$source_dir = SRC_DIR;
++$enc_url = strtr($project->master_url, "/", "_");
++$enc_url = substr($enc_url,7,strlen($enc_url));
++$path= "$host->host_dir/projects/$enc_url/upper_case";
++print "\n the path for checking download is :".$path;
++
++$pid = $host->run_asynch("-exit_when_idle -limit_transfer_rate 2048");
++$client_pid = $host->get_new_client_pid(null);
++assert($pid != -1);
++$first = 0;
++$file_size = 0;
++//Check download
++
++while(1)
++{
++
++ if(file_exists($path))
++ {
++ $temp = filesize($path);
++ if($temp < $file_size)
++ {
++ echo "\nfilesize dropped, problem downloading\n";
++ echo "temp is $temp, file_size is $file_size\n";
++ break;
++ }
++
++ else if($temp > $file_size)
++ {
++ print "\n filesize increased, it is : ".$temp;
++ if(($temp > 40000) && ($first ==0))
++ {
++ print "\n stopping and rerunning the client";
++ echo "\n now killing client_pid : $client_pid";
++ $host->kill($client_pid, null);
++ $host->run_asynch("-exit_when_idle -limit_transfer_rate 2048");
++ $client_pid = $host->get_new_client_pid($client_pid);
++ echo "\nNow executing : $client_pid";
++ $first++;
++ }
++
++ }
++
++ $file_size = $temp;
++
++ if($file_size == filesize("$source_dir/apps/upper_case"))
++ {
++ echo "\n download test succeeded";
++ break;
++ }
++
++ }
++}
++
++
++$file_size = 0;
++$path= "$project->project_dir/upload/uc_wu_0_0";
++$first =0;
++print "\nupload path is: ".$path;
++echo "\n Now checking upload";
++
++
++while(1)
++{
++ // echo "\n checking upload";
++
++
++ if(file_exists($path))
++ {
++
++ // echo "\nfile exists is download";
++ $temp = filesize($path);
++ if($temp < $file_size)
++ {
++ echo "\nfilesize dropped, problem uploading\n";
++ echo "temp is $temp, file_size if $file_size\n";
++ break;
++ }
++ if($temp > $file_size)
++ {
++ print "\n filesize increased, it is : ".$temp;
++ if(($temp > 20000) && ($first ==0))
++ {
++ print "\n stopping and rerunning the client";
++ print "\nkilling $client_pid";
++ $host->kill($client_pid,null);
++ $host->run_asynch("-exit_when_idle -limit_transfer_rate 2048");
++ $client_pid = $host->get_new_client_pid($client_pid);
++ echo "\nnew client_pid is $client_pid";
++ $first++;
++ }
++
++ }
++ $file_size = $temp;
++ if($file_size == filesize("$source_dir/test/uc_correct_output"))
++ {
++ print "\n all of the files has been uploaded";
++ print "\n stopping and rerunning the client";
++ $host->kill($client_pid, null);
++ $host->run("-exit_when_idle");
++ break;
++ }
++ }
++}
++
++
++$project->stop();
++
++$result->server_state = RESULT_SERVER_STATE_OVER;
++$result->stderr_out = "APP: upper_case: starting, argc 1";
++$result->exit_status = 0;
++$project->check_results(2, $result);
++$project->compare_file("uc_wu_0_0", "uc_correct_output");
++$project->compare_file("uc_wu_1_0", "uc_correct_output");
++
++?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_concat.py
+@@ -0,0 +1,47 @@
++#!/usr/bin/env python
++
++## $Id: test_concat.py 2144 2003-08-18 23:51:46Z quarl $
++
++# tests whether command-line arg passing works
++
++from testbase import *
++
++class WorkConcat(Work):
++ def __init__(self, redundancy, **kwargs):
++ Work.__init__(self, redundancy=redundancy)
++ self.wu_template = "concat_wu"
++ self.result_template = "concat_result"
++ self.input_files = ['input']*2
++ self.__dict__.update(kwargs)
++
++class ProjectConcat(TestProject):
++ def __init__(self, works=None, users=None, hosts=None):
++ (num_wu, redundancy) = get_redundancy_args()
++ TestProject.__init__(self,
++ appname = 'concat',
++ num_wu=num_wu, redundancy=redundancy,
++ expected_result = Result(),
++ works = works or [WorkConcat(redundancy=redundancy)],
++ users = users,
++ hosts = hosts)
++
++ # def check(self):
++ # self.sched_run('validate_test')
++ # result = {}
++ # result['server_state'] = RESULT_SERVER_STATE_OVER
++ # self.check_results(result)
++ # self.check_files_match("upload/concat_wu_%d_0", "concat_correct_output", count=self.redundancy)
++ # self.sched_run('assimilator')
++ # self.sched_run('file_deleter')
++ # self.check_deleted("download/input")
++ # self.check_deleted("upload/concat_wu_%d_0", count=self.redundancy)
++
++ # def run(self):
++ # self.install()
++ # self.sched_install('feeder')
++ # self.start_servers()
++
++if __name__ == '__main__':
++ test_msg("standard concat application");
++ ProjectConcat()
++ run_check_all()
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_uc.php
+@@ -0,0 +1,17 @@
++#!/usr/local/bin/php -q
++<?php {
++ // $Id: test_uc.php 1510 2003-06-17 01:36:47Z quarl $
++
++ // This tests whether the most basic mechanisms are working
++ // Also whether stderr output is reported correctly
++ // Also tests if water levels are working correctly
++
++ include_once("test_uc.inc");
++ test_msg("standard upper_case application");
++
++ $project = new ProjectUC;
++ $project->start_servers_and_host();
++ $project->validate_all_and_stop();
++
++ test_done();
++} ?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_time.php
+@@ -0,0 +1,49 @@
++#! /usr/local/bin/php
++<?php
++ // test whether CPU time is computed correctly across restarts
++
++ include_once("test.inc");
++
++ $project = new Project;
++ $user = new User();
++ $host = new Host($user);
++ $app = new App("uc_cpu");
++ $app_version = new App_Version($app);
++
++ $project->add_user($user);
++ $project->add_app($app);
++ $project->add_app_version($app_version);
++ $project->install(); // must install projects before adding to hosts
++
++ $host->log_flags = "log_flags.xml";
++ $host->add_project($project);
++ $host->install();
++
++ echo "adding work\n";
++
++ $work = new Work($app);
++ $work->wu_template = "uccpu_wu";
++ $work->result_template = "uccpu_result";
++ $work->redundancy = 1;
++ array_push($work->input_files, "small_input");
++ $work->install($project);
++
++ $project->start_feeder();
++ $app_time = 0;
++ $host->run("-exit_after_app_start 400");
++ $app_time += $host->read_cpu_time_file("app.time");
++ $host->run("-exit_when_idle");
++ $project->stop();
++
++ $result->server_state = RESULT_SERVER_STATE_OVER;
++ $project->check_results(1, $result);
++ $project->compare_file("uccpu_wu_0_0", "uc_small_correct_output");
++ $client_time = $host->read_cpu_time_file("client_time");
++ $x = mysql_query("select cpu_time from result where name='uccpu_wu_0'");
++ $result = mysql_fetch_object($x);
++ $db_time = $result->cpu_time;
++
++ if (abs($app_time-$client_time) > .01) echo "time mismatch\n";
++ if (abs($app_time-$db_time) > .01) echo "time mismatch\n";
++
++?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/uc_wu_sticky
+@@ -0,0 +1,10 @@
++<file_info>
++ <number>0</number>
++ <sticky/>
++</file_info>
++<workunit>
++ <file_ref>
++ <file_number>0</file_number>
++ <open_name>in</open_name>
++ </file_ref>
++</workunit>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_uc_win.php
+@@ -0,0 +1,46 @@
++#! /usr/local/bin/php
++<?php
++ // set up a test for the windows client
++ // set BOINC_PLATFORM to "windows_intelx86"
++
++ include_once("test.inc");
++
++ $project = new Project;
++ $user = new User();
++ $host = new Host($user);
++ $app = new App("upper_case");
++ $app_version = new App_Version($app);
++ $platform->name = "windows_intelx86";
++ $platform->user_friendly_name = "Windows";
++ $app_version->platform = $platform;
++ array_push($app_version->exec_names, "upper_case.exe");
++
++ $work = new Work($app);
++ $work->wu_template = "uc_wu";
++ $work->result_template = "uc_result";
++ $work->redundancy = 2;
++ array_push($work->input_files, "input");
++
++ $project->add_user($user);
++ $project->add_app($app);
++ $project->add_app_version($app_version);
++ $project->add_platform($platform);
++ $project->install();
++ $project->install_feeder();
++ $project->install_make_work($work,20,5);
++
++ echo "adding work\n";
++ $work->install($project);
++
++ $project->start_servers();
++
++ echo "Go run the client\n";
++ /*echo "Hit any key to stop the server\n";
++
++ $project->stop();
++
++ $project->check_results(2, $result);
++ $project->compare_file("uc_wu_0_0", "uc_correct_output");
++ $project->compare_file("uc_wu_1_0", "uc_correct_output");
++ */
++?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/uc_wu_nodelete
+@@ -0,0 +1,9 @@
++<file_info>
++ <number>0</number>
++</file_info>
++<workunit>
++ <file_ref>
++ <file_number>0</file_number>
++ <open_name>in</open_name>
++ </file_ref>
++</workunit>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_limit.php
+@@ -0,0 +1,70 @@
++#! /usr/local/bin/php
++<?php
++ // This tests whether the most basic mechanisms are working
++ // Also whether stderr output is reported correctly
++ // Also tests if water levels are working correctly
++
++ include_once("test.inc");
++
++ $retval = 0;
++
++ $project = new Project;
++
++ $app = new App("upper_case");
++ $app_version = new App_Version($app);
++
++ // the following is optional (makes client web download possible)
++ $core_app = new App("core client");
++ $core_app_version = new App_Version($core_app);
++ $project->add_app($core_app);
++ $project->add_app_version($core_app_version);
++
++ $project->add_app($app);
++ $project->add_app_version($app_version);
++
++ $user = new User();
++ $user->project_prefs = "<project_specific>\nfoobar\n</project_specific>\n";
++ $user->global_prefs = "<venue name=\"home\">\n".
++ "<work_buf_min_days>0</work_buf_min_days>\n".
++ "<work_buf_max_days>2</work_buf_max_days>\n".
++ "<run_on_batteries/>\n".
++ "<max_bytes_sec_down>400000</max_bytes_sec_down>\n".
++ "</venue>\n";
++
++ $project->add_user($user);
++ $project->install(); // must install projects before adding to hosts
++ $project->install_feeder();
++
++ $host = new Host();
++ $host->log_flags = "log_flags.xml";
++ $host->add_user($user, $project);
++ $host->install();
++
++ echo "adding work\n";
++
++ $work = new Work($app);
++ $work->wu_template = "ucs_wu";
++ $work->result_template = "uc_result";
++ $work->redundancy = 1;
++ $work->delay_bound = 2;
++ // Say that 1 WU takes 1 day on a ref comp
++ $work->rsc_fpops = 86400*1e9/2;
++ $work->rsc_iops = 86400*1e9/2;
++ $work->rsc_memory = 1024*1024;
++ $work->rsc_disk = 1;
++ array_push($work->input_files, "input");
++ $work->install($project);
++
++ $project->start_servers();
++ sleep(1); // make sure feeder has a chance to run
++ $host->run("-exit_when_idle -skip_cpu_benchmarks");
++
++ $result->server_state = RESULT_SERVER_STATE_OVER;
++ $result->stderr_out = "APP: upper_case: starting, argc 1";
++ $result->exit_status = 0;
++ $project->check_results(1, $result);
++
++ $project->stop();
++
++ exit($retval);
++?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_upload_resume.php
+@@ -0,0 +1,21 @@
++#!/usr/local/bin/php -q
++<?php {
++ // $Id: test_upload_resume.php 1510 2003-06-17 01:36:47Z quarl $
++
++ // This tests whether upload resuming works correctly.
++
++ $use_proxy_cgi = 1;
++
++ include_once("test_uc.inc");
++ test_msg("upload resumes");
++
++ $project = new ProjectUC;
++
++ // TODO
++ // start_proxy('exit 1 if ($nconnections ==1 && $bytes_transferred==ZZZ); if_done_kill(); if_done_ping();');
++
++ $project->start_servers_and_host();
++ $project->validate_all_and_stop();
++
++ test_done();
++} ?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_abort.py
+@@ -0,0 +1,29 @@
++#!/usr/bin/env python
++
++## $Id: test_abort.py 2114 2003-08-15 20:27:21Z quarl $
++
++# Makes sure that the client aborts when the output file size limit is
++# exceeded, and that the server knows it.
++
++from test_uc import *
++
++class WorkAbort(WorkUC):
++ def __init__(self):
++ WorkUC.__init__(self)
++ self.result_template = "abort_result"
++
++class ResultAbort(ResultUCError):
++ def __init__(self):
++ ResultUCError.__init__(self)
++ self.stderr_out.append('<message>Output file exceeded size limit')
++
++class ProjectAbort(ProjectUC):
++ def __init__(self):
++ ProjectUC.__init__(self, short_name='test_abort', works=[WorkAbort()])
++ def check(self):
++ self.check_client_error(ResultAbort())
++
++if __name__ == '__main__':
++ test_msg("result abort mechanism (disk space limit)")
++ ProjectAbort()
++ run_check_all()
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_backend.php
+@@ -0,0 +1,80 @@
++#!/usr/local/bin/php -q
++<?php {
++ // $Id: test_backend.php 1412 2003-06-11 23:47:36Z quarl $
++
++ // End to end test. Tests make_work, feeder, scheduling server, client,
++ // file_upload_handler, validator, assimilator, timeout_check, and
++ // file_deleter on a large batch of workunits. Confirms that credit
++ // is correctly granted and that unneeded files are deleted
++
++ include_once("test.inc");
++
++ test_msg("backend");
++
++ $project = new Project;
++ $user = new User();
++ $host = new Host($user);
++ $app = new App("upper_case");
++ $app_version = new App_Version($app);
++
++ $work = new Work($app);
++ $work->wu_template = "uc_wu";
++ $work->result_template = "uc_result";
++ $work->redundancy = 5;
++ $work->delay_bound = 70;
++ array_push($work->input_files, "input");
++
++ $project->add_user($user);
++ $project->add_app($app);
++ $project->add_app_version($app_version);
++ $project->install(); // must install projects before adding to hosts
++ $project->install_make_work($work, 499, 5);
++
++ $host->log_flags = "log_flags.xml";
++ $host->add_user($user,$project);
++ $host->install();
++
++ $work->install($project);
++
++ $project->start_servers();
++
++ // Start by generating a batch of 500 results
++ $n = 0;
++ while($n < 500 ) {
++ $n = $project->num_wus_left();
++ verbose_echo(1, "Generating results [$n/500]");
++ sleep(1);
++ }
++ verbose_echo(1, "Generating results... 500 done");
++
++ // Stop the project, deinstall make_work, and install the normal backend components
++ $project->stop();
++ $project->deinstall_make_work();
++ $project->install_assimilator($app);
++ $project->install_file_delete();
++ $project->install_validate($app, 5);
++ $project->install_feeder();
++ $project->install_timeout_check($app, 5, 5, 0);
++
++ while (($pid=exec("pgrep -n make_work")) != null) sleep(1);
++
++ // Restart the server
++ $project->restart();
++ $project->start_servers();
++
++ // Run the client until there's no more work
++ $host->run("-exit_when_idle -skip_cpu_benchmarks");
++
++ // Give the server 30 seconds to finish assimilating/deleting
++ sleep(30);
++
++ // *** DO CHECKS HERE
++ $result->server_state = RESULT_SERVER_STATE_OVER;
++ $result->exit_status = 0;
++ $project->check_results(500, $result);
++
++ // Stop the server
++ $project->stop();
++
++ test_done();
++} ?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_concat.php
+@@ -0,0 +1,42 @@
++#!/usr/local/bin/php -q
++<?php {
++ // $Id: test_concat.php 1383 2003-06-11 23:09:11Z quarl $
++ // tests whether command-line arg passing works
++
++ include_once("test.inc");
++
++ test_msg("standard concat application");
++
++ $project = new Project;
++ $project->add_core_and_version();
++ $project->add_app_and_version("concat");
++
++ $user = new User();
++ $host = new Host($user);
++
++ $project->add_user($user);
++ $project->install(); // must install projects before adding to hosts
++ $project->install_feeder();
++
++ $host->add_user($user,$project);
++ $host->install();
++
++ $work = new Work($app);
++ $work->wu_template = "concat_wu";
++ $work->result_template = "concat_result";
++ $work->redundancy = 2;
++ array_push($work->input_files, "input");
++ array_push($work->input_files, "input");
++ $work->install($project);
++
++ $project->start_servers();
++ $host->run("-exit_when_idle -skip_cpu_benchmarks");
++ $project->stop();
++
++ $result->server_state = RESULT_SERVER_STATE_OVER;
++ $project->check_results(2, $result);
++ $project->compare_file("concat_wu_0_0", "concat_correct_output");
++ $project->compare_file("concat_wu_1_0", "concat_correct_output");
++
++ test_done();
++} ?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_1sec.py
+@@ -0,0 +1,19 @@
++#!/usr/bin/env python
++
++## $Id: test_1sec.py 1734 2003-07-18 21:43:12Z quarl $
++
++# This tests whether the client handles multiple projects, and whether CPU
++# time is divided correctly between projects The client should do work for
++# project 2 5 times faster than for project 1
++
++from test_uc import *
++
++if __name__ == '__main__':
++ test_msg("multiple projects with resource share");
++ # create two projects with the same host/user
++ host = Host()
++ user = UserUC()
++ for i in range(2):
++ ProjectUC(users=[user], hosts=[host], redundancy=5,
++ short_name="test_1sec_%d"%i, resource_share=[1, 5][i])
++ run_check_all()
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_signal.py
+@@ -0,0 +1,29 @@
++#!/usr/bin/env python
++
++## $Id: test_signal.py 2114 2003-08-15 20:27:21Z quarl $
++
++# Make sure server hears that client died by a signal.
++
++from test_uc import *
++
++class WorkSignal(WorkUC):
++ def __init__(self):
++ WorkUC.__init__(self)
++ self.wu_template = "uc_sig_wu"
++
++class ResultSignal(ResultUCError):
++ def __init__(self):
++ ResultUCError.__init__(self)
++ self.stderr_out.append('SIGHUP: terminal line hangup')
++ self.stderr_out.append('<message>process exited with a non-zero exit code')
++
++class ProjectSignal(ProjectUC):
++ def __init__(self):
++ ProjectUC.__init__(self, short_name='test_signal', works=[WorkSignal()])
++ def check(self):
++ self.check_client_error(ResultSignal())
++
++if __name__ == '__main__':
++ test_msg("application signal report mechanism")
++ ProjectSignal()
++ run_check_all()
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/ta_correct_atc
+@@ -0,0 +1,2 @@
++<percent_done>0.000000</percent_done>
++<cpu_time_at_checkpoint>5.000000</cpu_time_at_checkpoint>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_rsc.php
+@@ -0,0 +1,41 @@
++#!/usr/local/bin/php -q
++<?php {
++ // $Id: test_rsc.php 1383 2003-06-11 23:09:11Z quarl $
++
++ // test whether the scheduling server filters out work units too big for
++ // client
++
++ include_once("test.inc");
++
++ test_msg("resource filtering for large work units");
++
++ $project = new Project;
++ $user = new User();
++ $host = new Host($user);
++ $project->add_app_and_version("upper_case");
++
++ $project->add_user($user);
++ $project->install(); // must install projects before adding to hosts
++ $project->install_feeder();
++
++ $host->add_user($user,$project);
++ $host->install();
++
++ $work = new Work($app);
++ $work->wu_template = "uc_wu";
++ $work->result_template = "uc_result";
++ $work->redundancy = 1;
++ $work->rsc_disk = 1000000000000; // 1 TB
++ $work->rsc_fpops = 0;
++ array_push($work->input_files, "input");
++ $work->install($project);
++
++ $project->start_servers();
++ $host->run("-exit_when_idle -skip_cpu_benchmarks");
++ $project->stop();
++
++ $result->server_state = RESULT_SERVER_STATE_UNSENT;
++ $project->check_results(1, $result);
++
++ test_done();
++} ?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/testproxy
+@@ -0,0 +1,245 @@
++#!/usr/bin/env perl
++
++# -T
++
++# $Id: testproxy 1676 2003-07-15 18:19:29Z davea $
++
++# testproxy - proxy a TCP/IP connection with configurable mid-way
++# disconnections, for simulating internet transfer failures
++
++use strict;
++use warnings;
++use Carp;
++use IO::Socket::INET;
++
++my $listen_port = shift;
++my $target_server = shift;
++my $testcode = join(' ', @ARGV);
++
++if (!$listen_port || !$target_server) {
++ print STDERR <<HELP;
++syntax: $0 <listen_port> <target_server:port> CODE...
++
++CODE is evaluated every 128 bytes transferred from server to client.
++ Some variables you can access/modify:
++ \$target, \$client : perl IO::Handle::INET objects
++ \$nconnections : number of connections so far
++ \$url : url of request (if applicable)
++ \$time : seconds since server started
++ \$chars, \$nchars : characters & length about to send to client.
++ \$bytes_transferred : characters already sent to client
++ \$start : beginning of connection
++ \$done, \$success : finished transfer; successful transfer
++ \$n, \$m : unused variables initialized to 0
++
++ For more, view the code.
++
++ Functions:
++ close_connection, kill_server, if_done_kill, if_done_ping, logmsg
++
++ You can also call standard perl functions such as print, sleep, exit.
++
++Examples:
++ # fail connections for first 3 connections
++ $0 8080 localhost:80 'close_connection if \$nconnections < 4'
++
++ # sleep 5 seconds in the middle of transfer, and print "success" if
++ # transfer succeeds; kill the server after the first connection
++ $0 8080 localhost:80 'sleep 5 if \$bytes_transferred == 256;
++ if (\$done) { print "success\\n" if \$success; kill_server; \$success }'
++
++ # equivalent to above:
++ $0 8080 localhost:80 'sleep 5 if \$bytes_transferred == 256;
++ if_done_kill(); if_done_ping();'
++
++HELP
++ ;
++ exit(1);
++}
++
++if ($target_server !~ /:/) {
++ $target_server .= ':http';
++}
++
++my $N = "\015\012";
++
++sub proxy;
++sub spawn;
++use POSIX qw/strftime/;
++sub logmsg { print STDERR "$0 $$ ", strftime("%Y/%m/%d %H:%M:%S", localtime), ": @_\n" }
++
++my $server = IO::Socket::INET->new(Listen => 5,
++ LocalAddr => inet_ntoa(INADDR_ANY),
++ LocalPort => $listen_port,
++ Proto => 'tcp',
++ ReuseAddr => 1)
++ or die "$0: creating socket on port $listen_port: $!";
++
++logmsg "server started on port $listen_port proxy to $target_server";
++
++my $waitedpid = 0;
++my $paddr;
++my $server_pid = $$;
++
++use POSIX ":sys_wait_h";
++sub REAPER {
++ while (($waitedpid = waitpid(-1,WNOHANG)) > 0) {
++ logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
++ }
++ # $SIG{CHLD} = \&REAPER; # loathe sysV
++}
++
++# $SIG{CHLD} = \&REAPER;
++
++my $time_started = time();
++my $nconnections = 0;
++my $cclient;
++
++# for ( $waitedpid = 0;
++# ($cclient = $server->accept()) || $waitedpid;
++# $waitedpid = 0)
++while (($cclient = $server->accept()))
++{
++ # next if $waitedpid and not $cclient;
++ die unless $cclient;
++ REAPER();
++ my $paddr = $cclient->peername();
++ my($port,$iaddr) = sockaddr_in($paddr);
++ my $name = gethostbyaddr($iaddr,AF_INET);
++
++ logmsg "connection from $name:$port"; # [", inet_ntoa($iaddr), "]"
++
++ ++$nconnections;
++
++ spawn \&proxy, $cclient;
++}
++
++sub spawn {
++ my $coderef = shift;
++
++ unless ($coderef && ref($coderef) eq 'CODE') {
++ confess "usage: spawn CODEREF";
++ }
++
++ my $pid;
++ if (!defined($pid = fork)) {
++ logmsg "cannot fork: $!";
++ return;
++ } elsif ($pid) {
++ logmsg "begat $pid";
++ return; # I'm the parent
++ }
++ # else I'm the child -- go spawn
++
++ exit &$coderef(@_);
++}
++
++sub kill_server()
++{
++ kill "INT", $server_pid;
++}
++
++my $start = 0;
++my $done = 0;
++my $success = 0;
++my $url;
++my $n = 0;
++my $m = 0;
++my $bytes_transferred = 0;
++my $chars;
++my $nchars;
++
++sub if_done_ping()
++{
++ if ($done) {
++ if ($success) {
++ print "success\n";
++ } else {
++ print "failed\n";
++ return 0;
++ }
++ }
++}
++
++sub if_done_kill()
++{
++ if ($done) {
++ kill_server();
++ }
++}
++
++sub eval_test_code()
++{
++ return unless $testcode;
++ my $time = time() - $time_started;
++ warn "test code failed: $!" unless defined eval $testcode;
++}
++
++my ($client, $target);
++
++sub close_connection {
++ my $ok = (shift) ? 1 : 0;
++ logmsg "closing connection ok=$ok";
++ # $client->close(), $target->close() doesn't always work for some reason
++ # (maybe to do with forked processes)
++ $client->shutdown(2);
++ $target->shutdown(2);
++ logmsg "exiting";
++ exit !$ok;
++}
++
++sub proxy {
++ $client = shift or die;
++
++ $target = IO::Socket::INET->new(PeerAddr => $target_server)
++ or die "$0: couldn't connect to $target_server: $!";
++
++ $client->autoflush(1);
++ $target->autoflush(1);
++
++ {
++ $bytes_transferred = 0;
++ $chars = undef; $nchars = 0;
++ $done = 0;
++ $success = 0;
++ $start = 1;
++ $url = '';
++ eval_test_code();
++ $start = 0;
++ }
++
++ # transfer lines from client -> server until we get an empty line
++
++ while (my $line = $client->getline()) {
++ if ($. == 1 && $line =~ /^(GET|PUT|POST) ([^\s]+)/) {
++ $url = $2;
++ logmsg "url = $url";
++ }
++ $target->print($line);
++ $line =~ s/[\015\012]+$//;
++ last unless $line;
++ }
++
++ # indicate we have stopped reading data from client and stopped writing
++ # data to server (not sure if this helps)
++ $client->shutdown(0);
++ $target->shutdown(1);
++
++ # transfer from server->client
++
++ while ($nchars = $target->read($chars, 128)) {
++ eval_test_code();
++ $bytes_transferred += $nchars;
++ $client->write($chars, $nchars);
++ }
++
++ {
++ $chars = undef; $nchars = 0;
++ $done = 1;
++ $success = $client->connected() && 1;
++ eval_test_code();
++ }
++
++ close_connection(1);
++ return 0;
++}
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/concat_correct_output
+@@ -0,0 +1,2651 @@
++<html>
++ <head>
++ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
++ <META http-equiv="Content-Type" CONTENT="text/html" CHARSET="UTF-8">
++ <META HTTP-EQUIV="Content-Style-Type" CONTENT="text/css">
++ <STYLE TYPE="text/css" MEDIA="screen">
++ BODY, H2, H3, H4, P, UL, OL, DL
++ {
++ font-family: "Verdana", "Helvetica", "Arial", "sans-serif"
++ }
++
++ H1 {color: #0058a0; font-size: 20pt}
++ H2 {color: #0058a0; font-size: 16pt}
++ H3 {color: #0058a0; font-size: 14pt}
++ H4 {color: #0058a0; font-size: 12pt}
++
++ A:link, A:active, A:visited
++ {
++ color: #0058a0;
++ text-decoration: none
++ }
++
++ P, UL, OL, DL {margin-left: 10%; margin-right: 10%; font-size: 10pt}
++ DT {margin-bottom: 0.5em}
++ .offset {margin-left: 10%}
++ .afterskip {margin-bottom: 1em}
++ .afterhalf {margin-bottom: 0.5em}
++ .example {margin-left: 10%; margin-right: 10%;
++ border-color: #0058a0; border-style:solid; border-width: 1pt; padding: 1pt}
++ CODE {font-family: "Courier"}
++ .comment {color: #0000ff}
++
++ P.offset {margin-left: 15%}
++ P.inner {margin-left: 2%; width: 96%}
++ P.note {margin-left: 10%; border-color: #0058a0;
++ border-style:solid; border-width: 1pt;
++ padding: 5pt; background-color:#e0e0e0 }
++
++ PRE {font-size: 10pt; padding: 5pt}
++
++ </STYLE>
++ <title>GAdoc - Sablotron 0.60</title>
++ </head>
++ <body bgcolor="#ffffff">
++ <h1 CLASS="afterskip">Sablotron 0.60</h1>
++ <DIV CLASS="afterskip">
++ <p>
++ <b>
++ <i>Tom Kaiser (Ginger Alliance)</i>
++ </b>
++ </p>
++ <p>
++ <i>June 17, 2001</i>
++ </p>
++ </DIV>
++ <h3>Abstract</h3>
++ <DIV CLASS="offset">This is a description of the current version of the
++ XSLT processor called Sablotron, including an overview of its
++ limitations as compared to the XSLT specification.
++ </DIV>
++ <h3>Contents</h3>
++<DIV STYLE="margin-left: 10%; margin-bottom: 2em; font-size: smaller">
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__25"></a> <a href="#i__25">
++ <b>1 This text</b>
++ </a>
++ <DIV class="offset"></DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__60"></a> <a href="#i__60">
++ <b>2 Changes from the last release</b>
++ </a>
++ <DIV class="offset"></DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__74"></a> <a href="#i__74">
++ <b>3 Introduction</b>
++ </a>
++ <DIV class="offset"> <a href="#i__81">3.1 XSLT</a>
++ <BR> <a href="#i__154">3.2 On Sablotron</a>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__227"></a> <a href="#i__227">
++ <b>4 The sources</b>
++ </a>
++ <DIV class="offset"> <a href="#i__238">4.1 Getting the sources</a>
++ <BR> <a href="#i__280">4.2 Joining the development</a>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__305"></a> <a href="#i__305">
++ <b>5 Implementation. Supported instructions and functions</b>
++ </a>
++ <DIV class="offset"> <a href="#i__343">5.1 Templates</a>
++ <BR> <a href="#i__364">5.2 Conditional processing</a>
++ <BR> <a href="#i__381">5.3 Loops</a>
++ <BR> <a href="#i__398">5.4 Variables and parameters</a>
++ <BR> <a href="#i__415">5.5 Element creation</a>
++ <BR> <a href="#i__439">5.6 Global definitions</a>
++ <BR> <a href="#i__476">5.7 Values and copying</a>
++ <BR> <a href="#i__508">5.8 Namespace processing</a>
++ <BR> <a href="#i__529">5.9 Sorting</a>
++ <BR> <a href="#i__577">5.10 Whitespace stripping</a>
++ <BR> <a href="#i__598">5.11 Includes</a>
++ <BR> <a href="#i__623">5.12 Other unimplemented instructions</a>
++ <BR> <a href="#i__654">5.13 Output conformance</a>
++ <BR> <a href="#i__686">5.14 XPath expressions</a>
++ <BR> <a href="#i__714">5.15 Built-in functions</a>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__804"></a> <a href="#i__804">
++ <b>6 Other implementation-related notes</b>
++ </a>
++ <DIV class="offset"> <a href="#i__811">6.1 Handlers</a>
++ <BR> <a href="#i__859">6.2 Encodings</a>
++ <BR> <a href="#i__887">6.3 Output methods</a>
++ <BR> <a href="#i__915">6.4 URIs</a>
++ <BR> <a href="#i__983">6.5 Named buffers</a>
++ <BR> <a href="#i__1015">6.6 Error and log messages</a>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__1048"></a> <a href="#i__1048">
++ <b>7 The C interface</b>
++ </a>
++ <DIV class="offset"> <a href="#i__1065">7.1 Shortcuts</a>
++ <BR> <a href="#i__1205">7.2 Basic functions</a>
++ <BR> <a href="#i__1416">7.3 Generalized interface functions</a>
++ <BR> <a href="#i__1578">7.4 The situation object</a>
++ <BR> <a href="#i__1631">7.5 Document Object Model (DOM) functions</a>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__1870"></a> <a href="#i__1870">
++ <b>8 The command line interface</b>
++ </a>
++ <DIV class="offset"></DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__2013"></a> <a href="#i__2013">
++ <b>9 References</b>
++ </a>
++ <DIV class="offset"></DIV>
++ </SPAN>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__25"></a>
++ <h2>
++ <a href="#toc_i__25">1 This text</a>
++ </h2>
++ <DIV>
++ <p CLASS="">The HTML form of this description
++ was compiled by Sablotron from the XML source
++ Sablot-0-60.xml.
++ </p>
++ <p CLASS="">
++ The material in the following sections includes:
++ </p>
++ <ul>
++ <li>some background information on XSLT and Sablotron,</li>
++ <li>a detailed comparison of the current version of
++ Sablotron to the XSLT spec,</li>
++ <li>Sablotron usage from the command line or as a
++ library.</li>
++ </ul>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__60"></a>
++ <h2>
++ <a href="#toc_i__60">2 Changes from the last release</a>
++ </h2>
++ <DIV>
++ <p CLASS="">Please see the RELEASE file.</p>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__74"></a>
++ <h2>
++ <a href="#toc_i__74">3 Introduction</a>
++ </h2>
++ <DIV>
++ <DIV class="afterskip">
++ <a name="i__81"></a>
++ <h3>
++ <a href="#toc_i__74">3.1 XSLT</a>
++ </h3>
++ <p CLASS="">XSLT is a language allowing to transform given XML data (the
++ <i>input</i>) according to a <i>stylesheet</i>. XSLT stylesheets
++ are themselves XML documents; that is, all instructions of the
++ language are expressed in the form of XML elements. The
++ <i>output</i>, i.e. the result of the processing, is typically a
++ XML document as well, although the syntactic requirements can be
++ relaxed to allow the creation of a HTML document (one that
++ contains unclosed tags and the like), or even plain text.
++ </p>
++ <p CLASS="">XSLT was designed by the World Wide Web Consortium (W3C) as
++ a part of the XSL stylesheet language, where it is complemented
++ by a powerful set of formatting instructions. The most precise
++ information about XSLT can be found in the W3C Recommendation <a href="#ref-xslt">[XSLT]</a>. In particular, Appendix B of the
++ Recommendation contains a handy syntax table. A good tutorial is
++ <a href="#ref-bible">[XMLBible14]</a>.
++ </p>
++ <p CLASS="">Other W3C Recommendations one often needs to consult are <a href="#ref-xml">[XML]</a> (for the definition of the XML
++ language) and <a href="#ref-xpath">[XPath]</a> (for details on
++ XPath, the language used to form expressions in XSLT and
++ elsewhere).
++ </p>
++ <p CLASS="">An excellent source of information about XSLT (indeed, about
++ anything related to XML and SGML) is <a href="#ref-rcover">[Cover]</a>; see also <a href="#ref-xslinfo">[XSLINFO]</a> and <a href="#ref-xmlorg">[XMLorg]</a>.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__154"></a>
++ <h3>
++ <a href="#toc_i__74">3.2 On Sablotron</a>
++ </h3>
++ <p CLASS="">Sablotron is a XSLT processor (though not quite conforming
++ yet..., see below) written in C++. Since the machines where it
++ is meant to run include various small mobile
++ clients, the main objectives of its design are the following:
++ </p>
++ <ul>
++ <li>portability,</li>
++ <li>compact code,</li>
++ <li>as much independence on other resources (Java etc.) as
++ possible.</li>
++ </ul>
++ <p CLASS="">Sablotron is a single shared library
++ (<code>sablot.dll</code> or <code>libsablot.so.0.60</code>). It can
++ also be used from the command line via the simple interface
++ called <code>sabcmd</code>. See <a href="#invocation">here</a> for
++ more information.
++ </p>
++ <p CLASS="">The only software Sablotron relies on is <b>expat</b>, the
++ XML parser by James Clark. See <a href="#expat">below</a> for
++ information on how to get expat.
++ </p>
++ <p CLASS="">For information on the available interfaces, e.g. for
++ Python, Perl and PHP, see <a href="http://www.gingerall.com">www.gingerall.com</a>.
++ </p>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__227"></a>
++ <h2>
++ <a href="#toc_i__227">4 The sources</a>
++ </h2>
++ <DIV>
++ <p CLASS="">
++ Sablotron is written in C++. The source files compile under
++ Win32 (using MS Visual C++ 6.0) and on Solaris and Linux (using
++ g++ 2.95.2) without change.</p>
++ <DIV class="afterskip">
++ <a name="i__238"></a>
++ <h3>
++ <a href="#toc_i__227">4.1 Getting the sources</a>
++ </h3>
++ <p CLASS="">The source or binary distributions of Sablotron can be downloaded
++ from <a href="http://www.gingerall.com">www.gingerall.com</a>. For
++ instructions on how to build the sources (if any), refer to the accompanying INSTALL file.
++ </p>
++ <p CLASS="">If you have access to the Ginger Alliance CVS server, you
++ can get the working version of Sablotron in the CVS module
++ <code>ga</code>. The access rights can be obtained on
++ request from <a href="mailto:cvsadmin at gingerall.com">the CVS admin</a>.
++ </p>
++ <p CLASS="">
++ <a name="expat"></a>
++ Since version 0.50, Sablotron uses expat 1.95.1, available from <a href="http://expat.sourceforge.org">SourceForge</a>.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__280"></a>
++ <h3>
++ <a href="#toc_i__227">4.2 Joining the development</a>
++ </h3>
++ <p CLASS="">
++ Sablotron is an open source project and all volunteers are most
++ welcome! The documentation of the sources is still somewhat
++ sparse but we will try to improve it. If you find the invitation
++ to work on Sablotron with us interesting, please <a href="mailto:sablotron at gingerall.com">contact us</a>. There is also
++ a mailing list available, see <a href="http://www.gingerall.com">www.gingerall.com</a>.
++ </p>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__305"></a>
++ <h2>
++ <a href="#toc_i__305">5 Implementation. Supported instructions and functions</a>
++ </h2>
++ <DIV>
++ <p CLASS="">The instruction set supported by this version of Sablotron is
++ already sufficient for many transformation tasks (e.g. the task of
++ formatting this document). On the other
++ hand, a comparison of it to the XSLT specification <a href="#ref-xslt">[XSLT]</a> shows that much is still to be
++ done. The purpose of the
++ following sections is to describe the varying degree of support
++ for the elements of the XSLT language. </p>
++ <p CLASS="">It may be helpful to refer to the syntax table in Appendix B
++ of <a href="#ref-xslt">[XSLT]</a>. The instructions/attributes that
++ are not listed as unsupported should be implemented. The <a href="mailto:sablotron at gingerall.com">authors</a> will appreciate being
++ told about any omissions found in the following
++ description.</p>
++ <p CLASS="">For readability, I sometimes omit the <code>xsl:</code> prefix
++ from the instruction names.</p>
++ <DIV class="afterskip">
++ <a name="i__343"></a>
++ <h3>
++ <a href="#toc_i__305">5.1 Templates</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ template, apply-templates, call-template
++ </code>
++ </p>
++ <p CLASS="">
++ Fully implemented. <code>xsl:sort</code> is supported since release 0.50.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__364"></a>
++ <h3>
++ <a href="#toc_i__305">5.2 Conditional processing</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ if, choose, when, otherwise
++ </code>
++ </p>
++ <p CLASS="">Fully implemented.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__381"></a>
++ <h3>
++ <a href="#toc_i__305">5.3 Loops</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>for-each</code>
++ </p>
++ <p CLASS="">Fully implemented.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__398"></a>
++ <h3>
++ <a href="#toc_i__305">5.4 Variables and parameters</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>variable, param, with-param</code>
++ </p>
++ <p CLASS="">Fully implemented. Top-level variables and parameters are
++ read in the document order, so no forward references are
++ resolved. This is a minor deviation from the spec. </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__415"></a>
++ <h3>
++ <a href="#toc_i__305">5.5 Element creation</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>element, attribute, text,
++ comment, processing-instruction, attribute-set</code>
++ </p>
++ <p CLASS="">
++ <code>xsl:attribute-set</code> is not implemented. For the
++ rest, <code>name</code> is the only recognized attribute (where
++ applicable). Literal result elements work.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__439"></a>
++ <h3>
++ <a href="#toc_i__305">5.6 Global definitions</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>stylesheet, transform, output</code>
++ </p>
++ <p CLASS="">For <code>stylesheet</code> and <code>transform</code>,
++ the only recognized attribute is
++ <code>version</code>. <code>xsl:output</code> should work
++ (see below for notes on the <code>encoding</code>
++ attribute). HTML indentation has been added in 0.60.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__476"></a>
++ <h3>
++ <a href="#toc_i__305">5.7 Values and copying</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>value-of, copy, copy-of</code>
++ </p>
++ <p CLASS="">
++ <code>copy-of</code> and <code>value-of</code> are fully
++ implemented. <code>copy</code> is implemented except for the
++ <code>use-attribute-sets</code> attribute.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__508"></a>
++ <h3>
++ <a href="#toc_i__305">5.8 Namespace processing</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>namespace-alias</code>
++ </p>
++ <p CLASS="">Namespaces should be processed correctly. The
++ <code>namespace-alias</code> instruction is now supported
++ (patch by Major).</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__529"></a>
++ <h3>
++ <a href="#toc_i__305">5.9 Sorting</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>sort</code>
++ </p>
++ <p CLASS="">
++ <code>xsl:sort</code> is implemented since 0.50. There are
++ minor limitations:
++ </p>
++ <ul>
++ <li>currently, the <code>lang</code> attribute may only
++ contain the values <code>"en"</code> or <code>"cz"</code>.</li>
++ <li>
++ <code>case-order</code> cannot be specified.</li>
++ </ul>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__577"></a>
++ <h3>
++ <a href="#toc_i__305">5.10 Whitespace stripping</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>strip-space, preserve-space</code>
++ </p>
++ <p CLASS="">Only the default whitespace stripping is done. That is,
++ all whitespace-only text nodes in any stylesheet, not appearing
++ inside a <code>xsl:text</code>, are removed. The two
++ instructions for whitespace stripping and preservation are
++ unsupported.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__598"></a>
++ <h3>
++ <a href="#toc_i__305">5.11 Includes</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>include, import, apply-imports</code>
++ </p>
++ <p CLASS="">Only <code>xsl:include</code> is implemented. Processing
++ involving multiple documents works, but has to get more testing,
++ eg. with respect to <code>generate-id()</code>.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__623"></a>
++ <h3>
++ <a href="#toc_i__305">5.12 Other unimplemented instructions</a>
++ </h3>
++ <ul>
++ <li>
++ <code>xsl:key,</code>
++ </li>
++ <li>
++ <code>xsl:number,</code>
++ </li>
++ <li>
++ <code>xsl:fallback.</code>
++ </li>
++ </ul>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__654"></a>
++ <h3>
++ <a href="#toc_i__305">5.13 Output conformance</a>
++ </h3>
++ <p CLASS="">The output mechanism is much closer to the spec than in
++ the versions prior to 0.4. The following issues remain for the
++ html method:</p>
++ <ul>
++ <li>Output the boolean attributes correctly.</li>
++ <li>Disable the escaping inside
++ <code><SCRIPT></code> and
++ <code><STYLE></code>
++ </li>.
++ </ul>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__686"></a>
++ <h3>
++ <a href="#toc_i__305">5.14 XPath expressions</a>
++ </h3>
++ <p CLASS="">Almost all features of XPath are fully implemented. This means
++ there should be no problems with expressions of any kind.</p>
++ <p CLASS="">One exception relates to axes. The <code>following</code> and
++ <code>preceding</code> axes haven't been implemented yet.</p>
++ <p CLASS="">Another possible exception may be numbers; we did not yet do a
++ thorough test of rounding, NaNs, infinity, etc.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__714"></a>
++ <h3>
++ <a href="#toc_i__305">5.15 Built-in functions</a>
++ </h3>
++ <p CLASS="">
++ <a name="corelib"></a>Only a few functions from the standard
++ function library remain
++ unimplemented:
++ </p>
++ <ul>
++ <li>
++ <code>id()</code>,</li>
++ <li>
++ <code>lang()</code> (accepted but always returns true),</li>
++ <li>
++ <code>key()</code>,</li>
++ <li>
++ <code>format-number()</code>,</li>
++ <li>
++ <code>unparsed-entity-uri()</code>.</li>
++ </ul>
++ <p CLASS="">As for the fuctions that <i>are</i> implemented, the
++ following is a list of differences from the spec:
++ </p>
++ <ul>
++ <li>
++ <code>document()</code> only accepts one argument, always
++ getting the base URI from the stylesheet URI.
++ </li>
++ <li>
++ <code>string-length()</code> returns the byte length of
++ the UTF-8 representation of the string. This will typically
++ differ from the actual length.
++ </li>
++ <li>
++ <code>generate-id()</code> might fail to generate unique identifiers
++ when several input documents are present (giving the same id to
++ nodes from different documents).
++ </li>
++ </ul>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__804"></a>
++ <h2>
++ <a href="#toc_i__804">6 Other implementation-related notes</a>
++ </h2>
++ <DIV>
++ <DIV class="afterskip">
++ <a name="i__811"></a>
++ <h3>
++ <a href="#toc_i__804">6.1 Handlers</a>
++ </h3>
++ <p CLASS="">It is possible for the user to supply the following
++ handlers to Sablotron:
++ <ul>
++ <li>message handler (to bypass the default way of displaying
++ error and warning messages and logging),</li>
++ <li>scheme handler (to retrieve documents whose URI use an
++ unsupported scheme),</li>
++ <li>streaming handler (an expat-like interface to the XML
++ document which is the result of the processing),</li>
++ <li>'miscellaneous' handler (which will probably server as a
++ collections of odd callbacks).</li>
++ </ul>
++ </p>
++ <p CLASS="">
++ The handlers are set using <code>SablotRegHandler()</code>
++ For details concerning the interface of these handlers,
++ consult the header files <code>sablot.h</code> and
++ <code>shandler.h</code>.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__859"></a>
++ <h3>
++ <a href="#toc_i__804">6.2 Encodings</a>
++ </h3>
++ <p CLASS="">
++ In version 0.52, the encoding conversion capabilities of
++ Sablotron have been much extended. The most important fact is the
++ following: if you have the iconv library installed on your system, you
++ can use any encoding it supports (that is, almost any encoding
++ whatsoever) for both the input and the output documents. Iconv
++ is available on most systems (it is a standard part of glibc2,
++ for instance). There are implementations for Win32 as well.
++ </p>
++ <p CLASS="">If iconv is not available, the encoding may still be supported internally by
++ Sablotron. At present, the list is of such encodings is rather
++ short: besides UTF-8, these are UTF-16, ASCII, iso-8859-1,
++ iso-8859-2 and windows-1250 on input, none on output. However,
++ we plan to implement a half independent light-weight
++ conversion library for use on systems without iconv,
++ extending the set of internally supported encodings
++ considerably.
++ </p>
++ <p CLASS="">Lastly, the user has the option to implement a custom
++ encoding conversion handler, which will be asked to perform any unsupported
++ conversion. See the <code>shandler.h</code> header file for
++ details.
++ </p>
++ <p CLASS="">The default input and output encoding is in all cases UTF-8.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__887"></a>
++ <h3>
++ <a href="#toc_i__804">6.3 Output methods</a>
++ </h3>
++ <p CLASS="">In addition to the standard output methods (xml, html and
++ text), it is possible to output xhtml. Documents output using
++ this method obey the XHTML 1.0 rules (in particular, all empty
++ elements are closed). To choose the method, use
++ <code><xsl:output method='xhtml'></code>. <b>Please note</b>
++ that the name of this method will possibly be changed since the XSLT
++ spec requires any processor-specific methods to have qualified
++ names, say <code>sab:xhtml</code>. On the other hand, the name
++ <code>xhtml</code> is considered in the XSLT 2.0 working draft.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__915"></a>
++ <h3>
++ <a href="#toc_i__804">6.4 URIs</a>
++ </h3>
++ <p CLASS="">Sablotron can handle
++ two URI schemes natively: 'file' and 'arg' (see
++ below). Moreover, it is possible to use the function
++ <code>SablotRegSchemeHandler</code> to register an external scheme
++ handler which will receive requests in all other schemes. See
++ the documentation in <code>sablot.h</code> and
++ <code>shandler.h</code>.
++ </p>
++ <p CLASS="">Relative URI references are resolved in conformance to RFC
++ 2396. The base URI is well defined when the relative reference appears
++ inside a XML document; when invoking sabcmd, the base URI is
++ taken to correspond to the current working directory.
++ </p>
++ <p CLASS="">
++ <a name="fname-rules"></a>When specifying filenames, the
++ following rules are in effect:
++ </p>
++ <ul>
++ <li>specify the "file:" scheme for any standard files,
++ i.e. refer to <code>stdin</code> as <code>file://stdin</code>
++ etc.</li>
++ <li>slashes and backslashes work equally fine, in Windows as
++ well as Linux.</li>
++ <li>to include a drive letter under Windows
++ (e.g. <code>C:\doc.xml</code>), it is necessary to say
++ <code>file://c:/doc.xml</code>.
++ </li>
++ </ul>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__983"></a>
++ <h3>
++ <a href="#toc_i__804">6.5 Named buffers</a>
++ </h3>
++ <p CLASS="">
++ <a name="argscheme"></a>Sablotron introduces an URI scheme
++ 'arg:' which enables one to use strings in named memory
++ buffers. The buffer names can have a tree-like structure so that
++ a relative reference from a document in a buffer can be resolved
++ as pointing to another buffer.
++ </p>
++ <p CLASS="">For instance, if we invoke Sablotron specifying that a
++ buffer named <code>/mybuf/1</code> contains the string
++ "<a>contents</a>", then the expression
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ document('arg:/mybuf/1')/a
++ </code>
++ </p>
++ <p CLASS="">has string-value "contents". If the document in arg:/mybuf/1
++ contained a relative URI reference "../theirbuf/2" then this
++ would be resolved as pointing to "arg:/theirbuf/2".</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1015"></a>
++ <h3>
++ <a href="#toc_i__804">6.6 Error and log messages</a>
++ </h3>
++ <p CLASS="">By default, Sablotron writes error and warning messages to
++ stderr, and does no logging. By a call to
++ <code>SablotSetLog()</code>, you can specify the name of the log
++ file to be used.</p>
++ <p CLASS="">Besides, you can use <code>SablotRegHandler()</code>
++ to override the default message handling. The handler you
++ register will receive all messages in a structured form that's
++ easy to process and filter. For details, see
++ the documentation in <code>sablot.h</code> and
++ <code>shandler.h</code>.</p>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1048"></a>
++ <h2>
++ <a href="#toc_i__1048">7 The C interface</a>
++ </h2>
++ <DIV>
++ <p CLASS="">
++ <a name="invocation"></a>
++ </p>
++ <p CLASS="">
++ This section describes the functions exported from the
++ Sablotron library. All of them have a return type of 'int'
++ and return an error flag (nonzero signals an error). Errors
++ are reported to the user by Sablotron itself.
++ </p>
++ <DIV class="afterskip">
++ <a name="i__1065"></a>
++ <h3>
++ <a href="#toc_i__1048">7.1 Shortcuts</a>
++ </h3>
++ <p CLASS="">
++ We'll first describe the 'shortcuts' that do the whole
++ processing in one call.
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotProcess(char *sheetURI, char *inputURI, char *resultURI,
++ char **params, char **arguments, char **resultArg);
++ </code>
++ </p>
++ <p CLASS="">
++ This is the basic function. The first three of its arguments
++ are the URIs of the XSLT stylesheet, the XML source and the
++ resulting document, respectively. For some notes on specifying
++ file names, see <a href="#fname-rules">above</a>.
++ </p>
++ <p CLASS="">
++ <code>params</code> is an array of pointers to the names
++ and contents of the top-level stylesheet parameters. Thus,
++ <code>params[0]</code> is a pointer to the null-terminated name
++ of the first parameter, <code>params[1]</code> points to the
++ (null-terminated) contents of the first parameter. The following
++ two array items do the same for the second parameter, etc. The
++ whole array is terminated by a NULL pointer in place of the
++ name. If no parameters are to be passed, you can specify NULL
++ for <code>params</code> itself.
++ </p>
++ <p CLASS="">
++ <code>arguments</code> is a similar array of named buffers
++ to be passed to the stylesheet. (They can be referred to via the
++ 'arg:' scheme, see <a href="#argscheme">above</a>.) Again, the
++ array is a sequence of (name, value) pairs terminated by NULL in
++ place of a name. If no named buffers are to be passed, you can
++ specify NULL for <code>arguments</code> itself.
++ </p>
++ <p CLASS="">
++ <code>resultArg</code> enables one to access the
++ resulting document in case the output went to a named buffer. In
++ that situation, <code>*resultArg</code> points to the resulting
++ null-terminated string, allocated by Sablotron. You can pass NULL
++ for <code>resultArg</code> if the output is sure to go to a
++ file.
++ </p>
++ <p CLASS="">
++ <b>Note:</b>When you are done processing the string
++ pointed to by <code>*resultArg</code>, free it using <a href="#sablotfree">
++ <code>SablotFree()</code>
++ </a> - never use
++ <code>free()</code>. The latter is guaranteed to produce a
++ segmentation fault under Linux.
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotProcessFiles(char *styleSheetName,
++ char *inputName,
++ char *resultName);
++ </code>
++ </p>
++ <p CLASS="">A wrapper for <code>SablotProcess()</code> working on
++ files. The parameters are the null-terminated file names of the
++ XSLT stylesheet, the XML input and the result,
++ respectively. Sablotron opens these files itself and closes them
++ after the processing is complete. Values like "file://stdin" are
++ allowed.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotProcessStrings(char *styleSheetStr, char *inputStr, char
++ **resultStr);
++ </code>
++ </p>
++ <p CLASS="">Another wrapper for <code>SablotProcess()</code>, this
++ time for accessing named buffers (i.e. user-allocated memory
++ blocks)only. Thus, the first parameter is a null-terminated
++ string containing the whole stylesheet; the second parameter
++ is a null-terminated string containing the XML
++ input. Sablotron allocates the buffer for the resulting string
++ and returns a pointer to it in resultStr. Hence, invoking
++ <code>puts(*resultStr)</code> after having called
++ <code>SablotProcessStrings</code> sends the result to
++ stdout. The buffer allocated <b>must</b> be freed by calling the
++ function <code>SablotFree</code> described next.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1205"></a>
++ <h3>
++ <a href="#toc_i__1048">7.2 Basic functions</a>
++ </h3>
++ <p CLASS="">The above shortcuts just call the basic, lower-level
++ functions described below. Note that if you need to set options
++ for logging etc., you may need to use the low-level
++ functions. </p>
++ <p CLASS="">A typical processing session may look like this:</p>
++ <p CLASS="">
++ <pre>
++ SablotHandle p;
++ char *my_buf;
++ SablotCreateProcessor(&p);
++ SablotSetLog(p, ...);
++ /* ...set other instance-specific options here... */
++ SablotRunProcessor(p, ...);
++ SablotGetResultArg(p, "arg:/somename", &my_buf)
++ /* ...do something with my_buf... */
++ /* can run the processor again if necessary */
++ SablotRunProcessor(p, ...);
++ SablotDestroyProcessor(p);
++ </pre>
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotCreateProcessor(SablotHandle *processorPtr);
++ </code>
++ </p>
++ <p CLASS="">Creates an instance of Sablotron and returns a pointer to
++ it in *processorPtr. This pointer is passed on all subsequent
++ calls to this instance. </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotDestroyProcessor(SablotHandle processor_);
++ </code>
++ </p>
++ <p CLASS="">Destroys an instance of the processor, deallocating all
++ the memory used up by it.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotRunProcessor(SablotHandle processor_,
++ char *sheetURI,
++ char *inputURI,
++ char *resultURI,
++ char **params,
++ char **arguments);
++ </code>
++ </p>
++ <p CLASS="">Processes documents using the given processor instance and
++ given params and args definitions. See
++ <code>SablotProcess()</code>.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotGetResultArg(SablotHandle processor_,
++ char *argURI,
++ char **argValue);
++ </code>
++ </p>
++ <p CLASS="">Copies the result 'arg' buffer with the given URI,
++ returning a pointer to the newly-allocated block in
++ *argValue. If no such buffer exists, returns NULL in *argValue.
++ </p>
++ <p CLASS="">This function is necessary, because if the result document
++ is output to memory, it would be lost when
++ <code>SablotDestroyProcessor()</code> is called. When
++ deallocating the copy obtained from
++ <code>SablotGetResultArg()</code>, use <code>SablotFree</code>
++ (never <code>free()</code>). </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotFreeResultArgs(SablotHandle processor_);
++ </code>
++ </p>
++ <p CLASS="">Removes the Sablotron-internal copies of the 'arg' buffers
++ from the last Sablotron run. Normally, there should be no reason
++ to call this function as it is called automatically on both
++ <code>SablotRunProcessor()</code> and
++ <code>SablotDestroyProcessor()</code>. </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ <a name="sablotfree"></a>
++ int SablotFree(char *resultBuf);
++ </code>
++ </p>
++ <p CLASS="">This function frees the buffer allocated on previous call
++ to <code>SablotProcessStrings</code>. Calling it with an
++ invalid pointer will cause a crash.
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotRegHandler(
++ SablotHandle processor_,
++ HandlerType type,
++ void *handler,
++ void *userData);
++ </code>
++ </p>
++ <p CLASS="">Registers an external handler. <code>type</code> can be
++ <code>HLR_MESSAGE</code>, <code>HLR_SCHEME</code>,
++ <code>HLR_SAX</code>, <code>HLR_MISC</code> or
++ <code>HLR_ENC</code>.
++ <code>handler</code> points to the
++ callback vector of the appropriate type. <code>userData</code>
++ is a data item to passed to all callbacks of this particular
++ handler. For details, check the <code>sablot.h</code> and
++ <code>shandler.h</code> header files.
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotUnregHandler(
++ SablotHandle processor_,
++ HandlerType type,
++ void *handler,
++ void *userData);
++ </code>
++ </p>
++ <p CLASS="">Unregisters the given external handler. For details, check the
++ <code>sablot.h</code> and <code>shandler.h</code> header
++ files.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotSetLog(
++ SablotHandle processor_,
++ const char *logFilename,
++ int logLevel);
++ </code>
++ </p>
++ <p CLASS="">Sets the log filename. The <code>logLevel</code> parameter
++ is currently not used. Pass NULL for <code>logFilename</code> to
++ turn logging off (default). </p>
++ <p CLASS="">The other functions published by sablot.h have been
++ included for experimental reasons or for compatibility, and it
++ is better not to use them.
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotClearError(SablotHandle processor_);
++ </code>
++ </p>
++ <p CLASS="">Clears the 'pending error' flag for this instance of
++ Sablotron.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1416"></a>
++ <h3>
++ <a href="#toc_i__1048">7.3 Generalized interface functions</a>
++ </h3>
++ <p CLASS="">The implementation of the <a href="#dom">DOM interface</a>
++ brought the need to extend some of the functions described in
++ the previous section. This extension enables the user to:
++ </p>
++ <ul>
++ <li>process documents created by the DOM functions, and</li>
++ <li>process frequently used documents in pre-parsed form.</li>
++ </ul>
++ <p CLASS="">An object called <i>situation</i> is used to provide a
++persistent context for all calls to the DOM-related
++functions. Functions used to manipulate the situation are described in
++<a href="#situation">the following section</a>.</p>
++ <p CLASS="">
++ <b>Note:</b> If not specified otherwise, all these
++ functions return an error code. A positive value indicates an error.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotCreateDocument(SablotSituation S,
++ SDOM_Document *D);
++ </code>
++ </p>
++ <p CLASS="">Creates an empty document. Typically followed by calls to
++ DOM functions to populate the document.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotDestroyDocument(SablotSituation S,
++ SDOM_Document D);
++ </code>
++ </p>
++ <p CLASS="">Destroys a document, freeing all the nodes it has created.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotParse(SablotSituation S,
++ const char *uri, SDOM_Document *D);
++ </code>
++ </p>
++ <p CLASS="">Reads in a document from the given URI.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotParseBuffer(SablotSituation S,
++ const char *buffer, SDOM_Document *D);
++ </code>
++ </p>
++ <p CLASS="">Reads in a document from the given in-memory buffer.</p>
++ <p CLASS="">These functions have variants to be used if the document
++ is to be interpreted as an XSLT stylesheet, namely
++ <code>SablotParseStylesheet</code> and
++ <code>SablotParseStylesheetBuffer</code>.</p>
++ <p CLASS="">The following functions generalize
++ <code>SablotRunProcessor</code> in that they make it possible to
++ utilize an extra kind of a source document: a DOM tree.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotRunProcessorGen(SablotSituation S,
++ void *processor_,
++ char *sheetURI,
++ char *inputURI,
++ char *resultURI);
++ </code>
++ </p>
++ <p CLASS="">A key ingredient of the extended interface. Only the URIs
++ of the sources and of the result document are given to it. The
++ rest of the information passed to
++ <code>SablotRunProcessor</code> is conveyed through
++ <code>SablotAddArgBuffer,</code> <code>SablotAddArgTree</code>
++ and <code>SablotAddParam.</code> The scheme part of the
++ stylesheet URI or the input URI may be "arg:", in which
++ case they refer to a buffer or tree passed by these
++ functions. </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotAddArgBuffer(SablotSituation S,
++ void *processor_,
++ const char *argName,
++ const char *bufferValue);
++</code>
++ </p>
++ <p CLASS="">Creates a named buffer for the next processor run. The
++ buffer's name and contents are passed as arguments. The name
++ is interpreted relative to the 'arg:/' scheme.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotAddArgTree(SablotSituation S,
++ void *processor_,
++ const char *argName,
++ SDOM_Document tree);
++</code>
++ </p>
++ <p CLASS="">Associates the given document with a name for the next
++ processor run. The document is <i>not</i> destroyed after the
++ run is finished. The name is interpreted relative to the 'arg:/'
++ scheme.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotAddParam(SablotSituation S,
++ void *processor_,
++ const char *paramName,
++ const char *paramValue);
++ </code>
++ </p>
++ <p CLASS="">Adds a global stylesheet parameter for the next processor
++ run.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1578"></a>
++ <h3>
++ <a href="#toc_i__1048">7.4 The situation object</a>
++ </h3>
++ <p CLASS="">
++ <a name="situation"></a>At present, the situation object primarily holds information on any pending errors. A
++situation is created using</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotCreateSituation(SablotSituation
++ *SP);</code>
++ </p>
++ <p CLASS="">and destroyed by</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotDestroySituation(SablotSituation
++ S);</code>
++ </p>
++ <p CLASS="">To clear the pending error flag in a situation, use</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotClearSituation(SablotSituation
++ S);</code>
++ </p>
++ <p CLASS="">The following self-explanatory functions extract parts of the error information
++ from the situation:</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ const char *SablotGetErrorURI(SablotSituation S);<br>
++ int SablotGetErrorLine(SablotSituation S);<br>
++ const char *SablotGetErrorMsg(SablotSituation S);
++ </code>
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1631"></a>
++ <h3>
++ <a href="#toc_i__1048">7.5 Document Object Model (DOM) functions</a>
++ </h3>
++ <p CLASS="">
++ <a name="dom"></a>Starting with version 0.60, Sablotron implements
++ a major subset of the DOM Level 1 Core Specification <a href="#ref-dom">[DOM]</a>. A brief
++ description of the implemented interface follows; for more
++ details, please refer to the header file named
++ <code>sdom.h.</code>
++ </p>
++ <p CLASS="">All of the names related to the DOM interface start with
++ SDOM_ (for Sablot DOM).</p>
++ <p CLASS="">Major new types are <code>SDOM_Document</code> (a DOM tree) and
++ <code>SDOM_Node</code> (a node of the tree). A document can also be used in
++ place of a node. This reflects the fact in the DOM spec,
++ Document is a subclass of Node. When used in this way, the
++ document represents its own root node (which is not the same as
++ the `root element').</p>
++ <p CLASS="">Other types include:</p>
++ <ul>
++ <li>
++ <code>SDOM_char:</code> a DOM character type. Currently, this is just
++ char. Note that the DOM spec requires that the DOM
++ implementations work with UTF-16. Sablotron deviates from this
++ by using UTF-8 instead. A separate set of functions taking
++ UTF-16 strings will be provided.</li>
++ <li>
++ <code>SDOM_NodeType:</code> a node type enum. Some of the values are
++ <code>SDOM_ELEMENT_NODE,</code> <code>SDOM_ATTRIBUTE_NODE</code> and <code>SDOM_TEXT_NODE.</code> See
++ <code>sdom.h</code> for the rest.</li>
++ <li>
++ <code>SDOM_NodeList:</code> a node list returned by some of the
++ functions.</li>
++ <li>
++ <code>SDOM_Exception:</code> DOM exception codes enum, with values such
++ as <code>SDOM_NOT_FOUND_ERR</code> or <code>SDOM_INVALID_NODE_TYPE</code>. See <code>sdom.h</code>
++ for details.</li>
++</ul>
++ <p CLASS="">The functions listed below are implemented more or less as defined in
++ the DOM Level 1 Specification, with two exceptions:
++ their names are prefixed with <code>SDOM_</code> and the first argument is
++ always a <code>SablotSituation.</code> All the functions return
++ a <code>SDOM_Exception.</code> </p>
++ <ul>
++<li>
++ <code>createElement, createAttribute, createTextNode,
++createCDATASection, createComment, createProcessingInstruction</code>
++ </li>
++<li>
++ <code>getNodeType, getNodeName, setNodeName, getNodeValue, setNodeValue</code>
++ </li>
++<li>
++ <code>getParentNode, getFirstChild, getLastChild, getPreviousSibling,
++getNextSibling, getOwnerDocument</code>
++ </li>
++<li>
++ <code>insertBefore, appendChild, removeChild, replaceChild</code>
++ </li>
++<li>
++ <code>cloneNode</code>
++ </li>
++<li>
++ <code>getAttribute, setAttribute, removeAttribute, getAttributeList</code>
++ </li>
++</ul>
++ <p CLASS="">Several functions have been added:</p>
++ <ul>
++<li>
++ <code>disposeNode</code> frees all memory used by the given node</li>
++<li>
++ <code>cloneForeignNode</code> clones a node from a different
++document</li>
++<li>
++ <code>docToString</code> serializes the document, returning the
++resulting string</li>
++<li>
++ <code>xql</code> performs an XPath query on the DOM tree,
++returning a list of the nodes satisfying it.</li>
++</ul>
++ <p CLASS="">In addition, there are some functions used to manipulate
++ the node lists returned by <code>xql</code> and
++ <code>getAttributeList</code>. These include
++ <code>getNodeListLength</code>, <code>getNodeListItem</code> and
++ <code>disposeNodeList</code>.</p>
++ <p CLASS="">Finally, there are functions to extract DOM
++ exception-related information from the situation object, namely
++ <code>getExceptionCode</code>, <code>getExceptionMessage</code>
++ and <code>getExceptionDetails</code>.</p>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1870"></a>
++ <h2>
++ <a href="#toc_i__1870">8 The command line interface</a>
++ </h2>
++ <DIV>
++ <p CLASS="">Sablotron comes with a command-line interface to the
++ shared library, which is a program named
++ <code>sabcmd</code>. At present, <code>sabcmd</code> is invoked
++ as follows:</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ sabcmd [<i>options</i>] <i>stylesheet</i> [<i>input</i> [<i>result</i>]] [<i>assignments</i>]
++ </code>
++ </p>
++ <p CLASS="">The arguments are the URIs of the XSLT stylesheet, the
++ XML input document, and the resulting document, respectively. The
++ default for <code>
++ <i>input</i>
++ </code> is
++ <code>file://stdin</code> (meaning plain old stdin);
++ <code>
++ <i>result</i>
++ </code> defaults to
++ <code>file://stdout</code>. Filenames have to include the extension (if
++ any).</p>
++ <p CLASS="">You can display the list of available options by typing
++ <code>sabcmd --help</code>. Among the more useful ones are
++ <code>--log-file</code> (for setting the log file) and
++ <code>--measure</code> (measures and outputs the total
++ processing time).
++ </p>
++ <p CLASS="">
++ <a href="#fname-rules">The rules for filenames</a> are the same as
++ with <code>SablotProcess()</code>.
++ </p>
++ <p CLASS="">
++ <code>assignments</code> is a series of definitions of the
++ form:</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ name1=value1 name2=value2 ...
++ </code>
++ </p>
++ <p CLASS="">
++ assigning values to top-level stylesheet parameters and to named
++ buffers. These two cases are distinguished by a leading '$' in
++ the name of a stylesheet parameter. The names of the buffers do
++ <i>not</i> start with "arg:". They may start with a slash; if
++ they don't, the slash is prepended.
++ </p>
++ <p CLASS="">
++ <b>Note:</b> In most cases, it will be necessary to quote
++ the individual assignments. Whether to use single or double
++ quotes may depend on the shell used (or may it?) Single quotes
++ work for bash, double quotes work in Windows.
++ </p>
++ <p CLASS="">If the result URI refers to a named buffer, the output
++ would normally remain buried in memory. Sabcmd dumps the buffer to standard
++ output instead.
++ </p>
++ <p CLASS="">To sum up and give an example, the following would be a
++ valid invocation of sabcmd:</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ sabcmd sheet.xsl arg:/the_input "the_input=<a/>"
++ "$use_defaults=1"
++ </code>
++ </p>
++ <p CLASS="">This processes the document passed in the buffer named
++ the_input, using a stylesheet found in file "sheet.xsl" in the
++ working directory. We assign 1 to the top-level parameter called
++ "use_defaults". The output goes to stdout by default.
++ </p>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__2013"></a>
++ <h2>
++ <a href="#toc_i__2013">9 References</a>
++ </h2>
++ <DIV>
++ <dl>
++ <dt>
++ <a name="ref-xslt"></a>[XSLT]</dt>
++ <dd>
++ <a href="http://www.w3.org/TR/1999/REC-xslt-19991116">
++ XSL Transformations (XSLT) Version 1.0
++ </a>
++ </dd>
++
++ <dt>
++ <a name="ref-xpath"></a>[XPath]</dt>
++ <dd>
++ <a href="http://www.w3.org/TR/1999/REC-xpath-19991116">
++ XML Path Language (XPath) Version 1.0
++ </a>
++ </dd>
++
++ <dt>
++ <a name="ref-xml"></a>[XML]</dt>
++ <dd>
++ <a href="http://www.w3.org/TR/1998/REC-xml-19980210">
++ Extensible Markup Language (XML) 1.0
++ </a>
++ </dd>
++
++ <dt>
++ <a name="ref-dom"></a>[DOM]</dt>
++ <dd>
++ <a href="http://www.w3.org/TR/REC-DOM-Level-1">
++ Document Object Model Level 1 Specification, Version 1.0
++ </a>
++ </dd>
++
++ <dt>
++ <a name="ref-rcover"></a>[Cover]</dt>
++ <dd>
++ <a href="http://www.oasis-open.org/cover/sgml-xml.html">
++ The XML Cover Pages</a>
++ </dd>
++
++ <dt>
++ <a name="ref-xmlorg"></a>[XMLorg]</dt>
++ <dd>
++ <a href="http://xml.org">XML.org</a>
++ </dd>
++
++ <dt>
++ <a name="ref-xslinfo"></a>[XSLINFO]</dt>
++ <dd>
++ <a href="http://www.xslinfo.com">XSLINFO.com</a>
++ </dd>
++
++ <dt>
++ <a name="ref-bible"></a>[XMLBible14]</dt>
++ <dd>
++ <a href="http://metalab.unc.edu/xml/books/bible/updates/14.html">
++ Harold, E. R.: XML Bible, Chapter 14 (online presentation)
++ </a>
++ </dd>
++ </dl>
++ </DIV>
++ </DIV>
++ <hr>
++ <p STYLE="font-style: italic; margin-left: 0">(c) 2000 Ginger Alliance s.r.o.</p>
++ </body>
++</html><html>
++ <head>
++ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
++ <META http-equiv="Content-Type" CONTENT="text/html" CHARSET="UTF-8">
++ <META HTTP-EQUIV="Content-Style-Type" CONTENT="text/css">
++ <STYLE TYPE="text/css" MEDIA="screen">
++ BODY, H2, H3, H4, P, UL, OL, DL
++ {
++ font-family: "Verdana", "Helvetica", "Arial", "sans-serif"
++ }
++
++ H1 {color: #0058a0; font-size: 20pt}
++ H2 {color: #0058a0; font-size: 16pt}
++ H3 {color: #0058a0; font-size: 14pt}
++ H4 {color: #0058a0; font-size: 12pt}
++
++ A:link, A:active, A:visited
++ {
++ color: #0058a0;
++ text-decoration: none
++ }
++
++ P, UL, OL, DL {margin-left: 10%; margin-right: 10%; font-size: 10pt}
++ DT {margin-bottom: 0.5em}
++ .offset {margin-left: 10%}
++ .afterskip {margin-bottom: 1em}
++ .afterhalf {margin-bottom: 0.5em}
++ .example {margin-left: 10%; margin-right: 10%;
++ border-color: #0058a0; border-style:solid; border-width: 1pt; padding: 1pt}
++ CODE {font-family: "Courier"}
++ .comment {color: #0000ff}
++
++ P.offset {margin-left: 15%}
++ P.inner {margin-left: 2%; width: 96%}
++ P.note {margin-left: 10%; border-color: #0058a0;
++ border-style:solid; border-width: 1pt;
++ padding: 5pt; background-color:#e0e0e0 }
++
++ PRE {font-size: 10pt; padding: 5pt}
++
++ </STYLE>
++ <title>GAdoc - Sablotron 0.60</title>
++ </head>
++ <body bgcolor="#ffffff">
++ <h1 CLASS="afterskip">Sablotron 0.60</h1>
++ <DIV CLASS="afterskip">
++ <p>
++ <b>
++ <i>Tom Kaiser (Ginger Alliance)</i>
++ </b>
++ </p>
++ <p>
++ <i>June 17, 2001</i>
++ </p>
++ </DIV>
++ <h3>Abstract</h3>
++ <DIV CLASS="offset">This is a description of the current version of the
++ XSLT processor called Sablotron, including an overview of its
++ limitations as compared to the XSLT specification.
++ </DIV>
++ <h3>Contents</h3>
++<DIV STYLE="margin-left: 10%; margin-bottom: 2em; font-size: smaller">
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__25"></a> <a href="#i__25">
++ <b>1 This text</b>
++ </a>
++ <DIV class="offset"></DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__60"></a> <a href="#i__60">
++ <b>2 Changes from the last release</b>
++ </a>
++ <DIV class="offset"></DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__74"></a> <a href="#i__74">
++ <b>3 Introduction</b>
++ </a>
++ <DIV class="offset"> <a href="#i__81">3.1 XSLT</a>
++ <BR> <a href="#i__154">3.2 On Sablotron</a>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__227"></a> <a href="#i__227">
++ <b>4 The sources</b>
++ </a>
++ <DIV class="offset"> <a href="#i__238">4.1 Getting the sources</a>
++ <BR> <a href="#i__280">4.2 Joining the development</a>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__305"></a> <a href="#i__305">
++ <b>5 Implementation. Supported instructions and functions</b>
++ </a>
++ <DIV class="offset"> <a href="#i__343">5.1 Templates</a>
++ <BR> <a href="#i__364">5.2 Conditional processing</a>
++ <BR> <a href="#i__381">5.3 Loops</a>
++ <BR> <a href="#i__398">5.4 Variables and parameters</a>
++ <BR> <a href="#i__415">5.5 Element creation</a>
++ <BR> <a href="#i__439">5.6 Global definitions</a>
++ <BR> <a href="#i__476">5.7 Values and copying</a>
++ <BR> <a href="#i__508">5.8 Namespace processing</a>
++ <BR> <a href="#i__529">5.9 Sorting</a>
++ <BR> <a href="#i__577">5.10 Whitespace stripping</a>
++ <BR> <a href="#i__598">5.11 Includes</a>
++ <BR> <a href="#i__623">5.12 Other unimplemented instructions</a>
++ <BR> <a href="#i__654">5.13 Output conformance</a>
++ <BR> <a href="#i__686">5.14 XPath expressions</a>
++ <BR> <a href="#i__714">5.15 Built-in functions</a>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__804"></a> <a href="#i__804">
++ <b>6 Other implementation-related notes</b>
++ </a>
++ <DIV class="offset"> <a href="#i__811">6.1 Handlers</a>
++ <BR> <a href="#i__859">6.2 Encodings</a>
++ <BR> <a href="#i__887">6.3 Output methods</a>
++ <BR> <a href="#i__915">6.4 URIs</a>
++ <BR> <a href="#i__983">6.5 Named buffers</a>
++ <BR> <a href="#i__1015">6.6 Error and log messages</a>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__1048"></a> <a href="#i__1048">
++ <b>7 The C interface</b>
++ </a>
++ <DIV class="offset"> <a href="#i__1065">7.1 Shortcuts</a>
++ <BR> <a href="#i__1205">7.2 Basic functions</a>
++ <BR> <a href="#i__1416">7.3 Generalized interface functions</a>
++ <BR> <a href="#i__1578">7.4 The situation object</a>
++ <BR> <a href="#i__1631">7.5 Document Object Model (DOM) functions</a>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__1870"></a> <a href="#i__1870">
++ <b>8 The command line interface</b>
++ </a>
++ <DIV class="offset"></DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__2013"></a> <a href="#i__2013">
++ <b>9 References</b>
++ </a>
++ <DIV class="offset"></DIV>
++ </SPAN>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__25"></a>
++ <h2>
++ <a href="#toc_i__25">1 This text</a>
++ </h2>
++ <DIV>
++ <p CLASS="">The HTML form of this description
++ was compiled by Sablotron from the XML source
++ Sablot-0-60.xml.
++ </p>
++ <p CLASS="">
++ The material in the following sections includes:
++ </p>
++ <ul>
++ <li>some background information on XSLT and Sablotron,</li>
++ <li>a detailed comparison of the current version of
++ Sablotron to the XSLT spec,</li>
++ <li>Sablotron usage from the command line or as a
++ library.</li>
++ </ul>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__60"></a>
++ <h2>
++ <a href="#toc_i__60">2 Changes from the last release</a>
++ </h2>
++ <DIV>
++ <p CLASS="">Please see the RELEASE file.</p>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__74"></a>
++ <h2>
++ <a href="#toc_i__74">3 Introduction</a>
++ </h2>
++ <DIV>
++ <DIV class="afterskip">
++ <a name="i__81"></a>
++ <h3>
++ <a href="#toc_i__74">3.1 XSLT</a>
++ </h3>
++ <p CLASS="">XSLT is a language allowing to transform given XML data (the
++ <i>input</i>) according to a <i>stylesheet</i>. XSLT stylesheets
++ are themselves XML documents; that is, all instructions of the
++ language are expressed in the form of XML elements. The
++ <i>output</i>, i.e. the result of the processing, is typically a
++ XML document as well, although the syntactic requirements can be
++ relaxed to allow the creation of a HTML document (one that
++ contains unclosed tags and the like), or even plain text.
++ </p>
++ <p CLASS="">XSLT was designed by the World Wide Web Consortium (W3C) as
++ a part of the XSL stylesheet language, where it is complemented
++ by a powerful set of formatting instructions. The most precise
++ information about XSLT can be found in the W3C Recommendation <a href="#ref-xslt">[XSLT]</a>. In particular, Appendix B of the
++ Recommendation contains a handy syntax table. A good tutorial is
++ <a href="#ref-bible">[XMLBible14]</a>.
++ </p>
++ <p CLASS="">Other W3C Recommendations one often needs to consult are <a href="#ref-xml">[XML]</a> (for the definition of the XML
++ language) and <a href="#ref-xpath">[XPath]</a> (for details on
++ XPath, the language used to form expressions in XSLT and
++ elsewhere).
++ </p>
++ <p CLASS="">An excellent source of information about XSLT (indeed, about
++ anything related to XML and SGML) is <a href="#ref-rcover">[Cover]</a>; see also <a href="#ref-xslinfo">[XSLINFO]</a> and <a href="#ref-xmlorg">[XMLorg]</a>.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__154"></a>
++ <h3>
++ <a href="#toc_i__74">3.2 On Sablotron</a>
++ </h3>
++ <p CLASS="">Sablotron is a XSLT processor (though not quite conforming
++ yet..., see below) written in C++. Since the machines where it
++ is meant to run include various small mobile
++ clients, the main objectives of its design are the following:
++ </p>
++ <ul>
++ <li>portability,</li>
++ <li>compact code,</li>
++ <li>as much independence on other resources (Java etc.) as
++ possible.</li>
++ </ul>
++ <p CLASS="">Sablotron is a single shared library
++ (<code>sablot.dll</code> or <code>libsablot.so.0.60</code>). It can
++ also be used from the command line via the simple interface
++ called <code>sabcmd</code>. See <a href="#invocation">here</a> for
++ more information.
++ </p>
++ <p CLASS="">The only software Sablotron relies on is <b>expat</b>, the
++ XML parser by James Clark. See <a href="#expat">below</a> for
++ information on how to get expat.
++ </p>
++ <p CLASS="">For information on the available interfaces, e.g. for
++ Python, Perl and PHP, see <a href="http://www.gingerall.com">www.gingerall.com</a>.
++ </p>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__227"></a>
++ <h2>
++ <a href="#toc_i__227">4 The sources</a>
++ </h2>
++ <DIV>
++ <p CLASS="">
++ Sablotron is written in C++. The source files compile under
++ Win32 (using MS Visual C++ 6.0) and on Solaris and Linux (using
++ g++ 2.95.2) without change.</p>
++ <DIV class="afterskip">
++ <a name="i__238"></a>
++ <h3>
++ <a href="#toc_i__227">4.1 Getting the sources</a>
++ </h3>
++ <p CLASS="">The source or binary distributions of Sablotron can be downloaded
++ from <a href="http://www.gingerall.com">www.gingerall.com</a>. For
++ instructions on how to build the sources (if any), refer to the accompanying INSTALL file.
++ </p>
++ <p CLASS="">If you have access to the Ginger Alliance CVS server, you
++ can get the working version of Sablotron in the CVS module
++ <code>ga</code>. The access rights can be obtained on
++ request from <a href="mailto:cvsadmin at gingerall.com">the CVS admin</a>.
++ </p>
++ <p CLASS="">
++ <a name="expat"></a>
++ Since version 0.50, Sablotron uses expat 1.95.1, available from <a href="http://expat.sourceforge.org">SourceForge</a>.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__280"></a>
++ <h3>
++ <a href="#toc_i__227">4.2 Joining the development</a>
++ </h3>
++ <p CLASS="">
++ Sablotron is an open source project and all volunteers are most
++ welcome! The documentation of the sources is still somewhat
++ sparse but we will try to improve it. If you find the invitation
++ to work on Sablotron with us interesting, please <a href="mailto:sablotron at gingerall.com">contact us</a>. There is also
++ a mailing list available, see <a href="http://www.gingerall.com">www.gingerall.com</a>.
++ </p>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__305"></a>
++ <h2>
++ <a href="#toc_i__305">5 Implementation. Supported instructions and functions</a>
++ </h2>
++ <DIV>
++ <p CLASS="">The instruction set supported by this version of Sablotron is
++ already sufficient for many transformation tasks (e.g. the task of
++ formatting this document). On the other
++ hand, a comparison of it to the XSLT specification <a href="#ref-xslt">[XSLT]</a> shows that much is still to be
++ done. The purpose of the
++ following sections is to describe the varying degree of support
++ for the elements of the XSLT language. </p>
++ <p CLASS="">It may be helpful to refer to the syntax table in Appendix B
++ of <a href="#ref-xslt">[XSLT]</a>. The instructions/attributes that
++ are not listed as unsupported should be implemented. The <a href="mailto:sablotron at gingerall.com">authors</a> will appreciate being
++ told about any omissions found in the following
++ description.</p>
++ <p CLASS="">For readability, I sometimes omit the <code>xsl:</code> prefix
++ from the instruction names.</p>
++ <DIV class="afterskip">
++ <a name="i__343"></a>
++ <h3>
++ <a href="#toc_i__305">5.1 Templates</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ template, apply-templates, call-template
++ </code>
++ </p>
++ <p CLASS="">
++ Fully implemented. <code>xsl:sort</code> is supported since release 0.50.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__364"></a>
++ <h3>
++ <a href="#toc_i__305">5.2 Conditional processing</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ if, choose, when, otherwise
++ </code>
++ </p>
++ <p CLASS="">Fully implemented.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__381"></a>
++ <h3>
++ <a href="#toc_i__305">5.3 Loops</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>for-each</code>
++ </p>
++ <p CLASS="">Fully implemented.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__398"></a>
++ <h3>
++ <a href="#toc_i__305">5.4 Variables and parameters</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>variable, param, with-param</code>
++ </p>
++ <p CLASS="">Fully implemented. Top-level variables and parameters are
++ read in the document order, so no forward references are
++ resolved. This is a minor deviation from the spec. </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__415"></a>
++ <h3>
++ <a href="#toc_i__305">5.5 Element creation</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>element, attribute, text,
++ comment, processing-instruction, attribute-set</code>
++ </p>
++ <p CLASS="">
++ <code>xsl:attribute-set</code> is not implemented. For the
++ rest, <code>name</code> is the only recognized attribute (where
++ applicable). Literal result elements work.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__439"></a>
++ <h3>
++ <a href="#toc_i__305">5.6 Global definitions</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>stylesheet, transform, output</code>
++ </p>
++ <p CLASS="">For <code>stylesheet</code> and <code>transform</code>,
++ the only recognized attribute is
++ <code>version</code>. <code>xsl:output</code> should work
++ (see below for notes on the <code>encoding</code>
++ attribute). HTML indentation has been added in 0.60.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__476"></a>
++ <h3>
++ <a href="#toc_i__305">5.7 Values and copying</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>value-of, copy, copy-of</code>
++ </p>
++ <p CLASS="">
++ <code>copy-of</code> and <code>value-of</code> are fully
++ implemented. <code>copy</code> is implemented except for the
++ <code>use-attribute-sets</code> attribute.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__508"></a>
++ <h3>
++ <a href="#toc_i__305">5.8 Namespace processing</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>namespace-alias</code>
++ </p>
++ <p CLASS="">Namespaces should be processed correctly. The
++ <code>namespace-alias</code> instruction is now supported
++ (patch by Major).</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__529"></a>
++ <h3>
++ <a href="#toc_i__305">5.9 Sorting</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>sort</code>
++ </p>
++ <p CLASS="">
++ <code>xsl:sort</code> is implemented since 0.50. There are
++ minor limitations:
++ </p>
++ <ul>
++ <li>currently, the <code>lang</code> attribute may only
++ contain the values <code>"en"</code> or <code>"cz"</code>.</li>
++ <li>
++ <code>case-order</code> cannot be specified.</li>
++ </ul>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__577"></a>
++ <h3>
++ <a href="#toc_i__305">5.10 Whitespace stripping</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>strip-space, preserve-space</code>
++ </p>
++ <p CLASS="">Only the default whitespace stripping is done. That is,
++ all whitespace-only text nodes in any stylesheet, not appearing
++ inside a <code>xsl:text</code>, are removed. The two
++ instructions for whitespace stripping and preservation are
++ unsupported.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__598"></a>
++ <h3>
++ <a href="#toc_i__305">5.11 Includes</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>include, import, apply-imports</code>
++ </p>
++ <p CLASS="">Only <code>xsl:include</code> is implemented. Processing
++ involving multiple documents works, but has to get more testing,
++ eg. with respect to <code>generate-id()</code>.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__623"></a>
++ <h3>
++ <a href="#toc_i__305">5.12 Other unimplemented instructions</a>
++ </h3>
++ <ul>
++ <li>
++ <code>xsl:key,</code>
++ </li>
++ <li>
++ <code>xsl:number,</code>
++ </li>
++ <li>
++ <code>xsl:fallback.</code>
++ </li>
++ </ul>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__654"></a>
++ <h3>
++ <a href="#toc_i__305">5.13 Output conformance</a>
++ </h3>
++ <p CLASS="">The output mechanism is much closer to the spec than in
++ the versions prior to 0.4. The following issues remain for the
++ html method:</p>
++ <ul>
++ <li>Output the boolean attributes correctly.</li>
++ <li>Disable the escaping inside
++ <code><SCRIPT></code> and
++ <code><STYLE></code>
++ </li>.
++ </ul>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__686"></a>
++ <h3>
++ <a href="#toc_i__305">5.14 XPath expressions</a>
++ </h3>
++ <p CLASS="">Almost all features of XPath are fully implemented. This means
++ there should be no problems with expressions of any kind.</p>
++ <p CLASS="">One exception relates to axes. The <code>following</code> and
++ <code>preceding</code> axes haven't been implemented yet.</p>
++ <p CLASS="">Another possible exception may be numbers; we did not yet do a
++ thorough test of rounding, NaNs, infinity, etc.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__714"></a>
++ <h3>
++ <a href="#toc_i__305">5.15 Built-in functions</a>
++ </h3>
++ <p CLASS="">
++ <a name="corelib"></a>Only a few functions from the standard
++ function library remain
++ unimplemented:
++ </p>
++ <ul>
++ <li>
++ <code>id()</code>,</li>
++ <li>
++ <code>lang()</code> (accepted but always returns true),</li>
++ <li>
++ <code>key()</code>,</li>
++ <li>
++ <code>format-number()</code>,</li>
++ <li>
++ <code>unparsed-entity-uri()</code>.</li>
++ </ul>
++ <p CLASS="">As for the fuctions that <i>are</i> implemented, the
++ following is a list of differences from the spec:
++ </p>
++ <ul>
++ <li>
++ <code>document()</code> only accepts one argument, always
++ getting the base URI from the stylesheet URI.
++ </li>
++ <li>
++ <code>string-length()</code> returns the byte length of
++ the UTF-8 representation of the string. This will typically
++ differ from the actual length.
++ </li>
++ <li>
++ <code>generate-id()</code> might fail to generate unique identifiers
++ when several input documents are present (giving the same id to
++ nodes from different documents).
++ </li>
++ </ul>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__804"></a>
++ <h2>
++ <a href="#toc_i__804">6 Other implementation-related notes</a>
++ </h2>
++ <DIV>
++ <DIV class="afterskip">
++ <a name="i__811"></a>
++ <h3>
++ <a href="#toc_i__804">6.1 Handlers</a>
++ </h3>
++ <p CLASS="">It is possible for the user to supply the following
++ handlers to Sablotron:
++ <ul>
++ <li>message handler (to bypass the default way of displaying
++ error and warning messages and logging),</li>
++ <li>scheme handler (to retrieve documents whose URI use an
++ unsupported scheme),</li>
++ <li>streaming handler (an expat-like interface to the XML
++ document which is the result of the processing),</li>
++ <li>'miscellaneous' handler (which will probably server as a
++ collections of odd callbacks).</li>
++ </ul>
++ </p>
++ <p CLASS="">
++ The handlers are set using <code>SablotRegHandler()</code>
++ For details concerning the interface of these handlers,
++ consult the header files <code>sablot.h</code> and
++ <code>shandler.h</code>.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__859"></a>
++ <h3>
++ <a href="#toc_i__804">6.2 Encodings</a>
++ </h3>
++ <p CLASS="">
++ In version 0.52, the encoding conversion capabilities of
++ Sablotron have been much extended. The most important fact is the
++ following: if you have the iconv library installed on your system, you
++ can use any encoding it supports (that is, almost any encoding
++ whatsoever) for both the input and the output documents. Iconv
++ is available on most systems (it is a standard part of glibc2,
++ for instance). There are implementations for Win32 as well.
++ </p>
++ <p CLASS="">If iconv is not available, the encoding may still be supported internally by
++ Sablotron. At present, the list is of such encodings is rather
++ short: besides UTF-8, these are UTF-16, ASCII, iso-8859-1,
++ iso-8859-2 and windows-1250 on input, none on output. However,
++ we plan to implement a half independent light-weight
++ conversion library for use on systems without iconv,
++ extending the set of internally supported encodings
++ considerably.
++ </p>
++ <p CLASS="">Lastly, the user has the option to implement a custom
++ encoding conversion handler, which will be asked to perform any unsupported
++ conversion. See the <code>shandler.h</code> header file for
++ details.
++ </p>
++ <p CLASS="">The default input and output encoding is in all cases UTF-8.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__887"></a>
++ <h3>
++ <a href="#toc_i__804">6.3 Output methods</a>
++ </h3>
++ <p CLASS="">In addition to the standard output methods (xml, html and
++ text), it is possible to output xhtml. Documents output using
++ this method obey the XHTML 1.0 rules (in particular, all empty
++ elements are closed). To choose the method, use
++ <code><xsl:output method='xhtml'></code>. <b>Please note</b>
++ that the name of this method will possibly be changed since the XSLT
++ spec requires any processor-specific methods to have qualified
++ names, say <code>sab:xhtml</code>. On the other hand, the name
++ <code>xhtml</code> is considered in the XSLT 2.0 working draft.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__915"></a>
++ <h3>
++ <a href="#toc_i__804">6.4 URIs</a>
++ </h3>
++ <p CLASS="">Sablotron can handle
++ two URI schemes natively: 'file' and 'arg' (see
++ below). Moreover, it is possible to use the function
++ <code>SablotRegSchemeHandler</code> to register an external scheme
++ handler which will receive requests in all other schemes. See
++ the documentation in <code>sablot.h</code> and
++ <code>shandler.h</code>.
++ </p>
++ <p CLASS="">Relative URI references are resolved in conformance to RFC
++ 2396. The base URI is well defined when the relative reference appears
++ inside a XML document; when invoking sabcmd, the base URI is
++ taken to correspond to the current working directory.
++ </p>
++ <p CLASS="">
++ <a name="fname-rules"></a>When specifying filenames, the
++ following rules are in effect:
++ </p>
++ <ul>
++ <li>specify the "file:" scheme for any standard files,
++ i.e. refer to <code>stdin</code> as <code>file://stdin</code>
++ etc.</li>
++ <li>slashes and backslashes work equally fine, in Windows as
++ well as Linux.</li>
++ <li>to include a drive letter under Windows
++ (e.g. <code>C:\doc.xml</code>), it is necessary to say
++ <code>file://c:/doc.xml</code>.
++ </li>
++ </ul>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__983"></a>
++ <h3>
++ <a href="#toc_i__804">6.5 Named buffers</a>
++ </h3>
++ <p CLASS="">
++ <a name="argscheme"></a>Sablotron introduces an URI scheme
++ 'arg:' which enables one to use strings in named memory
++ buffers. The buffer names can have a tree-like structure so that
++ a relative reference from a document in a buffer can be resolved
++ as pointing to another buffer.
++ </p>
++ <p CLASS="">For instance, if we invoke Sablotron specifying that a
++ buffer named <code>/mybuf/1</code> contains the string
++ "<a>contents</a>", then the expression
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ document('arg:/mybuf/1')/a
++ </code>
++ </p>
++ <p CLASS="">has string-value "contents". If the document in arg:/mybuf/1
++ contained a relative URI reference "../theirbuf/2" then this
++ would be resolved as pointing to "arg:/theirbuf/2".</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1015"></a>
++ <h3>
++ <a href="#toc_i__804">6.6 Error and log messages</a>
++ </h3>
++ <p CLASS="">By default, Sablotron writes error and warning messages to
++ stderr, and does no logging. By a call to
++ <code>SablotSetLog()</code>, you can specify the name of the log
++ file to be used.</p>
++ <p CLASS="">Besides, you can use <code>SablotRegHandler()</code>
++ to override the default message handling. The handler you
++ register will receive all messages in a structured form that's
++ easy to process and filter. For details, see
++ the documentation in <code>sablot.h</code> and
++ <code>shandler.h</code>.</p>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1048"></a>
++ <h2>
++ <a href="#toc_i__1048">7 The C interface</a>
++ </h2>
++ <DIV>
++ <p CLASS="">
++ <a name="invocation"></a>
++ </p>
++ <p CLASS="">
++ This section describes the functions exported from the
++ Sablotron library. All of them have a return type of 'int'
++ and return an error flag (nonzero signals an error). Errors
++ are reported to the user by Sablotron itself.
++ </p>
++ <DIV class="afterskip">
++ <a name="i__1065"></a>
++ <h3>
++ <a href="#toc_i__1048">7.1 Shortcuts</a>
++ </h3>
++ <p CLASS="">
++ We'll first describe the 'shortcuts' that do the whole
++ processing in one call.
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotProcess(char *sheetURI, char *inputURI, char *resultURI,
++ char **params, char **arguments, char **resultArg);
++ </code>
++ </p>
++ <p CLASS="">
++ This is the basic function. The first three of its arguments
++ are the URIs of the XSLT stylesheet, the XML source and the
++ resulting document, respectively. For some notes on specifying
++ file names, see <a href="#fname-rules">above</a>.
++ </p>
++ <p CLASS="">
++ <code>params</code> is an array of pointers to the names
++ and contents of the top-level stylesheet parameters. Thus,
++ <code>params[0]</code> is a pointer to the null-terminated name
++ of the first parameter, <code>params[1]</code> points to the
++ (null-terminated) contents of the first parameter. The following
++ two array items do the same for the second parameter, etc. The
++ whole array is terminated by a NULL pointer in place of the
++ name. If no parameters are to be passed, you can specify NULL
++ for <code>params</code> itself.
++ </p>
++ <p CLASS="">
++ <code>arguments</code> is a similar array of named buffers
++ to be passed to the stylesheet. (They can be referred to via the
++ 'arg:' scheme, see <a href="#argscheme">above</a>.) Again, the
++ array is a sequence of (name, value) pairs terminated by NULL in
++ place of a name. If no named buffers are to be passed, you can
++ specify NULL for <code>arguments</code> itself.
++ </p>
++ <p CLASS="">
++ <code>resultArg</code> enables one to access the
++ resulting document in case the output went to a named buffer. In
++ that situation, <code>*resultArg</code> points to the resulting
++ null-terminated string, allocated by Sablotron. You can pass NULL
++ for <code>resultArg</code> if the output is sure to go to a
++ file.
++ </p>
++ <p CLASS="">
++ <b>Note:</b>When you are done processing the string
++ pointed to by <code>*resultArg</code>, free it using <a href="#sablotfree">
++ <code>SablotFree()</code>
++ </a> - never use
++ <code>free()</code>. The latter is guaranteed to produce a
++ segmentation fault under Linux.
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotProcessFiles(char *styleSheetName,
++ char *inputName,
++ char *resultName);
++ </code>
++ </p>
++ <p CLASS="">A wrapper for <code>SablotProcess()</code> working on
++ files. The parameters are the null-terminated file names of the
++ XSLT stylesheet, the XML input and the result,
++ respectively. Sablotron opens these files itself and closes them
++ after the processing is complete. Values like "file://stdin" are
++ allowed.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotProcessStrings(char *styleSheetStr, char *inputStr, char
++ **resultStr);
++ </code>
++ </p>
++ <p CLASS="">Another wrapper for <code>SablotProcess()</code>, this
++ time for accessing named buffers (i.e. user-allocated memory
++ blocks)only. Thus, the first parameter is a null-terminated
++ string containing the whole stylesheet; the second parameter
++ is a null-terminated string containing the XML
++ input. Sablotron allocates the buffer for the resulting string
++ and returns a pointer to it in resultStr. Hence, invoking
++ <code>puts(*resultStr)</code> after having called
++ <code>SablotProcessStrings</code> sends the result to
++ stdout. The buffer allocated <b>must</b> be freed by calling the
++ function <code>SablotFree</code> described next.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1205"></a>
++ <h3>
++ <a href="#toc_i__1048">7.2 Basic functions</a>
++ </h3>
++ <p CLASS="">The above shortcuts just call the basic, lower-level
++ functions described below. Note that if you need to set options
++ for logging etc., you may need to use the low-level
++ functions. </p>
++ <p CLASS="">A typical processing session may look like this:</p>
++ <p CLASS="">
++ <pre>
++ SablotHandle p;
++ char *my_buf;
++ SablotCreateProcessor(&p);
++ SablotSetLog(p, ...);
++ /* ...set other instance-specific options here... */
++ SablotRunProcessor(p, ...);
++ SablotGetResultArg(p, "arg:/somename", &my_buf)
++ /* ...do something with my_buf... */
++ /* can run the processor again if necessary */
++ SablotRunProcessor(p, ...);
++ SablotDestroyProcessor(p);
++ </pre>
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotCreateProcessor(SablotHandle *processorPtr);
++ </code>
++ </p>
++ <p CLASS="">Creates an instance of Sablotron and returns a pointer to
++ it in *processorPtr. This pointer is passed on all subsequent
++ calls to this instance. </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotDestroyProcessor(SablotHandle processor_);
++ </code>
++ </p>
++ <p CLASS="">Destroys an instance of the processor, deallocating all
++ the memory used up by it.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotRunProcessor(SablotHandle processor_,
++ char *sheetURI,
++ char *inputURI,
++ char *resultURI,
++ char **params,
++ char **arguments);
++ </code>
++ </p>
++ <p CLASS="">Processes documents using the given processor instance and
++ given params and args definitions. See
++ <code>SablotProcess()</code>.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotGetResultArg(SablotHandle processor_,
++ char *argURI,
++ char **argValue);
++ </code>
++ </p>
++ <p CLASS="">Copies the result 'arg' buffer with the given URI,
++ returning a pointer to the newly-allocated block in
++ *argValue. If no such buffer exists, returns NULL in *argValue.
++ </p>
++ <p CLASS="">This function is necessary, because if the result document
++ is output to memory, it would be lost when
++ <code>SablotDestroyProcessor()</code> is called. When
++ deallocating the copy obtained from
++ <code>SablotGetResultArg()</code>, use <code>SablotFree</code>
++ (never <code>free()</code>). </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotFreeResultArgs(SablotHandle processor_);
++ </code>
++ </p>
++ <p CLASS="">Removes the Sablotron-internal copies of the 'arg' buffers
++ from the last Sablotron run. Normally, there should be no reason
++ to call this function as it is called automatically on both
++ <code>SablotRunProcessor()</code> and
++ <code>SablotDestroyProcessor()</code>. </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ <a name="sablotfree"></a>
++ int SablotFree(char *resultBuf);
++ </code>
++ </p>
++ <p CLASS="">This function frees the buffer allocated on previous call
++ to <code>SablotProcessStrings</code>. Calling it with an
++ invalid pointer will cause a crash.
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotRegHandler(
++ SablotHandle processor_,
++ HandlerType type,
++ void *handler,
++ void *userData);
++ </code>
++ </p>
++ <p CLASS="">Registers an external handler. <code>type</code> can be
++ <code>HLR_MESSAGE</code>, <code>HLR_SCHEME</code>,
++ <code>HLR_SAX</code>, <code>HLR_MISC</code> or
++ <code>HLR_ENC</code>.
++ <code>handler</code> points to the
++ callback vector of the appropriate type. <code>userData</code>
++ is a data item to passed to all callbacks of this particular
++ handler. For details, check the <code>sablot.h</code> and
++ <code>shandler.h</code> header files.
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotUnregHandler(
++ SablotHandle processor_,
++ HandlerType type,
++ void *handler,
++ void *userData);
++ </code>
++ </p>
++ <p CLASS="">Unregisters the given external handler. For details, check the
++ <code>sablot.h</code> and <code>shandler.h</code> header
++ files.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotSetLog(
++ SablotHandle processor_,
++ const char *logFilename,
++ int logLevel);
++ </code>
++ </p>
++ <p CLASS="">Sets the log filename. The <code>logLevel</code> parameter
++ is currently not used. Pass NULL for <code>logFilename</code> to
++ turn logging off (default). </p>
++ <p CLASS="">The other functions published by sablot.h have been
++ included for experimental reasons or for compatibility, and it
++ is better not to use them.
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotClearError(SablotHandle processor_);
++ </code>
++ </p>
++ <p CLASS="">Clears the 'pending error' flag for this instance of
++ Sablotron.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1416"></a>
++ <h3>
++ <a href="#toc_i__1048">7.3 Generalized interface functions</a>
++ </h3>
++ <p CLASS="">The implementation of the <a href="#dom">DOM interface</a>
++ brought the need to extend some of the functions described in
++ the previous section. This extension enables the user to:
++ </p>
++ <ul>
++ <li>process documents created by the DOM functions, and</li>
++ <li>process frequently used documents in pre-parsed form.</li>
++ </ul>
++ <p CLASS="">An object called <i>situation</i> is used to provide a
++persistent context for all calls to the DOM-related
++functions. Functions used to manipulate the situation are described in
++<a href="#situation">the following section</a>.</p>
++ <p CLASS="">
++ <b>Note:</b> If not specified otherwise, all these
++ functions return an error code. A positive value indicates an error.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotCreateDocument(SablotSituation S,
++ SDOM_Document *D);
++ </code>
++ </p>
++ <p CLASS="">Creates an empty document. Typically followed by calls to
++ DOM functions to populate the document.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotDestroyDocument(SablotSituation S,
++ SDOM_Document D);
++ </code>
++ </p>
++ <p CLASS="">Destroys a document, freeing all the nodes it has created.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotParse(SablotSituation S,
++ const char *uri, SDOM_Document *D);
++ </code>
++ </p>
++ <p CLASS="">Reads in a document from the given URI.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotParseBuffer(SablotSituation S,
++ const char *buffer, SDOM_Document *D);
++ </code>
++ </p>
++ <p CLASS="">Reads in a document from the given in-memory buffer.</p>
++ <p CLASS="">These functions have variants to be used if the document
++ is to be interpreted as an XSLT stylesheet, namely
++ <code>SablotParseStylesheet</code> and
++ <code>SablotParseStylesheetBuffer</code>.</p>
++ <p CLASS="">The following functions generalize
++ <code>SablotRunProcessor</code> in that they make it possible to
++ utilize an extra kind of a source document: a DOM tree.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotRunProcessorGen(SablotSituation S,
++ void *processor_,
++ char *sheetURI,
++ char *inputURI,
++ char *resultURI);
++ </code>
++ </p>
++ <p CLASS="">A key ingredient of the extended interface. Only the URIs
++ of the sources and of the result document are given to it. The
++ rest of the information passed to
++ <code>SablotRunProcessor</code> is conveyed through
++ <code>SablotAddArgBuffer,</code> <code>SablotAddArgTree</code>
++ and <code>SablotAddParam.</code> The scheme part of the
++ stylesheet URI or the input URI may be "arg:", in which
++ case they refer to a buffer or tree passed by these
++ functions. </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotAddArgBuffer(SablotSituation S,
++ void *processor_,
++ const char *argName,
++ const char *bufferValue);
++</code>
++ </p>
++ <p CLASS="">Creates a named buffer for the next processor run. The
++ buffer's name and contents are passed as arguments. The name
++ is interpreted relative to the 'arg:/' scheme.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotAddArgTree(SablotSituation S,
++ void *processor_,
++ const char *argName,
++ SDOM_Document tree);
++</code>
++ </p>
++ <p CLASS="">Associates the given document with a name for the next
++ processor run. The document is <i>not</i> destroyed after the
++ run is finished. The name is interpreted relative to the 'arg:/'
++ scheme.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotAddParam(SablotSituation S,
++ void *processor_,
++ const char *paramName,
++ const char *paramValue);
++ </code>
++ </p>
++ <p CLASS="">Adds a global stylesheet parameter for the next processor
++ run.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1578"></a>
++ <h3>
++ <a href="#toc_i__1048">7.4 The situation object</a>
++ </h3>
++ <p CLASS="">
++ <a name="situation"></a>At present, the situation object primarily holds information on any pending errors. A
++situation is created using</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotCreateSituation(SablotSituation
++ *SP);</code>
++ </p>
++ <p CLASS="">and destroyed by</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotDestroySituation(SablotSituation
++ S);</code>
++ </p>
++ <p CLASS="">To clear the pending error flag in a situation, use</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotClearSituation(SablotSituation
++ S);</code>
++ </p>
++ <p CLASS="">The following self-explanatory functions extract parts of the error information
++ from the situation:</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ const char *SablotGetErrorURI(SablotSituation S);<br>
++ int SablotGetErrorLine(SablotSituation S);<br>
++ const char *SablotGetErrorMsg(SablotSituation S);
++ </code>
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1631"></a>
++ <h3>
++ <a href="#toc_i__1048">7.5 Document Object Model (DOM) functions</a>
++ </h3>
++ <p CLASS="">
++ <a name="dom"></a>Starting with version 0.60, Sablotron implements
++ a major subset of the DOM Level 1 Core Specification <a href="#ref-dom">[DOM]</a>. A brief
++ description of the implemented interface follows; for more
++ details, please refer to the header file named
++ <code>sdom.h.</code>
++ </p>
++ <p CLASS="">All of the names related to the DOM interface start with
++ SDOM_ (for Sablot DOM).</p>
++ <p CLASS="">Major new types are <code>SDOM_Document</code> (a DOM tree) and
++ <code>SDOM_Node</code> (a node of the tree). A document can also be used in
++ place of a node. This reflects the fact in the DOM spec,
++ Document is a subclass of Node. When used in this way, the
++ document represents its own root node (which is not the same as
++ the `root element').</p>
++ <p CLASS="">Other types include:</p>
++ <ul>
++ <li>
++ <code>SDOM_char:</code> a DOM character type. Currently, this is just
++ char. Note that the DOM spec requires that the DOM
++ implementations work with UTF-16. Sablotron deviates from this
++ by using UTF-8 instead. A separate set of functions taking
++ UTF-16 strings will be provided.</li>
++ <li>
++ <code>SDOM_NodeType:</code> a node type enum. Some of the values are
++ <code>SDOM_ELEMENT_NODE,</code> <code>SDOM_ATTRIBUTE_NODE</code> and <code>SDOM_TEXT_NODE.</code> See
++ <code>sdom.h</code> for the rest.</li>
++ <li>
++ <code>SDOM_NodeList:</code> a node list returned by some of the
++ functions.</li>
++ <li>
++ <code>SDOM_Exception:</code> DOM exception codes enum, with values such
++ as <code>SDOM_NOT_FOUND_ERR</code> or <code>SDOM_INVALID_NODE_TYPE</code>. See <code>sdom.h</code>
++ for details.</li>
++</ul>
++ <p CLASS="">The functions listed below are implemented more or less as defined in
++ the DOM Level 1 Specification, with two exceptions:
++ their names are prefixed with <code>SDOM_</code> and the first argument is
++ always a <code>SablotSituation.</code> All the functions return
++ a <code>SDOM_Exception.</code> </p>
++ <ul>
++<li>
++ <code>createElement, createAttribute, createTextNode,
++createCDATASection, createComment, createProcessingInstruction</code>
++ </li>
++<li>
++ <code>getNodeType, getNodeName, setNodeName, getNodeValue, setNodeValue</code>
++ </li>
++<li>
++ <code>getParentNode, getFirstChild, getLastChild, getPreviousSibling,
++getNextSibling, getOwnerDocument</code>
++ </li>
++<li>
++ <code>insertBefore, appendChild, removeChild, replaceChild</code>
++ </li>
++<li>
++ <code>cloneNode</code>
++ </li>
++<li>
++ <code>getAttribute, setAttribute, removeAttribute, getAttributeList</code>
++ </li>
++</ul>
++ <p CLASS="">Several functions have been added:</p>
++ <ul>
++<li>
++ <code>disposeNode</code> frees all memory used by the given node</li>
++<li>
++ <code>cloneForeignNode</code> clones a node from a different
++document</li>
++<li>
++ <code>docToString</code> serializes the document, returning the
++resulting string</li>
++<li>
++ <code>xql</code> performs an XPath query on the DOM tree,
++returning a list of the nodes satisfying it.</li>
++</ul>
++ <p CLASS="">In addition, there are some functions used to manipulate
++ the node lists returned by <code>xql</code> and
++ <code>getAttributeList</code>. These include
++ <code>getNodeListLength</code>, <code>getNodeListItem</code> and
++ <code>disposeNodeList</code>.</p>
++ <p CLASS="">Finally, there are functions to extract DOM
++ exception-related information from the situation object, namely
++ <code>getExceptionCode</code>, <code>getExceptionMessage</code>
++ and <code>getExceptionDetails</code>.</p>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1870"></a>
++ <h2>
++ <a href="#toc_i__1870">8 The command line interface</a>
++ </h2>
++ <DIV>
++ <p CLASS="">Sablotron comes with a command-line interface to the
++ shared library, which is a program named
++ <code>sabcmd</code>. At present, <code>sabcmd</code> is invoked
++ as follows:</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ sabcmd [<i>options</i>] <i>stylesheet</i> [<i>input</i> [<i>result</i>]] [<i>assignments</i>]
++ </code>
++ </p>
++ <p CLASS="">The arguments are the URIs of the XSLT stylesheet, the
++ XML input document, and the resulting document, respectively. The
++ default for <code>
++ <i>input</i>
++ </code> is
++ <code>file://stdin</code> (meaning plain old stdin);
++ <code>
++ <i>result</i>
++ </code> defaults to
++ <code>file://stdout</code>. Filenames have to include the extension (if
++ any).</p>
++ <p CLASS="">You can display the list of available options by typing
++ <code>sabcmd --help</code>. Among the more useful ones are
++ <code>--log-file</code> (for setting the log file) and
++ <code>--measure</code> (measures and outputs the total
++ processing time).
++ </p>
++ <p CLASS="">
++ <a href="#fname-rules">The rules for filenames</a> are the same as
++ with <code>SablotProcess()</code>.
++ </p>
++ <p CLASS="">
++ <code>assignments</code> is a series of definitions of the
++ form:</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ name1=value1 name2=value2 ...
++ </code>
++ </p>
++ <p CLASS="">
++ assigning values to top-level stylesheet parameters and to named
++ buffers. These two cases are distinguished by a leading '$' in
++ the name of a stylesheet parameter. The names of the buffers do
++ <i>not</i> start with "arg:". They may start with a slash; if
++ they don't, the slash is prepended.
++ </p>
++ <p CLASS="">
++ <b>Note:</b> In most cases, it will be necessary to quote
++ the individual assignments. Whether to use single or double
++ quotes may depend on the shell used (or may it?) Single quotes
++ work for bash, double quotes work in Windows.
++ </p>
++ <p CLASS="">If the result URI refers to a named buffer, the output
++ would normally remain buried in memory. Sabcmd dumps the buffer to standard
++ output instead.
++ </p>
++ <p CLASS="">To sum up and give an example, the following would be a
++ valid invocation of sabcmd:</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ sabcmd sheet.xsl arg:/the_input "the_input=<a/>"
++ "$use_defaults=1"
++ </code>
++ </p>
++ <p CLASS="">This processes the document passed in the buffer named
++ the_input, using a stylesheet found in file "sheet.xsl" in the
++ working directory. We assign 1 to the top-level parameter called
++ "use_defaults". The output goes to stdout by default.
++ </p>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__2013"></a>
++ <h2>
++ <a href="#toc_i__2013">9 References</a>
++ </h2>
++ <DIV>
++ <dl>
++ <dt>
++ <a name="ref-xslt"></a>[XSLT]</dt>
++ <dd>
++ <a href="http://www.w3.org/TR/1999/REC-xslt-19991116">
++ XSL Transformations (XSLT) Version 1.0
++ </a>
++ </dd>
++
++ <dt>
++ <a name="ref-xpath"></a>[XPath]</dt>
++ <dd>
++ <a href="http://www.w3.org/TR/1999/REC-xpath-19991116">
++ XML Path Language (XPath) Version 1.0
++ </a>
++ </dd>
++
++ <dt>
++ <a name="ref-xml"></a>[XML]</dt>
++ <dd>
++ <a href="http://www.w3.org/TR/1998/REC-xml-19980210">
++ Extensible Markup Language (XML) 1.0
++ </a>
++ </dd>
++
++ <dt>
++ <a name="ref-dom"></a>[DOM]</dt>
++ <dd>
++ <a href="http://www.w3.org/TR/REC-DOM-Level-1">
++ Document Object Model Level 1 Specification, Version 1.0
++ </a>
++ </dd>
++
++ <dt>
++ <a name="ref-rcover"></a>[Cover]</dt>
++ <dd>
++ <a href="http://www.oasis-open.org/cover/sgml-xml.html">
++ The XML Cover Pages</a>
++ </dd>
++
++ <dt>
++ <a name="ref-xmlorg"></a>[XMLorg]</dt>
++ <dd>
++ <a href="http://xml.org">XML.org</a>
++ </dd>
++
++ <dt>
++ <a name="ref-xslinfo"></a>[XSLINFO]</dt>
++ <dd>
++ <a href="http://www.xslinfo.com">XSLINFO.com</a>
++ </dd>
++
++ <dt>
++ <a name="ref-bible"></a>[XMLBible14]</dt>
++ <dd>
++ <a href="http://metalab.unc.edu/xml/books/bible/updates/14.html">
++ Harold, E. R.: XML Bible, Chapter 14 (online presentation)
++ </a>
++ </dd>
++ </dl>
++ </DIV>
++ </DIV>
++ <hr>
++ <p STYLE="font-style: italic; margin-left: 0">(c) 2000 Ginger Alliance s.r.o.</p>
++ </body>
++</html>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/version.py.in
+@@ -0,0 +1,11 @@
++## $Id: version.py.in 3856 2004-07-13 10:36:18Z quarl $
++
++# define version numbers using autoconf
++BOINC_MAJOR_VERSION = @BOINC_MAJOR_VERSION@
++BOINC_MINOR_VERSION = @BOINC_MINOR_VERSION@
++CLIENT_BIN_FILENAME = "@CLIENT_BIN_FILENAME@"
++PLATFORM = "@host@"
++SRC_DIR = "@SOURCE_TOP_DIR@"
++
++# todo: use TOP_SRC_DIR, SRC_DIR, BUILD_DIR from autoconf; can remove AC_SUBST
++# for SOURCE_TOP_DIR
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/ucs_wu
+@@ -0,0 +1,10 @@
++<file_info>
++ <number>0</number>
++</file_info>
++<workunit>
++ <file_ref>
++ <file_number>0</file_number>
++ <open_name>in</open_name>
++ </file_ref>
++ <command_line>-run_slow</command_line>
++</workunit>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_water.php
+@@ -0,0 +1,19 @@
++#! /usr/local/bin/php
++<?php
++ //make sure that the scheduler sends the correct number of wu's in test_uc
++
++ PassThru("test_uc.php | grep -c '<scheduler_request>' > tw_results",
++ $retval
++ );
++ if($retval) {
++ echo "test_uc.php did not run correctly\n";
++ }
++ $f = fopen("tw_results", "r");
++ fscanf($f, "%d", $val);
++ if($val > 2) {
++ echo "Water marks are working\n";
++ } else {
++ echo "Water marks are not working\n";
++ }
++ PassThru("rm -f tw_results");
++?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_abort.php
+@@ -0,0 +1,42 @@
++#!/usr/local/bin/php -q
++<?php {
++ // This tests whether the result abort mechanism is working
++
++ include_once("test.inc");
++
++ test_msg("result abort mechanism (disk space limit)");
++
++ $project = new Project;
++ $project->add_app_and_version("upper_case");
++
++ $user = new User();
++
++ $project->add_user($user);
++ $project->install(); // must install projects before adding to hosts
++ $project->install_feeder();
++
++ $host = new Host();
++ $host->add_user($user, $project);
++ $host->install();
++
++ $work = new Work();
++ $work->wu_template = "uc_wu";
++ $work->result_template = "abort_result";
++ $work->redundancy = 2;
++ array_push($work->input_files, "input");
++ $work->install($project);
++
++ $project->start_servers();
++ $host->run("-exit_when_idle -skip_cpu_benchmarks -sched_retry_delay_min 1 >& /dev/null");
++
++ $project->validate(2);
++ $result->server_state = RESULT_SERVER_STATE_OVER;
++ $project->check_results(2, $result);
++
++ $project->assimilate();
++ $project->file_delete();
++
++ $project->stop();
++
++ test_done();
++} ?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/uc_multiple_download_wu
+@@ -0,0 +1,14 @@
++<file_info>
++ <name><INFILE_0/></name>
++ <url><DOWNLOAD_URL/>/<INFILE_0/></url>
++ <url><DOWNLOAD_URL/>0/<INFILE_0/></url>
++ <url><DOWNLOAD_URL/>1/<INFILE_0/></url>
++ <url><DOWNLOAD_URL/>2/<INFILE_0/></url>
++ <md5_cksum><MD5_0/></md5_cksum>
++</file_info>
++<workunit>
++ <file_ref>
++ <file_name><INFILE_0/></file_name>
++ <open_name>in</open_name>
++ </file_ref>
++</workunit>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/uc_multiple_uploads_result
+@@ -0,0 +1,16 @@
++<file_info>
++ <name><OUTFILE_0/></name>
++ <generated_locally/>
++ <upload_when_present/>
++ <max_nbytes>100000</max_nbytes>
++ <url><UPLOAD_URL/></url>
++ <url><UPLOAD_URL/>0</url>
++ <url><UPLOAD_URL/>1</url>
++ <url><UPLOAD_URL/>2</url>
++</file_info>
++<result>
++ <file_ref>
++ <file_name><OUTFILE_0/></file_name>
++ <open_name>out</open_name>
++ </file_ref>
++</result>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/1sec_correct_output
+@@ -0,0 +1 @@
++done
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_sticky.php
+@@ -0,0 +1,42 @@
++#!/usr/local/bin/php -q
++<?php {
++ // $Id: test_sticky.php 1412 2003-06-11 23:47:36Z quarl $
++
++ include_once("test.inc");
++
++ test_msg("sticky file mechanism");
++
++ $project = new Project;
++ $user = new User();
++ $host = new Host($user);
++
++ $project->add_user($user);
++ $project->add_app_and_version("upper_case");
++ $project->install(); // must install projects before adding to hosts
++ $project->install_feeder();
++
++ $host->add_user($user,$project);
++ $host->install();
++
++ $work = new Work($app);
++ $work->wu_template = "uc_wu_sticky";
++ $work->result_template = "uc_result_sticky";
++ $work->redundancy = 2;
++ array_push($work->input_files, "input");
++ $work->install($project);
++
++ $project->start_servers();
++ $host->run("-exit_when_idle -skip_cpu_benchmarks");
++ $project->stop();
++
++ $result->server_state = RESULT_SERVER_STATE_OVER;
++ $project->check_results(2, $result);
++ $project->compare_file("uc_wu_sticky_0_0", "uc_correct_output");
++ $project->compare_file("uc_wu_sticky_1_0", "uc_correct_output");
++
++ // make sure result files are still there
++ $host->check_file_present($project, "uc_wu_sticky_0_0");
++ $host->check_file_present($project, "uc_wu_sticky_1_0");
++
++ test_done();
++} ?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_uc.inc
+@@ -0,0 +1,75 @@
++<?php {
++ // $Id: test_uc.inc 1510 2003-06-17 01:36:47Z quarl $
++
++ include_once("test.inc");
++
++ class ProjectUC extends Project
++ {
++ var $work;
++ var $host;
++ var $user;
++
++ function ProjectUC() {
++ $this->Project();
++ $this->add_core_and_version();
++ $this->add_app_and_version("upper_case");
++
++ $this->user = new User();
++ $this->user->project_prefs = "<project_specific>\nfoobar\n</project_specific>\n";
++ $this->user->global_prefs = "<venue name=\"home\">\n".
++ "<work_buf_min_days>0</work_buf_min_days>\n".
++ "<work_buf_max_days>2</work_buf_max_days>\n".
++ "<disk_interval>1</disk_interval>\n".
++ "<run_on_batteries/>\n".
++ "<max_bytes_sec_down>400000</max_bytes_sec_down>\n".
++ "</venue>\n";
++
++ $this->add_user($this->user);
++ $this->install(); // must install projects before adding to hosts
++ $this->install_feeder();
++
++ $this->host = new Host();
++ $this->host->add_user($this->user, $this);
++ $this->host->install();
++
++ $this->work = new Work();
++ $this->work->wu_template = "uc_wu";
++ $this->work->result_template = "uc_result";
++ $this->work->redundancy = 2;
++ $this->work->delay_bound = 10;
++ // Say that 1 WU takes 1 day on a ref comp
++ $this->work->rsc_fpops = 86400*1e9/2;
++ $this->work->rsc_iops = 86400*1e9/2;
++ $this->work->rsc_disk = 10e8;
++ array_push($this->work->input_files, "input");
++ $this->work->install($this);
++ }
++
++ function start_servers_and_host()
++ {
++ $this->start_servers();
++ $this->host->run("-exit_when_idle -skip_cpu_benchmarks");
++ }
++
++ function validate_all_and_stop()
++ {
++ $this->validate($this->work->redundancy);
++ $result->server_state = RESULT_SERVER_STATE_OVER;
++ $result->stderr_out = "APP: upper_case: starting, argc 1
++APP: upper_case: argv[0] is upper_case
++APP: upper_case ending, wrote ";
++ $result->exit_status = 0;
++ $this->check_results(2, $result);
++ $this->compare_file("uc_wu_0_0", "uc_correct_output");
++ $this->compare_file("uc_wu_1_0", "uc_correct_output");
++
++ $this->assimilate();
++ $this->file_delete();
++
++ $this->check_server_deleted("download/input");
++ $this->check_server_deleted("upload/uc_wu_0_0");
++ $this->check_server_deleted("upload/uc_wu_1_0");
++ $this->stop();
++ }
++ }
++} ?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_sched_moved.py
+@@ -0,0 +1,27 @@
++#!/usr/bin/env python
++
++## $Id: test_sched_moved.py 1656 2003-07-10 00:59:56Z quarl $
++
++# DOESN"T WORK YET
++
++from test_uc import *
++
++class ProjectSchedMove(ProjectUC):
++ def run(self):
++ self.sched_install('feeder')
++ self.start_servers()
++
++
++if __name__ == '__main__':
++ test_msg("backing off and finding new scheduler URL from master URL")
++ verbose_echo(0, "BEFORE SCHEDULER MOVE")
++ proj = ProjectSchedMove(short_name='test_sched_moved')
++ proj.install()
++ run_check_all()
++
++ verbose_echo(0, "AFTER SCHEDULER MOVE")
++ # TODO: change scheduler url
++ proj.install_project()
++ proj.install_works()
++ run_check_all()
++
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/uc_correct_output
+@@ -0,0 +1,1326 @@
++<HTML>
++ <HEAD>
++ <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="TEXT/HTML; CHARSET=UTF-8">
++ <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="TEXT/HTML" CHARSET="UTF-8">
++ <META HTTP-EQUIV="CONTENT-STYLE-TYPE" CONTENT="TEXT/CSS">
++ <STYLE TYPE="TEXT/CSS" MEDIA="SCREEN">
++ BODY, H2, H3, H4, P, UL, OL, DL
++ {
++ FONT-FAMILY: "VERDANA", "HELVETICA", "ARIAL", "SANS-SERIF"
++ }
++
++ H1 {COLOR: #0058A0; FONT-SIZE: 20PT}
++ H2 {COLOR: #0058A0; FONT-SIZE: 16PT}
++ H3 {COLOR: #0058A0; FONT-SIZE: 14PT}
++ H4 {COLOR: #0058A0; FONT-SIZE: 12PT}
++
++ A:LINK, A:ACTIVE, A:VISITED
++ {
++ COLOR: #0058A0;
++ TEXT-DECORATION: NONE
++ }
++
++ P, UL, OL, DL {MARGIN-LEFT: 10%; MARGIN-RIGHT: 10%; FONT-SIZE: 10PT}
++ DT {MARGIN-BOTTOM: 0.5EM}
++ .OFFSET {MARGIN-LEFT: 10%}
++ .AFTERSKIP {MARGIN-BOTTOM: 1EM}
++ .AFTERHALF {MARGIN-BOTTOM: 0.5EM}
++ .EXAMPLE {MARGIN-LEFT: 10%; MARGIN-RIGHT: 10%;
++ BORDER-COLOR: #0058A0; BORDER-STYLE:SOLID; BORDER-WIDTH: 1PT; PADDING: 1PT}
++ CODE {FONT-FAMILY: "COURIER"}
++ .COMMENT {COLOR: #0000FF}
++
++ P.OFFSET {MARGIN-LEFT: 15%}
++ P.INNER {MARGIN-LEFT: 2%; WIDTH: 96%}
++ P.NOTE {MARGIN-LEFT: 10%; BORDER-COLOR: #0058A0;
++ BORDER-STYLE:SOLID; BORDER-WIDTH: 1PT;
++ PADDING: 5PT; BACKGROUND-COLOR:#E0E0E0 }
++
++ PRE {FONT-SIZE: 10PT; PADDING: 5PT}
++
++ </STYLE>
++ <TITLE>GADOC - SABLOTRON 0.60</TITLE>
++ </HEAD>
++ <BODY BGCOLOR="#FFFFFF">
++ <H1 CLASS="AFTERSKIP">SABLOTRON 0.60</H1>
++ <DIV CLASS="AFTERSKIP">
++ <P>
++ <B>
++ <I>TOM KAISER (GINGER ALLIANCE)</I>
++ </B>
++ </P>
++ <P>
++ <I>JUNE 17, 2001</I>
++ </P>
++ </DIV>
++ <H3>ABSTRACT</H3>
++ <DIV CLASS="OFFSET">THIS IS A DESCRIPTION OF THE CURRENT VERSION OF THE
++ XSLT PROCESSOR CALLED SABLOTRON, INCLUDING AN OVERVIEW OF ITS
++ LIMITATIONS AS COMPARED TO THE XSLT SPECIFICATION.
++ </DIV>
++ <H3>CONTENTS</H3>
++<DIV STYLE="MARGIN-LEFT: 10%; MARGIN-BOTTOM: 2EM; FONT-SIZE: SMALLER">
++ <SPAN CLASS="AFTERHALF">
++ <A NAME="TOC_I__25"></A>&NBSP;<A HREF="#I__25">
++ <B>1&NBSP;&NBSP;THIS TEXT</B>
++ </A>
++ <DIV CLASS="OFFSET"></DIV>
++ </SPAN>
++ <SPAN CLASS="AFTERHALF">
++ <A NAME="TOC_I__60"></A>&NBSP;<A HREF="#I__60">
++ <B>2&NBSP;&NBSP;CHANGES FROM THE LAST RELEASE</B>
++ </A>
++ <DIV CLASS="OFFSET"></DIV>
++ </SPAN>
++ <SPAN CLASS="AFTERHALF">
++ <A NAME="TOC_I__74"></A>&NBSP;<A HREF="#I__74">
++ <B>3&NBSP;&NBSP;INTRODUCTION</B>
++ </A>
++ <DIV CLASS="OFFSET">&NBSP;&NBSP;<A HREF="#I__81">3.1&NBSP;&NBSP;XSLT</A>
++ <BR>&NBSP;&NBSP;<A HREF="#I__154">3.2&NBSP;&NBSP;ON SABLOTRON</A>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="AFTERHALF">
++ <A NAME="TOC_I__227"></A>&NBSP;<A HREF="#I__227">
++ <B>4&NBSP;&NBSP;THE SOURCES</B>
++ </A>
++ <DIV CLASS="OFFSET">&NBSP;&NBSP;<A HREF="#I__238">4.1&NBSP;&NBSP;GETTING THE SOURCES</A>
++ <BR>&NBSP;&NBSP;<A HREF="#I__280">4.2&NBSP;&NBSP;JOINING THE DEVELOPMENT</A>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="AFTERHALF">
++ <A NAME="TOC_I__305"></A>&NBSP;<A HREF="#I__305">
++ <B>5&NBSP;&NBSP;IMPLEMENTATION. SUPPORTED INSTRUCTIONS AND FUNCTIONS</B>
++ </A>
++ <DIV CLASS="OFFSET">&NBSP;&NBSP;<A HREF="#I__343">5.1&NBSP;&NBSP;TEMPLATES</A>
++ <BR>&NBSP;&NBSP;<A HREF="#I__364">5.2&NBSP;&NBSP;CONDITIONAL PROCESSING</A>
++ <BR>&NBSP;&NBSP;<A HREF="#I__381">5.3&NBSP;&NBSP;LOOPS</A>
++ <BR>&NBSP;&NBSP;<A HREF="#I__398">5.4&NBSP;&NBSP;VARIABLES AND PARAMETERS</A>
++ <BR>&NBSP;&NBSP;<A HREF="#I__415">5.5&NBSP;&NBSP;ELEMENT CREATION</A>
++ <BR>&NBSP;&NBSP;<A HREF="#I__439">5.6&NBSP;&NBSP;GLOBAL DEFINITIONS</A>
++ <BR>&NBSP;&NBSP;<A HREF="#I__476">5.7&NBSP;&NBSP;VALUES AND COPYING</A>
++ <BR>&NBSP;&NBSP;<A HREF="#I__508">5.8&NBSP;&NBSP;NAMESPACE PROCESSING</A>
++ <BR>&NBSP;&NBSP;<A HREF="#I__529">5.9&NBSP;&NBSP;SORTING</A>
++ <BR>&NBSP;<A HREF="#I__577">5.10&NBSP;&NBSP;WHITESPACE STRIPPING</A>
++ <BR>&NBSP;<A HREF="#I__598">5.11&NBSP;&NBSP;INCLUDES</A>
++ <BR>&NBSP;<A HREF="#I__623">5.12&NBSP;&NBSP;OTHER UNIMPLEMENTED INSTRUCTIONS</A>
++ <BR>&NBSP;<A HREF="#I__654">5.13&NBSP;&NBSP;OUTPUT CONFORMANCE</A>
++ <BR>&NBSP;<A HREF="#I__686">5.14&NBSP;&NBSP;XPATH EXPRESSIONS</A>
++ <BR>&NBSP;<A HREF="#I__714">5.15&NBSP;&NBSP;BUILT-IN FUNCTIONS</A>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="AFTERHALF">
++ <A NAME="TOC_I__804"></A>&NBSP;<A HREF="#I__804">
++ <B>6&NBSP;&NBSP;OTHER IMPLEMENTATION-RELATED NOTES</B>
++ </A>
++ <DIV CLASS="OFFSET">&NBSP;&NBSP;<A HREF="#I__811">6.1&NBSP;&NBSP;HANDLERS</A>
++ <BR>&NBSP;&NBSP;<A HREF="#I__859">6.2&NBSP;&NBSP;ENCODINGS</A>
++ <BR>&NBSP;&NBSP;<A HREF="#I__887">6.3&NBSP;&NBSP;OUTPUT METHODS</A>
++ <BR>&NBSP;&NBSP;<A HREF="#I__915">6.4&NBSP;&NBSP;URIS</A>
++ <BR>&NBSP;&NBSP;<A HREF="#I__983">6.5&NBSP;&NBSP;NAMED BUFFERS</A>
++ <BR>&NBSP;&NBSP;<A HREF="#I__1015">6.6&NBSP;&NBSP;ERROR AND LOG MESSAGES</A>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="AFTERHALF">
++ <A NAME="TOC_I__1048"></A>&NBSP;<A HREF="#I__1048">
++ <B>7&NBSP;&NBSP;THE C INTERFACE</B>
++ </A>
++ <DIV CLASS="OFFSET">&NBSP;&NBSP;<A HREF="#I__1065">7.1&NBSP;&NBSP;SHORTCUTS</A>
++ <BR>&NBSP;&NBSP;<A HREF="#I__1205">7.2&NBSP;&NBSP;BASIC FUNCTIONS</A>
++ <BR>&NBSP;&NBSP;<A HREF="#I__1416">7.3&NBSP;&NBSP;GENERALIZED INTERFACE FUNCTIONS</A>
++ <BR>&NBSP;&NBSP;<A HREF="#I__1578">7.4&NBSP;&NBSP;THE SITUATION OBJECT</A>
++ <BR>&NBSP;&NBSP;<A HREF="#I__1631">7.5&NBSP;&NBSP;DOCUMENT OBJECT MODEL (DOM) FUNCTIONS</A>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="AFTERHALF">
++ <A NAME="TOC_I__1870"></A>&NBSP;<A HREF="#I__1870">
++ <B>8&NBSP;&NBSP;THE COMMAND LINE INTERFACE</B>
++ </A>
++ <DIV CLASS="OFFSET"></DIV>
++ </SPAN>
++ <SPAN CLASS="AFTERHALF">
++ <A NAME="TOC_I__2013"></A>&NBSP;<A HREF="#I__2013">
++ <B>9&NBSP;&NBSP;REFERENCES</B>
++ </A>
++ <DIV CLASS="OFFSET"></DIV>
++ </SPAN>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__25"></A>
++ <H2>
++ <A HREF="#TOC_I__25">1&NBSP;&NBSP;THIS TEXT</A>
++ </H2>
++ <DIV>
++ <P CLASS="">THE HTML FORM OF THIS DESCRIPTION
++ WAS COMPILED BY SABLOTRON FROM THE XML SOURCE
++ SABLOT-0-60.XML.
++ </P>
++ <P CLASS="">
++ THE MATERIAL IN THE FOLLOWING SECTIONS INCLUDES:
++ </P>
++ <UL>
++ <LI>SOME BACKGROUND INFORMATION ON XSLT AND SABLOTRON,</LI>
++ <LI>A DETAILED COMPARISON OF THE CURRENT VERSION OF
++ SABLOTRON TO THE XSLT SPEC,</LI>
++ <LI>SABLOTRON USAGE FROM THE COMMAND LINE OR AS A
++ LIBRARY.</LI>
++ </UL>
++ </DIV>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__60"></A>
++ <H2>
++ <A HREF="#TOC_I__60">2&NBSP;&NBSP;CHANGES FROM THE LAST RELEASE</A>
++ </H2>
++ <DIV>
++ <P CLASS="">PLEASE SEE THE RELEASE FILE.</P>
++ </DIV>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__74"></A>
++ <H2>
++ <A HREF="#TOC_I__74">3&NBSP;&NBSP;INTRODUCTION</A>
++ </H2>
++ <DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__81"></A>
++ <H3>
++ <A HREF="#TOC_I__74">3.1&NBSP;&NBSP;XSLT</A>
++ </H3>
++ <P CLASS="">XSLT IS A LANGUAGE ALLOWING TO TRANSFORM GIVEN XML DATA (THE
++ <I>INPUT</I>) ACCORDING TO A <I>STYLESHEET</I>. XSLT STYLESHEETS
++ ARE THEMSELVES XML DOCUMENTS; THAT IS, ALL INSTRUCTIONS OF THE
++ LANGUAGE ARE EXPRESSED IN THE FORM OF XML ELEMENTS. THE
++ <I>OUTPUT</I>, I.E. THE RESULT OF THE PROCESSING, IS TYPICALLY A
++ XML DOCUMENT AS WELL, ALTHOUGH THE SYNTACTIC REQUIREMENTS CAN BE
++ RELAXED TO ALLOW THE CREATION OF A HTML DOCUMENT (ONE THAT
++ CONTAINS UNCLOSED TAGS AND THE LIKE), OR EVEN PLAIN TEXT.
++ </P>
++ <P CLASS="">XSLT WAS DESIGNED BY THE WORLD WIDE WEB CONSORTIUM (W3C) AS
++ A PART OF THE XSL STYLESHEET LANGUAGE, WHERE IT IS COMPLEMENTED
++ BY A POWERFUL SET OF FORMATTING INSTRUCTIONS. THE MOST PRECISE
++ INFORMATION ABOUT XSLT CAN BE FOUND IN THE W3C RECOMMENDATION <A HREF="#REF-XSLT">[XSLT]</A>. IN PARTICULAR, APPENDIX B OF THE
++ RECOMMENDATION CONTAINS A HANDY SYNTAX TABLE. A GOOD TUTORIAL IS
++ <A HREF="#REF-BIBLE">[XMLBIBLE14]</A>.
++ </P>
++ <P CLASS="">OTHER W3C RECOMMENDATIONS ONE OFTEN NEEDS TO CONSULT ARE <A HREF="#REF-XML">[XML]</A> (FOR THE DEFINITION OF THE XML
++ LANGUAGE) AND <A HREF="#REF-XPATH">[XPATH]</A> (FOR DETAILS ON
++ XPATH, THE LANGUAGE USED TO FORM EXPRESSIONS IN XSLT AND
++ ELSEWHERE).
++ </P>
++ <P CLASS="">AN EXCELLENT SOURCE OF INFORMATION ABOUT XSLT (INDEED, ABOUT
++ ANYTHING RELATED TO XML AND SGML) IS <A HREF="#REF-RCOVER">[COVER]</A>; SEE ALSO <A HREF="#REF-XSLINFO">[XSLINFO]</A> AND <A HREF="#REF-XMLORG">[XMLORG]</A>.
++ </P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__154"></A>
++ <H3>
++ <A HREF="#TOC_I__74">3.2&NBSP;&NBSP;ON SABLOTRON</A>
++ </H3>
++ <P CLASS="">SABLOTRON IS A XSLT PROCESSOR (THOUGH NOT QUITE CONFORMING
++ YET..., SEE BELOW) WRITTEN IN C++. SINCE THE MACHINES WHERE IT
++ IS MEANT TO RUN INCLUDE VARIOUS SMALL MOBILE
++ CLIENTS, THE MAIN OBJECTIVES OF ITS DESIGN ARE THE FOLLOWING:
++ </P>
++ <UL>
++ <LI>PORTABILITY,</LI>
++ <LI>COMPACT CODE,</LI>
++ <LI>AS MUCH INDEPENDENCE ON OTHER RESOURCES (JAVA ETC.) AS
++ POSSIBLE.</LI>
++ </UL>
++ <P CLASS="">SABLOTRON IS A SINGLE SHARED LIBRARY
++ (<CODE>SABLOT.DLL</CODE> OR <CODE>LIBSABLOT.SO.0.60</CODE>). IT CAN
++ ALSO BE USED FROM THE COMMAND LINE VIA THE SIMPLE INTERFACE
++ CALLED <CODE>SABCMD</CODE>. SEE <A HREF="#INVOCATION">HERE</A> FOR
++ MORE INFORMATION.
++ </P>
++ <P CLASS="">THE ONLY SOFTWARE SABLOTRON RELIES ON IS <B>EXPAT</B>, THE
++ XML PARSER BY JAMES CLARK. SEE <A HREF="#EXPAT">BELOW</A> FOR
++ INFORMATION ON HOW TO GET EXPAT.
++ </P>
++ <P CLASS="">FOR INFORMATION ON THE AVAILABLE INTERFACES, E.G. FOR
++ PYTHON, PERL AND PHP, SEE <A HREF="HTTP://WWW.GINGERALL.COM">WWW.GINGERALL.COM</A>.
++ </P>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__227"></A>
++ <H2>
++ <A HREF="#TOC_I__227">4&NBSP;&NBSP;THE SOURCES</A>
++ </H2>
++ <DIV>
++ <P CLASS="">
++ SABLOTRON IS WRITTEN IN C++. THE SOURCE FILES COMPILE UNDER
++ WIN32 (USING MS VISUAL C++ 6.0) AND ON SOLARIS AND LINUX (USING
++ G++ 2.95.2) WITHOUT CHANGE.</P>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__238"></A>
++ <H3>
++ <A HREF="#TOC_I__227">4.1&NBSP;&NBSP;GETTING THE SOURCES</A>
++ </H3>
++ <P CLASS="">THE SOURCE OR BINARY DISTRIBUTIONS OF SABLOTRON CAN BE DOWNLOADED
++ FROM <A HREF="HTTP://WWW.GINGERALL.COM">WWW.GINGERALL.COM</A>. FOR
++ INSTRUCTIONS ON HOW TO BUILD THE SOURCES (IF ANY), REFER TO THE ACCOMPANYING INSTALL FILE.
++ </P>
++ <P CLASS="">IF YOU HAVE ACCESS TO THE GINGER ALLIANCE CVS SERVER, YOU
++ CAN GET THE WORKING VERSION OF SABLOTRON IN THE CVS MODULE
++ <CODE>GA</CODE>. THE ACCESS RIGHTS CAN BE OBTAINED ON
++ REQUEST FROM <A HREF="MAILTO:CVSADMIN at GINGERALL.COM">THE CVS ADMIN</A>.
++ </P>
++ <P CLASS="">
++ <A NAME="EXPAT"></A>
++ SINCE VERSION 0.50, SABLOTRON USES EXPAT 1.95.1, AVAILABLE FROM <A HREF="HTTP://EXPAT.SOURCEFORGE.ORG">SOURCEFORGE</A>.
++ </P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__280"></A>
++ <H3>
++ <A HREF="#TOC_I__227">4.2&NBSP;&NBSP;JOINING THE DEVELOPMENT</A>
++ </H3>
++ <P CLASS="">
++ SABLOTRON IS AN OPEN SOURCE PROJECT AND ALL VOLUNTEERS ARE MOST
++ WELCOME! THE DOCUMENTATION OF THE SOURCES IS STILL SOMEWHAT
++ SPARSE BUT WE WILL TRY TO IMPROVE IT. IF YOU FIND THE INVITATION
++ TO WORK ON SABLOTRON WITH US INTERESTING, PLEASE <A HREF="MAILTO:SABLOTRON at GINGERALL.COM">CONTACT US</A>. THERE IS ALSO
++ A MAILING LIST AVAILABLE, SEE <A HREF="HTTP://WWW.GINGERALL.COM">WWW.GINGERALL.COM</A>.
++ </P>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__305"></A>
++ <H2>
++ <A HREF="#TOC_I__305">5&NBSP;&NBSP;IMPLEMENTATION. SUPPORTED INSTRUCTIONS AND FUNCTIONS</A>
++ </H2>
++ <DIV>
++ <P CLASS="">THE INSTRUCTION SET SUPPORTED BY THIS VERSION OF SABLOTRON IS
++ ALREADY SUFFICIENT FOR MANY TRANSFORMATION TASKS (E.G. THE TASK OF
++ FORMATTING THIS DOCUMENT). ON THE OTHER
++ HAND, A COMPARISON OF IT TO THE XSLT SPECIFICATION <A HREF="#REF-XSLT">[XSLT]</A> SHOWS THAT MUCH IS STILL TO BE
++ DONE. THE PURPOSE OF THE
++ FOLLOWING SECTIONS IS TO DESCRIBE THE VARYING DEGREE OF SUPPORT
++ FOR THE ELEMENTS OF THE XSLT LANGUAGE. </P>
++ <P CLASS="">IT MAY BE HELPFUL TO REFER TO THE SYNTAX TABLE IN APPENDIX B
++ OF <A HREF="#REF-XSLT">[XSLT]</A>. THE INSTRUCTIONS/ATTRIBUTES THAT
++ ARE NOT LISTED AS UNSUPPORTED SHOULD BE IMPLEMENTED. THE <A HREF="MAILTO:SABLOTRON at GINGERALL.COM">AUTHORS</A> WILL APPRECIATE BEING
++ TOLD ABOUT ANY OMISSIONS FOUND IN THE FOLLOWING
++ DESCRIPTION.</P>
++ <P CLASS="">FOR READABILITY, I SOMETIMES OMIT THE <CODE>XSL:</CODE> PREFIX
++ FROM THE INSTRUCTION NAMES.</P>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__343"></A>
++ <H3>
++ <A HREF="#TOC_I__305">5.1&NBSP;&NBSP;TEMPLATES</A>
++ </H3>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ TEMPLATE, APPLY-TEMPLATES, CALL-TEMPLATE
++ </CODE>
++ </P>
++ <P CLASS="">
++ FULLY IMPLEMENTED. <CODE>XSL:SORT</CODE> IS SUPPORTED SINCE RELEASE 0.50.
++ </P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__364"></A>
++ <H3>
++ <A HREF="#TOC_I__305">5.2&NBSP;&NBSP;CONDITIONAL PROCESSING</A>
++ </H3>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ IF, CHOOSE, WHEN, OTHERWISE
++ </CODE>
++ </P>
++ <P CLASS="">FULLY IMPLEMENTED.
++ </P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__381"></A>
++ <H3>
++ <A HREF="#TOC_I__305">5.3&NBSP;&NBSP;LOOPS</A>
++ </H3>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>FOR-EACH</CODE>
++ </P>
++ <P CLASS="">FULLY IMPLEMENTED.
++ </P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__398"></A>
++ <H3>
++ <A HREF="#TOC_I__305">5.4&NBSP;&NBSP;VARIABLES AND PARAMETERS</A>
++ </H3>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>VARIABLE, PARAM, WITH-PARAM</CODE>
++ </P>
++ <P CLASS="">FULLY IMPLEMENTED. TOP-LEVEL VARIABLES AND PARAMETERS ARE
++ READ IN THE DOCUMENT ORDER, SO NO FORWARD REFERENCES ARE
++ RESOLVED. THIS IS A MINOR DEVIATION FROM THE SPEC. </P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__415"></A>
++ <H3>
++ <A HREF="#TOC_I__305">5.5&NBSP;&NBSP;ELEMENT CREATION</A>
++ </H3>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>ELEMENT, ATTRIBUTE, TEXT,
++ COMMENT, PROCESSING-INSTRUCTION, ATTRIBUTE-SET</CODE>
++ </P>
++ <P CLASS="">
++ <CODE>XSL:ATTRIBUTE-SET</CODE> IS NOT IMPLEMENTED. FOR THE
++ REST, <CODE>NAME</CODE> IS THE ONLY RECOGNIZED ATTRIBUTE (WHERE
++ APPLICABLE). LITERAL RESULT ELEMENTS WORK.</P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__439"></A>
++ <H3>
++ <A HREF="#TOC_I__305">5.6&NBSP;&NBSP;GLOBAL DEFINITIONS</A>
++ </H3>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>STYLESHEET, TRANSFORM, OUTPUT</CODE>
++ </P>
++ <P CLASS="">FOR <CODE>STYLESHEET</CODE> AND <CODE>TRANSFORM</CODE>,
++ THE ONLY RECOGNIZED ATTRIBUTE IS
++ <CODE>VERSION</CODE>. <CODE>XSL:OUTPUT</CODE> SHOULD WORK
++ (SEE BELOW FOR NOTES ON THE <CODE>ENCODING</CODE>
++ ATTRIBUTE). HTML INDENTATION HAS BEEN ADDED IN 0.60.
++ </P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__476"></A>
++ <H3>
++ <A HREF="#TOC_I__305">5.7&NBSP;&NBSP;VALUES AND COPYING</A>
++ </H3>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>VALUE-OF, COPY, COPY-OF</CODE>
++ </P>
++ <P CLASS="">
++ <CODE>COPY-OF</CODE> AND <CODE>VALUE-OF</CODE> ARE FULLY
++ IMPLEMENTED. <CODE>COPY</CODE> IS IMPLEMENTED EXCEPT FOR THE
++ <CODE>USE-ATTRIBUTE-SETS</CODE> ATTRIBUTE.</P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__508"></A>
++ <H3>
++ <A HREF="#TOC_I__305">5.8&NBSP;&NBSP;NAMESPACE PROCESSING</A>
++ </H3>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>NAMESPACE-ALIAS</CODE>
++ </P>
++ <P CLASS="">NAMESPACES SHOULD BE PROCESSED CORRECTLY. THE
++ <CODE>NAMESPACE-ALIAS</CODE> INSTRUCTION IS NOW SUPPORTED
++ (PATCH BY MAJOR).</P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__529"></A>
++ <H3>
++ <A HREF="#TOC_I__305">5.9&NBSP;&NBSP;SORTING</A>
++ </H3>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>SORT</CODE>
++ </P>
++ <P CLASS="">
++ <CODE>XSL:SORT</CODE> IS IMPLEMENTED SINCE 0.50. THERE ARE
++ MINOR LIMITATIONS:
++ </P>
++ <UL>
++ <LI>CURRENTLY, THE <CODE>LANG</CODE> ATTRIBUTE MAY ONLY
++ CONTAIN THE VALUES <CODE>"EN"</CODE> OR <CODE>"CZ"</CODE>.</LI>
++ <LI>
++ <CODE>CASE-ORDER</CODE> CANNOT BE SPECIFIED.</LI>
++ </UL>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__577"></A>
++ <H3>
++ <A HREF="#TOC_I__305">5.10&NBSP;&NBSP;WHITESPACE STRIPPING</A>
++ </H3>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>STRIP-SPACE, PRESERVE-SPACE</CODE>
++ </P>
++ <P CLASS="">ONLY THE DEFAULT WHITESPACE STRIPPING IS DONE. THAT IS,
++ ALL WHITESPACE-ONLY TEXT NODES IN ANY STYLESHEET, NOT APPEARING
++ INSIDE A <CODE>XSL:TEXT</CODE>, ARE REMOVED. THE TWO
++ INSTRUCTIONS FOR WHITESPACE STRIPPING AND PRESERVATION ARE
++ UNSUPPORTED.</P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__598"></A>
++ <H3>
++ <A HREF="#TOC_I__305">5.11&NBSP;&NBSP;INCLUDES</A>
++ </H3>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>INCLUDE, IMPORT, APPLY-IMPORTS</CODE>
++ </P>
++ <P CLASS="">ONLY <CODE>XSL:INCLUDE</CODE> IS IMPLEMENTED. PROCESSING
++ INVOLVING MULTIPLE DOCUMENTS WORKS, BUT HAS TO GET MORE TESTING,
++ EG. WITH RESPECT TO <CODE>GENERATE-ID()</CODE>.</P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__623"></A>
++ <H3>
++ <A HREF="#TOC_I__305">5.12&NBSP;&NBSP;OTHER UNIMPLEMENTED INSTRUCTIONS</A>
++ </H3>
++ <UL>
++ <LI>
++ <CODE>XSL:KEY,</CODE>
++ </LI>
++ <LI>
++ <CODE>XSL:NUMBER,</CODE>
++ </LI>
++ <LI>
++ <CODE>XSL:FALLBACK.</CODE>
++ </LI>
++ </UL>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__654"></A>
++ <H3>
++ <A HREF="#TOC_I__305">5.13&NBSP;&NBSP;OUTPUT CONFORMANCE</A>
++ </H3>
++ <P CLASS="">THE OUTPUT MECHANISM IS MUCH CLOSER TO THE SPEC THAN IN
++ THE VERSIONS PRIOR TO 0.4. THE FOLLOWING ISSUES REMAIN FOR THE
++ HTML METHOD:</P>
++ <UL>
++ <LI>OUTPUT THE BOOLEAN ATTRIBUTES CORRECTLY.</LI>
++ <LI>DISABLE THE ESCAPING INSIDE
++ <CODE><SCRIPT></CODE> AND
++ <CODE><STYLE></CODE>
++ </LI>.
++ </UL>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__686"></A>
++ <H3>
++ <A HREF="#TOC_I__305">5.14&NBSP;&NBSP;XPATH EXPRESSIONS</A>
++ </H3>
++ <P CLASS="">ALMOST ALL FEATURES OF XPATH ARE FULLY IMPLEMENTED. THIS MEANS
++ THERE SHOULD BE NO PROBLEMS WITH EXPRESSIONS OF ANY KIND.</P>
++ <P CLASS="">ONE EXCEPTION RELATES TO AXES. THE <CODE>FOLLOWING</CODE> AND
++ <CODE>PRECEDING</CODE> AXES HAVEN'T BEEN IMPLEMENTED YET.</P>
++ <P CLASS="">ANOTHER POSSIBLE EXCEPTION MAY BE NUMBERS; WE DID NOT YET DO A
++ THOROUGH TEST OF ROUNDING, NANS, INFINITY, ETC.</P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__714"></A>
++ <H3>
++ <A HREF="#TOC_I__305">5.15&NBSP;&NBSP;BUILT-IN FUNCTIONS</A>
++ </H3>
++ <P CLASS="">
++ <A NAME="CORELIB"></A>ONLY A FEW FUNCTIONS FROM THE STANDARD
++ FUNCTION LIBRARY REMAIN
++ UNIMPLEMENTED:
++ </P>
++ <UL>
++ <LI>
++ <CODE>ID()</CODE>,</LI>
++ <LI>
++ <CODE>LANG()</CODE> (ACCEPTED BUT ALWAYS RETURNS TRUE),</LI>
++ <LI>
++ <CODE>KEY()</CODE>,</LI>
++ <LI>
++ <CODE>FORMAT-NUMBER()</CODE>,</LI>
++ <LI>
++ <CODE>UNPARSED-ENTITY-URI()</CODE>.</LI>
++ </UL>
++ <P CLASS="">AS FOR THE FUCTIONS THAT <I>ARE</I> IMPLEMENTED, THE
++ FOLLOWING IS A LIST OF DIFFERENCES FROM THE SPEC:
++ </P>
++ <UL>
++ <LI>
++ <CODE>DOCUMENT()</CODE> ONLY ACCEPTS ONE ARGUMENT, ALWAYS
++ GETTING THE BASE URI FROM THE STYLESHEET URI.
++ </LI>
++ <LI>
++ <CODE>STRING-LENGTH()</CODE> RETURNS THE BYTE LENGTH OF
++ THE UTF-8 REPRESENTATION OF THE STRING. THIS WILL TYPICALLY
++ DIFFER FROM THE ACTUAL LENGTH.
++ </LI>
++ <LI>
++ <CODE>GENERATE-ID()</CODE> MIGHT FAIL TO GENERATE UNIQUE IDENTIFIERS
++ WHEN SEVERAL INPUT DOCUMENTS ARE PRESENT (GIVING THE SAME ID TO
++ NODES FROM DIFFERENT DOCUMENTS).
++ </LI>
++ </UL>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__804"></A>
++ <H2>
++ <A HREF="#TOC_I__804">6&NBSP;&NBSP;OTHER IMPLEMENTATION-RELATED NOTES</A>
++ </H2>
++ <DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__811"></A>
++ <H3>
++ <A HREF="#TOC_I__804">6.1&NBSP;&NBSP;HANDLERS</A>
++ </H3>
++ <P CLASS="">IT IS POSSIBLE FOR THE USER TO SUPPLY THE FOLLOWING
++ HANDLERS TO SABLOTRON:
++ <UL>
++ <LI>MESSAGE HANDLER (TO BYPASS THE DEFAULT WAY OF DISPLAYING
++ ERROR AND WARNING MESSAGES AND LOGGING),</LI>
++ <LI>SCHEME HANDLER (TO RETRIEVE DOCUMENTS WHOSE URI USE AN
++ UNSUPPORTED SCHEME),</LI>
++ <LI>STREAMING HANDLER (AN EXPAT-LIKE INTERFACE TO THE XML
++ DOCUMENT WHICH IS THE RESULT OF THE PROCESSING),</LI>
++ <LI>'MISCELLANEOUS' HANDLER (WHICH WILL PROBABLY SERVER AS A
++ COLLECTIONS OF ODD CALLBACKS).</LI>
++ </UL>
++ </P>
++ <P CLASS="">
++ THE HANDLERS ARE SET USING <CODE>SABLOTREGHANDLER()</CODE>
++ FOR DETAILS CONCERNING THE INTERFACE OF THESE HANDLERS,
++ CONSULT THE HEADER FILES <CODE>SABLOT.H</CODE> AND
++ <CODE>SHANDLER.H</CODE>.
++ </P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__859"></A>
++ <H3>
++ <A HREF="#TOC_I__804">6.2&NBSP;&NBSP;ENCODINGS</A>
++ </H3>
++ <P CLASS="">
++ IN VERSION 0.52, THE ENCODING CONVERSION CAPABILITIES OF
++ SABLOTRON HAVE BEEN MUCH EXTENDED. THE MOST IMPORTANT FACT IS THE
++ FOLLOWING: IF YOU HAVE THE ICONV LIBRARY INSTALLED ON YOUR SYSTEM, YOU
++ CAN USE ANY ENCODING IT SUPPORTS (THAT IS, ALMOST ANY ENCODING
++ WHATSOEVER) FOR BOTH THE INPUT AND THE OUTPUT DOCUMENTS. ICONV
++ IS AVAILABLE ON MOST SYSTEMS (IT IS A STANDARD PART OF GLIBC2,
++ FOR INSTANCE). THERE ARE IMPLEMENTATIONS FOR WIN32 AS WELL.
++ </P>
++ <P CLASS="">IF ICONV IS NOT AVAILABLE, THE ENCODING MAY STILL BE SUPPORTED INTERNALLY BY
++ SABLOTRON. AT PRESENT, THE LIST IS OF SUCH ENCODINGS IS RATHER
++ SHORT: BESIDES UTF-8, THESE ARE UTF-16, ASCII, ISO-8859-1,
++ ISO-8859-2 AND WINDOWS-1250 ON INPUT, NONE ON OUTPUT. HOWEVER,
++ WE PLAN TO IMPLEMENT A HALF INDEPENDENT LIGHT-WEIGHT
++ CONVERSION LIBRARY FOR USE ON SYSTEMS WITHOUT ICONV,
++ EXTENDING THE SET OF INTERNALLY SUPPORTED ENCODINGS
++ CONSIDERABLY.
++ </P>
++ <P CLASS="">LASTLY, THE USER HAS THE OPTION TO IMPLEMENT A CUSTOM
++ ENCODING CONVERSION HANDLER, WHICH WILL BE ASKED TO PERFORM ANY UNSUPPORTED
++ CONVERSION. SEE THE <CODE>SHANDLER.H</CODE> HEADER FILE FOR
++ DETAILS.
++ </P>
++ <P CLASS="">THE DEFAULT INPUT AND OUTPUT ENCODING IS IN ALL CASES UTF-8.</P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__887"></A>
++ <H3>
++ <A HREF="#TOC_I__804">6.3&NBSP;&NBSP;OUTPUT METHODS</A>
++ </H3>
++ <P CLASS="">IN ADDITION TO THE STANDARD OUTPUT METHODS (XML, HTML AND
++ TEXT), IT IS POSSIBLE TO OUTPUT XHTML. DOCUMENTS OUTPUT USING
++ THIS METHOD OBEY THE XHTML 1.0 RULES (IN PARTICULAR, ALL EMPTY
++ ELEMENTS ARE CLOSED). TO CHOOSE THE METHOD, USE
++ <CODE><XSL:OUTPUT METHOD='XHTML'></CODE>. <B>PLEASE NOTE</B>
++ THAT THE NAME OF THIS METHOD WILL POSSIBLY BE CHANGED SINCE THE XSLT
++ SPEC REQUIRES ANY PROCESSOR-SPECIFIC METHODS TO HAVE QUALIFIED
++ NAMES, SAY <CODE>SAB:XHTML</CODE>. ON THE OTHER HAND, THE NAME
++ <CODE>XHTML</CODE> IS CONSIDERED IN THE XSLT 2.0 WORKING DRAFT.</P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__915"></A>
++ <H3>
++ <A HREF="#TOC_I__804">6.4&NBSP;&NBSP;URIS</A>
++ </H3>
++ <P CLASS="">SABLOTRON CAN HANDLE
++ TWO URI SCHEMES NATIVELY: 'FILE' AND 'ARG' (SEE
++ BELOW). MOREOVER, IT IS POSSIBLE TO USE THE FUNCTION
++ <CODE>SABLOTREGSCHEMEHANDLER</CODE> TO REGISTER AN EXTERNAL SCHEME
++ HANDLER WHICH WILL RECEIVE REQUESTS IN ALL OTHER SCHEMES. SEE
++ THE DOCUMENTATION IN <CODE>SABLOT.H</CODE> AND
++ <CODE>SHANDLER.H</CODE>.
++ </P>
++ <P CLASS="">RELATIVE URI REFERENCES ARE RESOLVED IN CONFORMANCE TO RFC
++ 2396. THE BASE URI IS WELL DEFINED WHEN THE RELATIVE REFERENCE APPEARS
++ INSIDE A XML DOCUMENT; WHEN INVOKING SABCMD, THE BASE URI IS
++ TAKEN TO CORRESPOND TO THE CURRENT WORKING DIRECTORY.
++ </P>
++ <P CLASS="">
++ <A NAME="FNAME-RULES"></A>WHEN SPECIFYING FILENAMES, THE
++ FOLLOWING RULES ARE IN EFFECT:
++ </P>
++ <UL>
++ <LI>SPECIFY THE "FILE:" SCHEME FOR ANY STANDARD FILES,
++ I.E. REFER TO <CODE>STDIN</CODE> AS <CODE>FILE://STDIN</CODE>
++ ETC.</LI>
++ <LI>SLASHES AND BACKSLASHES WORK EQUALLY FINE, IN WINDOWS AS
++ WELL AS LINUX.</LI>
++ <LI>TO INCLUDE A DRIVE LETTER UNDER WINDOWS
++ (E.G. <CODE>C:\DOC.XML</CODE>), IT IS NECESSARY TO SAY
++ <CODE>FILE://C:/DOC.XML</CODE>.
++ </LI>
++ </UL>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__983"></A>
++ <H3>
++ <A HREF="#TOC_I__804">6.5&NBSP;&NBSP;NAMED BUFFERS</A>
++ </H3>
++ <P CLASS="">
++ <A NAME="ARGSCHEME"></A>SABLOTRON INTRODUCES AN URI SCHEME
++ 'ARG:' WHICH ENABLES ONE TO USE STRINGS IN NAMED MEMORY
++ BUFFERS. THE BUFFER NAMES CAN HAVE A TREE-LIKE STRUCTURE SO THAT
++ A RELATIVE REFERENCE FROM A DOCUMENT IN A BUFFER CAN BE RESOLVED
++ AS POINTING TO ANOTHER BUFFER.
++ </P>
++ <P CLASS="">FOR INSTANCE, IF WE INVOKE SABLOTRON SPECIFYING THAT A
++ BUFFER NAMED <CODE>/MYBUF/1</CODE> CONTAINS THE STRING
++ "&LT;A>CONTENTS&LT;/A>", THEN THE EXPRESSION
++ </P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ DOCUMENT('ARG:/MYBUF/1')/A
++ </CODE>
++ </P>
++ <P CLASS="">HAS STRING-VALUE "CONTENTS". IF THE DOCUMENT IN ARG:/MYBUF/1
++ CONTAINED A RELATIVE URI REFERENCE "../THEIRBUF/2" THEN THIS
++ WOULD BE RESOLVED AS POINTING TO "ARG:/THEIRBUF/2".</P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__1015"></A>
++ <H3>
++ <A HREF="#TOC_I__804">6.6&NBSP;&NBSP;ERROR AND LOG MESSAGES</A>
++ </H3>
++ <P CLASS="">BY DEFAULT, SABLOTRON WRITES ERROR AND WARNING MESSAGES TO
++ STDERR, AND DOES NO LOGGING. BY A CALL TO
++ <CODE>SABLOTSETLOG()</CODE>, YOU CAN SPECIFY THE NAME OF THE LOG
++ FILE TO BE USED.</P>
++ <P CLASS="">BESIDES, YOU CAN USE <CODE>SABLOTREGHANDLER()</CODE>
++ TO OVERRIDE THE DEFAULT MESSAGE HANDLING. THE HANDLER YOU
++ REGISTER WILL RECEIVE ALL MESSAGES IN A STRUCTURED FORM THAT'S
++ EASY TO PROCESS AND FILTER. FOR DETAILS, SEE
++ THE DOCUMENTATION IN <CODE>SABLOT.H</CODE> AND
++ <CODE>SHANDLER.H</CODE>.</P>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__1048"></A>
++ <H2>
++ <A HREF="#TOC_I__1048">7&NBSP;&NBSP;THE C INTERFACE</A>
++ </H2>
++ <DIV>
++ <P CLASS="">
++ <A NAME="INVOCATION"></A>
++ </P>
++ <P CLASS="">
++ THIS SECTION DESCRIBES THE FUNCTIONS EXPORTED FROM THE
++ SABLOTRON LIBRARY. ALL OF THEM HAVE A RETURN TYPE OF 'INT'
++ AND RETURN AN ERROR FLAG (NONZERO SIGNALS AN ERROR). ERRORS
++ ARE REPORTED TO THE USER BY SABLOTRON ITSELF.
++ </P>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__1065"></A>
++ <H3>
++ <A HREF="#TOC_I__1048">7.1&NBSP;&NBSP;SHORTCUTS</A>
++ </H3>
++ <P CLASS="">
++ WE'LL FIRST DESCRIBE THE 'SHORTCUTS' THAT DO THE WHOLE
++ PROCESSING IN ONE CALL.
++ </P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ INT SABLOTPROCESS(CHAR *SHEETURI, CHAR *INPUTURI, CHAR *RESULTURI,
++ CHAR **PARAMS, CHAR **ARGUMENTS, CHAR **RESULTARG);
++ </CODE>
++ </P>
++ <P CLASS="">
++ THIS IS THE BASIC FUNCTION. THE FIRST THREE OF ITS ARGUMENTS
++ ARE THE URIS OF THE XSLT STYLESHEET, THE XML SOURCE AND THE
++ RESULTING DOCUMENT, RESPECTIVELY. FOR SOME NOTES ON SPECIFYING
++ FILE NAMES, SEE <A HREF="#FNAME-RULES">ABOVE</A>.
++ </P>
++ <P CLASS="">
++ <CODE>PARAMS</CODE> IS AN ARRAY OF POINTERS TO THE NAMES
++ AND CONTENTS OF THE TOP-LEVEL STYLESHEET PARAMETERS. THUS,
++ <CODE>PARAMS[0]</CODE> IS A POINTER TO THE NULL-TERMINATED NAME
++ OF THE FIRST PARAMETER, <CODE>PARAMS[1]</CODE> POINTS TO THE
++ (NULL-TERMINATED) CONTENTS OF THE FIRST PARAMETER. THE FOLLOWING
++ TWO ARRAY ITEMS DO THE SAME FOR THE SECOND PARAMETER, ETC. THE
++ WHOLE ARRAY IS TERMINATED BY A NULL POINTER IN PLACE OF THE
++ NAME. IF NO PARAMETERS ARE TO BE PASSED, YOU CAN SPECIFY NULL
++ FOR <CODE>PARAMS</CODE> ITSELF.
++ </P>
++ <P CLASS="">
++ <CODE>ARGUMENTS</CODE> IS A SIMILAR ARRAY OF NAMED BUFFERS
++ TO BE PASSED TO THE STYLESHEET. (THEY CAN BE REFERRED TO VIA THE
++ 'ARG:' SCHEME, SEE <A HREF="#ARGSCHEME">ABOVE</A>.) AGAIN, THE
++ ARRAY IS A SEQUENCE OF (NAME, VALUE) PAIRS TERMINATED BY NULL IN
++ PLACE OF A NAME. IF NO NAMED BUFFERS ARE TO BE PASSED, YOU CAN
++ SPECIFY NULL FOR <CODE>ARGUMENTS</CODE> ITSELF.
++ </P>
++ <P CLASS="">
++ <CODE>RESULTARG</CODE> ENABLES ONE TO ACCESS THE
++ RESULTING DOCUMENT IN CASE THE OUTPUT WENT TO A NAMED BUFFER. IN
++ THAT SITUATION, <CODE>*RESULTARG</CODE> POINTS TO THE RESULTING
++ NULL-TERMINATED STRING, ALLOCATED BY SABLOTRON. YOU CAN PASS NULL
++ FOR <CODE>RESULTARG</CODE> IF THE OUTPUT IS SURE TO GO TO A
++ FILE.
++ </P>
++ <P CLASS="">
++ <B>NOTE:</B>WHEN YOU ARE DONE PROCESSING THE STRING
++ POINTED TO BY <CODE>*RESULTARG</CODE>, FREE IT USING <A HREF="#SABLOTFREE">
++ <CODE>SABLOTFREE()</CODE>
++ </A> - NEVER USE
++ <CODE>FREE()</CODE>. THE LATTER IS GUARANTEED TO PRODUCE A
++ SEGMENTATION FAULT UNDER LINUX.
++ </P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ INT SABLOTPROCESSFILES(CHAR *STYLESHEETNAME,
++ CHAR *INPUTNAME,
++ CHAR *RESULTNAME);
++ </CODE>
++ </P>
++ <P CLASS="">A WRAPPER FOR <CODE>SABLOTPROCESS()</CODE> WORKING ON
++ FILES. THE PARAMETERS ARE THE NULL-TERMINATED FILE NAMES OF THE
++ XSLT STYLESHEET, THE XML INPUT AND THE RESULT,
++ RESPECTIVELY. SABLOTRON OPENS THESE FILES ITSELF AND CLOSES THEM
++ AFTER THE PROCESSING IS COMPLETE. VALUES LIKE "FILE://STDIN" ARE
++ ALLOWED.</P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ INT SABLOTPROCESSSTRINGS(CHAR *STYLESHEETSTR, CHAR *INPUTSTR, CHAR
++ **RESULTSTR);
++ </CODE>
++ </P>
++ <P CLASS="">ANOTHER WRAPPER FOR <CODE>SABLOTPROCESS()</CODE>, THIS
++ TIME FOR ACCESSING NAMED BUFFERS (I.E. USER-ALLOCATED MEMORY
++ BLOCKS)ONLY. THUS, THE FIRST PARAMETER IS A NULL-TERMINATED
++ STRING CONTAINING THE WHOLE STYLESHEET; THE SECOND PARAMETER
++ IS A NULL-TERMINATED STRING CONTAINING THE XML
++ INPUT. SABLOTRON ALLOCATES THE BUFFER FOR THE RESULTING STRING
++ AND RETURNS A POINTER TO IT IN RESULTSTR. HENCE, INVOKING
++ <CODE>PUTS(*RESULTSTR)</CODE> AFTER HAVING CALLED
++ <CODE>SABLOTPROCESSSTRINGS</CODE> SENDS THE RESULT TO
++ STDOUT. THE BUFFER ALLOCATED <B>MUST</B> BE FREED BY CALLING THE
++ FUNCTION <CODE>SABLOTFREE</CODE> DESCRIBED NEXT.
++ </P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__1205"></A>
++ <H3>
++ <A HREF="#TOC_I__1048">7.2&NBSP;&NBSP;BASIC FUNCTIONS</A>
++ </H3>
++ <P CLASS="">THE ABOVE SHORTCUTS JUST CALL THE BASIC, LOWER-LEVEL
++ FUNCTIONS DESCRIBED BELOW. NOTE THAT IF YOU NEED TO SET OPTIONS
++ FOR LOGGING ETC., YOU MAY NEED TO USE THE LOW-LEVEL
++ FUNCTIONS. </P>
++ <P CLASS="">A TYPICAL PROCESSING SESSION MAY LOOK LIKE THIS:</P>
++ <P CLASS="">
++ <PRE>
++ SABLOTHANDLE P;
++ CHAR *MY_BUF;
++ SABLOTCREATEPROCESSOR(&P);
++ SABLOTSETLOG(P, ...);
++ /* ...SET OTHER INSTANCE-SPECIFIC OPTIONS HERE... */
++ SABLOTRUNPROCESSOR(P, ...);
++ SABLOTGETRESULTARG(P, "ARG:/SOMENAME", &MY_BUF)
++ /* ...DO SOMETHING WITH MY_BUF... */
++ /* CAN RUN THE PROCESSOR AGAIN IF NECESSARY */
++ SABLOTRUNPROCESSOR(P, ...);
++ SABLOTDESTROYPROCESSOR(P);
++ </PRE>
++ </P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ INT SABLOTCREATEPROCESSOR(SABLOTHANDLE *PROCESSORPTR);
++ </CODE>
++ </P>
++ <P CLASS="">CREATES AN INSTANCE OF SABLOTRON AND RETURNS A POINTER TO
++ IT IN *PROCESSORPTR. THIS POINTER IS PASSED ON ALL SUBSEQUENT
++ CALLS TO THIS INSTANCE. </P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ INT SABLOTDESTROYPROCESSOR(SABLOTHANDLE PROCESSOR_);
++ </CODE>
++ </P>
++ <P CLASS="">DESTROYS AN INSTANCE OF THE PROCESSOR, DEALLOCATING ALL
++ THE MEMORY USED UP BY IT.</P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ INT SABLOTRUNPROCESSOR(SABLOTHANDLE PROCESSOR_,
++ CHAR *SHEETURI,
++ CHAR *INPUTURI,
++ CHAR *RESULTURI,
++ CHAR **PARAMS,
++ CHAR **ARGUMENTS);
++ </CODE>
++ </P>
++ <P CLASS="">PROCESSES DOCUMENTS USING THE GIVEN PROCESSOR INSTANCE AND
++ GIVEN PARAMS AND ARGS DEFINITIONS. SEE
++ <CODE>SABLOTPROCESS()</CODE>.</P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ INT SABLOTGETRESULTARG(SABLOTHANDLE PROCESSOR_,
++ CHAR *ARGURI,
++ CHAR **ARGVALUE);
++ </CODE>
++ </P>
++ <P CLASS="">COPIES THE RESULT 'ARG' BUFFER WITH THE GIVEN URI,
++ RETURNING A POINTER TO THE NEWLY-ALLOCATED BLOCK IN
++ *ARGVALUE. IF NO SUCH BUFFER EXISTS, RETURNS NULL IN *ARGVALUE.
++ </P>
++ <P CLASS="">THIS FUNCTION IS NECESSARY, BECAUSE IF THE RESULT DOCUMENT
++ IS OUTPUT TO MEMORY, IT WOULD BE LOST WHEN
++ <CODE>SABLOTDESTROYPROCESSOR()</CODE> IS CALLED. WHEN
++ DEALLOCATING THE COPY OBTAINED FROM
++ <CODE>SABLOTGETRESULTARG()</CODE>, USE <CODE>SABLOTFREE</CODE>
++ (NEVER <CODE>FREE()</CODE>). </P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ INT SABLOTFREERESULTARGS(SABLOTHANDLE PROCESSOR_);
++ </CODE>
++ </P>
++ <P CLASS="">REMOVES THE SABLOTRON-INTERNAL COPIES OF THE 'ARG' BUFFERS
++ FROM THE LAST SABLOTRON RUN. NORMALLY, THERE SHOULD BE NO REASON
++ TO CALL THIS FUNCTION AS IT IS CALLED AUTOMATICALLY ON BOTH
++ <CODE>SABLOTRUNPROCESSOR()</CODE> AND
++ <CODE>SABLOTDESTROYPROCESSOR()</CODE>. </P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ <A NAME="SABLOTFREE"></A>
++ INT SABLOTFREE(CHAR *RESULTBUF);
++ </CODE>
++ </P>
++ <P CLASS="">THIS FUNCTION FREES THE BUFFER ALLOCATED ON PREVIOUS CALL
++ TO <CODE>SABLOTPROCESSSTRINGS</CODE>. CALLING IT WITH AN
++ INVALID POINTER WILL CAUSE A CRASH.
++ </P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ INT SABLOTREGHANDLER(
++ SABLOTHANDLE PROCESSOR_,
++ HANDLERTYPE TYPE,
++ VOID *HANDLER,
++ VOID *USERDATA);
++ </CODE>
++ </P>
++ <P CLASS="">REGISTERS AN EXTERNAL HANDLER. <CODE>TYPE</CODE> CAN BE
++ <CODE>HLR_MESSAGE</CODE>, <CODE>HLR_SCHEME</CODE>,
++ <CODE>HLR_SAX</CODE>, <CODE>HLR_MISC</CODE> OR
++ <CODE>HLR_ENC</CODE>.
++ <CODE>HANDLER</CODE> POINTS TO THE
++ CALLBACK VECTOR OF THE APPROPRIATE TYPE. <CODE>USERDATA</CODE>
++ IS A DATA ITEM TO PASSED TO ALL CALLBACKS OF THIS PARTICULAR
++ HANDLER. FOR DETAILS, CHECK THE <CODE>SABLOT.H</CODE> AND
++ <CODE>SHANDLER.H</CODE> HEADER FILES.
++ </P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ INT SABLOTUNREGHANDLER(
++ SABLOTHANDLE PROCESSOR_,
++ HANDLERTYPE TYPE,
++ VOID *HANDLER,
++ VOID *USERDATA);
++ </CODE>
++ </P>
++ <P CLASS="">UNREGISTERS THE GIVEN EXTERNAL HANDLER. FOR DETAILS, CHECK THE
++ <CODE>SABLOT.H</CODE> AND <CODE>SHANDLER.H</CODE> HEADER
++ FILES.</P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ INT SABLOTSETLOG(
++ SABLOTHANDLE PROCESSOR_,
++ CONST CHAR *LOGFILENAME,
++ INT LOGLEVEL);
++ </CODE>
++ </P>
++ <P CLASS="">SETS THE LOG FILENAME. THE <CODE>LOGLEVEL</CODE> PARAMETER
++ IS CURRENTLY NOT USED. PASS NULL FOR <CODE>LOGFILENAME</CODE> TO
++ TURN LOGGING OFF (DEFAULT). </P>
++ <P CLASS="">THE OTHER FUNCTIONS PUBLISHED BY SABLOT.H HAVE BEEN
++ INCLUDED FOR EXPERIMENTAL REASONS OR FOR COMPATIBILITY, AND IT
++ IS BETTER NOT TO USE THEM.
++ </P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ INT SABLOTCLEARERROR(SABLOTHANDLE PROCESSOR_);
++ </CODE>
++ </P>
++ <P CLASS="">CLEARS THE 'PENDING ERROR' FLAG FOR THIS INSTANCE OF
++ SABLOTRON.</P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__1416"></A>
++ <H3>
++ <A HREF="#TOC_I__1048">7.3&NBSP;&NBSP;GENERALIZED INTERFACE FUNCTIONS</A>
++ </H3>
++ <P CLASS="">THE IMPLEMENTATION OF THE <A HREF="#DOM">DOM INTERFACE</A>
++ BROUGHT THE NEED TO EXTEND SOME OF THE FUNCTIONS DESCRIBED IN
++ THE PREVIOUS SECTION. THIS EXTENSION ENABLES THE USER TO:
++ </P>
++ <UL>
++ <LI>PROCESS DOCUMENTS CREATED BY THE DOM FUNCTIONS, AND</LI>
++ <LI>PROCESS FREQUENTLY USED DOCUMENTS IN PRE-PARSED FORM.</LI>
++ </UL>
++ <P CLASS="">AN OBJECT CALLED <I>SITUATION</I> IS USED TO PROVIDE A
++PERSISTENT CONTEXT FOR ALL CALLS TO THE DOM-RELATED
++FUNCTIONS. FUNCTIONS USED TO MANIPULATE THE SITUATION ARE DESCRIBED IN
++<A HREF="#SITUATION">THE FOLLOWING SECTION</A>.</P>
++ <P CLASS="">
++ <B>NOTE:</B> IF NOT SPECIFIED OTHERWISE, ALL THESE
++ FUNCTIONS RETURN AN ERROR CODE. A POSITIVE VALUE INDICATES AN ERROR.</P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>INT SABLOTCREATEDOCUMENT(SABLOTSITUATION S,
++ SDOM_DOCUMENT *D);
++ </CODE>
++ </P>
++ <P CLASS="">CREATES AN EMPTY DOCUMENT. TYPICALLY FOLLOWED BY CALLS TO
++ DOM FUNCTIONS TO POPULATE THE DOCUMENT.</P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>INT SABLOTDESTROYDOCUMENT(SABLOTSITUATION S,
++ SDOM_DOCUMENT D);
++ </CODE>
++ </P>
++ <P CLASS="">DESTROYS A DOCUMENT, FREEING ALL THE NODES IT HAS CREATED.</P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>INT SABLOTPARSE(SABLOTSITUATION S,
++ CONST CHAR *URI, SDOM_DOCUMENT *D);
++ </CODE>
++ </P>
++ <P CLASS="">READS IN A DOCUMENT FROM THE GIVEN URI.</P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>INT SABLOTPARSEBUFFER(SABLOTSITUATION S,
++ CONST CHAR *BUFFER, SDOM_DOCUMENT *D);
++ </CODE>
++ </P>
++ <P CLASS="">READS IN A DOCUMENT FROM THE GIVEN IN-MEMORY BUFFER.</P>
++ <P CLASS="">THESE FUNCTIONS HAVE VARIANTS TO BE USED IF THE DOCUMENT
++ IS TO BE INTERPRETED AS AN XSLT STYLESHEET, NAMELY
++ <CODE>SABLOTPARSESTYLESHEET</CODE> AND
++ <CODE>SABLOTPARSESTYLESHEETBUFFER</CODE>.</P>
++ <P CLASS="">THE FOLLOWING FUNCTIONS GENERALIZE
++ <CODE>SABLOTRUNPROCESSOR</CODE> IN THAT THEY MAKE IT POSSIBLE TO
++ UTILIZE AN EXTRA KIND OF A SOURCE DOCUMENT: A DOM TREE.</P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>INT SABLOTRUNPROCESSORGEN(SABLOTSITUATION S,
++ VOID *PROCESSOR_,
++ CHAR *SHEETURI,
++ CHAR *INPUTURI,
++ CHAR *RESULTURI);
++ </CODE>
++ </P>
++ <P CLASS="">A KEY INGREDIENT OF THE EXTENDED INTERFACE. ONLY THE URIS
++ OF THE SOURCES AND OF THE RESULT DOCUMENT ARE GIVEN TO IT. THE
++ REST OF THE INFORMATION PASSED TO
++ <CODE>SABLOTRUNPROCESSOR</CODE> IS CONVEYED THROUGH
++ <CODE>SABLOTADDARGBUFFER,</CODE> <CODE>SABLOTADDARGTREE</CODE>
++ AND <CODE>SABLOTADDPARAM.</CODE> THE SCHEME PART OF THE
++ STYLESHEET URI OR THE INPUT URI MAY BE "ARG:", IN WHICH
++ CASE THEY REFER TO A BUFFER OR TREE PASSED BY THESE
++ FUNCTIONS. </P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>INT SABLOTADDARGBUFFER(SABLOTSITUATION S,
++ VOID *PROCESSOR_,
++ CONST CHAR *ARGNAME,
++ CONST CHAR *BUFFERVALUE);
++</CODE>
++ </P>
++ <P CLASS="">CREATES A NAMED BUFFER FOR THE NEXT PROCESSOR RUN. THE
++ BUFFER'S NAME AND CONTENTS ARE PASSED AS ARGUMENTS. THE NAME
++ IS INTERPRETED RELATIVE TO THE 'ARG:/' SCHEME.</P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>INT SABLOTADDARGTREE(SABLOTSITUATION S,
++ VOID *PROCESSOR_,
++ CONST CHAR *ARGNAME,
++ SDOM_DOCUMENT TREE);
++</CODE>
++ </P>
++ <P CLASS="">ASSOCIATES THE GIVEN DOCUMENT WITH A NAME FOR THE NEXT
++ PROCESSOR RUN. THE DOCUMENT IS <I>NOT</I> DESTROYED AFTER THE
++ RUN IS FINISHED. THE NAME IS INTERPRETED RELATIVE TO THE 'ARG:/'
++ SCHEME.</P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>INT SABLOTADDPARAM(SABLOTSITUATION S,
++ VOID *PROCESSOR_,
++ CONST CHAR *PARAMNAME,
++ CONST CHAR *PARAMVALUE);
++ </CODE>
++ </P>
++ <P CLASS="">ADDS A GLOBAL STYLESHEET PARAMETER FOR THE NEXT PROCESSOR
++ RUN.</P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__1578"></A>
++ <H3>
++ <A HREF="#TOC_I__1048">7.4&NBSP;&NBSP;THE SITUATION OBJECT</A>
++ </H3>
++ <P CLASS="">
++ <A NAME="SITUATION"></A>AT PRESENT, THE SITUATION OBJECT PRIMARILY HOLDS INFORMATION ON ANY PENDING ERRORS. A
++SITUATION IS CREATED USING</P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>INT SABLOTCREATESITUATION(SABLOTSITUATION
++ *SP);</CODE>
++ </P>
++ <P CLASS="">AND DESTROYED BY</P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>INT SABLOTDESTROYSITUATION(SABLOTSITUATION
++ S);</CODE>
++ </P>
++ <P CLASS="">TO CLEAR THE PENDING ERROR FLAG IN A SITUATION, USE</P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>INT SABLOTCLEARSITUATION(SABLOTSITUATION
++ S);</CODE>
++ </P>
++ <P CLASS="">THE FOLLOWING SELF-EXPLANATORY FUNCTIONS EXTRACT PARTS OF THE ERROR INFORMATION
++ FROM THE SITUATION:</P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ CONST CHAR *SABLOTGETERRORURI(SABLOTSITUATION S);<BR>
++ INT SABLOTGETERRORLINE(SABLOTSITUATION S);<BR>
++ CONST CHAR *SABLOTGETERRORMSG(SABLOTSITUATION S);
++ </CODE>
++ </P>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__1631"></A>
++ <H3>
++ <A HREF="#TOC_I__1048">7.5&NBSP;&NBSP;DOCUMENT OBJECT MODEL (DOM) FUNCTIONS</A>
++ </H3>
++ <P CLASS="">
++ <A NAME="DOM"></A>STARTING WITH VERSION 0.60, SABLOTRON IMPLEMENTS
++ A MAJOR SUBSET OF THE DOM LEVEL 1 CORE SPECIFICATION <A HREF="#REF-DOM">[DOM]</A>. A BRIEF
++ DESCRIPTION OF THE IMPLEMENTED INTERFACE FOLLOWS; FOR MORE
++ DETAILS, PLEASE REFER TO THE HEADER FILE NAMED
++ <CODE>SDOM.H.</CODE>
++ </P>
++ <P CLASS="">ALL OF THE NAMES RELATED TO THE DOM INTERFACE START WITH
++ SDOM_ (FOR SABLOT DOM).</P>
++ <P CLASS="">MAJOR NEW TYPES ARE <CODE>SDOM_DOCUMENT</CODE> (A DOM TREE) AND
++ <CODE>SDOM_NODE</CODE> (A NODE OF THE TREE). A DOCUMENT CAN ALSO BE USED IN
++ PLACE OF A NODE. THIS REFLECTS THE FACT IN THE DOM SPEC,
++ DOCUMENT IS A SUBCLASS OF NODE. WHEN USED IN THIS WAY, THE
++ DOCUMENT REPRESENTS ITS OWN ROOT NODE (WHICH IS NOT THE SAME AS
++ THE `ROOT ELEMENT').</P>
++ <P CLASS="">OTHER TYPES INCLUDE:</P>
++ <UL>
++ <LI>
++ <CODE>SDOM_CHAR:</CODE> A DOM CHARACTER TYPE. CURRENTLY, THIS IS JUST
++ CHAR. NOTE THAT THE DOM SPEC REQUIRES THAT THE DOM
++ IMPLEMENTATIONS WORK WITH UTF-16. SABLOTRON DEVIATES FROM THIS
++ BY USING UTF-8 INSTEAD. A SEPARATE SET OF FUNCTIONS TAKING
++ UTF-16 STRINGS WILL BE PROVIDED.</LI>
++ <LI>
++ <CODE>SDOM_NODETYPE:</CODE> A NODE TYPE ENUM. SOME OF THE VALUES ARE
++ <CODE>SDOM_ELEMENT_NODE,</CODE> <CODE>SDOM_ATTRIBUTE_NODE</CODE> AND <CODE>SDOM_TEXT_NODE.</CODE> SEE
++ <CODE>SDOM.H</CODE> FOR THE REST.</LI>
++ <LI>
++ <CODE>SDOM_NODELIST:</CODE> A NODE LIST RETURNED BY SOME OF THE
++ FUNCTIONS.</LI>
++ <LI>
++ <CODE>SDOM_EXCEPTION:</CODE> DOM EXCEPTION CODES ENUM, WITH VALUES SUCH
++ AS <CODE>SDOM_NOT_FOUND_ERR</CODE> OR <CODE>SDOM_INVALID_NODE_TYPE</CODE>. SEE <CODE>SDOM.H</CODE>
++ FOR DETAILS.</LI>
++</UL>
++ <P CLASS="">THE FUNCTIONS LISTED BELOW ARE IMPLEMENTED MORE OR LESS AS DEFINED IN
++ THE DOM LEVEL 1 SPECIFICATION, WITH TWO EXCEPTIONS:
++ THEIR NAMES ARE PREFIXED WITH <CODE>SDOM_</CODE> AND THE FIRST ARGUMENT IS
++ ALWAYS A <CODE>SABLOTSITUATION.</CODE> ALL THE FUNCTIONS RETURN
++ A <CODE>SDOM_EXCEPTION.</CODE> </P>
++ <UL>
++<LI>
++ <CODE>CREATEELEMENT, CREATEATTRIBUTE, CREATETEXTNODE,
++CREATECDATASECTION, CREATECOMMENT, CREATEPROCESSINGINSTRUCTION</CODE>
++ </LI>
++<LI>
++ <CODE>GETNODETYPE, GETNODENAME, SETNODENAME, GETNODEVALUE, SETNODEVALUE</CODE>
++ </LI>
++<LI>
++ <CODE>GETPARENTNODE, GETFIRSTCHILD, GETLASTCHILD, GETPREVIOUSSIBLING,
++GETNEXTSIBLING, GETOWNERDOCUMENT</CODE>
++ </LI>
++<LI>
++ <CODE>INSERTBEFORE, APPENDCHILD, REMOVECHILD, REPLACECHILD</CODE>
++ </LI>
++<LI>
++ <CODE>CLONENODE</CODE>
++ </LI>
++<LI>
++ <CODE>GETATTRIBUTE, SETATTRIBUTE, REMOVEATTRIBUTE, GETATTRIBUTELIST</CODE>
++ </LI>
++</UL>
++ <P CLASS="">SEVERAL FUNCTIONS HAVE BEEN ADDED:</P>
++ <UL>
++<LI>
++ <CODE>DISPOSENODE</CODE> FREES ALL MEMORY USED BY THE GIVEN NODE</LI>
++<LI>
++ <CODE>CLONEFOREIGNNODE</CODE> CLONES A NODE FROM A DIFFERENT
++DOCUMENT</LI>
++<LI>
++ <CODE>DOCTOSTRING</CODE> SERIALIZES THE DOCUMENT, RETURNING THE
++RESULTING STRING</LI>
++<LI>
++ <CODE>XQL</CODE> PERFORMS AN XPATH QUERY ON THE DOM TREE,
++RETURNING A LIST OF THE NODES SATISFYING IT.</LI>
++</UL>
++ <P CLASS="">IN ADDITION, THERE ARE SOME FUNCTIONS USED TO MANIPULATE
++ THE NODE LISTS RETURNED BY <CODE>XQL</CODE> AND
++ <CODE>GETATTRIBUTELIST</CODE>. THESE INCLUDE
++ <CODE>GETNODELISTLENGTH</CODE>, <CODE>GETNODELISTITEM</CODE> AND
++ <CODE>DISPOSENODELIST</CODE>.</P>
++ <P CLASS="">FINALLY, THERE ARE FUNCTIONS TO EXTRACT DOM
++ EXCEPTION-RELATED INFORMATION FROM THE SITUATION OBJECT, NAMELY
++ <CODE>GETEXCEPTIONCODE</CODE>, <CODE>GETEXCEPTIONMESSAGE</CODE>
++ AND <CODE>GETEXCEPTIONDETAILS</CODE>.</P>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__1870"></A>
++ <H2>
++ <A HREF="#TOC_I__1870">8&NBSP;&NBSP;THE COMMAND LINE INTERFACE</A>
++ </H2>
++ <DIV>
++ <P CLASS="">SABLOTRON COMES WITH A COMMAND-LINE INTERFACE TO THE
++ SHARED LIBRARY, WHICH IS A PROGRAM NAMED
++ <CODE>SABCMD</CODE>. AT PRESENT, <CODE>SABCMD</CODE> IS INVOKED
++ AS FOLLOWS:</P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ SABCMD [<I>OPTIONS</I>] <I>STYLESHEET</I> [<I>INPUT</I> [<I>RESULT</I>]] [<I>ASSIGNMENTS</I>]
++ </CODE>
++ </P>
++ <P CLASS="">THE ARGUMENTS ARE THE URIS OF THE XSLT STYLESHEET, THE
++ XML INPUT DOCUMENT, AND THE RESULTING DOCUMENT, RESPECTIVELY. THE
++ DEFAULT FOR <CODE>
++ <I>INPUT</I>
++ </CODE> IS
++ <CODE>FILE://STDIN</CODE> (MEANING PLAIN OLD STDIN);
++ <CODE>
++ <I>RESULT</I>
++ </CODE> DEFAULTS TO
++ <CODE>FILE://STDOUT</CODE>. FILENAMES HAVE TO INCLUDE THE EXTENSION (IF
++ ANY).</P>
++ <P CLASS="">YOU CAN DISPLAY THE LIST OF AVAILABLE OPTIONS BY TYPING
++ <CODE>SABCMD --HELP</CODE>. AMONG THE MORE USEFUL ONES ARE
++ <CODE>--LOG-FILE</CODE> (FOR SETTING THE LOG FILE) AND
++ <CODE>--MEASURE</CODE> (MEASURES AND OUTPUTS THE TOTAL
++ PROCESSING TIME).
++ </P>
++ <P CLASS="">
++ <A HREF="#FNAME-RULES">THE RULES FOR FILENAMES</A> ARE THE SAME AS
++ WITH <CODE>SABLOTPROCESS()</CODE>.
++ </P>
++ <P CLASS="">
++ <CODE>ASSIGNMENTS</CODE> IS A SERIES OF DEFINITIONS OF THE
++ FORM:</P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ NAME1=VALUE1 NAME2=VALUE2 ...
++ </CODE>
++ </P>
++ <P CLASS="">
++ ASSIGNING VALUES TO TOP-LEVEL STYLESHEET PARAMETERS AND TO NAMED
++ BUFFERS. THESE TWO CASES ARE DISTINGUISHED BY A LEADING '$' IN
++ THE NAME OF A STYLESHEET PARAMETER. THE NAMES OF THE BUFFERS DO
++ <I>NOT</I> START WITH "ARG:". THEY MAY START WITH A SLASH; IF
++ THEY DON'T, THE SLASH IS PREPENDED.
++ </P>
++ <P CLASS="">
++ <B>NOTE:</B> IN MOST CASES, IT WILL BE NECESSARY TO QUOTE
++ THE INDIVIDUAL ASSIGNMENTS. WHETHER TO USE SINGLE OR DOUBLE
++ QUOTES MAY DEPEND ON THE SHELL USED (OR MAY IT?) SINGLE QUOTES
++ WORK FOR BASH, DOUBLE QUOTES WORK IN WINDOWS.
++ </P>
++ <P CLASS="">IF THE RESULT URI REFERS TO A NAMED BUFFER, THE OUTPUT
++ WOULD NORMALLY REMAIN BURIED IN MEMORY. SABCMD DUMPS THE BUFFER TO STANDARD
++ OUTPUT INSTEAD.
++ </P>
++ <P CLASS="">TO SUM UP AND GIVE AN EXAMPLE, THE FOLLOWING WOULD BE A
++ VALID INVOCATION OF SABCMD:</P>
++ <P CLASS="" STYLE="BACKGROUND-COLOR: #FFFFEE">
++ <CODE>
++ SABCMD SHEET.XSL ARG:/THE_INPUT "THE_INPUT=&LT;A/>"
++ "$USE_DEFAULTS=1"
++ </CODE>
++ </P>
++ <P CLASS="">THIS PROCESSES THE DOCUMENT PASSED IN THE BUFFER NAMED
++ THE_INPUT, USING A STYLESHEET FOUND IN FILE "SHEET.XSL" IN THE
++ WORKING DIRECTORY. WE ASSIGN 1 TO THE TOP-LEVEL PARAMETER CALLED
++ "USE_DEFAULTS". THE OUTPUT GOES TO STDOUT BY DEFAULT.
++ </P>
++ </DIV>
++ </DIV>
++ <DIV CLASS="AFTERSKIP">
++ <A NAME="I__2013"></A>
++ <H2>
++ <A HREF="#TOC_I__2013">9&NBSP;&NBSP;REFERENCES</A>
++ </H2>
++ <DIV>
++ <DL>
++ <DT>
++ <A NAME="REF-XSLT"></A>[XSLT]</DT>
++ <DD>
++ <A HREF="HTTP://WWW.W3.ORG/TR/1999/REC-XSLT-19991116">
++ XSL TRANSFORMATIONS (XSLT) VERSION 1.0
++ </A>
++ </DD>
++
++ <DT>
++ <A NAME="REF-XPATH"></A>[XPATH]</DT>
++ <DD>
++ <A HREF="HTTP://WWW.W3.ORG/TR/1999/REC-XPATH-19991116">
++ XML PATH LANGUAGE (XPATH) VERSION 1.0
++ </A>
++ </DD>
++
++ <DT>
++ <A NAME="REF-XML"></A>[XML]</DT>
++ <DD>
++ <A HREF="HTTP://WWW.W3.ORG/TR/1998/REC-XML-19980210">
++ EXTENSIBLE MARKUP LANGUAGE (XML) 1.0
++ </A>
++ </DD>
++
++ <DT>
++ <A NAME="REF-DOM"></A>[DOM]</DT>
++ <DD>
++ <A HREF="HTTP://WWW.W3.ORG/TR/REC-DOM-LEVEL-1">
++ DOCUMENT OBJECT MODEL LEVEL 1 SPECIFICATION, VERSION 1.0
++ </A>
++ </DD>
++
++ <DT>
++ <A NAME="REF-RCOVER"></A>[COVER]</DT>
++ <DD>
++ <A HREF="HTTP://WWW.OASIS-OPEN.ORG/COVER/SGML-XML.HTML">
++ THE XML COVER PAGES</A>
++ </DD>
++
++ <DT>
++ <A NAME="REF-XMLORG"></A>[XMLORG]</DT>
++ <DD>
++ <A HREF="HTTP://XML.ORG">XML.ORG</A>
++ </DD>
++
++ <DT>
++ <A NAME="REF-XSLINFO"></A>[XSLINFO]</DT>
++ <DD>
++ <A HREF="HTTP://WWW.XSLINFO.COM">XSLINFO.COM</A>
++ </DD>
++
++ <DT>
++ <A NAME="REF-BIBLE"></A>[XMLBIBLE14]</DT>
++ <DD>
++ <A HREF="HTTP://METALAB.UNC.EDU/XML/BOOKS/BIBLE/UPDATES/14.HTML">
++ HAROLD, E. R.: XML BIBLE, CHAPTER 14 (ONLINE PRESENTATION)
++ </A>
++ </DD>
++ </DL>
++ </DIV>
++ </DIV>
++ <HR>
++ <P STYLE="FONT-STYLE: ITALIC; MARGIN-LEFT: 0">(C) 2000 GINGER ALLIANCE S.R.O.</P>
++ </BODY>
++</HTML>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/fake_php.py
+@@ -0,0 +1,24 @@
++#!/usr/bin/env python
++
++# $Id: fake_php.py 2180 2003-08-22 22:52:52Z chrisz $
++
++# fake php - all we really need is 'include schedulers.txt'
++
++import os, sys
++
++REQUEST_URI = os.environ['REQUEST_URI']
++
++print 'Content-Type: text/plain'
++print
++
++print """--- FAKE PHP ---
++
++[ REQUEST_URI=%s ]
++
++Since I can't find php4 on your system, this stub program fake_php.py just
++prints schedulers.txt as necessary.
++
++"""%REQUEST_URI
++
++if REQUEST_URI.endswith('/index.php'):
++ sys.stdout.write(open('schedulers.txt').read())
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/abort_result
+@@ -0,0 +1,13 @@
++<file_info>
++ <name><OUTFILE_0/></name>
++ <generated_locally/>
++ <upload_when_present/>
++ <max_nbytes>10000</max_nbytes>
++ <url><UPLOAD_URL/></url>
++</file_info>
++<result>
++ <file_ref>
++ <file_name><OUTFILE_0/></file_name>
++ <open_name>out</open_name>
++ </file_ref>
++</result>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_1sec.php
+@@ -0,0 +1,75 @@
++#!/usr/local/bin/php -q
++<?php {
++ // $Id: test_1sec.php 1383 2003-06-11 23:09:11Z quarl $
++
++ // This tests whether the client handles multiple projects,
++ // and whether CPU time is divided correctly between projects
++ // The client should do work for project 2 5 times faster
++ // than for project 1
++
++ include_once("test.inc");
++
++ test_msg("multiple projects with resource share");
++
++ $project1 = new Project;
++ $project2 = new Project;
++ $user = new User();
++ $host = new Host($user);
++
++ $project1->add_core_and_version();
++ $project1->add_app_and_version("upper_case");
++ $project2->add_core_and_version();
++ $project2->add_app_and_version("upper_case");
++
++ $work = new Work();
++ $work->wu_template = "uc_wu";
++ $work->result_template = "uc_result";
++ $work->redundancy = 5;
++ $work->delay_bound = 60;
++ array_push($work->input_files, "input");
++
++ $project1->resource_share = 1;
++ $project1->shmem_key = "0x12344321";
++ $project1->short_name = "Project1";
++ $project1->long_name = "Project1";
++ $project1->add_user($user);
++ $project1->install(); // must install projects before adding to hosts
++ $project1->install_feeder();
++
++ $project2->resource_share = 5;
++ $project2->shmem_key = "0x12345678";
++ $project2->short_name = "Project2";
++ $project2->long_name = "Project2";
++ $project2->add_user($user);
++ $project2->install(); // must install projects before adding to hosts
++ $project2->install_feeder();
++
++ $host->add_user($user,$project1);
++ $host->add_user($user,$project2);
++ $host->install();
++
++ $work->install($project1);
++ $work->install($project2);
++
++ $project1->start_servers();
++ $project2->start_servers();
++ $host->run("-exit_when_idle -skip_cpu_benchmarks");
++ $project1->stop(1);
++ $project2->stop();
++
++ $result->server_state = RESULT_SERVER_STATE_OVER;
++ $project1->check_results(5, $result);
++ $project1->compare_file("uc_wu_0_0", "uc_correct_output");
++ $project1->compare_file("uc_wu_1_0", "uc_correct_output");
++ $project1->compare_file("uc_wu_2_0", "uc_correct_output");
++ $project1->compare_file("uc_wu_3_0", "uc_correct_output");
++ $project1->compare_file("uc_wu_4_0", "uc_correct_output");
++ $project2->check_results(5, $result);
++ $project2->compare_file("uc_wu_0_0", "uc_correct_output");
++ $project2->compare_file("uc_wu_1_0", "uc_correct_output");
++ $project2->compare_file("uc_wu_2_0", "uc_correct_output");
++ $project2->compare_file("uc_wu_3_0", "uc_correct_output");
++ $project2->compare_file("uc_wu_4_0", "uc_correct_output");
++
++ test_done();
++} ?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/uc_small_correct_output
+@@ -0,0 +1 @@
++FJFIWFWNFWIEOWEFNKJ
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/1sec_result
+@@ -0,0 +1,13 @@
++<file_info>
++ <name><OUTFILE_0/></name>
++ <generated_locally/>
++ <upload_when_present/>
++ <url><UPLOAD_URL/></url>
++ <max_nbytes>100000</max_nbytes>
++</file_info>
++<result>
++ <file_ref>
++ <file_name><OUTFILE_0/></file_name>
++ <open_name>out</open_name>
++ </file_ref>
++</result>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/1sec_wu
+@@ -0,0 +1,2 @@
++<workunit>
++</workunit>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_sanity.py
+@@ -0,0 +1,101 @@
++#!/usr/bin/env python
++
++## $Id: test_sanity.py 2246 2003-09-04 05:07:17Z quarl $
++
++from testbase import *
++import urllib, random
++
++# Test makes sure that testing framework is sane:
++#
++# - executables compiled
++# - cgi server works
++# - test proxy works
++# - mysql permissions and command-line client works
++
++def read_url(url, quiet=False):
++ '''return 1 line from url'''
++ verbose_echo(2, " reading url: "+url)
++ err = ''
++ try:
++ return urllib.URLopener().open(url).readline().strip()
++ except IOError, e:
++ err = e
++ except AttributeError:
++ # Python urllib is buggy if connection is closed (by our proxy
++ # intentionally) right after opened
++ pass
++ if not quiet:
++ error("couldn't access url: %s %s" % (url, err))
++ else:
++ verbose_echo(2, "couldn't access url: %s %s" % (url, err))
++ return ''
++
++if __name__ == '__main__':
++ test_msg("framework sanity")
++
++ # verbose_echo(1, "Checking executables")
++ # check_core_client_executable()
++ # check_app_executable("upper_case")
++ # check_app_executable("concat")
++ # check_app_executable("1sec")
++
++ verbose_echo(1, "Checking directories")
++ for d in ['projects_dir',
++ 'cgi_dir', 'html_dir', 'hosts_dir']:
++ dir = options.__dict__[d]
++ if not os.path.isdir(dir):
++ error("%s doesn't exist: %s" % (d, dir))
++
++ magic = "Foo %x Bar" % random.randint(0,2**16)
++
++ html_path = os.path.join(options.html_dir, 'test_sanity.txt')
++ html_url = os.path.join(options.html_url, 'test_sanity.txt')
++ html_proxy_url = proxerize(html_url)
++ cgi_path = os.path.join(options.cgi_dir, 'test_sanity_cgi')
++ cgi_url = os.path.join(options.cgi_url, 'test_sanity_cgi')
++
++ verbose_echo(1, "Checking webserver setup: non-cgi")
++ print >>open(html_path,'w'), magic
++ if read_url(html_url) != magic:
++ error("couldn't access a file I just wrote: "+html_path+"\n using url: "+html_url)
++
++ verbose_echo(1, "Checking proxy setup")
++ if read_url(html_proxy_url, quiet=True):
++ error("Another proxy already running")
++ else:
++ proxy = Proxy('')
++ if read_url(html_proxy_url) != magic:
++ error("couldn't access file using proxy url: "+html_proxy_url)
++ else:
++ proxy.stop()
++
++ proxy = Proxy('close_connection if $nconnections < 2')
++ if read_url(html_proxy_url, quiet=True):
++ error("Proxy should have closed connection #1")
++ if read_url(html_proxy_url) != magic:
++ error("Proxy should have allowed connection #2")
++ proxy.stop()
++
++ os.unlink(html_path)
++
++ verbose_echo(1, "Checking webserver setup: cgi")
++ print >>open(cgi_path,'w'), '''#!/bin/sh
++echo "Content-Type: text/plain"
++echo ""
++echo "%s"
++''' % magic
++ os.chmod(cgi_path, 0755)
++
++ if read_url(cgi_url) != magic:
++ error("couldn't access a cgi file I just wrote: "+cgi_path+"\n using url: "+cgi_url)
++
++ os.unlink(cgi_path)
++
++
++ database_name = 'boinc_test_sanity_mysql_%s_%d'%(
++ os.environ['USER'], random.randint(0,2**16))
++
++ # create and drop a database
++ verbose_echo(1, "Checking mysql commandline and permissions")
++ shell_call('echo "create database %s" | mysql' % database_name)
++ shell_call('echo "drop database %s" | mysql' % database_name)
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_mdownload_backoff.php
+@@ -0,0 +1,58 @@
++#! /usr/local/bin/php
++<?php
++//This tests the exponential backoff mechanism on the client in case of downloadURLs going down. in this case multiple URLS stay up while one goes down.
++//This test is not automated. It has to be run, and then client.out (in the host directory) must be looked at to examine wether everything is working correctly.
++ include_once("test.inc");
++
++ $project = new Project;
++ $user = new User();
++ $host = new Host($user);
++
++ $app = new App("upper_case");
++ $app_version = new App_Version($app);
++
++ // the following is optional (makes client web download possible)
++ $core_app = new App("core client");
++ $core_app_version = new App_Version($core_app);
++ $project->add_app($core_app);
++ $project->add_app_version($core_app_version);
++
++ $project->add_user($user);
++ $project->add_app($app);
++ $project->add_app_version($app_version);
++
++ $project->install(); // must install projects before adding to hosts
++
++ $host->log_flags = "log_flags.xml";
++ $host->add_project($project);
++ $host->install();
++
++ echo "adding work\n";
++
++ $work = new Work($app);
++ $work->wu_template = "uc_multiple_download_wu";
++ $work->result_template = "uc_result";
++ $work->redundancy = 2;
++ $work->delay_bound = 10;
++ array_push($work->input_files, "input");
++ $work->install($project);
++
++ $project->start_feeder();
++ //delete the download_dir0 immediately
++ $project->delete_downloaddir(null, 0);
++ $project->delete_downloaddir(null, 1);
++ $project->delete_downloaddir(null, 2);
++
++ $pid = $host->run_asynch("-exit_when_idle");
++ $status = 0;
++ //wait until the host has stopped running
++ pcntl_waitpid($pid,$status,0);
++ $project->stop();
++
++ $result->server_state = RESULT_SERVER_STATE_OVER;
++ $result->stderr_out = "APP: upper_case: starting, argc 1";
++ $result->exit_status = 0;
++ $project->check_results(2, $result);
++ $project->compare_file("uc_multiple_download_wu_0_0", "uc_correct_output");
++ $project->compare_file("uc_multiple_download_wu_1_0", "uc_correct_output");
++?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_prefs.php
+@@ -0,0 +1,37 @@
++#! /usr/local/bin/php
++<?php
++ // test global preferences
++
++ include_once("test.inc");
++
++ $project = new Project;
++ $user = new User();
++ $host = new Host($user);
++ $app = new App("uc_slow");
++ $app_version = new App_Version($app);
++
++ $project->add_user($user);
++ $project->add_app($app);
++ $project->add_app_version($app_version);
++ $project->install(); // must install projects before adding to hosts
++
++ $host->log_flags = "log_flags.xml";
++ $host->add_project($project);
++ $host->global_prefs = "laptop_prefs";
++ $host->install();
++
++ echo "adding work\n";
++
++ $work = new Work($app);
++ $work->wu_template = "ucs_wu";
++ $work->result_template = "uc_result";
++ array_push($work->input_files, "small_input");
++ $work->install($project);
++
++ $project->start_feeder();
++
++ echo "Now run the client manually; start and stop it a few times.\n";
++
++ //$project->check_results(1, $result);
++ //$project->compare_file("ucs_wu_0_0", "uc_small_correct_output");
++?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/input
+@@ -0,0 +1,1326 @@
++<html>
++ <head>
++ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
++ <META http-equiv="Content-Type" CONTENT="text/html" CHARSET="UTF-8">
++ <META HTTP-EQUIV="Content-Style-Type" CONTENT="text/css">
++ <STYLE TYPE="text/css" MEDIA="screen">
++ BODY, H2, H3, H4, P, UL, OL, DL
++ {
++ font-family: "Verdana", "Helvetica", "Arial", "sans-serif"
++ }
++
++ H1 {color: #0058a0; font-size: 20pt}
++ H2 {color: #0058a0; font-size: 16pt}
++ H3 {color: #0058a0; font-size: 14pt}
++ H4 {color: #0058a0; font-size: 12pt}
++
++ A:link, A:active, A:visited
++ {
++ color: #0058a0;
++ text-decoration: none
++ }
++
++ P, UL, OL, DL {margin-left: 10%; margin-right: 10%; font-size: 10pt}
++ DT {margin-bottom: 0.5em}
++ .offset {margin-left: 10%}
++ .afterskip {margin-bottom: 1em}
++ .afterhalf {margin-bottom: 0.5em}
++ .example {margin-left: 10%; margin-right: 10%;
++ border-color: #0058a0; border-style:solid; border-width: 1pt; padding: 1pt}
++ CODE {font-family: "Courier"}
++ .comment {color: #0000ff}
++
++ P.offset {margin-left: 15%}
++ P.inner {margin-left: 2%; width: 96%}
++ P.note {margin-left: 10%; border-color: #0058a0;
++ border-style:solid; border-width: 1pt;
++ padding: 5pt; background-color:#e0e0e0 }
++
++ PRE {font-size: 10pt; padding: 5pt}
++
++ </STYLE>
++ <title>GAdoc - Sablotron 0.60</title>
++ </head>
++ <body bgcolor="#ffffff">
++ <h1 CLASS="afterskip">Sablotron 0.60</h1>
++ <DIV CLASS="afterskip">
++ <p>
++ <b>
++ <i>Tom Kaiser (Ginger Alliance)</i>
++ </b>
++ </p>
++ <p>
++ <i>June 17, 2001</i>
++ </p>
++ </DIV>
++ <h3>Abstract</h3>
++ <DIV CLASS="offset">This is a description of the current version of the
++ XSLT processor called Sablotron, including an overview of its
++ limitations as compared to the XSLT specification.
++ </DIV>
++ <h3>Contents</h3>
++<DIV STYLE="margin-left: 10%; margin-bottom: 2em; font-size: smaller">
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__25"></a> <a href="#i__25">
++ <b>1 This text</b>
++ </a>
++ <DIV class="offset"></DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__60"></a> <a href="#i__60">
++ <b>2 Changes from the last release</b>
++ </a>
++ <DIV class="offset"></DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__74"></a> <a href="#i__74">
++ <b>3 Introduction</b>
++ </a>
++ <DIV class="offset"> <a href="#i__81">3.1 XSLT</a>
++ <BR> <a href="#i__154">3.2 On Sablotron</a>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__227"></a> <a href="#i__227">
++ <b>4 The sources</b>
++ </a>
++ <DIV class="offset"> <a href="#i__238">4.1 Getting the sources</a>
++ <BR> <a href="#i__280">4.2 Joining the development</a>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__305"></a> <a href="#i__305">
++ <b>5 Implementation. Supported instructions and functions</b>
++ </a>
++ <DIV class="offset"> <a href="#i__343">5.1 Templates</a>
++ <BR> <a href="#i__364">5.2 Conditional processing</a>
++ <BR> <a href="#i__381">5.3 Loops</a>
++ <BR> <a href="#i__398">5.4 Variables and parameters</a>
++ <BR> <a href="#i__415">5.5 Element creation</a>
++ <BR> <a href="#i__439">5.6 Global definitions</a>
++ <BR> <a href="#i__476">5.7 Values and copying</a>
++ <BR> <a href="#i__508">5.8 Namespace processing</a>
++ <BR> <a href="#i__529">5.9 Sorting</a>
++ <BR> <a href="#i__577">5.10 Whitespace stripping</a>
++ <BR> <a href="#i__598">5.11 Includes</a>
++ <BR> <a href="#i__623">5.12 Other unimplemented instructions</a>
++ <BR> <a href="#i__654">5.13 Output conformance</a>
++ <BR> <a href="#i__686">5.14 XPath expressions</a>
++ <BR> <a href="#i__714">5.15 Built-in functions</a>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__804"></a> <a href="#i__804">
++ <b>6 Other implementation-related notes</b>
++ </a>
++ <DIV class="offset"> <a href="#i__811">6.1 Handlers</a>
++ <BR> <a href="#i__859">6.2 Encodings</a>
++ <BR> <a href="#i__887">6.3 Output methods</a>
++ <BR> <a href="#i__915">6.4 URIs</a>
++ <BR> <a href="#i__983">6.5 Named buffers</a>
++ <BR> <a href="#i__1015">6.6 Error and log messages</a>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__1048"></a> <a href="#i__1048">
++ <b>7 The C interface</b>
++ </a>
++ <DIV class="offset"> <a href="#i__1065">7.1 Shortcuts</a>
++ <BR> <a href="#i__1205">7.2 Basic functions</a>
++ <BR> <a href="#i__1416">7.3 Generalized interface functions</a>
++ <BR> <a href="#i__1578">7.4 The situation object</a>
++ <BR> <a href="#i__1631">7.5 Document Object Model (DOM) functions</a>
++ <BR>
++ </DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__1870"></a> <a href="#i__1870">
++ <b>8 The command line interface</b>
++ </a>
++ <DIV class="offset"></DIV>
++ </SPAN>
++ <SPAN CLASS="afterhalf">
++ <a name="toc_i__2013"></a> <a href="#i__2013">
++ <b>9 References</b>
++ </a>
++ <DIV class="offset"></DIV>
++ </SPAN>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__25"></a>
++ <h2>
++ <a href="#toc_i__25">1 This text</a>
++ </h2>
++ <DIV>
++ <p CLASS="">The HTML form of this description
++ was compiled by Sablotron from the XML source
++ Sablot-0-60.xml.
++ </p>
++ <p CLASS="">
++ The material in the following sections includes:
++ </p>
++ <ul>
++ <li>some background information on XSLT and Sablotron,</li>
++ <li>a detailed comparison of the current version of
++ Sablotron to the XSLT spec,</li>
++ <li>Sablotron usage from the command line or as a
++ library.</li>
++ </ul>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__60"></a>
++ <h2>
++ <a href="#toc_i__60">2 Changes from the last release</a>
++ </h2>
++ <DIV>
++ <p CLASS="">Please see the RELEASE file.</p>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__74"></a>
++ <h2>
++ <a href="#toc_i__74">3 Introduction</a>
++ </h2>
++ <DIV>
++ <DIV class="afterskip">
++ <a name="i__81"></a>
++ <h3>
++ <a href="#toc_i__74">3.1 XSLT</a>
++ </h3>
++ <p CLASS="">XSLT is a language allowing to transform given XML data (the
++ <i>input</i>) according to a <i>stylesheet</i>. XSLT stylesheets
++ are themselves XML documents; that is, all instructions of the
++ language are expressed in the form of XML elements. The
++ <i>output</i>, i.e. the result of the processing, is typically a
++ XML document as well, although the syntactic requirements can be
++ relaxed to allow the creation of a HTML document (one that
++ contains unclosed tags and the like), or even plain text.
++ </p>
++ <p CLASS="">XSLT was designed by the World Wide Web Consortium (W3C) as
++ a part of the XSL stylesheet language, where it is complemented
++ by a powerful set of formatting instructions. The most precise
++ information about XSLT can be found in the W3C Recommendation <a href="#ref-xslt">[XSLT]</a>. In particular, Appendix B of the
++ Recommendation contains a handy syntax table. A good tutorial is
++ <a href="#ref-bible">[XMLBible14]</a>.
++ </p>
++ <p CLASS="">Other W3C Recommendations one often needs to consult are <a href="#ref-xml">[XML]</a> (for the definition of the XML
++ language) and <a href="#ref-xpath">[XPath]</a> (for details on
++ XPath, the language used to form expressions in XSLT and
++ elsewhere).
++ </p>
++ <p CLASS="">An excellent source of information about XSLT (indeed, about
++ anything related to XML and SGML) is <a href="#ref-rcover">[Cover]</a>; see also <a href="#ref-xslinfo">[XSLINFO]</a> and <a href="#ref-xmlorg">[XMLorg]</a>.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__154"></a>
++ <h3>
++ <a href="#toc_i__74">3.2 On Sablotron</a>
++ </h3>
++ <p CLASS="">Sablotron is a XSLT processor (though not quite conforming
++ yet..., see below) written in C++. Since the machines where it
++ is meant to run include various small mobile
++ clients, the main objectives of its design are the following:
++ </p>
++ <ul>
++ <li>portability,</li>
++ <li>compact code,</li>
++ <li>as much independence on other resources (Java etc.) as
++ possible.</li>
++ </ul>
++ <p CLASS="">Sablotron is a single shared library
++ (<code>sablot.dll</code> or <code>libsablot.so.0.60</code>). It can
++ also be used from the command line via the simple interface
++ called <code>sabcmd</code>. See <a href="#invocation">here</a> for
++ more information.
++ </p>
++ <p CLASS="">The only software Sablotron relies on is <b>expat</b>, the
++ XML parser by James Clark. See <a href="#expat">below</a> for
++ information on how to get expat.
++ </p>
++ <p CLASS="">For information on the available interfaces, e.g. for
++ Python, Perl and PHP, see <a href="http://www.gingerall.com">www.gingerall.com</a>.
++ </p>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__227"></a>
++ <h2>
++ <a href="#toc_i__227">4 The sources</a>
++ </h2>
++ <DIV>
++ <p CLASS="">
++ Sablotron is written in C++. The source files compile under
++ Win32 (using MS Visual C++ 6.0) and on Solaris and Linux (using
++ g++ 2.95.2) without change.</p>
++ <DIV class="afterskip">
++ <a name="i__238"></a>
++ <h3>
++ <a href="#toc_i__227">4.1 Getting the sources</a>
++ </h3>
++ <p CLASS="">The source or binary distributions of Sablotron can be downloaded
++ from <a href="http://www.gingerall.com">www.gingerall.com</a>. For
++ instructions on how to build the sources (if any), refer to the accompanying INSTALL file.
++ </p>
++ <p CLASS="">If you have access to the Ginger Alliance CVS server, you
++ can get the working version of Sablotron in the CVS module
++ <code>ga</code>. The access rights can be obtained on
++ request from <a href="mailto:cvsadmin at gingerall.com">the CVS admin</a>.
++ </p>
++ <p CLASS="">
++ <a name="expat"></a>
++ Since version 0.50, Sablotron uses expat 1.95.1, available from <a href="http://expat.sourceforge.org">SourceForge</a>.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__280"></a>
++ <h3>
++ <a href="#toc_i__227">4.2 Joining the development</a>
++ </h3>
++ <p CLASS="">
++ Sablotron is an open source project and all volunteers are most
++ welcome! The documentation of the sources is still somewhat
++ sparse but we will try to improve it. If you find the invitation
++ to work on Sablotron with us interesting, please <a href="mailto:sablotron at gingerall.com">contact us</a>. There is also
++ a mailing list available, see <a href="http://www.gingerall.com">www.gingerall.com</a>.
++ </p>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__305"></a>
++ <h2>
++ <a href="#toc_i__305">5 Implementation. Supported instructions and functions</a>
++ </h2>
++ <DIV>
++ <p CLASS="">The instruction set supported by this version of Sablotron is
++ already sufficient for many transformation tasks (e.g. the task of
++ formatting this document). On the other
++ hand, a comparison of it to the XSLT specification <a href="#ref-xslt">[XSLT]</a> shows that much is still to be
++ done. The purpose of the
++ following sections is to describe the varying degree of support
++ for the elements of the XSLT language. </p>
++ <p CLASS="">It may be helpful to refer to the syntax table in Appendix B
++ of <a href="#ref-xslt">[XSLT]</a>. The instructions/attributes that
++ are not listed as unsupported should be implemented. The <a href="mailto:sablotron at gingerall.com">authors</a> will appreciate being
++ told about any omissions found in the following
++ description.</p>
++ <p CLASS="">For readability, I sometimes omit the <code>xsl:</code> prefix
++ from the instruction names.</p>
++ <DIV class="afterskip">
++ <a name="i__343"></a>
++ <h3>
++ <a href="#toc_i__305">5.1 Templates</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ template, apply-templates, call-template
++ </code>
++ </p>
++ <p CLASS="">
++ Fully implemented. <code>xsl:sort</code> is supported since release 0.50.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__364"></a>
++ <h3>
++ <a href="#toc_i__305">5.2 Conditional processing</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ if, choose, when, otherwise
++ </code>
++ </p>
++ <p CLASS="">Fully implemented.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__381"></a>
++ <h3>
++ <a href="#toc_i__305">5.3 Loops</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>for-each</code>
++ </p>
++ <p CLASS="">Fully implemented.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__398"></a>
++ <h3>
++ <a href="#toc_i__305">5.4 Variables and parameters</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>variable, param, with-param</code>
++ </p>
++ <p CLASS="">Fully implemented. Top-level variables and parameters are
++ read in the document order, so no forward references are
++ resolved. This is a minor deviation from the spec. </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__415"></a>
++ <h3>
++ <a href="#toc_i__305">5.5 Element creation</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>element, attribute, text,
++ comment, processing-instruction, attribute-set</code>
++ </p>
++ <p CLASS="">
++ <code>xsl:attribute-set</code> is not implemented. For the
++ rest, <code>name</code> is the only recognized attribute (where
++ applicable). Literal result elements work.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__439"></a>
++ <h3>
++ <a href="#toc_i__305">5.6 Global definitions</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>stylesheet, transform, output</code>
++ </p>
++ <p CLASS="">For <code>stylesheet</code> and <code>transform</code>,
++ the only recognized attribute is
++ <code>version</code>. <code>xsl:output</code> should work
++ (see below for notes on the <code>encoding</code>
++ attribute). HTML indentation has been added in 0.60.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__476"></a>
++ <h3>
++ <a href="#toc_i__305">5.7 Values and copying</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>value-of, copy, copy-of</code>
++ </p>
++ <p CLASS="">
++ <code>copy-of</code> and <code>value-of</code> are fully
++ implemented. <code>copy</code> is implemented except for the
++ <code>use-attribute-sets</code> attribute.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__508"></a>
++ <h3>
++ <a href="#toc_i__305">5.8 Namespace processing</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>namespace-alias</code>
++ </p>
++ <p CLASS="">Namespaces should be processed correctly. The
++ <code>namespace-alias</code> instruction is now supported
++ (patch by Major).</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__529"></a>
++ <h3>
++ <a href="#toc_i__305">5.9 Sorting</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>sort</code>
++ </p>
++ <p CLASS="">
++ <code>xsl:sort</code> is implemented since 0.50. There are
++ minor limitations:
++ </p>
++ <ul>
++ <li>currently, the <code>lang</code> attribute may only
++ contain the values <code>"en"</code> or <code>"cz"</code>.</li>
++ <li>
++ <code>case-order</code> cannot be specified.</li>
++ </ul>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__577"></a>
++ <h3>
++ <a href="#toc_i__305">5.10 Whitespace stripping</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>strip-space, preserve-space</code>
++ </p>
++ <p CLASS="">Only the default whitespace stripping is done. That is,
++ all whitespace-only text nodes in any stylesheet, not appearing
++ inside a <code>xsl:text</code>, are removed. The two
++ instructions for whitespace stripping and preservation are
++ unsupported.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__598"></a>
++ <h3>
++ <a href="#toc_i__305">5.11 Includes</a>
++ </h3>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>include, import, apply-imports</code>
++ </p>
++ <p CLASS="">Only <code>xsl:include</code> is implemented. Processing
++ involving multiple documents works, but has to get more testing,
++ eg. with respect to <code>generate-id()</code>.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__623"></a>
++ <h3>
++ <a href="#toc_i__305">5.12 Other unimplemented instructions</a>
++ </h3>
++ <ul>
++ <li>
++ <code>xsl:key,</code>
++ </li>
++ <li>
++ <code>xsl:number,</code>
++ </li>
++ <li>
++ <code>xsl:fallback.</code>
++ </li>
++ </ul>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__654"></a>
++ <h3>
++ <a href="#toc_i__305">5.13 Output conformance</a>
++ </h3>
++ <p CLASS="">The output mechanism is much closer to the spec than in
++ the versions prior to 0.4. The following issues remain for the
++ html method:</p>
++ <ul>
++ <li>Output the boolean attributes correctly.</li>
++ <li>Disable the escaping inside
++ <code><SCRIPT></code> and
++ <code><STYLE></code>
++ </li>.
++ </ul>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__686"></a>
++ <h3>
++ <a href="#toc_i__305">5.14 XPath expressions</a>
++ </h3>
++ <p CLASS="">Almost all features of XPath are fully implemented. This means
++ there should be no problems with expressions of any kind.</p>
++ <p CLASS="">One exception relates to axes. The <code>following</code> and
++ <code>preceding</code> axes haven't been implemented yet.</p>
++ <p CLASS="">Another possible exception may be numbers; we did not yet do a
++ thorough test of rounding, NaNs, infinity, etc.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__714"></a>
++ <h3>
++ <a href="#toc_i__305">5.15 Built-in functions</a>
++ </h3>
++ <p CLASS="">
++ <a name="corelib"></a>Only a few functions from the standard
++ function library remain
++ unimplemented:
++ </p>
++ <ul>
++ <li>
++ <code>id()</code>,</li>
++ <li>
++ <code>lang()</code> (accepted but always returns true),</li>
++ <li>
++ <code>key()</code>,</li>
++ <li>
++ <code>format-number()</code>,</li>
++ <li>
++ <code>unparsed-entity-uri()</code>.</li>
++ </ul>
++ <p CLASS="">As for the fuctions that <i>are</i> implemented, the
++ following is a list of differences from the spec:
++ </p>
++ <ul>
++ <li>
++ <code>document()</code> only accepts one argument, always
++ getting the base URI from the stylesheet URI.
++ </li>
++ <li>
++ <code>string-length()</code> returns the byte length of
++ the UTF-8 representation of the string. This will typically
++ differ from the actual length.
++ </li>
++ <li>
++ <code>generate-id()</code> might fail to generate unique identifiers
++ when several input documents are present (giving the same id to
++ nodes from different documents).
++ </li>
++ </ul>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__804"></a>
++ <h2>
++ <a href="#toc_i__804">6 Other implementation-related notes</a>
++ </h2>
++ <DIV>
++ <DIV class="afterskip">
++ <a name="i__811"></a>
++ <h3>
++ <a href="#toc_i__804">6.1 Handlers</a>
++ </h3>
++ <p CLASS="">It is possible for the user to supply the following
++ handlers to Sablotron:
++ <ul>
++ <li>message handler (to bypass the default way of displaying
++ error and warning messages and logging),</li>
++ <li>scheme handler (to retrieve documents whose URI use an
++ unsupported scheme),</li>
++ <li>streaming handler (an expat-like interface to the XML
++ document which is the result of the processing),</li>
++ <li>'miscellaneous' handler (which will probably server as a
++ collections of odd callbacks).</li>
++ </ul>
++ </p>
++ <p CLASS="">
++ The handlers are set using <code>SablotRegHandler()</code>
++ For details concerning the interface of these handlers,
++ consult the header files <code>sablot.h</code> and
++ <code>shandler.h</code>.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__859"></a>
++ <h3>
++ <a href="#toc_i__804">6.2 Encodings</a>
++ </h3>
++ <p CLASS="">
++ In version 0.52, the encoding conversion capabilities of
++ Sablotron have been much extended. The most important fact is the
++ following: if you have the iconv library installed on your system, you
++ can use any encoding it supports (that is, almost any encoding
++ whatsoever) for both the input and the output documents. Iconv
++ is available on most systems (it is a standard part of glibc2,
++ for instance). There are implementations for Win32 as well.
++ </p>
++ <p CLASS="">If iconv is not available, the encoding may still be supported internally by
++ Sablotron. At present, the list is of such encodings is rather
++ short: besides UTF-8, these are UTF-16, ASCII, iso-8859-1,
++ iso-8859-2 and windows-1250 on input, none on output. However,
++ we plan to implement a half independent light-weight
++ conversion library for use on systems without iconv,
++ extending the set of internally supported encodings
++ considerably.
++ </p>
++ <p CLASS="">Lastly, the user has the option to implement a custom
++ encoding conversion handler, which will be asked to perform any unsupported
++ conversion. See the <code>shandler.h</code> header file for
++ details.
++ </p>
++ <p CLASS="">The default input and output encoding is in all cases UTF-8.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__887"></a>
++ <h3>
++ <a href="#toc_i__804">6.3 Output methods</a>
++ </h3>
++ <p CLASS="">In addition to the standard output methods (xml, html and
++ text), it is possible to output xhtml. Documents output using
++ this method obey the XHTML 1.0 rules (in particular, all empty
++ elements are closed). To choose the method, use
++ <code><xsl:output method='xhtml'></code>. <b>Please note</b>
++ that the name of this method will possibly be changed since the XSLT
++ spec requires any processor-specific methods to have qualified
++ names, say <code>sab:xhtml</code>. On the other hand, the name
++ <code>xhtml</code> is considered in the XSLT 2.0 working draft.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__915"></a>
++ <h3>
++ <a href="#toc_i__804">6.4 URIs</a>
++ </h3>
++ <p CLASS="">Sablotron can handle
++ two URI schemes natively: 'file' and 'arg' (see
++ below). Moreover, it is possible to use the function
++ <code>SablotRegSchemeHandler</code> to register an external scheme
++ handler which will receive requests in all other schemes. See
++ the documentation in <code>sablot.h</code> and
++ <code>shandler.h</code>.
++ </p>
++ <p CLASS="">Relative URI references are resolved in conformance to RFC
++ 2396. The base URI is well defined when the relative reference appears
++ inside a XML document; when invoking sabcmd, the base URI is
++ taken to correspond to the current working directory.
++ </p>
++ <p CLASS="">
++ <a name="fname-rules"></a>When specifying filenames, the
++ following rules are in effect:
++ </p>
++ <ul>
++ <li>specify the "file:" scheme for any standard files,
++ i.e. refer to <code>stdin</code> as <code>file://stdin</code>
++ etc.</li>
++ <li>slashes and backslashes work equally fine, in Windows as
++ well as Linux.</li>
++ <li>to include a drive letter under Windows
++ (e.g. <code>C:\doc.xml</code>), it is necessary to say
++ <code>file://c:/doc.xml</code>.
++ </li>
++ </ul>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__983"></a>
++ <h3>
++ <a href="#toc_i__804">6.5 Named buffers</a>
++ </h3>
++ <p CLASS="">
++ <a name="argscheme"></a>Sablotron introduces an URI scheme
++ 'arg:' which enables one to use strings in named memory
++ buffers. The buffer names can have a tree-like structure so that
++ a relative reference from a document in a buffer can be resolved
++ as pointing to another buffer.
++ </p>
++ <p CLASS="">For instance, if we invoke Sablotron specifying that a
++ buffer named <code>/mybuf/1</code> contains the string
++ "<a>contents</a>", then the expression
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ document('arg:/mybuf/1')/a
++ </code>
++ </p>
++ <p CLASS="">has string-value "contents". If the document in arg:/mybuf/1
++ contained a relative URI reference "../theirbuf/2" then this
++ would be resolved as pointing to "arg:/theirbuf/2".</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1015"></a>
++ <h3>
++ <a href="#toc_i__804">6.6 Error and log messages</a>
++ </h3>
++ <p CLASS="">By default, Sablotron writes error and warning messages to
++ stderr, and does no logging. By a call to
++ <code>SablotSetLog()</code>, you can specify the name of the log
++ file to be used.</p>
++ <p CLASS="">Besides, you can use <code>SablotRegHandler()</code>
++ to override the default message handling. The handler you
++ register will receive all messages in a structured form that's
++ easy to process and filter. For details, see
++ the documentation in <code>sablot.h</code> and
++ <code>shandler.h</code>.</p>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1048"></a>
++ <h2>
++ <a href="#toc_i__1048">7 The C interface</a>
++ </h2>
++ <DIV>
++ <p CLASS="">
++ <a name="invocation"></a>
++ </p>
++ <p CLASS="">
++ This section describes the functions exported from the
++ Sablotron library. All of them have a return type of 'int'
++ and return an error flag (nonzero signals an error). Errors
++ are reported to the user by Sablotron itself.
++ </p>
++ <DIV class="afterskip">
++ <a name="i__1065"></a>
++ <h3>
++ <a href="#toc_i__1048">7.1 Shortcuts</a>
++ </h3>
++ <p CLASS="">
++ We'll first describe the 'shortcuts' that do the whole
++ processing in one call.
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotProcess(char *sheetURI, char *inputURI, char *resultURI,
++ char **params, char **arguments, char **resultArg);
++ </code>
++ </p>
++ <p CLASS="">
++ This is the basic function. The first three of its arguments
++ are the URIs of the XSLT stylesheet, the XML source and the
++ resulting document, respectively. For some notes on specifying
++ file names, see <a href="#fname-rules">above</a>.
++ </p>
++ <p CLASS="">
++ <code>params</code> is an array of pointers to the names
++ and contents of the top-level stylesheet parameters. Thus,
++ <code>params[0]</code> is a pointer to the null-terminated name
++ of the first parameter, <code>params[1]</code> points to the
++ (null-terminated) contents of the first parameter. The following
++ two array items do the same for the second parameter, etc. The
++ whole array is terminated by a NULL pointer in place of the
++ name. If no parameters are to be passed, you can specify NULL
++ for <code>params</code> itself.
++ </p>
++ <p CLASS="">
++ <code>arguments</code> is a similar array of named buffers
++ to be passed to the stylesheet. (They can be referred to via the
++ 'arg:' scheme, see <a href="#argscheme">above</a>.) Again, the
++ array is a sequence of (name, value) pairs terminated by NULL in
++ place of a name. If no named buffers are to be passed, you can
++ specify NULL for <code>arguments</code> itself.
++ </p>
++ <p CLASS="">
++ <code>resultArg</code> enables one to access the
++ resulting document in case the output went to a named buffer. In
++ that situation, <code>*resultArg</code> points to the resulting
++ null-terminated string, allocated by Sablotron. You can pass NULL
++ for <code>resultArg</code> if the output is sure to go to a
++ file.
++ </p>
++ <p CLASS="">
++ <b>Note:</b>When you are done processing the string
++ pointed to by <code>*resultArg</code>, free it using <a href="#sablotfree">
++ <code>SablotFree()</code>
++ </a> - never use
++ <code>free()</code>. The latter is guaranteed to produce a
++ segmentation fault under Linux.
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotProcessFiles(char *styleSheetName,
++ char *inputName,
++ char *resultName);
++ </code>
++ </p>
++ <p CLASS="">A wrapper for <code>SablotProcess()</code> working on
++ files. The parameters are the null-terminated file names of the
++ XSLT stylesheet, the XML input and the result,
++ respectively. Sablotron opens these files itself and closes them
++ after the processing is complete. Values like "file://stdin" are
++ allowed.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotProcessStrings(char *styleSheetStr, char *inputStr, char
++ **resultStr);
++ </code>
++ </p>
++ <p CLASS="">Another wrapper for <code>SablotProcess()</code>, this
++ time for accessing named buffers (i.e. user-allocated memory
++ blocks)only. Thus, the first parameter is a null-terminated
++ string containing the whole stylesheet; the second parameter
++ is a null-terminated string containing the XML
++ input. Sablotron allocates the buffer for the resulting string
++ and returns a pointer to it in resultStr. Hence, invoking
++ <code>puts(*resultStr)</code> after having called
++ <code>SablotProcessStrings</code> sends the result to
++ stdout. The buffer allocated <b>must</b> be freed by calling the
++ function <code>SablotFree</code> described next.
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1205"></a>
++ <h3>
++ <a href="#toc_i__1048">7.2 Basic functions</a>
++ </h3>
++ <p CLASS="">The above shortcuts just call the basic, lower-level
++ functions described below. Note that if you need to set options
++ for logging etc., you may need to use the low-level
++ functions. </p>
++ <p CLASS="">A typical processing session may look like this:</p>
++ <p CLASS="">
++ <pre>
++ SablotHandle p;
++ char *my_buf;
++ SablotCreateProcessor(&p);
++ SablotSetLog(p, ...);
++ /* ...set other instance-specific options here... */
++ SablotRunProcessor(p, ...);
++ SablotGetResultArg(p, "arg:/somename", &my_buf)
++ /* ...do something with my_buf... */
++ /* can run the processor again if necessary */
++ SablotRunProcessor(p, ...);
++ SablotDestroyProcessor(p);
++ </pre>
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotCreateProcessor(SablotHandle *processorPtr);
++ </code>
++ </p>
++ <p CLASS="">Creates an instance of Sablotron and returns a pointer to
++ it in *processorPtr. This pointer is passed on all subsequent
++ calls to this instance. </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotDestroyProcessor(SablotHandle processor_);
++ </code>
++ </p>
++ <p CLASS="">Destroys an instance of the processor, deallocating all
++ the memory used up by it.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotRunProcessor(SablotHandle processor_,
++ char *sheetURI,
++ char *inputURI,
++ char *resultURI,
++ char **params,
++ char **arguments);
++ </code>
++ </p>
++ <p CLASS="">Processes documents using the given processor instance and
++ given params and args definitions. See
++ <code>SablotProcess()</code>.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotGetResultArg(SablotHandle processor_,
++ char *argURI,
++ char **argValue);
++ </code>
++ </p>
++ <p CLASS="">Copies the result 'arg' buffer with the given URI,
++ returning a pointer to the newly-allocated block in
++ *argValue. If no such buffer exists, returns NULL in *argValue.
++ </p>
++ <p CLASS="">This function is necessary, because if the result document
++ is output to memory, it would be lost when
++ <code>SablotDestroyProcessor()</code> is called. When
++ deallocating the copy obtained from
++ <code>SablotGetResultArg()</code>, use <code>SablotFree</code>
++ (never <code>free()</code>). </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotFreeResultArgs(SablotHandle processor_);
++ </code>
++ </p>
++ <p CLASS="">Removes the Sablotron-internal copies of the 'arg' buffers
++ from the last Sablotron run. Normally, there should be no reason
++ to call this function as it is called automatically on both
++ <code>SablotRunProcessor()</code> and
++ <code>SablotDestroyProcessor()</code>. </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ <a name="sablotfree"></a>
++ int SablotFree(char *resultBuf);
++ </code>
++ </p>
++ <p CLASS="">This function frees the buffer allocated on previous call
++ to <code>SablotProcessStrings</code>. Calling it with an
++ invalid pointer will cause a crash.
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotRegHandler(
++ SablotHandle processor_,
++ HandlerType type,
++ void *handler,
++ void *userData);
++ </code>
++ </p>
++ <p CLASS="">Registers an external handler. <code>type</code> can be
++ <code>HLR_MESSAGE</code>, <code>HLR_SCHEME</code>,
++ <code>HLR_SAX</code>, <code>HLR_MISC</code> or
++ <code>HLR_ENC</code>.
++ <code>handler</code> points to the
++ callback vector of the appropriate type. <code>userData</code>
++ is a data item to passed to all callbacks of this particular
++ handler. For details, check the <code>sablot.h</code> and
++ <code>shandler.h</code> header files.
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotUnregHandler(
++ SablotHandle processor_,
++ HandlerType type,
++ void *handler,
++ void *userData);
++ </code>
++ </p>
++ <p CLASS="">Unregisters the given external handler. For details, check the
++ <code>sablot.h</code> and <code>shandler.h</code> header
++ files.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotSetLog(
++ SablotHandle processor_,
++ const char *logFilename,
++ int logLevel);
++ </code>
++ </p>
++ <p CLASS="">Sets the log filename. The <code>logLevel</code> parameter
++ is currently not used. Pass NULL for <code>logFilename</code> to
++ turn logging off (default). </p>
++ <p CLASS="">The other functions published by sablot.h have been
++ included for experimental reasons or for compatibility, and it
++ is better not to use them.
++ </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ int SablotClearError(SablotHandle processor_);
++ </code>
++ </p>
++ <p CLASS="">Clears the 'pending error' flag for this instance of
++ Sablotron.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1416"></a>
++ <h3>
++ <a href="#toc_i__1048">7.3 Generalized interface functions</a>
++ </h3>
++ <p CLASS="">The implementation of the <a href="#dom">DOM interface</a>
++ brought the need to extend some of the functions described in
++ the previous section. This extension enables the user to:
++ </p>
++ <ul>
++ <li>process documents created by the DOM functions, and</li>
++ <li>process frequently used documents in pre-parsed form.</li>
++ </ul>
++ <p CLASS="">An object called <i>situation</i> is used to provide a
++persistent context for all calls to the DOM-related
++functions. Functions used to manipulate the situation are described in
++<a href="#situation">the following section</a>.</p>
++ <p CLASS="">
++ <b>Note:</b> If not specified otherwise, all these
++ functions return an error code. A positive value indicates an error.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotCreateDocument(SablotSituation S,
++ SDOM_Document *D);
++ </code>
++ </p>
++ <p CLASS="">Creates an empty document. Typically followed by calls to
++ DOM functions to populate the document.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotDestroyDocument(SablotSituation S,
++ SDOM_Document D);
++ </code>
++ </p>
++ <p CLASS="">Destroys a document, freeing all the nodes it has created.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotParse(SablotSituation S,
++ const char *uri, SDOM_Document *D);
++ </code>
++ </p>
++ <p CLASS="">Reads in a document from the given URI.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotParseBuffer(SablotSituation S,
++ const char *buffer, SDOM_Document *D);
++ </code>
++ </p>
++ <p CLASS="">Reads in a document from the given in-memory buffer.</p>
++ <p CLASS="">These functions have variants to be used if the document
++ is to be interpreted as an XSLT stylesheet, namely
++ <code>SablotParseStylesheet</code> and
++ <code>SablotParseStylesheetBuffer</code>.</p>
++ <p CLASS="">The following functions generalize
++ <code>SablotRunProcessor</code> in that they make it possible to
++ utilize an extra kind of a source document: a DOM tree.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotRunProcessorGen(SablotSituation S,
++ void *processor_,
++ char *sheetURI,
++ char *inputURI,
++ char *resultURI);
++ </code>
++ </p>
++ <p CLASS="">A key ingredient of the extended interface. Only the URIs
++ of the sources and of the result document are given to it. The
++ rest of the information passed to
++ <code>SablotRunProcessor</code> is conveyed through
++ <code>SablotAddArgBuffer,</code> <code>SablotAddArgTree</code>
++ and <code>SablotAddParam.</code> The scheme part of the
++ stylesheet URI or the input URI may be "arg:", in which
++ case they refer to a buffer or tree passed by these
++ functions. </p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotAddArgBuffer(SablotSituation S,
++ void *processor_,
++ const char *argName,
++ const char *bufferValue);
++</code>
++ </p>
++ <p CLASS="">Creates a named buffer for the next processor run. The
++ buffer's name and contents are passed as arguments. The name
++ is interpreted relative to the 'arg:/' scheme.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotAddArgTree(SablotSituation S,
++ void *processor_,
++ const char *argName,
++ SDOM_Document tree);
++</code>
++ </p>
++ <p CLASS="">Associates the given document with a name for the next
++ processor run. The document is <i>not</i> destroyed after the
++ run is finished. The name is interpreted relative to the 'arg:/'
++ scheme.</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotAddParam(SablotSituation S,
++ void *processor_,
++ const char *paramName,
++ const char *paramValue);
++ </code>
++ </p>
++ <p CLASS="">Adds a global stylesheet parameter for the next processor
++ run.</p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1578"></a>
++ <h3>
++ <a href="#toc_i__1048">7.4 The situation object</a>
++ </h3>
++ <p CLASS="">
++ <a name="situation"></a>At present, the situation object primarily holds information on any pending errors. A
++situation is created using</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotCreateSituation(SablotSituation
++ *SP);</code>
++ </p>
++ <p CLASS="">and destroyed by</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotDestroySituation(SablotSituation
++ S);</code>
++ </p>
++ <p CLASS="">To clear the pending error flag in a situation, use</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>int SablotClearSituation(SablotSituation
++ S);</code>
++ </p>
++ <p CLASS="">The following self-explanatory functions extract parts of the error information
++ from the situation:</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ const char *SablotGetErrorURI(SablotSituation S);<br>
++ int SablotGetErrorLine(SablotSituation S);<br>
++ const char *SablotGetErrorMsg(SablotSituation S);
++ </code>
++ </p>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1631"></a>
++ <h3>
++ <a href="#toc_i__1048">7.5 Document Object Model (DOM) functions</a>
++ </h3>
++ <p CLASS="">
++ <a name="dom"></a>Starting with version 0.60, Sablotron implements
++ a major subset of the DOM Level 1 Core Specification <a href="#ref-dom">[DOM]</a>. A brief
++ description of the implemented interface follows; for more
++ details, please refer to the header file named
++ <code>sdom.h.</code>
++ </p>
++ <p CLASS="">All of the names related to the DOM interface start with
++ SDOM_ (for Sablot DOM).</p>
++ <p CLASS="">Major new types are <code>SDOM_Document</code> (a DOM tree) and
++ <code>SDOM_Node</code> (a node of the tree). A document can also be used in
++ place of a node. This reflects the fact in the DOM spec,
++ Document is a subclass of Node. When used in this way, the
++ document represents its own root node (which is not the same as
++ the `root element').</p>
++ <p CLASS="">Other types include:</p>
++ <ul>
++ <li>
++ <code>SDOM_char:</code> a DOM character type. Currently, this is just
++ char. Note that the DOM spec requires that the DOM
++ implementations work with UTF-16. Sablotron deviates from this
++ by using UTF-8 instead. A separate set of functions taking
++ UTF-16 strings will be provided.</li>
++ <li>
++ <code>SDOM_NodeType:</code> a node type enum. Some of the values are
++ <code>SDOM_ELEMENT_NODE,</code> <code>SDOM_ATTRIBUTE_NODE</code> and <code>SDOM_TEXT_NODE.</code> See
++ <code>sdom.h</code> for the rest.</li>
++ <li>
++ <code>SDOM_NodeList:</code> a node list returned by some of the
++ functions.</li>
++ <li>
++ <code>SDOM_Exception:</code> DOM exception codes enum, with values such
++ as <code>SDOM_NOT_FOUND_ERR</code> or <code>SDOM_INVALID_NODE_TYPE</code>. See <code>sdom.h</code>
++ for details.</li>
++</ul>
++ <p CLASS="">The functions listed below are implemented more or less as defined in
++ the DOM Level 1 Specification, with two exceptions:
++ their names are prefixed with <code>SDOM_</code> and the first argument is
++ always a <code>SablotSituation.</code> All the functions return
++ a <code>SDOM_Exception.</code> </p>
++ <ul>
++<li>
++ <code>createElement, createAttribute, createTextNode,
++createCDATASection, createComment, createProcessingInstruction</code>
++ </li>
++<li>
++ <code>getNodeType, getNodeName, setNodeName, getNodeValue, setNodeValue</code>
++ </li>
++<li>
++ <code>getParentNode, getFirstChild, getLastChild, getPreviousSibling,
++getNextSibling, getOwnerDocument</code>
++ </li>
++<li>
++ <code>insertBefore, appendChild, removeChild, replaceChild</code>
++ </li>
++<li>
++ <code>cloneNode</code>
++ </li>
++<li>
++ <code>getAttribute, setAttribute, removeAttribute, getAttributeList</code>
++ </li>
++</ul>
++ <p CLASS="">Several functions have been added:</p>
++ <ul>
++<li>
++ <code>disposeNode</code> frees all memory used by the given node</li>
++<li>
++ <code>cloneForeignNode</code> clones a node from a different
++document</li>
++<li>
++ <code>docToString</code> serializes the document, returning the
++resulting string</li>
++<li>
++ <code>xql</code> performs an XPath query on the DOM tree,
++returning a list of the nodes satisfying it.</li>
++</ul>
++ <p CLASS="">In addition, there are some functions used to manipulate
++ the node lists returned by <code>xql</code> and
++ <code>getAttributeList</code>. These include
++ <code>getNodeListLength</code>, <code>getNodeListItem</code> and
++ <code>disposeNodeList</code>.</p>
++ <p CLASS="">Finally, there are functions to extract DOM
++ exception-related information from the situation object, namely
++ <code>getExceptionCode</code>, <code>getExceptionMessage</code>
++ and <code>getExceptionDetails</code>.</p>
++ </DIV>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__1870"></a>
++ <h2>
++ <a href="#toc_i__1870">8 The command line interface</a>
++ </h2>
++ <DIV>
++ <p CLASS="">Sablotron comes with a command-line interface to the
++ shared library, which is a program named
++ <code>sabcmd</code>. At present, <code>sabcmd</code> is invoked
++ as follows:</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ sabcmd [<i>options</i>] <i>stylesheet</i> [<i>input</i> [<i>result</i>]] [<i>assignments</i>]
++ </code>
++ </p>
++ <p CLASS="">The arguments are the URIs of the XSLT stylesheet, the
++ XML input document, and the resulting document, respectively. The
++ default for <code>
++ <i>input</i>
++ </code> is
++ <code>file://stdin</code> (meaning plain old stdin);
++ <code>
++ <i>result</i>
++ </code> defaults to
++ <code>file://stdout</code>. Filenames have to include the extension (if
++ any).</p>
++ <p CLASS="">You can display the list of available options by typing
++ <code>sabcmd --help</code>. Among the more useful ones are
++ <code>--log-file</code> (for setting the log file) and
++ <code>--measure</code> (measures and outputs the total
++ processing time).
++ </p>
++ <p CLASS="">
++ <a href="#fname-rules">The rules for filenames</a> are the same as
++ with <code>SablotProcess()</code>.
++ </p>
++ <p CLASS="">
++ <code>assignments</code> is a series of definitions of the
++ form:</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ name1=value1 name2=value2 ...
++ </code>
++ </p>
++ <p CLASS="">
++ assigning values to top-level stylesheet parameters and to named
++ buffers. These two cases are distinguished by a leading '$' in
++ the name of a stylesheet parameter. The names of the buffers do
++ <i>not</i> start with "arg:". They may start with a slash; if
++ they don't, the slash is prepended.
++ </p>
++ <p CLASS="">
++ <b>Note:</b> In most cases, it will be necessary to quote
++ the individual assignments. Whether to use single or double
++ quotes may depend on the shell used (or may it?) Single quotes
++ work for bash, double quotes work in Windows.
++ </p>
++ <p CLASS="">If the result URI refers to a named buffer, the output
++ would normally remain buried in memory. Sabcmd dumps the buffer to standard
++ output instead.
++ </p>
++ <p CLASS="">To sum up and give an example, the following would be a
++ valid invocation of sabcmd:</p>
++ <p CLASS="" STYLE="background-color: #ffffee">
++ <code>
++ sabcmd sheet.xsl arg:/the_input "the_input=<a/>"
++ "$use_defaults=1"
++ </code>
++ </p>
++ <p CLASS="">This processes the document passed in the buffer named
++ the_input, using a stylesheet found in file "sheet.xsl" in the
++ working directory. We assign 1 to the top-level parameter called
++ "use_defaults". The output goes to stdout by default.
++ </p>
++ </DIV>
++ </DIV>
++ <DIV class="afterskip">
++ <a name="i__2013"></a>
++ <h2>
++ <a href="#toc_i__2013">9 References</a>
++ </h2>
++ <DIV>
++ <dl>
++ <dt>
++ <a name="ref-xslt"></a>[XSLT]</dt>
++ <dd>
++ <a href="http://www.w3.org/TR/1999/REC-xslt-19991116">
++ XSL Transformations (XSLT) Version 1.0
++ </a>
++ </dd>
++
++ <dt>
++ <a name="ref-xpath"></a>[XPath]</dt>
++ <dd>
++ <a href="http://www.w3.org/TR/1999/REC-xpath-19991116">
++ XML Path Language (XPath) Version 1.0
++ </a>
++ </dd>
++
++ <dt>
++ <a name="ref-xml"></a>[XML]</dt>
++ <dd>
++ <a href="http://www.w3.org/TR/1998/REC-xml-19980210">
++ Extensible Markup Language (XML) 1.0
++ </a>
++ </dd>
++
++ <dt>
++ <a name="ref-dom"></a>[DOM]</dt>
++ <dd>
++ <a href="http://www.w3.org/TR/REC-DOM-Level-1">
++ Document Object Model Level 1 Specification, Version 1.0
++ </a>
++ </dd>
++
++ <dt>
++ <a name="ref-rcover"></a>[Cover]</dt>
++ <dd>
++ <a href="http://www.oasis-open.org/cover/sgml-xml.html">
++ The XML Cover Pages</a>
++ </dd>
++
++ <dt>
++ <a name="ref-xmlorg"></a>[XMLorg]</dt>
++ <dd>
++ <a href="http://xml.org">XML.org</a>
++ </dd>
++
++ <dt>
++ <a name="ref-xslinfo"></a>[XSLINFO]</dt>
++ <dd>
++ <a href="http://www.xslinfo.com">XSLINFO.com</a>
++ </dd>
++
++ <dt>
++ <a name="ref-bible"></a>[XMLBible14]</dt>
++ <dd>
++ <a href="http://metalab.unc.edu/xml/books/bible/updates/14.html">
++ Harold, E. R.: XML Bible, Chapter 14 (online presentation)
++ </a>
++ </dd>
++ </dl>
++ </DIV>
++ </DIV>
++ <hr>
++ <p STYLE="font-style: italic; margin-left: 0">(c) 2000 Ginger Alliance s.r.o.</p>
++ </body>
++</html>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_masterurl_failure.py
+@@ -0,0 +1,19 @@
++#!/usr/bin/env python
++
++## $Id: test_masterurl_failure.py 1655 2003-07-10 00:35:51Z quarl $
++
++from test_uc import *
++
++if __name__ == '__main__':
++ test_msg("scheduler exponential backoff (master url failure)")
++ Proxy('close_connection if $nconnections < 2; ', html=1)
++ # Proxy(('print "hi nc=$nconnections start=$start nchars=$nchars url=$url\n"; ' +
++ # 'close_connection if $nconnections < 2; '),
++ # html=1)
++ # Proxy(( 'print "hi nc=$nconnections start=$start nchars=$nchars url=$url\n"; ' +
++ # ''),
++ # html=1)
++ ProjectUC(short_name='test_masterurl_failure')
++ run_check_all()
++
++ ## TODO: verify it took ??? seconds
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_uc_slow.php
+@@ -0,0 +1,31 @@
++#!/usr/local/bin/php -q
++<?php {
++ // $Id: test_uc_slow.php 1496 2003-06-16 17:59:38Z eheien $
++
++ include_once("test.inc");
++
++ test_msg("client checkpoint/restart mechanism");
++
++ $project = new Project;
++ $user = new User();
++ $host = new Host();
++
++ $project->add_user($user);
++ $project->add_app_and_version("upper_case");
++ $project->install(); // must install projects before adding to hosts
++
++ $host->add_user($user, $project);
++ $host->install();
++
++ $work = new Work();
++ $work->wu_template = "ucs_wu";
++ $work->result_template = "uc_result";
++ array_push($work->input_files, "small_input");
++ $work->install($project);
++
++ $project->install_feeder();
++ $project->start_servers();
++
++ verbose_echo(0, "Now run the client manually; start and stop it a few times");
++ //compare_file("ucs_wu_0_0", "uc_small_correct_output");
++} ?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_sched_failure.php
+@@ -0,0 +1,57 @@
++#! /usr/local/bin/php
++<?php
++//This tests the exponential backoff mechanism on the client in case of scheduling server failures.
++//This test is not automated. It has to be run, and then client.out (in the host directory) must be looked at to examine wether everything is working correctly.
++ include_once("test.inc");
++
++ $project = new Project;
++ $user = new User();
++ $host = new Host($user);
++
++ $app = new App("upper_case");
++ $app_version = new App_Version($app);
++
++ // the following is optional (makes client web download possible)
++ $core_app = new App("core client");
++ $core_app_version = new App_Version($core_app);
++ $project->add_app($core_app);
++ $project->add_app_version($core_app_version);
++
++ $project->add_user($user);
++ $project->add_app($app);
++ $project->add_app_version($app_version);
++
++ $project->install(); // must install projects before adding to hosts
++
++ $host->log_flags = "log_flags.xml";
++ $host->add_project($project);
++ $host->install();
++
++ echo "adding work\n";
++
++ $work = new Work($app);
++ $work->wu_template = "uc_wu";
++ $work->result_template = "uc_result";
++ $work->redundancy = 2;
++ $work->delay_bound = 10;
++ array_push($work->input_files, "input");
++ $work->install($project);
++
++ $project->start_feeder();
++ $project->delete_scheduler();
++ $pid = $host->run_asynch("-exit_when_idle");
++ echo "sleeping for 100 seconds\n";
++ sleep(100);
++ $project->reinstall_scheduler();
++ $status = 0;
++ //wait until the host has stopped running
++ pcntl_waitpid($pid,$status,0);
++ $project->stop();
++
++ $result->server_state = RESULT_SERVER_STATE_OVER;
++ $result->stderr_out = "APP: upper_case: starting, argc 1";
++ $result->exit_status = 0;
++ $project->check_results(2, $result);
++ $project->compare_file("uc_wu_0_0", "uc_correct_output");
++ $project->compare_file("uc_wu_1_0", "uc_correct_output");
++?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/version.inc.in
+@@ -0,0 +1,12 @@
++<?php
++
++// version.inc.in
++
++// defines version numbers using autoconf
++define("MAJOR_VERSION", @MAJOR_VERSION@);
++define("MINOR_VERSION", @MINOR_VERSION@);
++define("CLIENT_BIN_FILENAME", "@CLIENT_BIN_FILENAME@");
++define("PLATFORM", "@host@");
++define("SRC_DIR", "@SOURCE_TOP_DIR@");
++
++?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_rsc.py
+@@ -0,0 +1,27 @@
++#!/usr/bin/env python
++
++## $Id: test_rsc.py 2243 2003-09-04 00:41:51Z davea $
++
++# Test whether the scheduling server filters out work units too big for client
++
++from test_uc import *
++
++class WorkTooBig(WorkUC):
++ def __init__(self):
++ WorkUC.__init__(self)
++ self.rsc_disk_bound = 1000000000000 # 1 TB
++
++class ResultUnsent:
++ def __init__(self):
++ self.server_state = RESULT_SERVER_STATE_UNSENT
++
++class ProjectRsc(ProjectUC):
++ def __init__(self):
++ ProjectUC.__init__(self, short_name='test_rsc', works=[WorkTooBig()])
++ def check(self):
++ self.check_results(ResultUnsent())
++
++if __name__ == '__main__':
++ test_msg("resource filtering for large work units")
++ ProjectRsc()
++ run_check_all()
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_download_backoff.php
+@@ -0,0 +1,53 @@
++#! /usr/local/bin/php
++<?php
++// Tests the exponential backoff mechanism on the client for failed downloads
++// This test is not automated. It has to be run, and then client.out (in the host directory) must be looked at to examine wether everything is working correctly.
++ include_once("test.inc");
++
++ $project = new Project;
++ $user = new User();
++ $host = new Host($user);
++
++ $app = new App("upper_case");
++ $app_version = new App_Version($app);
++
++ $project->add_user($user);
++ $project->add_app($app);
++ $project->add_app_version($app_version);
++
++ $project->install(); // must install projects before adding to hosts
++ $project->install_feeder();
++
++ $host->log_flags = "log_flags.xml";
++ $host->add_user($user, $project);
++ $host->install();
++
++ echo "adding work\n";
++
++ $work = new Work($app);
++ $work->wu_template = "uc_wu";
++ $work->result_template = "uc_result";
++ $work->redundancy = 2;
++ array_push($work->input_files, "input");
++ $work->install($project);
++
++ //delete the download_dir immediately
++ $project->delete_downloaddir();
++
++ $project->start_servers();
++ $pid = $host->run_asynch("-exit_when_idle");
++ echo "sleeping 100 secs\n";
++ sleep(100);
++ $project->reinstall_downloaddir(null);
++ $status = 0;
++ //wait until the host has stopped running
++ pcntl_waitpid($pid, $status, 0);
++ $project->stop();
++
++ $result->server_state = RESULT_SERVER_STATE_OVER;
++ $result->stderr_out = "APP: upper_case: starting, argc 1";
++ $result->exit_status = 0;
++ $project->check_results(2, $result);
++ $project->compare_file("uc_wu_0_0", "uc_correct_output");
++ $project->compare_file("uc_wu_1_0", "uc_correct_output");
++?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/gen_keys.php
+@@ -0,0 +1,9 @@
++#! /usr/local/bin/php
++<?php
++ // Generate encryption keys
++
++ include_once("test.inc");
++
++ create_keys();
++
++?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_sanity.php
+@@ -0,0 +1,36 @@
++#!/usr/local/bin/php -q
++<?php {
++ // $Id: test_sanity.php 1357 2003-06-11 22:11:32Z quarl $
++
++ // tests makes sure that testing framework is sane
++
++ include_once("test.inc");
++
++ // make sure applications executable
++
++ check_core_client_executable();
++ check_app_executable("upper_case");
++ check_app_executable("concat");
++ check_app_executable("1sec");
++
++ if (!is_dir(KEY_DIR)) {
++ error("Keydir doesn't exist: ".KEY_DIR);
++ }
++ if (!is_dir(PROJECTS_DIR)) {
++ error("Projects dir doesn't exist: ".PROJECTS_DIR);
++ }
++ if (!is_dir(HOSTS_DIR)) {
++ error("Hosts dir doesn't exist: ".HOSTS_DIR);
++ }
++ if (!is_dir(CGI_DIR)) {
++ error("CGI dir doesn't exist: ".CGI_DIR);
++ }
++ if (!is_dir(HTML_DIR)) {
++ error("HTML dir doesn't exist: ".HTML_DIR);
++ }
++ if (!fopen(HTML_URL, 'r')) {
++ error("Couldn't open html url: ".HTML_URL);
++ }
++
++ test_done();
++} ?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/uc_result_sticky
+@@ -0,0 +1,14 @@
++<file_info>
++ <name><OUTFILE_0/></name>
++ <generated_locally/>
++ <upload_when_present/>
++ <max_nbytes>100000</max_nbytes>
++ <url><UPLOAD_URL/></url>
++ <sticky/>
++</file_info>
++<result>
++ <file_ref>
++ <file_name><OUTFILE_0/></file_name>
++ <open_name>out</open_name>
++ </file_ref>
++</result>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/concat_wu
+@@ -0,0 +1,17 @@
++<file_info>
++ <number>0</number>
++</file_info>
++<file_info>
++ <number>1</number>
++</file_info>
++<workunit>
++ <file_ref>
++ <file_number>0</file_number>
++ <open_name>in1</open_name>
++ </file_ref>
++ <file_ref>
++ <file_number>1</file_number>
++ <open_name>in2</open_name>
++ </file_ref>
++ <command_line>in1 in2 out</command_line>
++</workunit>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_uc.py
+@@ -0,0 +1,79 @@
++#!/usr/bin/env python
++
++## $Id: test_uc.py 5506 2005-02-23 19:44:59Z boincadm $
++
++# This tests whether the most basic mechanisms are working
++# Also whether stderr output is reported correctly
++# Also tests if work buffer limits are working correctly
++
++from testbase import *
++
++class UserUC(User):
++ def init(self):
++ self.User.__init__()
++ self.project_prefs = """<project_preferences>
++<project_specific>
++foobar
++</project_specific>
++</project_preferences>
++"""
++ self.global_prefs = """<global_preferences>
++<venue name=\"home\">
++<work_buf_min_days>0</work_buf_min_days>
++<work_buf_max_days>2</work_buf_max_days>
++<disk_interval>1</disk_interval>
++<run_on_batteries/>
++<max_bytes_sec_down>400000</max_bytes_sec_down>
++</venue>
++</global_preferences>
++"""
++
++class WorkUC(Work):
++ def __init__(self, redundancy, **kwargs):
++ Work.__init__(self, redundancy=redundancy)
++ self.wu_template = "uc_wu_nodelete"
++ self.result_template = "uc_result"
++ self.input_files = ['input']
++ self.__dict__.update(kwargs)
++
++class ResultUC(ExpectedResult):
++ def __init__(self):
++ ExpectedResult.__init__(self)
++ self.stderr_out = MATCH_REGEXPS([
++ "<stderr_txt>",
++ "APP: upper_case: starting, argc \\d+",
++ "APP: upper_case: argv[[]0[]] is upper_case",
++ "APP: upper_case ending, wrote \\d+ chars"])
++
++class ResultComputeErrorUC(ExpectedResultComputeError):
++ def __init__(self):
++ ExpectedResultComputeError.__init__(self)
++ self.stderr_out = MATCH_REGEXPS([ """<stderr_txt>
++APP: upper_case: starting, argc \\d+"""])
++
++## TODO: check that uc_wu_%d_0 matches uc_correct_output BEFORE deleted by
++## file deleter!
++
++class ProjectUC(TestProject):
++ def __init__(self,
++ num_wu=None, redundancy=None,
++ expect_success=True,
++ works=None, users=None, hosts=None,
++ short_name=None, long_name=None,
++ resource_share=1):
++ (num_wu, redundancy) = get_redundancy_args(num_wu, redundancy)
++ TestProject.__init__(self,
++ appname = 'upper_case',
++ num_wu=num_wu, redundancy=redundancy,
++ expected_result = (expect_success and ResultUC() or ResultComputeErrorUC()),
++ works = works or [WorkUC(redundancy=redundancy)],
++ users = users or [UserUC()],
++ hosts = hosts,
++ short_name=short_name, long_name=long_name,
++ resource_share=resource_share
++ )
++
++if __name__ == '__main__':
++ test_msg("standard upper_case application");
++ ProjectUC()
++ run_check_all()
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_api.php
+@@ -0,0 +1,10 @@
++#! /usr/local/bin/php
++<?php
++ include_once("init.inc");
++
++ clean_api();
++ run_api_test();
++ compare_files("foobar", "ta_correct_f");
++ clean_api();
++?>
++
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_suite.php
+@@ -0,0 +1,28 @@
++#! /usr/local/bin/php
++<?php
++ //Run the comprehensive suite of tests
++ //
++
++ passthru("./test_1sec.php", $retval);
++ if($retval) printf("./test_1sec.php did not run correctly\n");
++ sleep(3);
++
++ PassThru("./test_backend.php", $retval);
++ if($retval) printf("./test_backend.php did not run correctly\n");
++ sleep(3);
++
++ PassThru("./test_concat.php", $retval);
++ if($retval) printf("./test_concat.php did not run correctly\n");
++ sleep(3);
++
++ PassThru("./test_rsc.php", $retval);
++ if($retval) printf("./test_rsc.php did not run correctly\n");
++ sleep(3);
++
++ PassThru("./test_sticky.php", $retval);
++ if($retval) printf("./test_sticky.php did not run correctly\n");
++ sleep(3);
++
++ passthru("./test_uc.php", $retval);
++ if($retval) printf("./test_uc.php did not run correctly\n");
++?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/make_project_sah.php
+@@ -0,0 +1,61 @@
++#!/bin/sh
++
++echo "this file is obsolete! cvs remove when ready"
++exit 1
++
++
++#! /usr/local/bin/php
++<?php
++ // This script creates a BOINC project.
++ // You just need to plug in an application,
++ // and back-end systems for creating work and validating results
++
++ include_once("test.inc");
++
++ $project = new Project;
++ $project->short_name = "sah";
++ $project->long_name = "SETI at home II";
++
++ $platform = new Platform("windows_intelx86", "Windows");
++
++ $app = new App("Astropulse");
++ $app_version = new App_Version($app);
++ $app_version->platform = $platform;
++ $app_version->exec_dir = "../apps";
++ $app_version->version = 5;
++ $app_version->exec_name = "ap_win_0.05.exe";
++
++ $core_app = new App("core client");
++ $core_app_version = new App_Version($core_app);
++ $core_app_version->platform = $platform;
++ $core_app_version->exec_dir = "../apps";
++ $core_app_version->version = 13;
++ $core_app_version->exec_name = "BOINC_0.13a.exe";
++
++ $project->add_app($app);
++ $project->add_app_version($app_version);
++ $project->add_app($core_app);
++ $project->add_app_version($core_app_version);
++ $project->start_assimilator = false;
++ $project->start_feeder = true;
++ $project->start_file_deleter = false;
++ $project->start_make_work = true;
++ $project->make_work_wu_template = "pulse_wu";
++ $project->make_work_result_template = "pulse_result";
++ $project->start_timeout_check = false;
++ $project->start_validate = false;
++ $project->shmem_key = 0x31415928;
++ $project->project_php_file = "project_sah.inc";
++
++ $project->install();
++
++ $work = new Work($app);
++ $work->wu_template = "pulse_wu";
++ $work->result_template = "pulse_result";
++ $work->redundancy = 5;
++ array_push($work->input_files, "03au00ab_20575_00000.wu");
++ $work->install($project);
++ $project->http_password("admin","mypass");
++
++ $project->start_servers();
++?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/make_project.php
+@@ -0,0 +1,47 @@
++#!/bin/sh
++
++echo "this file is obsolete! cvs remove when ready"
++exit 1
++
++
++#! /usr/local/bin/php
++<?php
++ // This script creates a BOINC project.
++ // You just need to plug in an application,
++ // and back-end systems for creating work and validating results
++
++ include_once("test.inc");
++
++ $project = new Project;
++ $project->short_name = "project_name";
++ $project->long_name = "Your Project";
++
++ $platform = new Platform("windows_intelx86", "Windows");
++
++ $app = new App("Astropulse");
++ $app_version = new App_Version($app);
++ $app_version->platform = $platform;
++ $app_version->exec_dir = "../apps";
++ $app_version->exec_name = "ap_win_0.02.exe";
++
++ $core_app = new App("core client");
++ $core_app_version = new App_Version($core_app);
++ $core_app_version->platform = $platform;
++ $core_app_version->exec_dir = "../apps";
++ $core_app_version->exec_name = "BOINC_0.10.exe";
++
++ $project->add_app($app);
++ $project->add_app_version($app_version);
++ $project->add_app($core_app);
++ $project->add_app_version($core_app_version);
++ $project->start_assimilator = true;
++ $project->start_feeder = true;
++ $project->start_file_deleter = true;
++ $project->start_make_work = true;
++ $project->start_timeout_check = true;
++ $project->start_validate = true;
++ $project->shmem_key = 0x31415926;
++
++ $project->install();
++ $project->start_feeder();
++?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_upload_backoff.php
+@@ -0,0 +1,20 @@
++#!/usr/local/bin/php -q
++<?php {
++ // $Id: test_upload_backoff.php 1526 2003-06-18 02:59:57Z quarl $
++
++ $use_proxy_cgi = 1;
++
++ include_once("test_uc.inc");
++ test_msg("upload backoff");
++
++ start_proxy('print "#$nconnections url=$url time=$time\n"; exit 1 if ($nconnections < 4); if_done_kill(); if_done_ping();');
++
++ $project = new ProjectUC;
++
++ // $pid = $host->run_asynch("-exit_when_idle");
++
++ $project->start_servers_and_host();
++ $project->validate_all_and_stop();
++
++ test_done();
++} ?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/uc_exit_wu
+@@ -0,0 +1,10 @@
++<file_info>
++ <number>0</number>
++</file_info>
++<workunit>
++ <file_ref>
++ <file_number>0</file_number>
++ <open_name>in</open_name>
++ </file_ref>
++ <command_line>-exit</command_line>
++</workunit>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/uc_sig_wu
+@@ -0,0 +1,10 @@
++<file_info>
++ <number>0</number>
++</file_info>
++<workunit>
++ <file_ref>
++ <file_number>0</file_number>
++ <open_name>in</open_name>
++ </file_ref>
++ <command_line>-signal</command_line>
++</workunit>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_masterurl_failure.php
+@@ -0,0 +1,22 @@
++#!/usr/local/bin/php -q
++<?php {
++ // $Id: test_masterurl_failure.php 1510 2003-06-17 01:36:47Z quarl $
++
++ $use_proxy_html = 1;
++
++ include_once("test_uc.inc");
++ test_msg("master url failure");
++
++ $project = new ProjectUC;
++
++ start_proxy('exit 1 if $nconnections < 4; if_done_kill(); if_done_ping();');
++
++ // TODO: verify it took ??? seconds
++
++ // TODO: time out after ??? seconds and fail this test
++
++ $project->start_servers_and_host();
++ $project->validate_all_and_stop();
++
++ test_done();
++} ?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/test_exit.py
+@@ -0,0 +1,28 @@
++#!/usr/bin/env python
++
++## $Id: test_exit.py 2114 2003-08-15 20:27:21Z quarl $
++
++# Make sure server hears that client exited with nonzero status.
++
++from test_uc import *
++
++class WorkExit(WorkUC):
++ def __init__(self):
++ WorkUC.__init__(self)
++ self.wu_template = "uc_exit_wu"
++
++class ResultExit(ResultUCError):
++ def __init__(self):
++ ResultUCError.__init__(self)
++ self.stderr_out.append('<message>process exited with a non-zero exit code')
++
++class ProjectExit(ProjectUC):
++ def __init__(self):
++ ProjectUC.__init__(self, short_name='test_exit', works=[WorkExit()])
++ def check(self):
++ self.check_client_error(ResultExit())
++
++if __name__ == '__main__':
++ test_msg("application exit report mechanism")
++ ProjectExit()
++ run_check_all()
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/init.inc
+@@ -0,0 +1,310 @@
++<?php
++
++define("VERSION", "1");
++define("CORE_CLIENT", "boinc_".VERSION."_$BOINC_PLATFORM");
++define("PROJECTS", "localhost.localdomain zoot");
++
++
++function clear_db() {
++ PassThru("cd ../db; init_db");
++}
++
++$BOINC_DOWNLOAD_DIR = null;
++$BOINC_UPLOAD_DIR = null;
++$BOINC_PLATFORM = null;
++$BOINC_EMAIL = null;
++$BOINC_DOWNLOAD_URL = null;
++$BOINC_KEY_DIR = null;
++$BOINC_MASTER_URL = null;
++$BOINC_DB_NAME = null;
++
++function open_db() {
++ global $BOINC_DB_NAME;
++
++ $retval = mysql_connect();
++ if (!$retval) {
++ echo "mysql_connect() failed\n";
++ exit();
++ }
++ $retval = mysql_select_db($BOINC_DB_NAME);
++ if (!$retval) {
++ echo "mysql_select_db() failed\n";
++ exit();
++ }
++}
++
++function check_env_vars() {
++ global $BOINC_DOWNLOAD_DIR;
++ global $BOINC_UPLOAD_DIR;
++ global $BOINC_PLATFORM;
++ global $BOINC_EMAIL;
++ global $BOINC_DOWNLOAD_URL;
++ global $BOINC_KEY_DIR;
++ global $BOINC_MASTER_URL;
++ global $BOINC_DB_NAME;
++
++ $bad = false;
++ $BOINC_DOWNLOAD_DIR = getenv("BOINC_DOWNLOAD_DIR");
++ if ($BOINC_DOWNLOAD_DIR == null) {
++ echo "Must define BOINC_DOWNLOAD_DIR\n";
++ $bad = true;
++ }
++ $BOINC_UPLOAD_DIR = getenv("BOINC_UPLOAD_DIR");
++ if ($BOINC_UPLOAD_DIR == null) {
++ echo "Must define BOINC_UPLOAD_DIR\n";
++ $bad = true;
++ }
++ $BOINC_PLATFORM = getenv("BOINC_PLATFORM");
++ if ($BOINC_PLATFORM == null) {
++ echo "Must define BOINC_PLATFORM\n";
++ $bad = true;
++ }
++ $BOINC_EMAIL = getenv("BOINC_EMAIL");
++ if ($BOINC_EMAIL == null) {
++ echo "Must define BOINC_EMAIL\n";
++ $bad = true;
++ }
++ $BOINC_DOWNLOAD_URL = getenv("BOINC_DOWNLOAD_URL");
++ if ($BOINC_DOWNLOAD_URL == null) {
++ echo "Must define BOINC_DOWNLOAD_URL\n";
++ $bad = true;
++ }
++ $BOINC_KEY_DIR = getenv("BOINC_KEY_DIR");
++ if ($BOINC_KEY_DIR == null) {
++ echo "Must define BOINC_KEY_DIR\n";
++ $bad = true;
++ }
++ $BOINC_MASTER_URL = getenv("BOINC_MASTER_URL");
++ if ($BOINC_MASTER_URL == null) {
++ echo "Must define BOINC_MASTER_URL\n";
++ $bad = true;
++ }
++ $BOINC_DB_NAME = getenv("BOINC_DB_NAME");
++ if ($BOINC_DB_NAME == null) {
++ echo "Must define BOINC_DB_NAME\n";
++ $bad = true;
++ }
++ if ($bad) exit();
++}
++
++function clear_server_dirs($clear_key_dir) {
++ global $BOINC_DOWNLOAD_DIR;
++ global $BOINC_UPLOAD_DIR;
++ global $BOINC_KEY_DIR;
++
++ $bad = false;
++ if ($BOINC_DOWNLOAD_DIR == null) {
++ echo "Must define BOINC_DOWNLOAD_DIR\n";
++ $bad = true;
++ }
++ if ($BOINC_UPLOAD_DIR == null) {
++ echo "Must define BOINC_UPLOAD_DIR\n";
++ $bad = true;
++ }
++ if ($BOINC_KEY_DIR == null) {
++ echo "Must define BOINC_KEY_DIR\n";
++ $bad = true;
++ }
++ if ($bad) exit();
++
++ PassThru("rm -f $BOINC_DOWNLOAD_DIR/*");
++ PassThru("rm -f $BOINC_UPLOAD_DIR/*");
++ if ($clear_key_dir) {
++ PassThru("rm -f $BOINC_KEY_DIR/*");
++ }
++}
++
++function clear_client_dirs() {
++ PassThru("rm -rf projects/*" );
++}
++
++function init_client_dirs($prefs_file, $account_file) {
++ global $BOINC_MASTER_URL;
++
++ PassThru("rm -f client_state.xml");
++ PassThru("rm -rf ".PROJECTS);
++ PassThru("rm -rf slots");
++ PassThru("cp $prefs_file prefs.xml");
++ PassThru("sed -e s/BOINC_MASTER_URL/$BOINC_MASTER_URL/ $account_file > account_foo.xml");
++}
++
++function copy_to_download_dir($f) {
++ global $BOINC_DOWNLOAD_DIR;
++
++ PassThru("cp $f $BOINC_DOWNLOAD_DIR");
++}
++
++function add_user($global_prefs_file) {
++ global $BOINC_EMAIL;
++ global $BOINC_MASTER_URL;
++
++ $cmd = "../tools/add user -email_addr $BOINC_EMAIL -user_name David -web_password foobar -authenticator 3f7b90793a0175ad0bda68684e8bd136 ";
++ if ($global_prefs_file) {
++ PassThru("sed -e s/BOINC_MASTER_URL/$BOINC_MASTER_URL/ $global_prefs_file > prefs_temp.xml");
++ $cmd = $cmd." -global_prefs_file prefs_temp.xml";
++ }
++ PassThru($cmd);
++}
++
++function add_project($short_name,$long_name) {
++ PassThru("../tools/add project -project_short_name '$short_name' -project_long_name '$long_name'");
++}
++
++function add_platform($platform) {
++ global $BOINC_PLATFORM;
++
++ if( $platform ) {
++ PassThru("../tools/add platform -platform_name $platform");
++ } else {
++ PassThru("../tools/add platform -platform_name $BOINC_PLATFORM");
++ }
++}
++
++function add_core_client_message($message, $priority, $platform) {
++ global $BOINC_DOWNLOAD_DIR;
++ global $BOINC_UPLOAD_DIR;
++ global $BOINC_PLATFORM;
++ global $BOINC_KEY_DIR;
++
++ if( $platform == null ) {
++ $plat = $BOINC_PLATFORM;
++ } else {
++ $plat = $platform;
++ }
++ PassThru("../tools/add app -app_name core_client -version ".VERSION);
++ $cmd = "../tools/add app_version -app_name core_client -platform_name $plat -version ".VERSION." -download_dir $BOINC_DOWNLOAD_DIR -download_url $BOINC_DOWNLOAD_URL -message '$message' -message_priority '$priority' -code_sign_keyfile $BOINC_KEY_DIR/code_sign_private -exec_dir ../client -exec_files ".CORE_CLIENT;
++ //echo "$cmd\n";
++ PassThru($cmd);
++ PassThru("cp ../client/".CORE_CLIENT." $BOINC_DOWNLOAD_DIR");
++}
++
++function add_core_client($platform) {
++ add_core_client_message("", "", $platform);
++}
++
++function add_app($name, $platform, $exec_name) {
++ PassThru("../tools/add app -app_name $name -version ".VERSION);
++ add_app_version( $name, $platform, $exec_name );
++}
++
++function add_app_version($name, $platform, $exec_name) {
++ global $BOINC_DOWNLOAD_DIR;
++ global $BOINC_PLATFORM;
++ global $BOINC_DOWNLOAD_URL;
++ global $BOINC_KEY_DIR;
++
++ if( $exec_name == null ) {
++ $exec_name = $name;
++ }
++ if( $platform == null ) {
++ $plat = $BOINC_PLATFORM;
++ } else {
++ $plat = $platform;
++ }
++
++ $cmd = "../tools/add app_version -app_name $name -platform_name $plat -version ".VERSION." -download_dir $BOINC_DOWNLOAD_DIR -download_url $BOINC_DOWNLOAD_URL -code_sign_keyfile $BOINC_KEY_DIR/code_sign_private -exec_dir ../apps -exec_files $exec_name";
++ //echo "$cmd\n";
++ PassThru($cmd);
++ PassThru("cp ../apps/$exec_name $BOINC_DOWNLOAD_DIR");
++}
++
++function create_work($x) {
++ global $BOINC_KEY_DIR;
++ PassThru("../tools/create_work -keyfile $BOINC_KEY_DIR/upload_private $x");
++}
++
++function create_keys() {
++ global $BOINC_KEY_DIR;
++ PassThru("../lib/crypt_prog -genkey 1024 $BOINC_KEY_DIR/upload_private $BOINC_KEY_DIR/upload_public");
++ PassThru("../lib/crypt_prog -genkey 1024 $BOINC_KEY_DIR/code_sign_private $BOINC_KEY_DIR/code_sign_public");
++}
++
++function run_client($args) {
++ PassThru("../client/".CORE_CLIENT." $args");
++}
++
++function start_feeder() {
++ PassThru("cd ../sched; feeder -asynch > feeder_out");
++}
++
++function stop_feeder() {
++ $f = fopen("../sched/feeder_trigger", "w");
++ fputs($f, "<quit/>\n");
++ fclose($f);
++}
++
++function compare_file($out, $correct) {
++ global $BOINC_UPLOAD_DIR;
++
++ PassThru("diff $BOINC_UPLOAD_DIR/$out $correct", $retval);
++ if ($retval) {
++ echo "File mismatch: $out $correct\n";
++ } else {
++ echo "Files match: $out $correct\n";
++ }
++}
++
++function check_results_done() {
++ open_db();
++ $result = mysql_query("select * from result where state<>4");
++ while ($x = mysql_fetch_object($result)) {
++ echo "result $x->id is not done\n";
++ }
++}
++
++function num_wus_left() {
++ open_db();
++ $numwus = mysql_query("select count(*) as nres from result where state<>4");
++ $result = mysql_fetch_object($numwus);
++ return $result->nres;
++}
++
++function compare_files($out, $correct) {
++ PassThru("diff $out $correct", $retval);
++ if ($retval) {
++ echo "File mismatch: $out $correct\n";
++ } else {
++ echo "Files match: $out $correct\n";
++ }
++}
++
++function run_api_test() {
++ PassThru("../api/api_test");
++}
++
++function clean_api() {
++ PassThru("rm -f counter app_to_core.xml core_to_app.xml foobar");
++}
++
++function get_time($file_name) {
++ $time_file = fopen($file_name, "r");
++ if($time_file == NULL) return 0;
++ fscanf($time_file, "%f", $app_time);
++ PassThru("rm -f ".$file_name);
++ return $app_time;
++}
++
++function compare_time($app_time) {
++ $epsilon = 0.0001;
++ open_db();
++ $data = mysql_query("select cpu_time from result where name = 'uccpu_wu_0'");
++ $result = mysql_fetch_object($data);
++ $db_time = $result->cpu_time;
++ $client_time = get_time("client_time");
++ if(abs($app_time - $client_time) > $epsilon) {
++ printf("Time mismatch: app %f client %f\n", $app_time, $client_time);
++ }
++ else {
++ printf("Client time %f matches app time %f\n", $client_time, $app_time)
++;
++ }
++ if(abs($db_time - $app_time) > $epsilon) {
++ printf("Time mismatch: client %f server %f\n", $client_time, $db_time);
++ }
++ else {
++ printf("Reported time %f matches client time %f\n", $db_time, $client_time);
++ }
++ PassThru("rm -f client_time app_time");
++}
++
++?>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/concat_result
+@@ -0,0 +1,13 @@
++<file_info>
++ <name><OUTFILE_0/></name>
++ <generated_locally/>
++ <upload_when_present/>
++ <url><UPLOAD_URL/></url>
++ <max_nbytes>120000</max_nbytes>
++</file_info>
++<result>
++ <file_ref>
++ <file_name><OUTFILE_0/></file_name>
++ <open_name>out</open_name>
++ </file_ref>
++</result>
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/ta_correct_f
+@@ -0,0 +1,2 @@
++blah 17 34.500000
++foo
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/db_def_to_py
+@@ -0,0 +1,16 @@
++#!/usr/bin/env perl
++
++## $Id: db_def_to_py 1528 2003-06-18 03:04:06Z quarl $
++
++## parse the db #defines to php.
++
++## syntax: ./db_def_to_php < ../db/boinc_db.h > boinc_db.inc
++
++print "# Generated by db_def_to_py on ";
++system('date');
++
++while (<>) {
++ if (/^\s*#define\s+([^\s]+)\s+([0-9]+)\s*$/) {
++ print qq/$1 = $2\n/;
++ }
++}
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/small_input
+@@ -0,0 +1 @@
++fjfiwfwnfwieowefnkj
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/db_def_to_php
+@@ -0,0 +1,20 @@
++#!/usr/bin/env perl
++
++## $Id: db_def_to_php 2587 2003-10-28 00:41:04Z quarl $
++
++## parse the db #defines to php.
++
++## syntax: ./db_def_to_php < ../db/boinc_db.h > boinc_db.inc
++
++print "<?php\n";
++print " // Generated by db_def_to_php\n";
++# print " // Generated by db_def_to_php on ";
++# system('date');
++
++while (<>) {
++ if (/^\s*#define\s+([^\s]+)\s+([0-9]+)\s*$/) {
++ print qq/ define("$1", $2);\n/;
++ }
++}
++
++print "?>\n";
+--- /dev/null
++++ boinc-7.0.38+dfsg/test/cgiserver.py
+@@ -0,0 +1,197 @@
++#!/usr/bin/env python
++
++# $Id: cgiserver.py 2680 2003-11-25 07:40:45Z quarl $
++# cgi/php web server
++
++import BaseHTTPServer, CGIHTTPServer
++import sys, os, urllib, select
++import random, time # XXX
++
++php_path = None
++possible_php_paths = [ '/usr/lib/cgi-bin/php4',
++ 'PROGRAM_PATH/fake_php.py' ]
++def setup_php(program_path):
++ global php_path
++ for p in possible_php_paths:
++ p = p.replace('PROGRAM_PATH', program_path)
++ if os.path.exists(p):
++ php_path = p
++ return
++ raise Exception("No php binary found - not even fake_php.py (program_path=%s) !"%program_path)
++
++class PHPHTTPRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler):
++ def is_cgi(self):
++ if os.path.split(self.path)[1] == '':
++ index_php = os.path.join(self.path, 'index.php')
++ if os.path.exists(self.translate_path(index_php)):
++ self.path = index_php
++ if self.path.find('.php') != -1:
++ self.cgi_info = os.path.split(self.path)
++ return True
++
++ for p in self.cgi_directories:
++ p = os.path.join(p,'')
++ if self.path.startswith(p):
++ self.cgi_info = os.path.split(self.path)
++ return True
++ return False
++
++ def run_cgi(self):
++ """Execute a CGI script."""
++ dir, rest = self.cgi_info
++ i = rest.rfind('?')
++ if i >= 0:
++ rest, query = rest[:i], rest[i+1:]
++ else:
++ query = ''
++ i = rest.find('/')
++ if i >= 0:
++ script, rest = rest[:i], rest[i:]
++ else:
++ script, rest = rest, ''
++ scriptname = dir + '/' + script
++ is_php = script.endswith('.php')
++ # print "#### cgi_info=%s,dir=%s,rest=%s,script=%s,scriptname=%s,is_php=%s"%(self.cgi_info,dir,rest,script,scriptname,is_php)
++ if is_php:
++ if not php_path: raise Exception('php_path not set')
++ scriptfile = php_path
++ sourcefile = self.translate_path(scriptname)
++ else:
++ scriptfile = self.translate_path(scriptname)
++ if not os.path.exists(scriptfile):
++ self.send_error(404, "No such CGI script (%s)" % `scriptname`)
++ return
++ if not os.path.isfile(scriptfile):
++ self.send_error(403, "CGI script is not a plain file (%s)" %
++ `scriptname`)
++ return
++ ispy = self.is_python(scriptname)
++ if not ispy:
++ if not (self.have_fork or self.have_popen2 or self.have_popen3):
++ self.send_error(403, "CGI script is not a Python script (%s)" %
++ `scriptname`)
++ return
++ if not self.is_executable(scriptfile):
++ self.send_error(403, "CGI script is not executable (%s)" %
++ `scriptname`)
++ return
++
++ # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html
++ # XXX Much of the following could be prepared ahead of time!
++ env = {}
++ env['DOCUMENT_ROOT'] = os.getcwd()
++ env['SERVER_SOFTWARE'] = self.version_string()
++ env['SERVER_NAME'] = self.server.server_name
++ env['GATEWAY_INTERFACE'] = 'CGI/1.1'
++ env['SERVER_PROTOCOL'] = self.protocol_version
++ env['SERVER_PORT'] = str(self.server.server_port)
++ env['REQUEST_METHOD'] = self.command
++ uqrest = urllib.unquote(self.cgi_info[1])
++ env['REQUEST_URI'] = self.path
++ # env['PATH_INFO'] = uqrest
++ # env['PATH_TRANSLATED'] = self.translate_path(uqrest)
++ env['SCRIPT_NAME'] = scriptname
++ env['SCRIPT_FILENAME'] = self.translate_path(scriptname)
++ if query:
++ env['QUERY_STRING'] = query
++ host = self.address_string()
++ if host != self.client_address[0]:
++ env['REMOTE_HOST'] = host
++ env['REMOTE_ADDR'] = self.client_address[0]
++ env['REDIRECT_STATUS'] = '1' # for php
++ # XXX AUTH_TYPE
++ # XXX REMOTE_USER
++ # XXX REMOTE_IDENT
++ if self.headers.typeheader is None:
++ env['CONTENT_TYPE'] = self.headers.type
++ else:
++ env['CONTENT_TYPE'] = self.headers.typeheader
++ length = self.headers.getheader('content-length')
++ if length:
++ env['CONTENT_LENGTH'] = length
++ accept = []
++ for line in self.headers.getallmatchingheaders('accept'):
++ if line[:1] in "\t\n\r ":
++ accept.append(line.strip())
++ else:
++ accept = accept + line[7:].split(',')
++ env['HTTP_ACCEPT'] = ','.join(accept)
++ ua = self.headers.getheader('user-agent')
++ if ua:
++ env['HTTP_USER_AGENT'] = ua
++ co = filter(None, self.headers.getheaders('cookie'))
++ if co:
++ env['HTTP_COOKIE'] = ', '.join(co)
++ # XXX Other HTTP_* headers
++ if not self.have_fork:
++ # Since we're setting the env in the parent, provide empty
++ # values to override previously set values
++ for k in ('QUERY_STRING', 'REMOTE_HOST', 'CONTENT_LENGTH',
++ 'HTTP_USER_AGENT', 'HTTP_COOKIE'):
++ env.setdefault(k, "")
++ os.environ.update(env)
++
++ self.send_response(200, "Script output follows")
++
++ decoded_query = query.replace('+', ' ')
++
++ if self.have_fork:
++ # Unix -- fork as we should
++ if is_php:
++ args = [php_path, sourcefile]
++ else:
++ args = [script]
++ if '=' not in decoded_query:
++ args.append(decoded_query)
++ self.wfile.flush() # Always flush before forking
++ pid = os.fork()
++ if pid != 0:
++ # Parent
++ pid, sts = os.waitpid(pid, 0)
++ # throw away additional data [see bug #427345]
++ while select.select([self.rfile], [], [], 0)[0]:
++ try:
++ if not self.rfile.read(1):
++ break
++ except:
++ break
++ if sts:
++ self.log_error("CGI script exit status %#x", sts)
++ return
++ # Child
++ try:
++ if 0:
++ time.sleep(.1)
++ fn = '/tmp/a%d'%random.randint(1000,10000)
++ f = open(fn, 'w')
++ s = ''
++ while select.select([self.rfile], [], [], 0)[0]:
++ try:
++ c = self.rfile.read(1)
++ if not c:
++ break
++ s += c
++ except:
++ break
++ print '### input:', repr(s)
++ print >>f, s
++ f.close()
++ self.rfile = open(fn, 'r')
++ os.dup2(self.rfile.fileno(), 0)
++ os.dup2(self.wfile.fileno(), 1)
++ os.chdir(self.translate_path(dir)) # KC
++ os.execve(scriptfile, args, os.environ)
++ except:
++ self.server.handle_error(self.request, self.client_address)
++ os._exit(127)
++
++ else:
++ raise SystemExit('need fork()')
++
++def serve(bind='localhost', port=8000, handler=PHPHTTPRequestHandler):
++ httpd = BaseHTTPServer.HTTPServer((bind,port), handler)
++ httpd.serve_forever()
++
++if __name__ == '__main__':
++ setup_php(os.path.realpath(os.path.dirname(sys.argv[0])))
++ serve()
diff --git a/debian/patches/series b/debian/patches/series
index b3b8f38..491f022 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -68,3 +68,4 @@ boinclib_shared.patch
dynamic_libboinc.patch
Missing_libSched.patch
missing_libs_wrapper.patch
+add-missing-test-files.patch
--
BOINC packaging
More information about the pkg-boinc-commits
mailing list