This document contains technical notes on using cgi.tcl. This document is a draft and has not been officially reviewed.
This document assumes that you have read the Tcl '96 paper "CGI Scripting in Tcl". That document will give you the feel for what this code is all about. In contrast, this document provides the details.
This document assumes you know HTML. I'm not going to explain what particular tags do or how to use them effectively, except as necessary to understand the document.
Some of the commands may not work with all browsers. For example, the cgi_center command is generally understood only by some Netscape browsers because it produces <center></center> tags which are not commonly supported. You'll have to use your judgement. Remember: Just because a command exists to produce the HTML doesn't mean your browser will do anything meaningful with it. In that sense, using this code is no different than handcoding HTML.
All procedures are named cgi_XXX. You can also call them without the cgi_ prefix. Using the cgi_XXX form is no big deal for rarely used procedures, but the aliases are particularly convenient for things like hr and br. Aliases are suppressed if procedures exist by those names already. (Thus,
cgi_eval cannot be invoked as "eval"!) Similarly, you can overwrite the aliases with impunity. Internally, references are only made to the cgi_ names.
I'm still thinking about this. If you have strong feelings about it, let me know.
I frequently see statements saying that Tcl (and other interpretive languages, for that matter) are insecure and should not be used for writing CGI.
I disagree. It is possible to use Tcl securely and it really isn't very hard. The key, of course, is to not blindly evaluate user input. There really isn't much reason to. For instance, this library itself is pretty big and does lots of things, but nothing in it evaluates user input. (It does do a lot of evaluation of programmer input, but that's quite acceptable.)
The two classes of commands you should pay close attention to are commands that do eval operations and commands that invoke external programs.
There are several basic styles of parameter passing.
The last argument is typically a block of code. Other arguments = become attributes. For example:
cgi_body bgcolor=red background=white { h4 "hello" }
produces:
<body bgcolor="red" background="white"> <h4>hello</h4> </body>
Some commands have required arguments. Required arguments which are relatively long, are passed after all others. For example:
cgi_h4 align=left "Foo's Bar & Grill"
Another example:
cgi_body bgcolor=red background=white { cgi_h4 "Foo's Bar & Grill" }
Commands with relatively short arguments have the short arguments passed before all others. This avoids many redundant keywords. In the following example, the "img=" is omitted because it is already implied by the command. The "alt=" is not optional (although the entire argument is).
cgi_img foo.gif "alt=Foo's Bar & Grill"
Note the quotes around the alt argument. This is only necessary if the argument has whitespace in it - a consequence of Tcl's normal scanning rules. The resulting HTML automatically includes quotes around the value attribute. (See Case-sensitivity.)
Attribute names are case sensitive. Use lowercase names for "normal" handling. For example, values for attributes such as "url" and "value" are quoted and encoded. Use uppercase names to suppress the usual processing. (For example, you might want to test how a browser responds to incorrect HTML.)
Consider:
cgi_body bgcolor=#123456 { cgi_img foo.gif "alt=Foo's Bar & Grill" }
This is translated to
<body bgcolor="#123456"> <img url="foo.gif" alt="Foo's Bar & Grill"> </body>
Notice how the ampersand in the alt value has been encoded. Also notice how quotes have been added to the values of bgcolor, url, and alt. Thus you no longer have to add quotes all over the place (or remember when you need to).
Many commands produce tags that use "name" and "value" attributes. Because these attributes are almost always used in such commands, the first argument is always of the form name=value so the literal "name" and "value" can be omitted. For example:
cgi_text color=Red size=5
produces:
<input name="color" value="Red" size=5>
Reasonable defaults exist. For example, if you don't need the value of a submit button (but the user still needs to see it appear as the label), omit the name:
cgi_submit_button =Execute
If no "=" is present, the string is assumed to be the "name" attribute. For example:
cgi_checkbox Vegies
produces a checkbox associated with the variable named "Vegies". (With no specified value, it will be set to "on" if checked.)
Most of the commands have reasonable defaults. For example, to quickly script a submit button, the following suffices:
cgi_submit_button
Certain constructions make no sense and are therefore disallowed. For example, a submit button with a name but no value makes no sense, so cgi_submit_button doesn't allow it. (In other words, if you provide an argument, it has to have "=" in it.)
JavaScript event attributes such as onClick are handled just like any other attributes in terms of quoting and case sensitivity. Because there are so many attributes on so many tags, they are not documented explicitly in this manual. However, they are all supported. Here is an example:
cgi_text age=18 onChange=MinimumAge(this.form.age)
You can interactively run and debug CGI scripts by simply running them from the shell, or a Tcl or C debugger. (For convenience, I use Expect instead of tclsh just so that I get the debugger.) In fact, I've never had to resort to the C debugger. However, simply watching the raw output from a shell is very handy. This catches the really basic errors such as incorrect protections, incorrect #! line, etc. Once your script is actually executing, you can rely on cgi_eval (see below).
cgi_uid_check user
Typically, a CGI script is intended to run from a particular uid, such as "nobody". If you run such scripts interactively, you can end up with conflicts. For example, if the script creates files, files can accidentally end up being owned by you.
cgi_uid_check is a convenient mechanism to warn against this problem. Simply call cgi_uid_check in your script. The argument is the uid under which the script should be running. If the given uid does not match the actual uid,
cgi_uid_check will generate an error.
cgi_eval
cgi_eval is the primary error catching/reporting mechanism. Execute commands from cgi_eval so that errors can be caught and reported in a nice way. By default, errors are emailed back to the administrator. "cgi_debug -on" makes errors be immediately viewable in the browser.
cgi_error_occurred
cgi_error_occurred returns 1 if an error occurred and was caught by cgi_eval. This separate function simplifies exit handling - for example, rather than always checking the return value of cgi_eval, an app can just test this from a redefined exit.
cgi_admin_mail_addr addr
cgi_admin_mail_addr sets the administrator's email address. Diagnostics are sent via email if a problem is encountered = with the script and debugging is not enabled.
cgi_name name
cgi_name defines a name for the service. If called with no arguments, the name is returned. The name is currently used in the following places:
- If email is sent, it comes from [cgi_name].
- If errors are emailed, the subject is "[cgi_name]: CGI problem"
cgi_debug args
cgi_debug provides rudimentary support for generating debugging messages. Here are some example calls:
cgi_debug cmd
If debugging is on, the command is evaluated. For example:
cgi_debug { h2 "completed initialization" }or
cgi_debug {h2 "completed initialization"}Note this is more than simply calling h2. Context is rewound or forwarded to get to a place where this is safe. (And conversely, this call can suppress things such as header elements that haven't been processed yet.) The flag "-noprint" suppresses this manipulation - this is useful for early code that causes no printing.
The -- flag causes the next argument to treated as a = command even if it looks like another flag.
cgi_debug -on
Enables debugging messages. This includes debugging messages generated by explicit calls to cgi_debug as well as implicit diagnostics, for example, that report on form input.
cgi_debug -temp text
Enable debugging for this one line.
cgi_debug -off
Disable debugging. cgi_debug always returns the old setting ("-on" or "-off"). The initial value is -off.
cgi_parray arrayname
cgi_parray prints out the elements of a Tcl array.
cgi_parrayis just like Tcl's parray except that its output is appropriately formatted for a browser.
Typically, the basic structure of most CGI scripts is:
package require cgi cgi_eval { cgi_http_head {cmds} cgi_html { cgi_head {cmds} cgi_body {cmds} } }
Much of this can be omitted, however. In fact, a typical script looks more like this:
package require cgi cgi_eval { cgi_title "title" cgi_body { cmds } }
(If you're not using the Tcl package support, replace the 'package require' command with a 'source' command of the specific file containing the cgi.tcl source.)
(The "...." in the examples above should be replaced by the true path to the cgi.tcl file.)
I'll now go through each of these in more detail as well as some other possibilities for the overall structure.
cgi_http_head cmds
CGI scripts must produce various headers to explain how the remainder of the output is to be interpreted. No other output may preceed this!
With no argument, an HTML content type is produced if the script is running in the CGI environment. This means that most people need not bother calling cgi_http_head. However, if you want to see the HTTP headers and you are not running in the CGI environment, you should call cgi_http_head explicitly. (Alternatively, you can make it appear that you are in the CGI environment by defining the environment variable REQUEST_METHOD.)
The remaining commands in this section may be used in cgi_http_head. Most should be intuitively obvious and thus need no explanation.
cgi_content_type type
Generates a "Content-type:" header. With no argument, cgi_content_type generates a declaration for HTML. If specified, the 'type' argument should be the full MIME-style type/subtype declaration. Any MIME-style parameters should be included in the type argument.
cgi_redirect location
Generates a redirect header (Status:/Location:/URI:)
cgi_target
Generates a "Window-target:" header.
cgi_refresh seconds url
Generates a "Refresh:" header. The url argument is optional.
cgi_pragma pragma
Generates a "Pragma:" header.
cgi_status number string
Generates a "Status:" header.
cgi_cookie_set name=val args
Define a cookie with given name, value, and other arguments. Cookie values are automatically encoded to protect odd characters.
A couple expirations are predefined (with intuitive meaning):
expires=never expires=now expires=...actual date...Here are some examples:
cgi_cookie_set user=don domain=nist.gov expires=never cgi_cookie_set user=don expires=now secure
cgi_export_cookie name args
Export the named Tcl variable as a cookie. Other arguments are processed as with cgi_cookie_set.
Cookies may be read only after calling cgi_input. The = following routines read cookie names or specific cookies.
cgi_cookie_list
Returns the list of all cookies supplied by the server.
cgi_cookie_get name
Returns the value of the named cookie. If multiple values exists the most specific path mapping is used.
If the "-all" flag is used (before the cookie name), a list is returned containing all cookie values for the given name. The list is ordered most-specific (path mapping) to least. I.e., the first value on the list is the same one returned by calling cgi_cookie get without a flag.
cgi_import_cookie name
Define a Tcl variable with the value of the cookie of the same name. For example, the following command retrieves the cookie named "Password" and stores it in the Tcl variable "Password".
cgi_import_cookie Password
cgi_import_filename flag name
Uploaded files are saved on the CGI server. To avoid collisions with other file upload instances, files are not stored in their original names. The name of the file as it is stored on the CGI server is retrieved using the "-server" flag. The original name of the file as it was stored on the user's host is retrieved using the "-client" flag.
Uploaded files are the responsibility of the CGI programmer. In particular, if you do not delete them, they will remain until /tmp is cleaned up in some other way.
If the user does not enter a filename, an empty file will be delivered with a null remote filename.
For example, the following code echos the contents of a file that = was uploaded using the variable "file":
cgi_input cgi_body { set server [cgi_import_filename -server $v] set client [cgi_import_filename -client $v] if [string length $client] { h4 "Uploaded: $client, contents:" cgi_preformatted {puts [exec cat $server]} } exec /bin/rm -f $server }The present implementation supports binary upload only if you are using the Expect extension. If you are using Expect but want to suppress binary loading, create the global variable _cgi(no_binary_upload). (The reason you might want to suppress binary loading is that it is noticably slower.)
cgi_html
<html></html> tags can be generated using cgi_html. An argument to cgi_html is evaluated to produce the actual HTML code.
In practice, it is not necessary to use cgi_html. CGI.tcl will automatically generate the tags when appropriate. (Oddly, modern HTML specs don't require it and most if not all browsers never cared anyway.)
cgi_doctype
cgi_doctype is a user-defined procedure that produces a SGML DOCTYPE declaration. If it exists, cgi_doctype is automatically invoked at the beginning of cgi_html. (This library does not automatically create DOCTYPE declarations since the library is not restricted to generating SGML for any single DTD. Realistically, DOCTYPEs are pointless for HTML generation since web browsers don't require DOCTYPE declarations. However, if you are creating pages for some other purpose that requires such a declaration, use cgi_doctype.)
cgi_head
<head></head> tags can be generated using cgi_head. An argument to cgi_head is evaluated to produce the actual headers.
In practice, it is not necessary to use cgi_head. CGI.tcl will automatically generate the tags when appropriate. (Oddly, modern HTML specs don't require it and most if not all browsers never cared anyway). So for example:
cgi_head { cgi_title "my page" }is equivalent to:
cgi_title "my page"Note that cgi_title will be called automatically if you omit = cgi_title, cgi_head, or call cgi_head with no arguments.
cgi_title title
cgi_title defines the title of a page. It is called from within a <head></head> pair. If not called from within cgi_head, it implicitly forces it to occur.
cgi_title always returns the title. With no argument, cgi_title returns the old title without changing it.
cgi_http_equiv
cgi_http_equiv is equivalent to cgi_http_head
but from within cgi_head. This procedure is defined for completeness - there is no reason to use it. In fact, it doesn't allow all cgi_http_head declarations, so it should be avoided.
cgi_meta
cgi_meta generates a <meta> tag. You can do whatever you want with these. (Read some an HTML document for more = info.) For example:
meta name=author {content="Don Libes"}
cgi_script cmd
cgi_script evaluates its arguments inside of <script></script>
tags. This is appropriate for putting in client-side scripting. Optional arguments are passed as attributes to the <script> tag.Note that the cmd argument is a Tcl command, not a command in the other scripting language. So if all you want to do is print out some script, use cgi_puts:
cgi_script { cgi_puts { some scripting stuff in whatever weird funky language you want } }
cgi_javascript cmd
cgi_javascript is a version of cgi_script
specialized for javascript. At present, all it does is add the comment hacks so that the javascript can't be seen by old browsers.
cgi_noscript cmd
cgi_noscript evaluates its argument to generate code for browsers that do not understand cgi_script or its variants.
cgi_body
<body></body> tags are generated using cgi_body. An argument to cgi_body is evaluated to produce the actual body.
Executing "return" from within cgi_body causes cgi_body to return. This is useful if more code follows the cgi_body within the cgi_eval. Compare to cgi_exit (see elsewhere).
cgi_body_args
Arguments to cgi_body_args are made available to cgi_body
as if they had been specified in the call to cgi_body. This provides a convenient way for using the same colors, backgrounds, etc, in a set of pages.
cgi_exit
cgi_exit provides a fast way of cleanly exiting a CGI script without having to manually unwind procedures. In particular, cgi_exit forces closure of all open tags. It then calls exit. This is useful if you want to exit from a CGI script at any point and still have the HTML be correct.
cgi_frameset cmd
Instead of cgi_body, you can call cgi_frameset to create framed documents. This produces <frameset></frameset> tags with the content filled by evaluation of cmd. Optional arguments are passed on as attributes.
cgi_frame name=url
cgi_frame defines a frame with the given name and url. The argument handling is the same as for other name-value commands (even though the value here is a url). The url is automatically = double-quoted. Other optional arguments are passed on as attributes.
cgi_noframes cmd
cgi_noframes produces = <noframes></noframes>
tags with the content filled evaluation of cmd. Optional arguments are passed on as attributes.
cgi_division
cgi_division evaluates its last argument, grouping it together. This is useful for acting on a group of paragraphs, such = as for alignment purposes.
cgi_center
cgi_center is similar to "cgi_division = align=center".
Everything in this section generates a single paragraph or line = break. Most of these take a string as the last argument which is appropriately formatted. Any other arguments are used as tag attributes.
cgi_p cgi_address cgi_blockquote cgi_h1 through h7
Most of these procedures should be intuitive. They all take a string and display it in the appropriate way. For example, a level 2 heading:
h2 "Paragraph Support"
Here's a paragraph with some formatting (see next section for more info):
p "I [bold love] Tcl but hate [blink "blinking text"]"
Note that some of these generate tags that are not supported by all browsers. See the format-tour.cgi script to see these in use.
cgi_br
cgi_br causes a paragraph break to be printed. Additional arguments are passed on as attributes.
To embed a paragraph break (rather than printing it), use cgi_nl. In the following example, it is much more convenient to call cgi_br than cgi_nl:
radio_button "version=1" br radio_button "version=2"
See cgi_nl for more info.
The following procedures take a string and return an appropriately formatted version. The string is always the last argument. Any other arguments are used as tag attributes.
cgi_bold cgi_italic cgi_underline cgi_strikeout cgi_subscript cgi_superscript cgi_typewriter cgi_blink cgi_emphasis cgi_strong cgi_cite cgi_sample cgi_keyboard cgi_variable cgi_definition cgi_big cgi_small cgi_font
p "I [bold love] Tcl but hate [blink "blinking text"]"
Note that some of these generate tags that are not supported by all browsers. See the format-tour.cgi script to see these in use.
cgi_basefont
cgi_basefont defines the base font.
The following procedures produce characters such that when = interpreted by a browser returns the indicated character.
code Returns cgi_lt < cgi_gt > cgi_amp & cgi_quote " cgi_enspace en space cgi_emspace em space cgi_nbspace nonbreaking space cgi_tm registered trademark cgi_copyright copyright cgi_isochar n ISO character #n
cgi_nl
cgi_nl returns a paragraph break string suitable for embedding in a string just as you would embed a newline in a Tcl string via \n.
To print a paragraph break rather than returning it, use cgi_br. In the following example, it is much more convenient to call cgi_nl than than cgi_br:
h2 "This appears[nl]on two lines."See cgi_br for more info.
cgi_breakable
cgi_breakable indicates a place in a word at which the browser can break a string across two lines.
cgi_unbreakable cmd
cgi_unbreakable evaluates a cmd in such a way that the output will not be broken across lines by the browser just because the screen width is exceeded. Instead a horizontal scrollbar will appear so that the browser can be manually scrolled to see the long line.
cgi_unbreakable_string string
cgi_unbreakable_string returns its arguments so that it will not be broken across lines by the browser just because the screen width is exceeded. Instead a horizontal scrollbar will appear so that the browser can be manually scrolled to see the long line.
Notes:
- It is my assumption that cgi_unbreakable will be much more commonly used than the _string version, hence the choice of names. Feel free to let me know what I'm wrong.
- I have seen browsers handle unbreakables incorrectly, particularly in interaction with other features. If you can't get your unbreakables to behave correctly, consider alternative layouts or alternative HTML. For example, unbreakable table data should be done using "table_data nowrap". I have no idea why but it works whereas unbreakable causes the table rows to overlap. Clearly, this is a browser bug.
cgi_form action args cmd
cgi_form defines a form. The form is populated by executing the command (last argument of cgi_form). action defines the url to process the form. Any other arguments are passed as attributes. A typical call looks like this:
cgi_form response { .... }Here "response" names the URL to process the form. If the URL does not begin with a protocol name (such as "http:"), a common root is prepended and ".cgi" is appended. This can be changed by redefining the procedure cgi_cgi.
cgi_root
cgi_root defines the common root used by cgi_form
(see above). For example:cgi_root "http://www.nist.gov/cgi-bin/cgi.tcl-examples"With one argument, cgi_root returns the new root. With no arguments, cgi_root returns the old root.
cgi_suffix
cgi_suffix defines the common suffix used by = cgi_cgi and anything that uses it such as cgi_form. The default suffix is ".cgi".
cgi_cgi
cgi_cgi_set
cgi_cgi controls exactly how cgi_form creates URLs from its action argument. By default, cgi_cgi takes an argument, prepends [cgi_root] and appends [cgi_suffix]. The suffix can be overridden by using the -suffix flag and an argument to be used instead of [cgi_suffix].
Any additional arguments are joined together in the style required for a GET style request. These arguments should be preformatted using cgi_cgi_set to guarantee proper encoding. For example:
cgi_cgi myscript \ [cgi_cgi_set owner "Don"] \ [cgi_cgi_set color "black & white"]generates:
....?owner=Don&color=black+%26+white
cgi_isindex
cgi_isindex generates an <isindex> tag. Optional arguments are passed on as attributes. In the processing CGI script, the value of the isindex query is found in the "anonymous" variable.
cgi_relationship rel url
cgi_relationship expresses a relationship between this document and another. For example, the following says that the url named by homepage is the home document of the current document.
cgi_relationship home $homepageOptional arguments are passed on as additional attributes. Here's an example that references an external style sheet that is a CSS type (cascading style sheet).
cgi_relationship stylesheet basic.css type=text/css
cgi_input
CGI input means "cookies, files, and get/post data". cgi_input reads in all input, decodes it, and makes it available to a variety of other routines.
For debugging, cgi_input can be given arguments to fake input. This allows you to run your cgi_script interactively or under a debugger (either Tcl or C debugger). Provide GET/POST data as the first argument. Provide cookie data as the second argument. The arguments should be encoded (see cgi_cgi_set). For example:
cgi_input = "name=libes&old=foo&new1=bar&new2=hello"This is convenient because when you run into a misbehaving CGI script, the first thing it does is tell you the input in exactly this format. Now simply cut and paste it into your program and you can then interactively debug it without using the real form or the CGI server.
If cgi_input is invoked from the CGI environment, the fake inputs are ignored. (If you want to force fake inputs in the CGI environment, unset env(REQUEST_METHOD)).
Forms encoded as multipart/form-data are usually used to handle file input. Since file data usually implies a large amount of data, the data is saved to /tmp/CGIdbg.[pid] if debugging is enabled. This file can be fed back to cgi_input by providing the filename as the first argument of cgi_input. In addition, env(CONTENT_TYPE) must be set to the appropriate content type. This can found in env(CONTENT_TYPE). Removal of the debugging file is the responsibility of the script or the script programmer. (Typically, I examine the file after my CGI script is over and then delete them by hand.)
Execs before cgi_input reads POST data should have standard input redirected ("< /dev/null" for instance) so that the exec'd process doesn't inherit the CGI script's standard input.
Variable names should only end with "List" if they correspond to form elements which generate multiple values (some but not all uses of select, checkbox, etc). List variables will be given Tcl-style list values.
cgi_input enforces this restriction by issuing diagnostics when it can detect violations.
This is done in order to distinguish whether a value such as "foo bar" is a single element "foo bar" or two elements "foo" and "bar".
Here are examples:
# pull-down menu cgi_select Foo { cgi_option "a" cgi_option "a b" }
# scrolled list, allow multiple selections cgi_select FooList multiple { cgi_option "a" cgi_option "a b" }
Input is made available in two ways: variables and cookies.
cgi_import_list
cgi_import_list returns a list of variable names supplied as input to the script.
cgi_cookie_list
cgi_cookie_list returns a list of cookie names supplied to the script.
cgi_import name
cgi_import retrieves the value of the named variable and places it in a Tcl variable of the same name. The value is also returned as the return value.
cgi_import_as name tclvar
cgi_import_as is similar to cgi_import but the value is assigned to the Tcl variable named by the second argument.
cgi_import_cookie name
cgi_import is similar to cgi_import, however if the cgi variable does not exist, the value is fetched from the cookie by that name. (This allows the user to override a cookie if the form allows it.)
cgi_import_cookie_as name tclvar
cgi_import_cookie_as is similar to = cgi_import_cookie
but the value is assigned to the Tcl variable named by the second = argument.
cgi_cookie_get name
cgi_cookie_get returns the value of the named cookie.
Form elements automatically export their values. See FORM ELEMENTS for more information.
cgi_export name=value
cgi_export makes the named variable available with the = given value. The "=value" is optional. If not present, the value = of the Tcl variable by the same name is used.
cgi_export is implemented with variables of = type=hidden.
cgi_export is implemented as an all-or-nothing operation. = In particular, no HTML is emitted if the variable does not exist. That = means it is not necessary to test for existence in situations where you would like to export a variable IF it exists. Rather, it is sufficient to = embed cgi_export within a catch. For example, the following generates nothing if xyz doesn't exist and it generates the appropriate HTML if xyz does exist.
catch {cgi_export xyz}
cgi_export_cookie name
cgi_export_cookie is similar to cgi_export except that the value is made available as a cookie. Additional arguments are handled as with cgi_cookie_set (see below).
cgi_cookie_set name=val
cgi_cookie_set sets the named cookie. All optional = arguments are handled specially. All arguments are encoded appropriately. The = expires keyword is handled specially to simplify common cases. In particular, = the values "now" and "never" produce appropriate GMT values.
Here are some example of cgi_cookie_set:
cgi_cookie_set user=don domain=nist.gov expires=never cgi_cookie_set user=don domain=nist.gov expires=now cgi_cookie_set user=don domain=nist.gov expires=...actual = date...Note that cookie setting must be done during http head = generation.
cgi_link tag
cgi_link tag display url
cgi_link provides a convenient mechanism for maintaining and referencing from a set of URLs.
cgi_link returns the string <A>...</A> corresponding to the given tag. A tag is defined by calling cgi_link with the tag, the clickable text that the use should see, and the url.
For example, suppose you want to produce the following (where xyz indicates xyz is a hyperlink):
I am married to Don Libes who works in the Manufacturing Collaboration Technologies Group at NIST.
Using cgi_link with appropriate link definitions, the scripting to produce this is:
p "I am married to [link Libes] who works in the [link MCTG] at = [link NIST]."This expands to:
I am married to <A HREF="http://elib.cme.nist.gov/msid/staff /libes/ libes.don.html">Don Libes</A> who works in the <A = HREF="http:// elib.cme.nist.gov/msid/groups/mctg.htm"> Manufacturing Collaboration Technologies Group</A> at <A HREF="http:// = www.nist.gov">NIST</A>The links themselves are defined thusly:
link Libes "Don Libes" http://www.cme.nist.gov/msid/staff/libes link MCTG "$MCT Group" http://www.cme.nist.gov/msid/mctg link NIST = "NIST" http://www.nist.govNow if my home page ever changes, rather than updating every = occurrence, I just have to edit the one definition.
Tcl variables can further simplify updates. For instance, URLs for = Libes and MCTG are in a common directory. It makes sense to store that in a = single variable. Rewritten this appears:
set MSID http://www.cme.nist.gov/msidlink Libes "Don Libes" $MSID/staff/libes link MCTG "$MCT Group" $MSID/mctg link NIST "NIST" http://www.nist.govThen if the MSID directory ever moves, only one line need be updated. This may seem like no big deal here, but if you have many links and many uses of them, this pays off handsomely.
Optional attributes can be provided as additional arguments (see IMG example below).
An existing link can be given a different "display" temporarily by calling cgi_link with the different display and omitting the url.
cgi_imglink
imglink works similar to cgi_link (see that documentation for more info) except that no display argument is used and the second argument is assumed to be the image source. Example:
imglink taj tajmahal.gifOther attributes can be provided as additional arguments.
imglink taj tajmahal.gif alt="The Taj Mahal"
cgi_url display href args
By using cgi_url, URLs can be generated immediately (without using cgi_link first). This is convenient when you need a URL that will only appear once - so that there is no point in storing it in a dictionary. For example:
cgi_li "[cgi_url "Plume" http://pastime.anu.edu.au/Plume] is a Tcl-based WWW browser written by Steve Ball, Australian National University. Among its interesting features is the ability to execute Tcl applets and the ability to dynamically extend the browser at runtime."
cgi_img href args
cgi_img returns a formatted <img> tag. It is useful for one-time tags. Tags that are used multiple times should use cgi_imglink. Example:
cgi_img foo.gif "alt=Foo's Bar & Grill"
cgi_anchor_name name
cgi_anchor_name returns an anchor that can be used in an HTML body that it can be linked to using the #name syntax. For example, to make a heading that you want to be able to link to:
h2 "[cgi_anchor_name future]Future Improvements"Then to reference the "future" tag:
p "Look for [cgi_url "improvements" future] in the = future."
cgi_base args
cgi_base defines a base or window target for urls.
cgi_unquote_input string
cgi_unquote_input undoes "url-encoding" and returns the result. This is normally applied automatically to input sources including URLs and cookies. So you shouldn't have to call this manually.
cgi_quote_html string
cgi_quote_html returns the string but with any html-special characters escaped. For example, "<" is replaced by "\<". This is useful for displaying a literal "<" in the browser.
cgi_dquote_html string
cgi_dquote_html does the same thing as cgi_quote_html
but also adds on double quotes. cgi_quote_html is called automatically for implicit value attributes.
cgi_quote_url string
cgi_quote_url quotes strings appropriately to appear in a url, cookie, etc. This is useful if you want to publish a url by hand (and must do the conversion manually that the client normally does for you).
If you are generating cgi-style URLs for forms, use cgi_cgi_set.
cgi_preformatted cmd
cgi_preformatted evaluates its last argument to produce fixed-width preformatted output. Optional arguments are passed as attributes to the tags.
cgi_preformatted allows a subset of tags to be interpreted by the browser. For example, the <a> tag is interpreted but font change tags are not. To prevent all interpretation, use cgi_quote_html. For example, the following prints a file that might contain HTML but without any risk to throwing off formatting.
cgi_preformatted { puts [cgi_quote_html [read $fid]] }
cgi_li string
cgi_li prints its string as a list element. Optional arguments are passed through as attributes. cgi_li does not = have to appear in a list container, but it can.
cgi_term text
cgi_term_definition text
cgi_term and cgi_term_definition are usually paired up (although they need not be) to creates terms and defintions. They do not have to appear in a list container, but usually appear in a cgi_definition_list.
cgi_number_list cmd
cgi_bullet_list cmd
cgi_number_list and cgi_bullet_list take their cmd argument and evaluate it in a list container context. (I don't know about you but I could never remember <ol>, <ul>, and all the other ones. This names seem much easier to remember.)
cgi_li is a typical command to call inside of a list container, but you can use regular paragraphs (or anything else) as well.
cgi_definition_list
cgi_definition_list is the usual list container for cgi_term and cgi_term_definition. It may contain other things as well.
cgi_menu_list
cgi_directory_list
cgi_menu_list and cgi_directory are more list containers with the obvious semantics. Previous remarks about other list containers apply.
cgi_table cmd
cgi_table produces
<table></table>tags with the content filled by evaluation of cmd. Optional arguments are passed on as attributes.
cgi_caption cmd
cgi_caption produces
<caption></caption> tags with the content filled by evaluation of cmd. Optional arguments are passed on as attributes.
cgi_table_row cmd
cgi_table_head cmd
cgi_table_data cmd
These functions all produce the appropriate tags with the content filled by evaluation of cmd. Optional arguments are passed on as attributes.
cgi_tr table_data
cgi_td table_data
cgi_th table_data
cgi_tr, cgi_td, and cgi_th are shortcuts for relatively simple rows.
cgi_td outputs a table element. Unlike = cgi_table_data, the argument is not evalled. This allows more terse specification of = simple rows. The following example produces a table with three elements, the = last of which is prevented from wrapping:
table_row {td Don;td Steve;td nowrap "Really Long Name"}As the example suggests, optional arguments are passed on as data-specific attributes.
cgi_th is identical to cgi_td except that it produces table heading elements.
cgi_tr outputs a row of elements without having to call cgi_td or cgi_table_data. As with td, eval is not called. Data-specific attributes cannot be provided. All the elements are passed as a single argument. For example:
tr {Don Steve {Really Long Name}} or tr [list Don Steve $reallylongname]Optional arguments are passed on as row-specific attributes.
cgi_submit_button name=value
cgi_radio_button name=value
cgi_image_button name=value
These procedure create buttons. The first argument indicates the variable name and value. (See notes on "Name-value" commands earlier to understand behavior of omitted names/values.) Unless otherwise mentioned below, additional arguments are passed on as attributes.
cgi_submit_button "=Submit Form" cgi_submit_button "Action=Pay Raise"cgi_radio_button "version=1" cgi_radio_button "version=2" checkedcgi_image_button "=http://www.cme.nist.gov/images/title.gif" cgi_image_button = "Map=http://www.cme.nist.gov/images/msid3.gif"Groups of radio buttons must share the same variable name. To address the obvious question: No, there is no single command to produce a group of radio buttons because you might very well want to do arbitrarily-complex calculations in between them. And with a long-enough line of buttons, the obvious behavior (laying them all out in a line like CGI.pm does) makes it hard to tell at a glance if the buttons associate with the label to the left or the right of them. Anyway, you'll almost certainly want to write another procedure to call cgi_radio_button and that can control the variable name.
The radio button argument "checked_if_equal=xxx" = indicates that the current name should be shown selected if it is equal to = xxx. This is handy if you are creating radio buttons by iterating over a = list.
cgi_file_button name
cgi_file_button provides a filename entry box. When the form is submitted, the file is "uploaded" (sent from the client to the server). The argument enctype=multipart/form-data must be given to = the cgi_form command when using cgi_file_button.
After uploading, the file is the responsibility of the CGI programmer. In particular, if you do not delete it, it will remain until /tmp is cleaned up in some other way.
For example, to upload a single file, the form might look like this:
cgi_form upload height=3 enctype=multipart/form-data { cgi_file_button file cgi_submit_button =Upload }Uploaded files are automatically made available to the CGI script using
cgi_import_filename. (See elsewhere for more information.)
cgi_reset_button value
cgi_reset_button creates a a reset button. An argument overrides the default label. For example:
cgi_reset_button cgi_reset_button "Not the Default Reset Button"
cgi_map name cmd
cgi_area args
These procedures are used to specify client-side image maps. The first argument of cgi_map is the map name. The last argument is evaluated to fill the contents of <map></map> tags. cgi_area's arguments are embedded as arguments in an <area> tag.
Warning: These two commands will likely be redefined as I get more familiar with how they are typically used.
cgi_checkbox name=value
cgi_checkbox is similar to cgi_radio_button
(see above) except that multiple values can be checked at the same time. As explained earlier, the variable name must end with "List" in order for it to group all the values as a list in the resulting CGI script. Other arguments are passed on as attributes except for the argument "checked_if_equal=xxx" which indicates that the current name should be shown selected if it is equal to xxx. This is handy if you are creating checkboxes by iterating over a list.
cgi_text name=value
cgi_text provides a one-line text entry box. It works similarly to other form elements. (Read "Name-value commands" elsewhere.) Additional arguments are passed on as attributes. Examples:
cgi_text Foo cgi_text Foo= cgi_text Foo=value2 cgi_text Foo=value2 size=5 cgi_text Foo=value2 size=5 maxlength=10 cgi_text Foo=value2 size=10 maxlength=5 cgi_text Foo=value2 maxlength=5
cgi_textarea name=value
cgi_text provides a multiline text entry box. It works similarly to other form elements. (Read "Name-value commands" elsewhere.) Additional arguments are passed on as attributes.
set value "A really long line so that we can compare the\ effect of wrap options."cgi_textarea Foo cgi_textarea Foo= cgi_textarea Foo=$value cgi_textarea Foo=$value rows=3 cgi_textarea Foo=$value rows=3 cols=7 cgi_textarea Foo=$value rows=3 cols=7 wrap=virtual
cgi_select name cmd
cgi_select can be used to produce pull-down menus and scrolled lists. (And depending upon the future of HTML, I may provide better-named commands to indicate this.) Its behavior is controlled by additional arguments which are simply the appropriate attributes.
cgi_select evaluates cmd which typically contains multiple calls to cgi_option.
cgi_option string
cgi_option adds options to cgi_select. By default, the string is displayed and sent back as the value of the cgi_select variable. The value can be overridden by an explicit "value=" argument. Additional options are passed on as attributes, except for "selected_if_equal".
"selected_if_equal=xxx" indicates that the current option should be shown selected if the value is equal to xxx. This is useful if you are generating cgi_options in a loop rather than manually.
Here are examples:
# pull-down menu cgi_select Foo { cgi_option one selected cgi_option two cgi_option many value=hello }# scrolled list, allow multiple selections, show all elements cgi_select FooList multiple { cgi_option one selected cgi_option two selected cgi_option many }# scrolled list, allow multiple selections, show 2 elements max cgi_select FooList multiple size=2 { cgi_option one selected cgi_option two selected cgi_option many }# choose "selected" dynamically # example: list all Tcl command and select "exit" automatically cgi_select FooList multiple size=5 { foreach o [info comm] { cgi_option $o selected_if_equal=exit } }Note: If both value= and selected_if_equal= appear, the test for selection is made against the last value string (implicit or explicit) that appears before the selected_if_equal argument. In other words, if you want selected_if_equal= to be tested against the explicit
value= argument, put the selected_if_equal= after the value=.
cgi_applet parameters cmd
cgi_applet produces <applet></applet> tags such as for Java.
cgi_param name=value
cgi_param produces <param> tags for passing parameters to applets.
For example:
cgi_applet codebase="../" code="some.class" width=640 = height=480 { cgi_param parm=value }
cgi_embed src widthxheight
cgi_embed creates an <embed> tag. The first argument is the source. The second argument is the width and height in the style "WxH". Optional arguments are passed on to the tag. For example:
cgi_embed myavi.avi 320x200 autostart=trueproduces:
<embed src="myavi.avi" width="320" height="200" autostart=true>Notice the autostart value is unquoted because autostart is not specifically defined by the spec. The argument "-quote" causes all remaining attributes to be url encoded and quoted. For example:
cgi_embed myavi.avi 320x200 a=b -quote c=d e=fproduces:
<embed src="myavi.avi" width="320" height="200" a=b c="d" e="f">
cgi_hr
cgi_hr produces horizontal rules. Optional arguments are passed on as attributes.
cgi_comment stuff
cgi_comment can comment out anything including blocks of code.
cgi_html_comment stuff
cgi_html_comment comments out things in such a way that the comment appears in the final html itself.
cgi_put string
cgi_put prints the string with no new terminating newline. This is simply a shorthand for puts -nonewline.
cgi_puts
Many routines in this library send output to the standard output by default. This is convenient for CGI scripts. However, if you want to generate multiple files, it is useful to be able to redirect output dynamically. Output can be redirected by redefining cgi_puts. The default definition of cgi_puts is:
proc cgi_puts {args} { eval puts $args }cgi_puts must allow for an optional -nonewline argument. For example, here is a definition that writes to a file identified by the global "fd".
proc cgi_puts {args} { global fd puts -nonewline $fd [lindex $args end] if {[llength $args] > 1} { puts $fd "" } }
cgi_buffer cmd
cgi_buffer evaluates its argument in such a way that output (through explicit or implicit calls to cgi_puts) is not produced. Instead, the output is returned.
For example, the following cmd generates a link with the hyperlinked portion being a header and two paragraphs.
link tag [cgi_buffer { h3 "Level 3 header" p "New paragraph" p "Another paragraph" }] $URLcgi_buffer can be called recursively.
cgi_buffer_nl string
By default, cgi_buffer generates newlines at the end of every line in the style of puts. It is occasionally useful to be able to disable this - for example, when calling it inside cgi_preformatted. The newline definition can be changed via cgi_buffer_nl. (There is no point to redefining cgi_puts since cgi_buffer doesn't use it.) A null argument suppresses any newline. For example:
cgi_buffer_nl ""cgi_buffer_nl returns the previous definition.
Rudimentary email support is provided, in part, because it is useful for trapping errors - if debugging is disabled (i.e., during actual use) and an error is encountered, errors are emailed to the service admin.
The current implementation only permits one email transaction at a time.
cgi_mail_addr addr
cgi_mail_addr defines the email address that mail comes from. Your email system must allow this, of course. (If your system doesn't allow it, the request is usually ignored.)
cgi_mail_start addr
cgi_mail_start creates a mail message to be delivered the given addr. cgi_mail_add should be used to provide a subject and body.
cgi_mail_add string
cgi_mail_add adds strings to the current mail message. No argument causes a blank line to be added.
cgi_mail_end
cgi_mail_end queues the the current mail message for delivery.
cgi_mail_start libes@nist.gov cgi_mail_add "Subject: [cgi_name] request succeeded cgi_mail_add cgi_mail_add "Your request has been processed." cgi_mail_add "Thanks for using [cgi_name]. cgi_mail_end
cgi_mail_relay host
cgi_mail_relay identifies a host to be used for mail relay services. (This is currently only used when sendmail support is not available.) If a relay is not defined, email is sent directly to the recipient.