parse-procs.tcl

ADP to Tcl Compiler for the ArsDigita Templating System,

Location:
packages/acs-templating/tcl/parse-procs.tcl
Authors:
Karl Goldstein
Stanislav Freidin
Jon Salz
CVS Identification:
$Id: parse-procs.tcl,v 1.68 2024/11/13 08:40:51 gustafn Exp $

Procedures in this file

Detailed information

template::adp_abort (public)

 template::adp_abort

Terminates processing of a template and throws away all output.

Partial Call Graph (max 5 caller/called nodes):
%3

Testcases:
No testcase defined.

template::adp_append_code (public)

 template::adp_append_code code [ nobreak ]

Adds a line of code to the Tcl output from the compiler. Called by basically any adp custom tag implementation and also from developer support.

Parameters:
code (required)
A line of Tcl code
nobreak (optional)
Options:
-nobreak
Flag indicating that code should be appended to the current last line rather than adding a new line, for cases where code must continue on the same line, such as the "else" tag.

Partial Call Graph (max 5 caller/called nodes):
%3 test_adp_parse_tags adp_parse_tags (test acs-templating) template::adp_append_code template::adp_append_code test_adp_parse_tags->template::adp_append_code test_template_widget_file template_widget_file (test acs-templating) test_template_widget_file->template::adp_append_code ds_adp_end_box ds_adp_end_box (public) ds_adp_end_box->template::adp_append_code ds_adp_start_box ds_adp_start_box (public) ds_adp_start_box->template::adp_append_code packages/acs-templating/tcl/tag-init.tcl packages/acs-templating/ tcl/tag-init.tcl packages/acs-templating/tcl/tag-init.tcl->template::adp_append_code publish::process_tag publish::process_tag (private) publish::process_tag->template::adp_append_code template::adp_append_string template::adp_append_string (private) template::adp_append_string->template::adp_append_code

Testcases:
template_widget_file, adp_parse_tags

template::adp_append_string (private)

 template::adp_append_string s

Adds a line of code that appends a string to the Tcl output from the compiler.

Parameters:
s (required)
A string containing markup that does not contain any embedded ATS tags. Variable references and procedure calls are interpreted as for any double-quoted string in Tcl.

Partial Call Graph (max 5 caller/called nodes):
%3 packages/acs-templating/tcl/tag-init.tcl packages/acs-templating/ tcl/tag-init.tcl template::adp_append_string template::adp_append_string packages/acs-templating/tcl/tag-init.tcl->template::adp_append_string template::adp_compile_chunk template::adp_compile_chunk (public) template::adp_compile_chunk->template::adp_append_string template::adp_tag_init template::adp_tag_init (private) template::adp_tag_init->template::adp_append_string template::adp_append_code template::adp_append_code (public) template::adp_append_string->template::adp_append_code

Testcases:
No testcase defined.

template::adp_array_variable_regexp (public)

 template::adp_array_variable_regexp

The regexp pattern used to find adp array variables in a piece of text (i.e. @array_name.variable_name@). Captures the character preceding the first @ in \1, the array_name in \2, and variable_name in \3

Author:
Peter Marklund <peter@collaboraid.biz>
Created:
25 October 2002

Partial Call Graph (max 5 caller/called nodes):
%3 test_template_variable template_variable (test acs-templating) template::adp_array_variable_regexp template::adp_array_variable_regexp test_template_variable->template::adp_array_variable_regexp lang::util::convert_adp_variables_to_percentage_signs lang::util::convert_adp_variables_to_percentage_signs (private) lang::util::convert_adp_variables_to_percentage_signs->template::adp_array_variable_regexp lang::util::convert_percentage_signs_to_adp_variables lang::util::convert_percentage_signs_to_adp_variables (private) lang::util::convert_percentage_signs_to_adp_variables->template::adp_array_variable_regexp lang::util::replace_adp_text_with_message_tags lang::util::replace_adp_text_with_message_tags (public) lang::util::replace_adp_text_with_message_tags->template::adp_array_variable_regexp template::adp_compile template::adp_compile (public) template::adp_compile->template::adp_array_variable_regexp

Testcases:
template_variable

template::adp_array_variable_regexp_literal (public)

 template::adp_array_variable_regexp_literal

adp_array_variable_regexp's pattern augmented by "literal"

Author:
Gustaf Neumann
Created:
December 2012

Partial Call Graph (max 5 caller/called nodes):
%3 test_template_variable template_variable (test acs-templating) template::adp_array_variable_regexp_literal template::adp_array_variable_regexp_literal test_template_variable->template::adp_array_variable_regexp_literal template::adp_compile template::adp_compile (public) template::adp_compile->template::adp_array_variable_regexp_literal

Testcases:
template_variable

template::adp_array_variable_regexp_noi18n (public)

 template::adp_array_variable_regexp_noi18n

adp_array_variable_regexp's pattern augmented by "noi18n"

Author:
Gustaf Neumann
Created:
June 2015

Partial Call Graph (max 5 caller/called nodes):
%3 test_template_variable template_variable (test acs-templating) template::adp_array_variable_regexp_noi18n template::adp_array_variable_regexp_noi18n test_template_variable->template::adp_array_variable_regexp_noi18n template::adp_compile template::adp_compile (public) template::adp_compile->template::adp_array_variable_regexp_noi18n

Testcases:
template_variable

template::adp_array_variable_regexp_noquote (public)

 template::adp_array_variable_regexp_noquote

adp_array_variable_regexp's pattern augmented by "noquote"

Author:
Dirk Gomez <openacs@dirkgomez.de>
Created:
12 February 2003

Partial Call Graph (max 5 caller/called nodes):
%3 test_template_variable template_variable (test acs-templating) template::adp_array_variable_regexp_noquote template::adp_array_variable_regexp_noquote test_template_variable->template::adp_array_variable_regexp_noquote lang::util::convert_adp_variables_to_percentage_signs lang::util::convert_adp_variables_to_percentage_signs (private) lang::util::convert_adp_variables_to_percentage_signs->template::adp_array_variable_regexp_noquote lang::util::convert_percentage_signs_to_adp_variables lang::util::convert_percentage_signs_to_adp_variables (private) lang::util::convert_percentage_signs_to_adp_variables->template::adp_array_variable_regexp_noquote lang::util::replace_adp_text_with_message_tags lang::util::replace_adp_text_with_message_tags (public) lang::util::replace_adp_text_with_message_tags->template::adp_array_variable_regexp_noquote template::adp_compile template::adp_compile (public) template::adp_compile->template::adp_array_variable_regexp_noquote

Testcases:
template_variable

template::adp_compile (public)

 template::adp_compile [ -file file ] [ -string string ]

Converts an ADP template into a chunk of Tcl code. Caching this code avoids the need to reparse the ADP template with each request.

Switches:
-file (optional)
The filename of the source
-string (optional)
string to be compiled
Returns:
The compiled code. Valid options are either -string or -file

Partial Call Graph (max 5 caller/called nodes):
%3 test_ad_dimensional ad_dimensional (test acs-templating) template::adp_compile template::adp_compile test_ad_dimensional->template::adp_compile test_template_widget_file template_widget_file (test acs-templating) test_template_widget_file->template::adp_compile test_xowiki_test_cases xowiki_test_cases (test xowiki) test_xowiki_test_cases->template::adp_compile lang::message::lookup lang::message::lookup (public) template::adp_compile->lang::message::lookup lang::util::localize lang::util::localize (public) template::adp_compile->lang::util::localize template::adp_array_variable_regexp template::adp_array_variable_regexp (public) template::adp_compile->template::adp_array_variable_regexp template::adp_array_variable_regexp_literal template::adp_array_variable_regexp_literal (public) template::adp_compile->template::adp_array_variable_regexp_literal template::adp_array_variable_regexp_noi18n template::adp_array_variable_regexp_noi18n (public) template::adp_compile->template::adp_array_variable_regexp_noi18n general_comments_get_comments general_comments_get_comments (public) general_comments_get_comments->template::adp_compile packages/acs-api-browser/www/content-page-view.tcl packages/acs-api-browser/ www/content-page-view.tcl packages/acs-api-browser/www/content-page-view.tcl->template::adp_compile rp_handle_request rp_handle_request (private) rp_handle_request->template::adp_compile template::adp_init template::adp_init (public) template::adp_init->template::adp_compile template::cmp_page_filter template::cmp_page_filter (private) template::cmp_page_filter->template::adp_compile

