- I OpenACS For Everyone
- I.1 High level information: What is OpenACS?
- I.1.1 Overview
- I.1.2 OpenACS Release Notes
- I.2 OpenACS: robust web development framework
- I.2.1 Introduction
- I.2.2 Basic infrastructure
- I.2.3 Advanced infrastructure
- I.2.4 Domain level tools
- I.1 High level information: What is OpenACS?
- II Administrator's Guide
- II.2 Installation Overview
- II.2.1 Basic Steps
- II.2.2 Prerequisite Software
- II.3 Complete Installation
- II.3.1 Install a Unix-like system and supporting software
- II.3.2 Install Oracle 10g XE on debian
- II.3.2.1 Install Oracle 8.1.7
- II.3.3 Install PostgreSQL
- II.3.4 Install AOLserver 4
- II.3.5 Quick Install of OpenACS
- II.3.5.1 Complex Install OpenACS 5.3
- II.3.6 OpenACS Installation Guide for Windows2000
- II.3.7 OpenACS Installation Guide for Mac OS X
- II.4 Configuring a new OpenACS Site
- II.4.1 Installing OpenACS packages
- II.4.2 Mounting OpenACS packages
- II.4.3 Configuring an OpenACS package
- II.4.4 Setting Permissions on an OpenACS package
- II.4.5 How Do I?
- II.4.6 Configure OpenACS look and feel with templates
- II.5 Upgrading
- II.5.1 Overview
- II.5.2 Upgrading 4.5 or higher to 4.6.3
- II.5.3 Upgrading OpenACS 4.6.3 to 5.0
- II.5.4 Upgrading an OpenACS 5.0.0 or greater installation
- II.5.5 Upgrading the OpenACS files
- II.5.6 Upgrading Platform components
- II.6 Production Environments
- II.6.1 Starting and Stopping an OpenACS instance.
- II.6.2 AOLserver keepalive with inittab
- II.6.3 Running multiple services on one machine
- II.6.4 High Availability/High Performance Configurations
- II.6.5 Staged Deployment for Production Networks
- II.6.6 Installing SSL Support for an OpenACS service
- II.6.7 Set up Log Analysis Reports
- II.6.8 External uptime validation
- II.6.9 Diagnosing Performance Problems
- II.7 Database Management
- II.7.1 Running a PostgreSQL database on another server
- II.7.2 Deleting a tablespace
- II.7.3 Vacuum Postgres nightly
- II.8 Backup and Recovery
- II.8.1 Backup Strategy
- II.8.2 Manual backup and recovery
- II.8.3 Automated Backup
- II.8.4 Using CVS for backup-recovery
- II.A Install Red Hat 8/9
- II.B Install additional supporting software
- II.B.1 Unpack the OpenACS tarball
- II.B.2 Initialize CVS (OPTIONAL)
- II.B.3 Add PSGML commands to emacs init file (OPTIONAL)
- II.B.4 Install Daemontools (OPTIONAL)
- II.B.5 Install qmail (OPTIONAL)
- II.B.6 Install Analog web file analyzer
- II.B.7 Install nspam
- II.B.8 Install Full Text Search
- II.B.9 Install Full Text Search using Tsearch2
- II.B.10 Install Full Text Search using OpenFTS (deprecated see tsearch2)
- II.B.11 Install nsopenssl
- II.B.12 Install tclwebtest.
- II.B.13 Install PHP for use in AOLserver
- II.B.14 Install Squirrelmail for use as a webmail system for OpenACS
- II.B.15 Install PAM Radius for use as external authentication
- II.B.16 Install LDAP for use as external authentication
- II.B.17 Install AOLserver 3.3oacs1
- II.C Credits
- II.C.1 Where did this document come from?
- II.C.2 Linux Install Guides
- II.C.3 Security Information
- II.C.4 Resources
- II.2 Installation Overview
- III For OpenACS Package Developers
- III.9 Development Tutorial
- III.9.1 Creating an Application Package
- III.9.2 Setting Up Database Objects
- III.9.3 Creating Web Pages
- III.9.4 Debugging and Automated Testing
- III.10 Advanced Topics
- III.10.1 Write the Requirements and Design Specs
- III.10.2 Add the new package to CVS
- III.10.3 OpenACS Edit This Page Templates
- III.10.4 Adding Comments
- III.10.5 Admin Pages
- III.10.6 Categories
- III.10.7 Profile your code
- III.10.8 Prepare the package for distribution.
- III.10.9 Distributing upgrades of your package
- III.10.10 Notifications
- III.10.11 Hierarchical data
- III.10.12 Using .vuh files for pretty urls
- III.10.13 Laying out a page with CSS instead of tables
- III.10.14 Sending HTML email from your application
- III.10.15 Basic Caching
- III.10.16 Scheduled Procedures
- III.10.17 Enabling WYSIWYG
- III.10.18 Adding in parameters for your package
- III.10.19 Writing upgrade scripts
- III.10.20 Connect to a second database
- III.10.21 Future Topics
- III.11 Development Reference
- III.11.1 OpenACS Packages
- III.11.2 OpenACS Data Models and the Object System
- III.11.3 The Request Processor
- III.11.4 The OpenACS Database Access API
- III.11.5 Using Templates in OpenACS
- III.11.6 Groups, Context, Permissions
- III.11.7 Writing OpenACS Application Pages
- III.11.8 Parties in OpenACS
- III.11.9 OpenACS Permissions Tediously Explained
- III.11.10 Object Identity
- III.11.11 Programming with AOLserver
- III.11.12 Using Form Builder: building html forms dynamically
- III.12 Engineering Standards
- III.12.1 OpenACS Style Guide
- III.12.2 Release Version Numbering
- III.12.3 Constraint naming standard
- III.12.4 ACS File Naming and Formatting Standards
- III.12.5 PL/SQL Standards
- III.12.6 Variables
- III.12.7 Automated Testing
- III.13 CVS Guidelines
- III.13.1 Using CVS with OpenACS
- III.13.2 OpenACS CVS Concepts
- III.13.3 Contributing code back to OpenACS
- III.13.4 Additional Resources for CVS
- III.14 Documentation Standards
- III.14.1 OpenACS Documentation Guide
- III.14.2 Using PSGML mode in Emacs
- III.14.3 Using nXML mode in Emacs
- III.14.4 Detailed Design Documentation Template
- III.14.5 System/Application Requirements Template
- III.15 TCLWebtest
- III.16 Internationalization
- III.16.1 Internationalization and Localization Overview
- III.16.2 How Internationalization/Localization works in OpenACS
- III.16.4 Design Notes
- III.16.5 Translator's Guide
- III.D Using CVS with an OpenACS Site
- III.9 Development Tutorial
- IV For OpenACS Platform Developers
- IV.17 Kernel Documentation
- IV.17.1 Overview
- IV.17.2 Object Model Requirements
- IV.17.3 Object Model Design
- IV.17.4 Permissions Requirements
- IV.17.5 Permissions Design
- IV.17.6 Groups Requirements
- IV.17.7 Groups Design
- IV.17.8 Subsites Requirements
- IV.17.9 Subsites Design Document
- IV.17.10 Package Manager Requirements
- IV.17.11 Package Manager Design
- IV.17.12 Database Access API
- IV.17.13 OpenACS Internationalization Requirements
- IV.17.14 Security Requirements
- IV.17.15 Security Design
- IV.17.16 Security Notes
- IV.17.17 Request Processor Requirements
- IV.17.18 Request Processor Design
- IV.17.19 Documenting Tcl Files: Page Contracts and Libraries
- IV.17.20 Bootstrapping OpenACS
- IV.17.21 External Authentication Requirements
- IV.18 Releasing OpenACS
- IV.18.1 OpenACS Core and .LRN
- IV.18.2 How to Update the OpenACS.org repository
- IV.18.3 How to package and release an OpenACS Package
- IV.18.4 How to Update the translations
- IV.17 Kernel Documentation
- V Tcl for Web Nerds
- V.1 Tcl for Web Nerds Introduction
- V.2 Basic String Operations
- V.3 List Operations
- V.4 Pattern matching
- V.5 Array Operations
- V.6 Numbers
- V.7 Control Structure
- V.8 Scope, Upvar and Uplevel
- V.9 File Operations
- V.10 Eval
- V.11 Exec
- V.12 Tcl for Web Use
- V.13 OpenACS conventions for TCL
- V.14 Solutions
- VI SQL for Web Nerds
- VI.1 SQL Tutorial
- VI.1.1 SQL Tutorial
- VI.1.2 Answers
- VI.2 SQL for Web Nerds Introduction
- VI.3 Data modeling
- VI.3.1 The Discussion Forum -- philg's personal odyssey
- VI.3.2 Data Types (Oracle)
- VI.3.4 Tables
- VI.3.5 Constraints
- VI.4 Simple queries
- VI.5 More complex queries
- VI.6 Transactions
- VI.7 Triggers
- VI.8 Views
- VI.9 Style
- VI.10 Escaping to the procedural world
- VI.11 Trees
- VI.1 SQL Tutorial
V.2 Basic String Operations
If your program receives data from a Web client, it comes in as a string. If your program sends an HTML page back to a Web client, it goes out as a string. This puts the string data type at the heart of Web page development:If you're processing data from the user, typically entered into an HTML form, you'll be using a rich variety of built-in string-handling procedures. Suppose that a user is registering at your site with the form variables
set whole_page "some stuff for the top of the page\n\n" append whole_page "some stuff for the middle of the page\n\n" append whole_page "some stuff for the bottom of the page\n\n" # done composing the page, let's write it back to the user ns_return 200 text/html $whole_page
first_names, last_name, email, password
. Here's how we might build up a list of exceptions (using the Tcl lappend
command, described in the chapter on lists):
If there aren't any exceptions, we have to get these data ready for insertion into the database:
# compare the first_names value to the empty string if { [string compare $first_names ""] == 0 } { lappend exception_list "You forgot to type your first name" } # see if their email address has the form # something at-sign something if { ![regexp {.+@.+} $email] } { lappend exception_list "Your email address doesn't look valid." } if { [string length $password] > 20 } { lappend exception_list "The password you selected is too long." }
# remove whitespace from ends of input (if any) set last_name_trimmed [string trim $last_name] # escape any single quotes with an extra one (since the SQL # string literal quoting system uses single quotes) regsub -all ' $last_name_trimmed '' last_name_final set sql_insert "insert into users (..., last_name, ...) values (..., '$last_name_final', ...)"
Looking for stuff in a string
The simplest way to look for a substring within a string is with the string first
command. Some users of photo.net complained that they didn't like seeing classified ads that were simply pointers to the eBay auction site. Here's a simplified snippet from http://software.arsdigita.com/www/gc/place-ad-3.tcl:
an alternative formulation would be
if { [string first "ebay" [string tolower $full_ad]] != -1 } { # return an exception ... }
Both implementations will catch any capitalization variant of "eBAY". Both implementations will miss "e-bay" but it doesn't matter because if the poster of the ad includes a link with a URL, the hyperlink will contain "ebay". What about false positives? If you visit www.m-w.com and search for "*ebay*" you'll find that both implementations might bite someone selling rhododendrons or a water-powered mill. That's why the toolkit code checks a "DisalloweBay" parameter, set by the publisher, before declaring this an exception.
if { [regexp -nocase {ebay} $full_ad] } { # return an exception ... }
If you're just trying to find a substring, you can use either string first
or regexp
. If you're trying to do something more subtle, you'll need regexp (described more fully in the chapter "Pattern Matching"):
if { ![regexp {[a-z]} $full_ad] } { # no lowercase letters in the ad! append exception_text "Your ad appears to be all uppercase. ON THE INTERNET THIS IS CONSIDERED SHOUTING. IT IS ALSO MUCH HARDER TO READ THAN MIXED CASE TEXT. So we don't allow it, out of decorum and consideration for people who may be visually impaired." incr exception_count }
Using only part of a string
In the ArsDigita Community System, we have a page that shows a user's complete history with a Web service, e.g., http://photo.net/shared/community-member.tcl?user_id=23069 shows all of the postings by Philip Greenspun. If a comment on a static page is short, we want to show the entire message. If not, we want to show just the first 1000 characters.
In http://software.arsdigita.com/www/shared/community-member.tcl, we find the following use of the string range
command:
if { [string length $message] > 1000 } { set complete_message "[string range $message 0 1000]... " } else { set complete_message $message }
Fortran-style formatting and reading of numbers
The Tcl commands format
and scan
resemble C's printf
and scanf
commands. That's pretty much all that any Tcl manual will tell you about these commands, which means that you're kind of S.O.L. if you don't know C. The basic idea of these commands comes from Fortran, a computer language developed by John Backus at IBM in 1954. The FORMAT command in Fortran would let you control the printed display of a number, including such aspects as spaces of padding to the left and digits of precision after the decimal point.
With Tcl format
, the first argument is a pattern for how you'd like the final output to look. Inside the pattern are placeholders for values. The second through Nth arguments to format
are the values themselves:
We can never figure out how to use format without either copying an earlier fragment of pattern or referring to the man page (http://www.tcl.tk/man/tcl8.4/TclCmd/format.htm). However, here are some examples for you to copy:
format pattern value1 value2 value3 .. valueN
The Tcl command
% # format prices with two digits after the point % format "Price: %0.2f" 17 Price: 17.00 % # pad some stuff out to fill 20 spaces % format "%20s" "a long thing" a long thing % format "%20s" "23" 23 % # notice that the 20 spaces is a MINIMUM; use string range % # if you might need to truncate % format "%20s" "something way longer than 20 spaces" something way longer than 20 spaces % # turn a number into an ASCII character % format "%c" 65 A
scan
performs the reverse operation, i.e., parses an input string according to a pattern and stuffs values as it finds them into variables:
Notice that the number returned by
% # turn an ASCII character into a number % scan "A" "%c" the_ascii_value 1 % set the_ascii_value 65 %
scan
is a count of how many conversions it was able to perform successfully. If you really want to use scan
, you'll need to visit the man page: http://www.tcl.tk/man/tcl8.4/TclCmd/scan.htm. For an idea of how useful this is for Web development, consider that the entire 250,000-line ArsDigita Community System does not contain a single use of the scan
command.
Reference: String operations
append variable_name value1 value2 value3 ... valueN
sets the variable defined by variable_name to the concatenation of the old value and all the remaining arguments (http://www.tcl.tk/man/tcl8.4/TclCmd/append.htm)regexp ?switches? expression string ?matchVar? ?subMatchVar subMatchVar ...?
Returns 1 ifexpression
matchesstring
; 0 otherwise. If successful,regexp
sets the match variables to the parts ofstring
that matches the corresponding parts ofexpression
.
(more: the pattern matching chapter and http://www.tcl.tk/man/tcl8.4/TclCmd/regexp.htm)% set fraction "5/6" 5/6 % regexp {(.*)/(.*)} $fraction match num denom 1 % set match 5/6 % set num 5 % set denom 6
regsub ?switches? expression string substitution_spec result_variable_name
Returns a count of the number of matching items that were found and replaced. Primarily called for its effect in settingresult_variable_name
.Here's an example where we ask a user to type in keywords, separated by commands. We then expect to feed this list to a full-text search indexer that will throw an error if handed two commas in a row. We use
regsub
to clean up what the user typed:
(more: the pattern matching chapter and http://www.tcl.tk/man/tcl8.4/TclCmd/regsub.htm)# here we destructively modify the variable $query_string' # replacing every occurrence of one or more commas with a single # command % set query_string "samoyed,, sledding, harness" samoyed,, sledding, harness % regsub -all {,+} $query_string "," query_string 2 % set query_string samoyed, sledding, harness
were dramatically improved with the Tcl 8.1 release. For a Web developer the most important feature is the inclusion of non-greedy regular expressions. This makes it easy to match the contents of HTML tags. See http://www.scriptics.com/services/support/howto/regexp81.html for a full discussion of the differences.
B.) Commands that start with
string
A.) Commands that don't start with string
- string compare string1 string2
returns 0 if the two strings are equal, -1 if string1 sorts lexicographically before string2, 1 if string2 sorts lexicographically before string1:string compare apple applesauce ==> -1 string compare apple Apple ==> 1
- string first string1 string2
returns -1 if string1 is not within string2, else returns the index of the first occurrence. Indices start from zero, e.g.,string first tcl catclaw ==> 2
- string last string1 string2
-1 if string1 is not within string2, else index of last occurrence.string last abra abracadabra ==> 7
- string match pattern string
1 if string matches pattern, 0 if not. See the chapter on pattern matching for an explanation of patterns. - string range string i j
range of characters in string from index i to j, inclusive.string range catclaw 2 4 ==> tcl
- string tolower string
string in lower case.string compare weBmaster Webmaster => 1 string compare [string tolower weBmaster] \ [string tolower Webmaster] => 0
- string toupper string
string in upper case.set password "ferrari" string compare "FERRARI" [string toupper $password] ==> 0
- string trim string ?chars?
trims chars from right and left side of string; defaults to whitespace.set password [string trim $form_password] ; # see above example
- string trimleft string ?chars?
trims chars from left of string; defaults to whitespace.set password [string trimleft $form_password]
- string trimright string ?chars?
trims chars from right of string; defaults to whitespace.set password [string trimright $form_password]
- string wordend string index
index of the first character after the last character of the word containing index.string wordend "tcl is the greatest" 0 ==>3
- string wordstart string index
index of the first char of the word containing index.string wordstart "tcl is the greatest" 5 ==> 4
Exercises ( see section V.3 List Operations )
---
based on Tcl for Web Nerds