Testcases:
ad_dimensional, template_widget_file, xowiki_test_cases

template::adp_compile_chunk (public)

 template::adp_compile_chunk chunk

Parses a single chunk of a template. A chunk is either the entire template or the portion of a template contained within a balanced tag. This procedure does not return the compiled chunk; compiled code is assembled in the template::parse_list variable.

Parameters:
chunk (required)
A string containing markup, potentially with embedded ADP tags.

Partial Call Graph (max 5 caller/called nodes):
%3 test_adp_parse_tags adp_parse_tags (test acs-templating) template::adp_compile_chunk template::adp_compile_chunk test_adp_parse_tags->template::adp_compile_chunk template::adp_append_string template::adp_append_string (private) template::adp_compile_chunk->template::adp_append_string template::adp_parse_string template::adp_parse_string (public) template::adp_compile_chunk->template::adp_parse_string template::adp_quote_chunk template::adp_quote_chunk (private) template::adp_compile_chunk->template::adp_quote_chunk packages/acs-templating/tcl/tag-init.tcl packages/acs-templating/ tcl/tag-init.tcl packages/acs-templating/tcl/tag-init.tcl->template::adp_compile_chunk template::adp_compile template::adp_compile (public) template::adp_compile->template::adp_compile_chunk template::adp_parse_tags template::adp_parse_tags (public) template::adp_parse_tags->template::adp_compile_chunk template::template_tag_if_condition template::template_tag_if_condition (private) template::template_tag_if_condition->template::adp_compile_chunk

Testcases:
adp_parse_tags

template::adp_eval (public)

 template::adp_eval coderef

Evaluates a chunk of compiled template code in the calling stack frame. The resulting output is placed in __adp_output in the calling frame, and also returned for convenience.

Parameters:
coderef (required)
Returns:
The output produced by the compiled template code.

Partial Call Graph (max 5 caller/called nodes):
%3 test_ad_dimensional ad_dimensional (test acs-templating) template::adp_eval template::adp_eval test_ad_dimensional->template::adp_eval test_template_widget_file template_widget_file (test acs-templating) test_template_widget_file->template::adp_eval test_xowiki_test_cases xowiki_test_cases (test xowiki) test_xowiki_test_cases->template::adp_eval template::util::lpop template::util::lpop (public) template::adp_eval->template::util::lpop general_comments_get_comments general_comments_get_comments (public) general_comments_get_comments->template::adp_eval rp_handle_request rp_handle_request (private) rp_handle_request->template::adp_eval template::form::generate template::form::generate (private) template::form::generate->template::adp_eval template::list::render template::list::render (public) template::list::render->template::adp_eval template::list::render_row template::list::render_row (private) template::list::render_row->template::adp_eval

Testcases:
ad_dimensional, template_widget_file, xowiki_test_cases

template::adp_include (public)

 template::adp_include [ -uplevel uplevel ] src varlist

return the output of a Tcl/ADP pair as a string. adp_level is set to the calling procedure so that pass by reference works. and example of using this is in the search indexer for various content types:

    bookshelf::book::get -book_id $book_id -array bookdata
    set body [template::adp_include /packages/bookshelf/lib/one-book  [list &book "bookdata" base $base style feed]]
    
The [list &book "bookdata" ...] tells adp_include to pass the book array by reference to the adp include, where it is referred to via @book.field@.

Switches:
-uplevel (optional, defaults to "1")
how far up the stack should the adp_level be set to (default is the calling procedures level)
Parameters:
src (required)
should be the path to the Tcl/ADP pair relative to the server root, as with the src attribute to the include tag.
varlist (required)
a list of {key value key value ... } varlist can also be &var foo for things passed by reference (arrays and multirows)
Returns:
the string generated by the Tcl/ADP pair.
Author:
Jeff Davis davis@xarg.net
Created:
2004-06-02
See Also:

Partial Call Graph (max 5 caller/called nodes):
%3 test_page_contracts page_contracts (test acs-tcl) template::adp_include template::adp_include test_page_contracts->template::adp_include test_templates_and_scripts templates_and_scripts (test acs-templating) test_templates_and_scripts->template::adp_include template::adp_parse template::adp_parse (public) template::adp_include->template::adp_parse template::util::lpop template::util::lpop (public) template::adp_include->template::util::lpop template::util::url_to_file template::util::url_to_file (public) template::adp_include->template::util::url_to_file ad_dimensional ad_dimensional (public) ad_dimensional->template::adp_include apm_build_repository apm_build_repository (private) apm_build_repository->template::adp_include apm_git_build_repository apm_git_build_repository (private) apm_git_build_repository->template::adp_include bug_tracker::search::bug::datasource bug_tracker::search::bug::datasource (private) bug_tracker::search::bug::datasource->template::adp_include callback::user::workspace::impl::acs-subsite callback::user::workspace::impl::acs-subsite (private) callback::user::workspace::impl::acs-subsite->template::adp_include

Testcases:
page_contracts, templates_and_scripts

template::adp_init (public)

 template::adp_init type file_stub

Ensures that both data source Tcl files and compiled ADP templates are wrapped in procedures in the current interpreter. Procedures are cached in byte code form in the interpreter, so this is more efficient than sourcing a Tcl file or parsing the template every time. Also checks the modification time on the source file to ensure that the procedure is up-to-date.

Parameters:
type (required)
Either ADP (template) or Tcl (code)
file_stub (required)
The root (sans file extension) of the absolute path to the .adp or .tcl file to source.

Partial Call Graph (max 5 caller/called nodes):
%3 test_callgraph__bad_page_calls callgraph__bad_page_calls (test acs-api-browser) template::adp_init template::adp_init test_callgraph__bad_page_calls->template::adp_init apm_package_id_from_key apm_package_id_from_key (public) template::adp_init->apm_package_id_from_key parameter::get parameter::get (public) template::adp_init->parameter::get template::adp_compile template::adp_compile (public) template::adp_init->template::adp_compile template::iconset template::iconset (private) template::adp_init->template::iconset template::util::read_file template::util::read_file (public) template::adp_init->template::util::read_file template::adp_parse template::adp_parse (public) template::adp_parse->template::adp_init template::adp_prepare template::adp_prepare (private) template::adp_prepare->template::adp_init template::form::template template::form::template (private) template::form::template->template::adp_init template::list::render_filters template::list::render_filters (public) template::list::render_filters->template::adp_init template::list::render_form_filters template::list::render_form_filters (private) template::list::render_form_filters->template::adp_init

Testcases:
callgraph__bad_page_calls

template::adp_level (public)

 template::adp_level [ up ]

Get the stack frame level at which the template is being evaluated. This is used extensively for obtaining references to data sources, as well template objects such as forms and wizards

Parameters:
up (optional)
A relative reference to the "parse level" of interest. Useful in the context of an included template to reach into the stack frame in which the container template is being parsed, for accessing data sources or other objects. The default is the highest parse level.
Returns:
A number, as returned by [info level], representing the stack frame in which a template is being parsed.

Partial Call Graph (max 5 caller/called nodes):
%3 test_adp_level adp_level (test acs-templating) template::adp_level template::adp_level test_adp_level->template::adp_level Class ::Generic::Form Class ::Generic::Form (public) Class ::Generic::Form->template::adp_level Class ::xowiki::WikiForm Class ::xowiki::WikiForm (public) Class ::xowiki::WikiForm->template::adp_level ad_cache_returnredirect ad_cache_returnredirect (public) ad_cache_returnredirect->template::adp_level ad_form ad_form (public) ad_form->template::adp_level ad_set_element_value ad_set_element_value (private) ad_set_element_value->template::adp_level

Testcases:
adp_level

template::adp_levels (public, deprecated)

 template::adp_levels
Deprecated. Invoking this procedure generates a warning.

Returns:
all stack frame levels
See Also:

Partial Call Graph (max 5 caller/called nodes):
%3 ad_log_deprecated ad_log_deprecated (public) template::adp_levels template::adp_levels template::adp_levels->ad_log_deprecated

Testcases:
No testcase defined.

template::adp_parse (public)

 template::adp_parse __adp_stub __args

Execute procedures to prepare data sources and then to output template. Assumes adp_level is set on entry. in general the public version template::adp_include should be used for generating strings from adp files.

Parameters:
__adp_stub (required)
The root (without the file extension) of the absolute path to the template and associated code.
__args (required)
One list containing any number of key-value pairs passed to an included template from its container. All data sources may be passed by reference.
See Also:

Partial Call Graph (max 5 caller/called nodes):
%3 test_xowiki_test_cases xowiki_test_cases (test xowiki) template::adp_parse template::adp_parse test_xowiki_test_cases->template::adp_parse _ _ (public) template::adp_parse->_ ad_conn ad_conn (public) template::adp_parse->ad_conn ds_collection_enabled_p ds_collection_enabled_p (public) template::adp_parse->ds_collection_enabled_p ds_enabled_p ds_enabled_p (public) template::adp_parse->ds_enabled_p ds_page_fragment_cache_enabled_p ds_page_fragment_cache_enabled_p (public) template::adp_parse->ds_page_fragment_cache_enabled_p ad_return_template ad_return_template (public) ad_return_template->template::adp_parse adp_parse_ad_conn_file adp_parse_ad_conn_file (private) adp_parse_ad_conn_file->template::adp_parse content::deploy content::deploy (public, deprecated) content::deploy->template::adp_parse db_qd_get_fullname db_qd_get_fullname (public) db_qd_get_fullname->template::adp_parse packages/calendar/www/view-list-display.tcl packages/calendar/ www/view-list-display.tcl packages/calendar/www/view-list-display.tcl->template::adp_parse

Testcases:
xowiki_test_cases

template::adp_parse_tags (public)

 template::adp_parse_tags HTML

Parse the tags of the provided HTML text. This function is similar to

template::adp_compile -string $HTML
but it just performs tag substitution, but not ADP variable substitution, since this is done differently in some contextes on the provided HTML chunk. An example for specialized handling is the handling of instance attributes in xowiki.

Parameters:
HTML (required)
text containing potentially ADP tags
Returns:
HTML text with substituted ADP tags

Partial Call Graph (max 5 caller/called nodes):
%3 test_adp_parse_tags adp_parse_tags (test acs-templating) template::adp_parse_tags template::adp_parse_tags test_adp_parse_tags->template::adp_parse_tags ad_log ad_log (public) template::adp_parse_tags->ad_log template::adp_compile_chunk template::adp_compile_chunk (public) template::adp_parse_tags->template::adp_compile_chunk Class ::xowf::test_item::AssessmentInterface Class ::xowf::test_item::AssessmentInterface (public) Class ::xowf::test_item::AssessmentInterface->template::adp_parse_tags adp_parse_ad_conn_file adp_parse_ad_conn_file (private) adp_parse_ad_conn_file->template::adp_parse_tags template::adp_parse_tags_and_localize template::adp_parse_tags_and_localize (private) template::adp_parse_tags_and_localize->template::adp_parse_tags xowf::test_item::AssessmentInterface instproc export_links xowf::test_item::AssessmentInterface instproc export_links (protected) xowf::test_item::AssessmentInterface instproc export_links->template::adp_parse_tags xowf::test_item::AssessmentInterface instproc render_feedback_files xowf::test_item::AssessmentInterface instproc render_feedback_files (public) xowf::test_item::AssessmentInterface instproc render_feedback_files->template::adp_parse_tags

Testcases:
adp_parse_tags

template::adp_parse_tags_and_localize (private)

 template::adp_parse_tags_and_localize HTML

Helper proc to combine "adp_parse_tags" and "lang::util::localize" as used in the regsub operations for resolving template variables.

Parameters:
HTML (required)

Partial Call Graph (max 5 caller/called nodes):
%3 template::adp_compile template::adp_compile (public) template::adp_parse_tags_and_localize template::adp_parse_tags_and_localize template::adp_compile->template::adp_parse_tags_and_localize lang::util::localize lang::util::localize (public) template::adp_parse_tags_and_localize->lang::util::localize template::adp_parse_tags template::adp_parse_tags (public) template::adp_parse_tags_and_localize->template::adp_parse_tags

Testcases:
No testcase defined.

template::adp_prepare (private)

 template::adp_prepare

Executes the code to prepare the data sources for a template. The code is executed in the stack frame of the calling procedure (adp_parse) so that variables are accessible when the compiled template code is executed. If the preparation code executes the set_file command, the procedure will recurse and execute the code for the next template as well.

Returns:
boolean (0 or 1): whether the (ultimate) script was found.

Partial Call Graph (max 5 caller/called nodes):
%3 template::adp_parse template::adp_parse (public) template::adp_prepare template::adp_prepare template::adp_parse->template::adp_prepare template::frm_page_handler template::frm_page_handler (public) template::frm_page_handler->template::adp_prepare ad_script_abort ad_script_abort (public) template::adp_prepare->ad_script_abort template::adp_init template::adp_init (public) template::adp_prepare->template::adp_init

Testcases:
No testcase defined.

template::adp_puts (private)

 template::adp_puts text

Add text to the ADP currently being rendered. Maybe used within escaped Tcl code in the template to add to the output.

Parameters:
text (required)
A string containing text or markup.

Partial Call Graph (max 5 caller/called nodes):
%3

Testcases:
No testcase defined.

template::adp_quote_chunk (private)

 template::adp_quote_chunk chunk_var_name quoted_var_name

Quotes (precedes by backslash) all square brackets, curly braces, double quotes, backslashes, and dollar signs in a chunk of adp.

Parameters:
chunk_var_name (required)
The name of the variable to quote
quoted_var_name (required)
The name of the variable to put the quoted result in
Author:
Peter Marklund <peter@collaboraid.biz>
Created:
2002-10-16

Partial Call Graph (max 5 caller/called nodes):
%3 template::adp_compile_chunk template::adp_compile_chunk (public) template::adp_quote_chunk template::adp_quote_chunk template::adp_compile_chunk->template::adp_quote_chunk template::adp_tag_init template::adp_tag_init (private) template::adp_tag_init->template::adp_quote_chunk

Testcases:
No testcase defined.

template::adp_set_vars (private)

 template::adp_set_vars

Set variables passes from a container template, including onerow and multirow data sources. This code must be executed in the same stack frame as adp_parse, but is in a separate proc to improve code readability.

Partial Call Graph (max 5 caller/called nodes):
%3 _ _ (public) template::adp_level template::adp_level (public) template::adp_set_vars template::adp_set_vars template::adp_set_vars->_ template::adp_set_vars->template::adp_level

Testcases:
No testcase defined.

template::adp_tag_init (private)

 template::adp_tag_init [ tag_name ]

Called at the beginning of every tag handler to flush the ADP buffer of output accumulated from the last tag (or from the beginning of the file).

Parameters:
tag_name (optional)
The name of the tag. Used for debugging purposes only.

Partial Call Graph (max 5 caller/called nodes):
%3 template::adp_append_string template::adp_append_string (private) template::adp_quote_chunk template::adp_quote_chunk (private) template::adp_tag_init template::adp_tag_init template::adp_tag_init->template::adp_append_string template::adp_tag_init->template::adp_quote_chunk

Testcases:
No testcase defined.

template::adp_variable_regexp (public)

 template::adp_variable_regexp

The regexp pattern used to find adp variables in a piece of text, i.e. occurrences of @variable_name@. Captures the character preceding the first @ in \1 and the variable_name in \2.

Author:
Peter Marklund <peter@collaboraid.biz>
Created:
25 October 2002

Partial Call Graph (max 5 caller/called nodes):
%3 test_template_variable template_variable (test acs-templating) template::adp_variable_regexp template::adp_variable_regexp test_template_variable->template::adp_variable_regexp Class ::xowf::test_item::Question_manager Class ::xowf::test_item::Question_manager (public) Class ::xowf::test_item::Question_manager->template::adp_variable_regexp lang::util::convert_adp_variables_to_percentage_signs lang::util::convert_adp_variables_to_percentage_signs (private) lang::util::convert_adp_variables_to_percentage_signs->template::adp_variable_regexp lang::util::convert_percentage_signs_to_adp_variables lang::util::convert_percentage_signs_to_adp_variables (private) lang::util::convert_percentage_signs_to_adp_variables->template::adp_variable_regexp lang::util::replace_adp_text_with_message_tags lang::util::replace_adp_text_with_message_tags (public) lang::util::replace_adp_text_with_message_tags->template::adp_variable_regexp template::adp_compile template::adp_compile (public) template::adp_compile->template::adp_variable_regexp

Testcases:
template_variable

template::adp_variable_regexp_literal (public)

 template::adp_variable_regexp_literal

adp_variable_regexp augmented by "literal"

Author:
Gustaf Neumann
Created:
December 2012

Partial Call Graph (max 5 caller/called nodes):
%3 test_template_variable template_variable (test acs-templating) template::adp_variable_regexp_literal template::adp_variable_regexp_literal test_template_variable->template::adp_variable_regexp_literal template::adp_compile template::adp_compile (public) template::adp_compile->template::adp_variable_regexp_literal

Testcases:
template_variable

template::adp_variable_regexp_noi18n (public)

 template::adp_variable_regexp_noi18n

adp_variable_regexp augmented by "noi18n"

Author:
Gustaf Neumann
Created:
June 2015

Partial Call Graph (max 5 caller/called nodes):
%3 test_template_variable template_variable (test acs-templating) template::adp_variable_regexp_noi18n template::adp_variable_regexp_noi18n test_template_variable->template::adp_variable_regexp_noi18n template::adp_compile template::adp_compile (public) template::adp_compile->template::adp_variable_regexp_noi18n

Testcases:
template_variable

template::adp_variable_regexp_noquote (public)

 template::adp_variable_regexp_noquote

adp_variable_regexp augmented by "noquote"

Author:
Dirk Gomez <openacs@dirkgomez.de>
Created:
12 February 2003

Partial Call Graph (max 5 caller/called nodes):
%3 test_template_variable template_variable (test acs-templating) template::adp_variable_regexp_noquote template::adp_variable_regexp_noquote test_template_variable->template::adp_variable_regexp_noquote lang::util::convert_adp_variables_to_percentage_signs lang::util::convert_adp_variables_to_percentage_signs (private) lang::util::convert_adp_variables_to_percentage_signs->template::adp_variable_regexp_noquote lang::util::convert_percentage_signs_to_adp_variables lang::util::convert_percentage_signs_to_adp_variables (private) lang::util::convert_percentage_signs_to_adp_variables->template::adp_variable_regexp_noquote lang::util::replace_adp_text_with_message_tags lang::util::replace_adp_text_with_message_tags (public) lang::util::replace_adp_text_with_message_tags->template::adp_variable_regexp_noquote template::adp_compile template::adp_compile (public) template::adp_compile->template::adp_variable_regexp_noquote

Testcases:
template_variable

template::current_tag (private)

 template::current_tag

Return the top level tag from the stack.

Returns:
the tag from the top of the tag stack.
Author:
Lee Denison <lee@runtime-collective.com>
Created:
2002-01-30

Partial Call Graph (max 5 caller/called nodes):
%3 packages/acs-templating/tcl/tag-init.tcl packages/acs-templating/ tcl/tag-init.tcl template::current_tag template::current_tag packages/acs-templating/tcl/tag-init.tcl->template::current_tag

Testcases:
No testcase defined.

template::enclosing_tag (private)

 template::enclosing_tag tag

Reach back into the tag stack for the last enclosing instance of a tag. Typically used where the usage of a tag depends on its context, such as the "group" tag within a "multiple" tag.

Parameters:
tag (required)
the type (e.g. multiple) of the enclosing tag to look for.
Returns:
the tag identifier for the enclosing tag
Author:
Lee Denison <lee@runtime-collective.com>
Created:
2002-01-30

Partial Call Graph (max 5 caller/called nodes):
%3 packages/acs-templating/tcl/tag-init.tcl packages/acs-templating/ tcl/tag-init.tcl template::enclosing_tag template::enclosing_tag packages/acs-templating/tcl/tag-init.tcl->template::enclosing_tag

Testcases:
No testcase defined.

template::expand_percentage_signs (public)

 template::expand_percentage_signs message

Expand variables marked with percentage signs in caller's scope. Some examples - if example and array(variable) has the values Erik and Oluf in the caller's scope - the following expansion will occur: Here is an %example% variable. -> Here is an Erik variable. Here is an %array.variable% for you -> Here is an Oluf for you

Parameters:
message (required)
Author:
Christian Hvid

Partial Call Graph (max 5 caller/called nodes):
%3 test_expand_percentage_signs expand_percentage_signs (test acs-templating) template::expand_percentage_signs template::expand_percentage_signs test_expand_percentage_signs->template::expand_percentage_signs lang::message::embedded_vars_regexp lang::message::embedded_vars_regexp (public) template::expand_percentage_signs->lang::message::embedded_vars_regexp template::adp_compile template::adp_compile (public) template::adp_compile->template::expand_percentage_signs

Testcases:
expand_percentage_signs

template::get_attribute (public)

 template::get_attribute tag params name [ default ]

Retrieves a named attribute value from the parameter set passed to a tag handler. If a default is not specified, assumes the attribute is required and throws an error.

Parameters:
tag (required)
The name of the tag.
params (required)
The ns_set passed to the tag handler.
name (required)
The name of the attribute.
default (optional, defaults to "ERROR")
A default value to return if the attribute is not specified in the template. A default value of "ERROR" will cause the proc to throw an error if the attribute wasn't supplied.
Returns:
The value of the attribute.

Partial Call Graph (max 5 caller/called nodes):
%3 packages/acs-templating/tcl/tag-init.tcl packages/acs-templating/ tcl/tag-init.tcl template::get_attribute template::get_attribute packages/acs-templating/tcl/tag-init.tcl->template::get_attribute publish::process_tag publish::process_tag (private) publish::process_tag->template::get_attribute

Testcases:
No testcase defined.

template::set_file (public)

 template::set_file path

Set the path of the template to render. This is typically used to implement multiple "skins" on a common set of data sources. The initial code (which may be in a .tcl file not associated with a .adp file) sets up any number of data sources, and then calls set_file to specify the template to actually render. Any code associated with the specified template is executed in the same stack frame as the initial code, so that each "skin" may reference additional specific data or logic as necessary.

Parameters:
path (required)
The root (sans file extension) of the absolute path to the next template to parse.

Partial Call Graph (max 5 caller/called nodes):
%3 ad_return_template ad_return_template (public) template::set_file template::set_file ad_return_template->template::set_file packages/xolirc/www/portlets/include.tcl packages/xolirc/ www/portlets/include.tcl packages/xolirc/www/portlets/include.tcl->template::set_file packages/xowiki/lib/portlets/include.tcl packages/xowiki/ lib/portlets/include.tcl packages/xowiki/lib/portlets/include.tcl->template::set_file packages/xowiki/www/admin/samples/ajax-chat.tcl packages/xowiki/ www/admin/samples/ajax-chat.tcl packages/xowiki/www/admin/samples/ajax-chat.tcl->template::set_file template::request::is_valid template::request::is_valid (public) template::request::is_valid->template::set_file template::adp_level template::adp_level (public) template::set_file->template::adp_level

Testcases:
No testcase defined.

template::tag_attribute (private)

 template::tag_attribute tag attribute

Return an attribute from a tag that has already been processed.

Parameters:
tag (required)
the tag identifier
attribute (required)
the attribute name
Returns:
the value of the tag's attribute
Author:
Lee Denison <lee@runtime-collective.com>
Created:
2002-01-30

Partial Call Graph (max 5 caller/called nodes):
%3 packages/acs-templating/tcl/tag-init.tcl packages/acs-templating/ tcl/tag-init.tcl template::tag_attribute template::tag_attribute packages/acs-templating/tcl/tag-init.tcl->template::tag_attribute

Testcases:
No testcase defined.
[ hide source ] | [ make this the default ]

Content File Source

ad_library {
    ADP to Tcl Compiler for the ArsDigita Templating System,

    @author Karl Goldstein
    @author Stanislav Freidin
    @author Jon Salz

    @cvs-id $Id: parse-procs.tcl,v 1.68 2024/11/13 08:40:51 gustafn Exp $
}

# Based on the original ADP to Tcl compiler by Jon Salz (jsalz@mit.edu)

# Copyright (C) 1999-2000 ArsDigita Corporation

# This is free software distributed under the terms of the GNU Public
# License.  Full text of the license is available from the GNU Project:
# http://www.fsf.org/copyleft/gpl.html


namespace eval template {}

d_proc -public template::adp_include {
    {-uplevel 1}
    src
    varlist
} {
    return the output of a Tcl/ADP pair as a string.  adp_level is
    set to the calling procedure so that pass by reference works.
    and example of using this is in the search indexer for various content
    types:
    <pre>
    bookshelf::book::get -book_id $book_id -array bookdata
    set body [template::adp_include /packages/bookshelf/lib/one-book \
              [list &book "bookdata" base $base style feed]]
    </pre>

    The [list &book "bookdata" ...] tells adp_include to pass the book array
    by reference to the adp include, where it is referred to via @book.field@.

    @param uplevel how far up the stack should the adp_level be set to
    (default is the calling procedures level)
    @param src should be the path to the Tcl/ADP pair relative to the server root, as
    with the src attribute to the include tag.
    @param varlist a list of {key value key value ... } varlist can also be &var foo
    for things passed by reference (arrays and multirows)

    @return the string generated by the Tcl/ADP pair.

    @author Jeff Davis davis@xarg.net
    @creation-date 2004-06-02

    @see template::adp_parse
} {
    # set the stack frame at which the template is being parsed so that
    # other procedures can reference variables cleanly
    lappend ::template::parse_level [expr {[info level] - $uplevel}]

    set __adp_out [template::adp_parse [template::util::url_to_file $src$varlist]

    # pop off parse level
    template::util::lpop ::template::parse_level

    return $__adp_out
}

ad_proc -public template::adp_parse { __adp_stub __args } {
    Execute procedures to prepare data sources and then to output
    template.  Assumes adp_level is set on entry.  in general the
    public version template::adp_include should be used for generating
    strings from adp files.

    @param __adp_stub   The root (without the file extension) of the
                        absolute path to the template and associated code.
    @param __args       One list containing any number of key-value pairs
                        passed to an included template from its container.
                        All data sources may be passed by reference.
    @see template::adp_include
} {
    # declare any variables passed in to an include or master
    # TODO: call adp_set_vars instead.

    foreach {__key __value} $__args {
        #
        # Keys starting with "&" trigger call by reference.
        #
        if {[string range $__key 0 0] eq "&"} {
            if {"&" ne $__key } {
                set __name [string range $__key 1 end]
            } else {
                set __name $__value
            }
            upvar \#[adp_level$__value $__name \
                $__value:rowcount $__name:rowcount \
                $__value:columns  $__name:columns
            # upvar :rowcount and :columns just in case it is a multirow
            if { [info exists $__name:rowcount] } {
                for { set __i 0 } { $__i <= [set $__name:rowcount] } { incr __i } {
                    upvar \#[adp_level$__value:$__i $__name:$__i
                }
            }
        } else {
            #
            # Key does not start with "&" => normal arg (no reference).
            #
            set $__key $__value
        }
    }

    #
    # Set the stack frame at which the template is being parsed so
    # that other procedures can reference variables cleanly.
    #
    lappend ::template::parse_level [info level]

    # execute the code to prepare the data sources for a template
    set return_code [catch {
        set found_script_p [adp_prepare]

        # if we get here, adp_prepare ran without throwing an error.

        # initialize the ADP output
        set __adp_output ""

        set mime_type [get_mime_type]
        set template_extension [get_mime_template_extension $mime_type]

        #
        # Generate ADP output if a template exists (otherwise assume
        # plain Tcl page)
        #
        set templated_p 0
        if { [ad_conn locale] ne ""
             && [file exists "$__adp_stub.[ad_conn locale].$template_extension"]} {
            # it's a localized version of a templated page
            set templated_p 1
            append __adp_stub ".[ad_conn locale]"
        } elseif {[file exists "$__adp_stub.$template_extension"]} {
            # it's a regular templated page
            set templated_p 1
        }

        if { [namespace which ::ds_page_fragment_cache_enabled_p] ne ""
             && [::ds_enabled_p]
             && [::ds_page_fragment_cache_enabled_p]
             && [::ds_collection_enabled_p] } {
            ns_cache lappend ds_page_bits [ad_conn request] \
                $__adp_stub.$template_extension
        }

        if { $templated_p } {
            #
            # Ensure that template output procedure exists and is
            # up-to-date. By executing the reset, get result of
            # template output procedure into __adp_output, and
            # properties into __adp_properties
            #
            [template::adp_init $template_extension $__adp_stub]

            # JCD: Lets keep a copy of all the page fragments!  WooHoo.
            if { [namespace which ::ds_page_fragment_cache_enabled_p] ne ""
                 && [::ds_enabled_p]
                 && [::ds_page_fragment_cache_enabled_p]
                 && [::ds_collection_enabled_p] } {
                ns_cache set ds_page_bits \
                    "[ad_conn request]:$__adp_stub.$template_extension" $__adp_output
            }

            # call the master template if one has been defined
            if { [info exists __adp_master] } {
                # pass properties on to master template
                set __adp_output [template::adp_parse $__adp_master \
                                      [concat \
                                           [list __adp_slave $__adp_output] \
                                           [array get __adp_properties]]]
            }
        } else {
            #
            # No template; found_script_p tells us if adp_prepare at
            # least found a script.
            #
            if { !$found_script_p } {
                # No template. Perhaps there is an HTML file.
                if { [file exists $__adp_stub.html] } {
                    ns_log debug "getting output from ${__adp_stub}.html"
                    set __adp_output [template::util::read_file "${__adp_stub}.html"]
                } elseif  { [file exists $__adp_stub.htm] } {
                    ns_log debug "getting output from ${__adp_stub}.htm"
                    set __adp_output [template::util::read_file "${__adp_stub}.htm"]
                } else {
                    error "No script or template found for page '$__adp_stub'"
                }
            }
        }

        return $__adp_output                ; # empty in non-templated page
    } return_value]

    set s_errorInfo $::errorInfo
    set s_errorCode $::errorCode

    # Always pop off the parse_level no matter how we exit
    template::util::lpop ::template::parse_level

    switch -- $return_code {
        0 - 2 {
            # CODE executed without a non-local exit -- return what it
            # evaluated to.
            return $return_value
        }
        1 {
            # Error
            return -code error -errorinfo $s_errorInfo -errorcode $s_errorCode $return_value
        }
        default {
            if {$return_value eq "ADP_ABORT"} {
                # return without rendering any HTML if the code aborts
                return ""
            } else {
                return -code $return_code $return_value
            }
        }
    }
}

ad_proc -private template::adp_set_vars {} {
    Set variables passes from a container template, including onerow and
    multirow data sources.  This code must be executed in the same stack frame
    as adp_parse, but is in a separate proc to improve code readability.
} {
    uplevel {
        set __adp_level [adp_level 2]
        foreach {__adp_key __adp_value} $args {

            set __adp_expr {^@([[:alnum:]_]+)\.\*@$}
            if { [regexp  $__adp_expr $__adp_value __adp_x __adp_name] } {

                upvar #$__adp_level $__adp_name $__adp_key
                if { ! [array exists $__adp_key] } {

                    upvar #$__adp_level $__adp_name:rowcount $__adp_key:rowcount

                    if { [info exists $__adp_key:rowcount] } {

                        set size [set $__adp_key:rowcount]

                        for { set i 1 } { $i <= [set $__adp_key:rowcount] } { incr i } {
                            upvar #$__adp_level $__adp_name:$i $__adp_key:$i
                        }
                    }
                }
            } else {
                set $__adp_key $__adp_value
            }
        }
    }
}
# Terminates processing of a template and throws away all output.

ad_proc -public template::adp_abort {} {
    Terminates processing of a template and throws away all output.
} {
    error ADP_ABORT
}

ad_proc -public template::adp_eval { coderef } {
    Evaluates a chunk of compiled template code in the calling stack frame.
    The resulting output is placed in __adp_output in the calling frame,
    and also returned for convenience.

    @return The output produced by the compiled template code.
} {
    upvar $coderef code __adp_output output
    lappend ::template::parse_level [expr {[info level]-1}]

    uplevel $code

    template::util::lpop ::template::parse_level
    return $output
}

ad_proc -public template::adp_level { { up "" } } {
    Get the stack frame level at which the template is being evaluated.
    This is used extensively for obtaining references to data sources,
    as well template objects such as forms and wizards

    @param up A relative reference to the "parse level" of interest.
    Useful in the context of an included template to reach into the
    stack frame in which the container template is being parsed, for
    accessing data sources or other objects.  The default is the
    highest parse level.

    @return A number, as returned by [info level], representing the stack frame
    in which a template is being parsed.
} {
    set result ""

    # when serving a page, this variable is always defined.
    # but we need to check it for the case of isolated compilation

    if { [info exists ::template::parse_level] } {
        if {$up eq ""} {
            set result [lindex $::template::parse_level end]
        } else {
            set result [lindex $::template::parse_level [llength $::template::parse_level]-$up]
        }
    }

    return $result
}


ad_proc -deprecated template::adp_levels {} {
    @return all stack frame levels
    @see template::adp_level
} {
    if { [info exists ::template::parse_level] } {return $::template::parse_level}
    return ""
}

ad_proc -private template::adp_prepare {} {
    Executes the code to prepare the data sources for a template.  The
    code is executed in the stack frame of the calling procedure
    (adp_parse) so that variables are accessible when the compiled
    template code is executed.  If the preparation code executes the
    set_file command, the procedure will recurse and execute the code
    for the next template as well.

    @return boolean (0 or 1): whether the (ultimate) script was found.
} {
    uplevel {

        if { [file exists $__adp_stub.tcl] } {

            # Remember the file_stub in case the procedure changes it
            set __adp_remember_stub $__adp_stub

            # Ensure that data source preparation procedure exists and
            # is up-to-date and execute it.
            [adp_init tcl $__adp_stub]

            # propagate aborting
            if {[info exists ::request_aborted]} {
                ns_log warning "propagating abortion from $__adp_remember_stub.tcl" \
                    "(status [lindex $::request_aborted 0]:"\
                    "'[lindex $::request_aborted 1]'"
                unset ::request_aborted
                ad_script_abort
                #adp_abort
                return 0
            }

            # if the file has changed then prepare again
            if { $__adp_stub ne $__adp_remember_stub } {
                adp_prepare          ;# propagate result up
            } { return 1 }
        }
        return 0
    }
}

ad_proc -public template::set_file { path } {
    Set the path of the template to render.  This is typically used to
    implement multiple "skins" on a common set of data sources.  The
    initial code (which may be in a .tcl file not associated with a .adp
    file) sets up any number of data sources, and then calls set_file to
    specify the template to actually render.  Any code associated with
    the specified template is executed in the same stack frame as the
    initial code, so that each "skin" may reference additional specific
    data or logic as necessary.

    @param path The root (sans file extension) of the absolute path to the
    next template to parse.
} {
    set level [adp_level]

    upvar #$level __adp_stub file_stub
    set file_stub $path
}

ad_proc -public template::adp_init { type file_stub } {
    Ensures that both data source Tcl files and compiled ADP templates
    are wrapped in procedures in the current interpreter.  Procedures
    are cached in byte code form in the interpreter, so this is more
    efficient than sourcing a Tcl file or parsing the template every
    time.  Also checks the modification time on the source file to
    ensure that the procedure is up-to-date.

    @param type       Either ADP (template) or Tcl (code)
    @param file_stub  The root (sans file extension) of the absolute path
                      to the .adp or .tcl file to source.
} {
    #
    # Depending on the iconset, the result of the compiled template
    # might be different. So, cache per iconset
    #
    set cache [iconset]-$type
    #
    # Check, if the compiled proc exists already.
    #
    set proc_name [namespace which ::template::mtimes::${cache}::$file_stub]
    #ns_log notice "$type $file_stub -> '$proc_name'"
    
    set pkg_id [apm_package_id_from_key acs-templating]
    set refresh_cache [parameter::get \
                           -package_id $pkg_id \
                           -parameter RefreshCache \
                           -default "as needed"]

    if {$proc_name eq "" || $refresh_cache ne "never" } {
        set mtime [file mtime $file_stub.$type]
        if {$proc_name eq ""
            || $mtime != [$proc_name]
            || $refresh_cache eq "always"} {
            #
            # Either the procedure does not already exist or is not
            # up-to-date
            #
            namespace eval ::template::code::${cache} {}
            switch -exact $type {

                tcl {
                    set code [template::util::read_file $file_stub.tcl]
                }
                default {
                    set code [adp_compile -file $file_stub.$type]
                }
            }
            #ns_log notice "$type $file_stub -> compiled '$code'"

            #
            # Wrap the code for both types of files within an uplevel
            # in the declared procedure, so that data sources are set
            # in the same frame as the code that outputs the template.
            #
            # Here we add profiling calls if developer support exists
            # on the system.
            #
            if {[namespace which ::ds_enabled_p] ne ""} {
                proc ::template::code::${cache}::$file_stub {} "if {\[::ds_enabled_p\] && \[::ds_collection_enabled_p\] && \[::ds_profiling_enabled_p\]} { ds_profile start $file_stub.$type }
uplevel {
    $code
}
if {\[::ds_enabled_p\] && \[::ds_collection_enabled_p\] &&\[::ds_profiling_enabled_p\]} { ds_profile stop $file_stub.$type }\n"
      } else {
        proc ::template::code::${cache}::$file_stub {} "
uplevel {
    $code
}\n"
      }
      namespace eval ::template::mtimes::${cache} {}
      proc ::template::mtimes::${cache}::$file_stub {} "return $mtime"
    }
  }
  return ::template::code::${cache}::$file_stub
}

ad_proc -public template::expand_percentage_signs { message } {
    Expand variables marked with percentage signs in caller's scope.

    Some examples - if example and array(variable) has the values Erik
    and Oluf in the caller's scope - the following expansion will occur:

    Here is an %example% variable. -> Here is an Erik variable.
    Here is an %array.variable% for you -> Here is an Oluf for you

    @author Christian Hvid

} {
    set remaining_message $message
    set formatted_message ""
    while { [regexp [lang::message::embedded_vars_regexp$remaining_message \
                 match before_percent percent_match remaining_message] } {
        append formatted_message $before_percent

        if {$percent_match eq "%%"} {
            # A quoted percentage sign
            set substitution "%"
        } else {
            # An embedded variable

            # Remove any noquote instruction
            set quote_p 1
            if { [regsub {;noquote} $percent_match {} substitution] } {
                # We removed a noquote instruction so don't quote
                set quote_p 0
            }

            # Convert syntax to Tcl syntax:
            # It's either an array variable or a Tcl variable
            #   array variables
            # TODO: ns_quotehtml
            # TODO: lang::util::localize
            regsub -all -- {[\]\[\{\}\"]\\$} $substitution {\\&} substitution
            if { [regexp {^%([[:alnum:]_]+)\.([[:alnum:]_]+)%$} $substitution match arr key] } {
                # the array key name is substitured by the Tcl parser s
                regsub -all -- {[\]\[\{\}\"]\\$} $key {\\&} key
                set command "set ${arr}(${key})"
                set substitution [uplevel $command]
            }
            if { [regexp {^%([[:alnum:]_:]+)%$} $substitution match var] } {
                set command "set $var"
                set substitution [uplevel $command]
            }
            if {$quote_p} {
                set substitution [ns_quotehtml $substitution]
            }
        }

        append formatted_message $substitution
    }

    append formatted_message $remaining_message

    return $formatted_message
}

d_proc -public template::adp_compile {
    {-file ""}
    {-string ""}
} {
    Converts an ADP template into a chunk of Tcl code.  Caching this code
    avoids the need to reparse the ADP template with each request.

    @param file The filename of the source
    @param string string to be compiled
    @return The compiled code.

    Valid options are either -string or -file
} {
    variable parse_list
    # initialize the compiled code
    set parse_list [list "set __adp_output {}; set __ad_conn_locale \[ad_conn locale\]"]

    if {$file ne "" && $string ne ""} {
        error "you must specify either -file or -string"
    } elseif {$file ne ""} {
        set chunk [template::util::read_file $file]
    } else {
        set chunk $string
    }

    # substitute <% ... %> blocks with registered tags so they can be handled
    # by our proc rather than evaluated.

    regsub -all -- {<%} $chunk {<tcl>} chunk
    # avoid substituting when it is a percentage attribute to an HTML tag.
    regsub -all -- {([^0-9])%>} $chunk {\1</tcl>} chunk
    # warn about the first ambiguity in the source
    if {[regexp {[0-9]+%>} $chunk match]} {
        ns_log warning "ambiguous '$match'; write Tcl escapes with a space like" \
            {<% set x 50 %> and HTML tags with proper quoting, like <hr width="50%">} \
            "when compiling ADP source: " \
            [list template::adp_compile -file $file -string $string]
    }

    # recursively parse the template
    adp_compile_chunk $chunk

    # ensure that code returns with the output
    lappend parse_list "set __adp_output"

    # the parse list now contains the code
    set code [join $parse_list "\n"]

    #ns_log notice "CODE before i18n\n$code\n"

    # Substitute #foo# message keys with values from the message catalog

    # Since messages may read the variables of the adp page they go through
    # expand_percentage_signs which amongst other things does an uplevel subst
    while {[regsub -all \
                {([^\\])\#([-[:alnum:]_:]+[.][-[:alnum:]_:]+)\#} \
                $code \
                {\1[template::expand_percentage_signs [lang::message::lookup $__ad_conn_locale {\2} {TRANSLATION MISSING} {} -1]]} \
                code]} {}

    #
    # We do each substitution set in several pieces, separately for
    # normal variables and for variables having ";noquote", ";no18n",
    # and ";literal" attached to them.  Specifically, @x@ gets
    # translated to [ns_quotehtml ${x}], whereas @x;noquote@ gets
    # translated to ${x}.  The same goes for array variable
    # references.
    #
    # The approach with several regexp operations can be optimized,
    # but since this is happening only at ADP compile time, this does
    # not seem critical.

    # substitute array variable references
    while {[regsub -all -- [adp_array_variable_regexp_noquote] $code {\1[template::adp_parse_tags_and_localize $\2(\3)]} code]} {}
    while {[regsub -all -- [template::adp_array_variable_regexp_noi18n$code {\1[ns_quotehtml $\2(\3)]} code]} {}
    while {[regsub -all -- [template::adp_array_variable_regexp_literal$code {\1$\2(\3)} code]} {}
    while {[regsub -all -- [template::adp_array_variable_regexp$code {\1[ns_quotehtml [lang::util::localize $\2(\3)]]} code]} {}

    # substitute simple variable references
    while {[regsub -all -- [adp_variable_regexp_noquote] $code {\1[template::adp_parse_tags_and_localize ${\2}]} code]} {}
    while {[regsub -all -- [template::adp_variable_regexp_noi18n$code {\1[ns_quotehtml ${\2}]} code]} {}
    while {[regsub -all -- [template::adp_variable_regexp_literal$code {\1${\2}} code]} {}
    while {[regsub -all -- [template::adp_variable_regexp$code {\1[ns_quotehtml [lang::util::localize ${\2}]]} code]} {}


    # unescape protected "#" and "@" references
    set code [string map { \\@ @ \\# #} $code]

    return $code
}

ad_proc -public template::adp_array_variable_regexp {} {
    The regexp pattern used to find adp array variables in
    a piece of text (i.e. @array_name.variable_name@). Captures the character preceding
    the first @ in \1, the array_name in \2, and variable_name in \3

    @author Peter Marklund (peter@collaboraid.biz)
    @creation-date 25 October 2002
} {
    return {(^|[^\\])@([[:alnum:]_:]+)\.([[:alnum:]_\.:]+)@}
}

ad_proc -public template::adp_array_variable_regexp_noquote {} {
    adp_array_variable_regexp's pattern augmented by "noquote"

    @author Dirk Gomez (openacs@dirkgomez.de)
    @creation-date 12 February 2003
} {
    return {(^|[^\\])@([[:alnum:]_:]+)\.([[:alnum:]_:\.]+);noquote@}
}

ad_proc -public template::adp_array_variable_regexp_literal {} {
    adp_array_variable_regexp's pattern augmented by "literal"

    @author Gustaf Neumann
    @creation-date December 2012
} {
    return {(^|[^\\])@([[:alnum:]_:]+)\.([[:alnum:]_:\.]+);literal@}
}

ad_proc -public template::adp_array_variable_regexp_noi18n {} {
    adp_array_variable_regexp's pattern augmented by "noi18n"

    @author Gustaf Neumann
    @creation-date June 2015
} {
    return {(^|[^\\])@([[:alnum:]_:]+)\.([[:alnum:]_:\.]+);noi18n@}
}

ad_proc -public template::adp_variable_regexp {} {
    The regexp pattern used to find adp variables in
    a piece of text, i.e. occurrences of @variable_name@.
    Captures the character preceding the first @ in \1 and
    the variable_name in \2.

    @author Peter Marklund (peter@collaboraid.biz)
    @creation-date 25 October 2002
} {
    return {(^|[^\\])@([[:alnum:]_:]+)@}
}

ad_proc -public template::adp_variable_regexp_noquote {} {
    adp_variable_regexp augmented by "noquote"

    @author Dirk Gomez (openacs@dirkgomez.de)
    @creation-date 12 February 2003
} {
    return {(^|[^\\])@([[:alnum:]_:]+);noquote@}
}

ad_proc -public template::adp_variable_regexp_literal {} {
    adp_variable_regexp augmented by "literal"

    @author Gustaf Neumann
    @creation-date December 2012
} {
    return {(^|[^\\])@([[:alnum:]_:]+);literal@}
}

ad_proc -public template::adp_variable_regexp_noi18n {} {
    adp_variable_regexp augmented by "noi18n"

    @author Gustaf Neumann
    @creation-date June 2015
} {
    return {(^|[^\\])@([[:alnum:]_:]+);noi18n@}
}

ad_proc -public template::adp_compile_chunk { chunk } {
    Parses a single chunk of a template.  A chunk is either the entire
    template or the portion of a template contained within a balanced
    tag.  This procedure does not return the compiled chunk; compiled
    code is assembled in the template::parse_list variable.

    @param chunk   A string containing markup, potentially with embedded
    ADP tags.
} {
    # parse the template chunk inside the tag
    set remaining [adp_parse_string $chunk]

    # add everything from either the beginning of the chunk or the
    # last balanced tag in the chunk to the list

    if { ! [string is space $remaining] } {
        adp_quote_chunk remaining remaining_quoted
        adp_append_string $remaining_quoted
    }
}

ad_proc -public template::adp_parse_tags {HTML} {

    Parse the tags of the provided HTML text.  This function is
    similar to

    <blockquote>
       template::adp_compile -string $HTML
    </blockquote>

    but it just performs tag substitution, but not ADP variable
    substitution, since this is done differently in some contextes on
    the provided HTML chunk.  An example for specialized handling is
    the handling of instance attributes in xowiki.

    @param HTML text containing potentially ADP tags
    @return HTML text with substituted ADP tags
} {
    #
    #ns_log notice "adp_parse_tags BEGIN [info exists ::template::parse_list]: $HTML"
    if {[string is space $HTML]} {
        return $HTML
    }
    set old_parse_list [expr {[info exists ::template::parse_list] ? $::template::parse_list : ""}]
    set ::template::parse_list ""
    #
    # The following exception handler is just for safety to achieve a
    # high-level of backward compatibility. In case
    # "adp_compile_chunk" and or the evaluation of the resulting code
    # fails, fall back to the original behavior without ADP tag
    # substitution.
    #
    try {
        template::adp_compile_chunk $HTML
        lappend ::template::parse_list {set __adp_output}
        #ns_log notice "adp_parse_tags parse list '[join $::template::parse_list \n]'"
        set HTML [eval [join $::template::parse_list \n]]
    } on error {errorMsg} {
        ad_log warning "adp_parse_tags failed on parsing:\n'$HTML'"
    }
    set ::template::parse_list $old_parse_list
    #ns_log notice "adp_parse_tags END: $HTML"
    return $HTML
}

ad_proc -private template::adp_parse_tags_and_localize {HTML} {

    Helper proc to combine "adp_parse_tags" and "lang::util::localize"
    as used in the regsub operations for resolving template variables.

} {
    if {$HTML ne ""} {
        #ns_log notice "YYYY adp_parse_tags_and_localize called with '$HTML'"
        return [::lang::util::localize [adp_parse_tags $HTML]]
    }
}


ad_proc -private template::adp_quote_chunk { chunk_var_name quoted_var_name } {
    Quotes (precedes by backslash) all square brackets, curly braces,
    double quotes, backslashes, and dollar signs in a chunk of adp.

    @param chunk_var_name  The name of the variable to quote
    @param quoted_var_name The name of the variable to put the quoted result in

    @author Peter Marklund (peter@collaboraid.biz)

    @creation-date 2002-10-16
} {
    upvar $chunk_var_name chunk $quoted_var_name quoted

    regsub -all -- {[\]\[\{\}\"\\$]} $chunk {\\&} quoted
}

ad_proc -private template::adp_append_string { s } {
    Adds a line of code that appends a string to the Tcl output
    from the compiler.

    @param s   A string containing markup that does not contain any embedded
    ATS tags.  Variable references and procedure calls are
    interpreted as for any double-quoted string in Tcl.
} {
    adp_append_code "append __adp_output \"$s\""
}

ad_proc -public template::adp_append_code { code { nobreak "" } } {
    Adds a line of code to the Tcl output from the compiler.

    Called by basically any adp custom tag implementation and also
    from developer support.

    @param code       A line of Tcl code

    @option nobreak   Flag indicating that code should be appended to the
    current last line rather than adding a new line, for
    cases where code must continue on the same line, such
    as the "else" tag.
} {
    if { [string is space $code] } { return }

    variable parse_list

    if {$nobreak eq "-nobreak"} {

        set last_line [lindex $parse_list end]
        append last_line $code"
        lset parse_list end $last_line

    } else {

        lappend parse_list $code
    }
}

ad_proc -private template::adp_puts { text } {
    Add text to the ADP currently being rendered.  Maybe used within escaped
    Tcl code in the template to add to the output.

    @param text A string containing text or markup.
} {
    upvar __adp_output __adp_output

    append __adp_output $text
}

ad_proc -private template::adp_tag_init { {tag_name ""} } {
    Called at the beginning of every tag handler to flush the ADP buffer of
    output accumulated from the last tag (or from the beginning of the file).

    @param tag_name  The name of the tag.  Used for debugging purposes only.
} {
    # add everything either from the beginning of the template or from
    # the last balanced tag up to the current point in the template

    set chunk [ns_adp_dump]

    if { ! [string is space $chunk] } {
        adp_quote_chunk chunk chunk_quoted
        adp_append_string $chunk_quoted
    }

    # flush the output buffer so that the next dump will only catch
    # the next chunk of the template

    ns_adp_trunc
}

d_proc -private template::tag_attribute {
    tag
    attribute
} {
    Return an attribute from a tag that has already been processed.

    @author Lee Denison (lee@runtime-collective.com)
    @creation-date 2002-01-30

    @return the value of the tag's attribute
    @param tag the tag identifier
    @param attribute the attribute name
} {
    return [ns_set iget $tag $attribute]
}

ad_proc -private template::current_tag {} {
    Return the top level tag from the stack.

    @author Lee Denison (lee@runtime-collective.com)
    @creation-date 2002-01-30

    @return the tag from the top of the tag stack.
} {
    variable tag_stack

    return [lindex $tag_stack end 1]
}

d_proc -private template::enclosing_tag {
    tag
} {
    Reach back into the tag stack for the last enclosing instance of a tag.

    Typically used where the usage of a tag depends on its context, such
    as the "group" tag within a "multiple" tag.

    @author Lee Denison (lee@runtime-collective.com)
    @creation-date 2002-01-30

    @return the tag identifier for the enclosing tag
    @param tag the type (e.g. multiple) of the enclosing tag to look for.
} {
    set name ""

    variable tag_stack

    set last [expr {[llength $tag_stack] - 2}]

    for { set i $last } { $i >= 0 } { incr i -1 } {

        set pair [lindex $tag_stack $i]

        if {[lindex $pair 0] eq $tag} {
            set name [lindex $pair 1]
            break
        }
    }

    return $name
}

ad_proc -public template::get_attribute { tag params name { default "ERROR" } } {
    Retrieves a named attribute value from the parameter set passed to a
    tag handler.  If a default is not specified, assumes the attribute
    is required and throws an error.

    @param tag      The name of the tag.
    @param params   The ns_set passed to the tag handler.
    @param name     The name of the attribute.
    @param default  A default value to return if the attribute is
    not specified in the template. A default value of
    "ERROR" will cause the proc
    to throw an error if the attribute wasn't supplied.

    @return The value of the attribute.
} {
    set value [ns_set iget $params $name]

    if {$value eq ""} {
        if { $default eq "ERROR" } {
            error "Missing [string toupper $name] property\
             in [string toupper $tag] tag"
        } else {
            set value $default
        }
    }

    return $value
}

#
# Local variables:
#    mode: tcl
#    tcl-indent-level: 4
#    indent-tabs-mode: nil
# End: