summaryrefslogtreecommitdiffstats
path: root/tkhtml1/src/htmlform.c
diff options
context:
space:
mode:
Diffstat (limited to 'tkhtml1/src/htmlform.c')
-rw-r--r--tkhtml1/src/htmlform.c606
1 files changed, 606 insertions, 0 deletions
diff --git a/tkhtml1/src/htmlform.c b/tkhtml1/src/htmlform.c
new file mode 100644
index 0000000..210ae62
--- /dev/null
+++ b/tkhtml1/src/htmlform.c
@@ -0,0 +1,606 @@
+/*
+** Routines used for processing HTML makeup for forms.
+**
+** Copyright (C) 1997-2000 D. Richard Hipp
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+** Library General Public License for more details.
+**
+** You should have received a copy of the GNU Library General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+**
+** Author contact information:
+** drh@acm.org
+** http://www.hwaci.com/drh/
+*/
+#include <tk.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include "htmlform.h"
+
+/*
+** Unmap any input control that is currently mapped.
+*/
+void HtmlUnmapControls(HtmlWidget *htmlPtr){
+ HtmlElement *p;
+
+ for(p=htmlPtr->firstInput; p; p=p->input.pNext){
+ if( p->input.tkwin!=0 && Tk_IsMapped(p->input.tkwin) ){
+ Tk_UnmapWindow(p->input.tkwin);
+ }
+ }
+}
+
+/*
+** Map any control that should be visible according to the
+** current scroll position. At the same time, if any controls that
+** should not be visible are mapped, unmap them. After this routine
+** finishes, all <INPUT> controls should be in their proper places
+** regardless of where they might have been before.
+**
+** Return the number of controls that are currently visible.
+*/
+int HtmlMapControls(HtmlWidget *htmlPtr){
+ HtmlElement *p; /* For looping over all controls */
+ int x, y, w, h; /* Part of the virtual canvas that is visible */
+ int cnt = 0; /* Number of visible controls */
+
+ x = htmlPtr->xOffset;
+ y = htmlPtr->yOffset;
+ w = Tk_Width(htmlPtr->clipwin);
+ h = Tk_Height(htmlPtr->clipwin);
+ for(p=htmlPtr->firstInput; p; p=p->input.pNext){
+ if( p->input.tkwin==0 ) continue;
+ if( p->input.y < y+h
+ && p->input.y + p->input.h > y
+ && p->input.x < x+w
+ && p->input.x + p->input.w > x
+ ){
+ /* The control should be visible. Make is so if it isn't already */
+ Tk_MoveResizeWindow(p->input.tkwin,
+ p->input.x - x, p->input.y - y,
+ p->input.w, p->input.h);
+ if( !Tk_IsMapped(p->input.tkwin) ){
+ Tk_MapWindow(p->input.tkwin);
+ }
+ cnt++;
+ }else{
+ /* This control should not be visible. Unmap it. */
+ if( Tk_IsMapped(p->input.tkwin) ){
+ Tk_UnmapWindow(p->input.tkwin);
+ }
+ }
+ }
+ return cnt;
+}
+
+/*
+** Delete all input controls. This happens when the HTML widget
+** is cleared.
+**
+** When the TCL "exit" command is invoked, the order of operations
+** here is very touchy.
+*/
+void HtmlDeleteControls(HtmlWidget *htmlPtr){
+ HtmlElement *p; /* For looping over all controls */
+ Tcl_Interp *interp; /* The interpreter */
+
+ interp = htmlPtr->interp;
+ p = htmlPtr->firstInput;
+ htmlPtr->firstInput = 0;
+ htmlPtr->lastInput = 0;
+ htmlPtr->nInput = 0;
+ if( p==0 || htmlPtr->tkwin==0 ) return;
+ HtmlLock(htmlPtr);
+ for(; p; p=p->input.pNext){
+ if( p->input.pForm && p->input.pForm->form.id>0
+ && htmlPtr->zFormCommand && htmlPtr->zFormCommand[0]
+ && !Tcl_InterpDeleted(interp) && htmlPtr->clipwin ){
+ Tcl_DString cmd;
+ int result;
+ char zBuf[60];
+ Tcl_DStringInit(&cmd);
+ Tcl_DStringAppend(&cmd, htmlPtr->zFormCommand, -1);
+ sprintf(zBuf," %d flush", p->input.pForm->form.id);
+ Tcl_DStringAppend(&cmd, zBuf, -1);
+ result = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&cmd));
+ Tcl_DStringFree(&cmd);
+ if( !Tcl_InterpDeleted(interp) ){
+ if( result != TCL_OK ){
+ Tcl_AddErrorInfo(htmlPtr->interp,
+ "\n (-formcommand flush callback executed by html widget)");
+ Tcl_BackgroundError(htmlPtr->interp);
+ TestPoint(0);
+ }
+ Tcl_ResetResult(htmlPtr->interp);
+ }
+ p->input.pForm->form.id = 0;
+ }
+ if( p->input.tkwin ){
+ if( htmlPtr->clipwin!=0 ) Tk_DestroyWindow(p->input.tkwin);
+ p->input.tkwin = 0;
+ }
+ p->input.sized = 0;
+ }
+ HtmlUnlock(htmlPtr);
+}
+
+/*
+** Return an appropriate type value for the given <INPUT> markup.
+*/
+static int InputType(HtmlElement *p){
+ int type = INPUT_TYPE_Unknown;
+ char *z;
+ int i;
+ static struct {
+ char *zName;
+ int type;
+ } types[] = {
+ { "checkbox", INPUT_TYPE_Checkbox },
+ { "file", INPUT_TYPE_File },
+ { "hidden", INPUT_TYPE_Hidden },
+ { "image", INPUT_TYPE_Image },
+ { "password", INPUT_TYPE_Password },
+ { "radio", INPUT_TYPE_Radio },
+ { "reset", INPUT_TYPE_Reset },
+ { "submit", INPUT_TYPE_Submit },
+ { "text", INPUT_TYPE_Text },
+ };
+
+ switch( p->base.type ){
+ case Html_INPUT:
+ z = HtmlMarkupArg(p, "type", "text");
+ if( z==0 ){ TestPoint(0); break; }
+ for(i=0; i<sizeof(types)/sizeof(types[0]); i++){
+ if( stricmp(types[i].zName,z)==0 ){
+ type = types[i].type;
+ TestPoint(0);
+ break;
+ }
+ TestPoint(0);
+ }
+ break;
+ case Html_SELECT:
+ type = INPUT_TYPE_Select;
+ TestPoint(0);
+ break;
+ case Html_TEXTAREA:
+ type = INPUT_TYPE_TextArea;
+ TestPoint(0);
+ break;
+ case Html_APPLET:
+ case Html_IFRAME:
+ case Html_EMBED:
+ type = INPUT_TYPE_Applet;
+ TestPoint(0);
+ break;
+ default:
+ CANT_HAPPEN;
+ break;
+ }
+ return type;
+}
+
+/*
+** Create the window name for a child widget. Space to hold the name
+** is obtained from HtmlAlloc() and must be freed by the calling function.
+*/
+static char *MakeWindowName(
+ HtmlWidget *htmlPtr, /* The HTML widget */
+ HtmlElement *pElem /* The input that needs a child widget */
+){
+ int n;
+ char *zBuf;
+
+ n = strlen(Tk_PathName(htmlPtr->clipwin));
+ zBuf = HtmlAlloc( n + 20 );
+ sprintf(zBuf,"%s.x%d",Tk_PathName(htmlPtr->clipwin), pElem->input.cnt);
+ return zBuf;
+}
+
+/*
+** A Input element is the input. Mark this element as being
+** empty. It has no widget and doesn't appear on the screen.
+**
+** This is called for HIDDEN inputs or when the -formcommand
+** callback doesn't create the widget.
+*/
+static void EmptyInput(HtmlElement *pElem){
+ pElem->input.tkwin = 0;
+ pElem->input.w = 0;
+ pElem->input.h = 0;
+ pElem->base.flags &= !HTML_Visible;
+ pElem->base.style.flags |= STY_Invisible;
+ pElem->input.sized = 1;
+}
+
+/*
+** This routine is called when one of the child windows for a form
+** wants to change its size.
+*/
+static void HtmlInputRequestProc(ClientData clientData, Tk_Window tkwin){
+ HtmlElement *pElem = (HtmlElement*)clientData;
+ if( pElem->base.type!=Html_INPUT ){ CANT_HAPPEN; return; }
+ if( pElem->input.tkwin!=tkwin ){ CANT_HAPPEN; return; }
+ pElem->input.w = Tk_ReqWidth(tkwin);
+ pElem->input.h = Tk_ReqHeight(tkwin);
+ if( pElem->input.htmlPtr && pElem->input.htmlPtr->tkwin!=0 ){
+ pElem->input.htmlPtr->flags |= RELAYOUT;
+ HtmlScheduleRedraw(pElem->input.htmlPtr);
+ }
+}
+
+/*
+** This routine is called when another entity takes over geometry
+** management for a widget corresponding to an input element.
+*/
+static void HtmlInputLostSlaveProc(ClientData clientData, Tk_Window tkwin){
+ HtmlElement *pElem = (HtmlElement*)clientData;
+ if( pElem->base.type!=Html_INPUT ){ CANT_HAPPEN; return; }
+ if( pElem->input.tkwin!=tkwin ){ CANT_HAPPEN; return; }
+ EmptyInput(pElem);
+ if( pElem->input.htmlPtr && pElem->input.htmlPtr->tkwin!=0 ){
+ pElem->input.htmlPtr->flags |= RELAYOUT;
+ HtmlScheduleRedraw(pElem->input.htmlPtr);
+ }
+}
+
+/*
+** This routine catches DestroyNotify events on a INPUT window so
+** that we will know the window is been deleted.
+*/
+static void HtmlInputEventProc(ClientData clientData, XEvent *eventPtr){
+ HtmlElement *pElem = (HtmlElement*)clientData;
+ /* if( pElem->base.type!=Html_INPUT ){ CANT_HAPPEN; return; } */
+ if( eventPtr->type==DestroyNotify ){
+ EmptyInput(pElem);
+ if( pElem->input.htmlPtr && pElem->input.htmlPtr->tkwin!=0 ){
+ pElem->input.htmlPtr->flags |= RELAYOUT;
+ HtmlScheduleRedraw(pElem->input.htmlPtr);
+ }
+ }
+}
+
+/*
+** The geometry manager for the HTML widget
+*/
+static Tk_GeomMgr htmlGeomType = {
+ "html", /* Name */
+ HtmlInputRequestProc, /* Called when widget changes size */
+ HtmlInputLostSlaveProc, /* Called when someone else takes over management */
+};
+
+/*
+** zWin is the name of a child widget that is used to implement an
+** input element. Query Tk for information about this widget (such
+** as its size) and put that information in the pElem structure
+** that represents the input.
+*/
+static void SizeAndLink(HtmlWidget *htmlPtr, char *zWin, HtmlElement *pElem){
+ pElem->input.tkwin = Tk_NameToWindow(htmlPtr->interp, zWin, htmlPtr->clipwin);
+ if( pElem->input.tkwin==0 ){
+ Tcl_ResetResult(htmlPtr->interp);
+ EmptyInput(pElem);
+ }else if( pElem->input.type==INPUT_TYPE_Hidden ){
+ pElem->input.w = 0;
+ pElem->input.h = 0;
+ pElem->base.flags &= !HTML_Visible;
+ pElem->base.style.flags |= STY_Invisible;
+ }else{
+ pElem->input.w = Tk_ReqWidth(pElem->input.tkwin);
+ pElem->input.h = Tk_ReqHeight(pElem->input.tkwin);
+ pElem->base.flags |= HTML_Visible;
+ pElem->input.htmlPtr = htmlPtr;
+ Tk_ManageGeometry(pElem->input.tkwin, &htmlGeomType, pElem);
+ Tk_CreateEventHandler(pElem->input.tkwin, StructureNotifyMask,
+ HtmlInputEventProc, pElem);
+ }
+ pElem->input.pNext = 0;
+ if( htmlPtr->firstInput==0 ){
+ htmlPtr->firstInput = pElem;
+ }else{
+ htmlPtr->lastInput->input.pNext = pElem;
+ }
+ htmlPtr->lastInput = pElem;
+ pElem->input.sized = 1;
+}
+
+/* Append all text and space tokens between pStart and pEnd to
+** the given Tcl_DString.
+*/
+static void HtmlAppendText(
+ Tcl_DString *str, /* Append the text here */
+ HtmlElement *pFirst, /* The first token */
+ HtmlElement *pEnd /* The last token */
+){
+ while( pFirst && pFirst!=pEnd ){
+ switch( pFirst->base.type ){
+ case Html_Text: {
+ Tcl_DStringAppend(str, pFirst->text.zText, -1);
+ break;
+ }
+ case Html_Space: {
+ if( pFirst->base.flags & HTML_NewLine ){
+ Tcl_DStringAppend(str, "\n", 1);
+ }else{
+ int cnt;
+ static char zSpaces[] = " ";
+ cnt = pFirst->base.count;
+ while( cnt>sizeof(zSpaces)-1 ){
+ Tcl_DStringAppend(str, zSpaces, sizeof(zSpaces)-1);
+ cnt -= sizeof(zSpaces)-1;
+ }
+ if( cnt>0 ){
+ Tcl_DStringAppend(str, zSpaces, cnt);
+ }
+ }
+ break;
+ }
+ default:
+ /* Do nothing */
+ break;
+ }
+ pFirst = pFirst->pNext;
+ }
+}
+
+/*
+** The "p" argument points to a <select>. This routine scans all
+** subsequent elements (up to the next </select>) looking for
+** <option> tags. For each option tag, it appends three elements
+** to the "str" DString:
+**
+** * 1 or 0 to indicated whether or not the element is
+** selected.
+**
+** * The value returned if this element is selected.
+**
+** * The text displayed for this element.
+*/
+static void AddSelectOptions(
+ Tcl_DString *str, /* Add text here */
+ HtmlElement *p, /* The <SELECT> markup */
+ HtmlElement *pEnd /* The </SELECT> markup */
+){
+ while( p && p!=pEnd && p->base.type!=Html_EndSELECT ){
+ if( p->base.type==Html_OPTION ){
+ char *zValue;
+ Tcl_DStringStartSublist(str);
+ if( HtmlMarkupArg(p, "selected", 0)==0 ){
+ Tcl_DStringAppend(str, "0 ", 2);
+ }else{
+ Tcl_DStringAppend(str, "1 ", 2);
+ }
+ zValue = HtmlMarkupArg(p, "value", "");
+ Tcl_DStringAppendElement(str, zValue);
+ Tcl_DStringStartSublist(str);
+ p = p->pNext;
+ while( p && p!=pEnd && p->base.type!=Html_EndOPTION
+ && p->base.type!=Html_OPTION && p->base.type!=Html_EndSELECT ){
+ if( p->base.type==Html_Text ){
+ Tcl_DStringAppend(str, p->text.zText, -1);
+ }else if( p->base.type==Html_Space ){
+ Tcl_DStringAppend(str, " ", 1);
+ }
+ p = p->pNext;
+ }
+ Tcl_DStringEndSublist(str);
+ Tcl_DStringEndSublist(str);
+ }else{
+ p = p->pNext;
+ }
+ }
+}
+
+/*
+** This routine implements the Sizer() function for <INPUT>,
+** <SELECT> and <TEXTAREA> markup.
+**
+** A side effect of sizing these markups is that widgets are
+** created to represent the corresponding input controls.
+**
+** The function normally returns 0. But if it is dealing with
+** a <SELECT> or <TEXTAREA> that is incomplete, 1 is returned.
+** In that case, the sizer will be called again at some point in
+** the future when more information is available.
+*/
+int HtmlControlSize(HtmlWidget *htmlPtr, HtmlElement *pElem){
+ char *zWin; /* Name of child widget that implements this input */
+ int incomplete = 0; /* True if data is incomplete */
+ Tcl_DString cmd; /* The complete -formcommand callback */
+
+ if( pElem->input.sized ) return 0;
+ pElem->input.type = InputType(pElem);
+ switch( pElem->input.type ){
+ case INPUT_TYPE_Checkbox:
+ case INPUT_TYPE_Hidden:
+ case INPUT_TYPE_Image:
+ case INPUT_TYPE_Radio:
+ case INPUT_TYPE_Reset:
+ case INPUT_TYPE_Submit:
+ case INPUT_TYPE_Text:
+ case INPUT_TYPE_Password:
+ case INPUT_TYPE_File: {
+ int result;
+ char zToken[50];
+
+ if( pElem->input.pForm==0 || htmlPtr->zFormCommand==0
+ || htmlPtr->zFormCommand[0]==0 ){
+ EmptyInput(pElem);
+ break;
+ }
+ Tcl_DStringInit(&cmd);
+ Tcl_DStringAppend(&cmd, htmlPtr->zFormCommand, -1);
+ sprintf(zToken," %d input ",pElem->input.pForm->form.id);
+ Tcl_DStringAppend(&cmd, zToken, -1);
+ pElem->input.cnt = ++htmlPtr->nInput;
+ zWin = MakeWindowName(htmlPtr, pElem);
+ Tcl_DStringAppend(&cmd, zWin, -1);
+ Tcl_DStringStartSublist(&cmd);
+ HtmlAppendArglist(&cmd, pElem);
+ Tcl_DStringEndSublist(&cmd);
+ HtmlLock(htmlPtr);
+ result = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&cmd));
+ Tcl_DStringFree(&cmd);
+ if( !HtmlUnlock(htmlPtr) ){
+ SizeAndLink(htmlPtr, zWin, pElem);
+ }
+ HtmlFree(zWin);
+ break;
+ }
+ case INPUT_TYPE_Select: {
+ int result;
+ char zToken[50];
+
+ if( pElem->input.pForm==0 || htmlPtr->zFormCommand==0
+ || htmlPtr->zFormCommand[0]==0 ){
+ EmptyInput(pElem);
+ break;
+ }
+ Tcl_DStringInit(&cmd);
+ Tcl_DStringAppend(&cmd, htmlPtr->zFormCommand, -1);
+ sprintf(zToken," %d select ",pElem->input.pForm->form.id);
+ Tcl_DStringAppend(&cmd, zToken, -1);
+ pElem->input.cnt = ++htmlPtr->nInput;
+ zWin = MakeWindowName(htmlPtr, pElem);
+ Tcl_DStringAppend(&cmd, zWin, -1);
+ Tcl_DStringStartSublist(&cmd);
+ HtmlAppendArglist(&cmd, pElem);
+ Tcl_DStringEndSublist(&cmd);
+ Tcl_DStringStartSublist(&cmd);
+ AddSelectOptions(&cmd, pElem, pElem->input.pEnd);
+ Tcl_DStringEndSublist(&cmd);
+ HtmlLock(htmlPtr);
+ result = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&cmd));
+ Tcl_DStringFree(&cmd);
+ if( !HtmlUnlock(htmlPtr) ){
+ SizeAndLink(htmlPtr, zWin, pElem);
+ }
+ HtmlFree(zWin);
+ break;
+ }
+ case INPUT_TYPE_TextArea: {
+ int result;
+ char zToken[50];
+
+ if( pElem->input.pForm==0 || htmlPtr->zFormCommand==0
+ || htmlPtr->zFormCommand[0]==0 ){
+ EmptyInput(pElem);
+ break;
+ }
+ Tcl_DStringInit(&cmd);
+ Tcl_DStringAppend(&cmd, htmlPtr->zFormCommand, -1);
+ sprintf(zToken," %d textarea ",pElem->input.pForm->form.id);
+ Tcl_DStringAppend(&cmd, zToken, -1);
+ pElem->input.cnt = ++htmlPtr->nInput;
+ zWin = MakeWindowName(htmlPtr, pElem);
+ Tcl_DStringAppend(&cmd, zWin, -1);
+ Tcl_DStringStartSublist(&cmd);
+ HtmlAppendArglist(&cmd, pElem);
+ Tcl_DStringEndSublist(&cmd);
+ Tcl_DStringStartSublist(&cmd);
+ HtmlAppendText(&cmd, pElem, pElem->input.pEnd);
+ Tcl_DStringEndSublist(&cmd);
+ HtmlLock(htmlPtr);
+ result = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&cmd));
+ Tcl_DStringFree(&cmd);
+ if( !HtmlUnlock(htmlPtr) ){
+ SizeAndLink(htmlPtr, zWin, pElem);
+ }
+ HtmlFree(zWin);
+ break;
+ }
+ case INPUT_TYPE_Applet: {
+ int result;
+
+ if( htmlPtr->zAppletCommand==0 || htmlPtr->zAppletCommand[0]==0 ){
+ EmptyInput(pElem);
+ break;
+ }
+ Tcl_DStringInit(&cmd);
+ Tcl_DStringAppend(&cmd, htmlPtr->zAppletCommand, -1);
+ Tcl_DStringAppend(&cmd, " ", 1);
+ pElem->input.cnt = ++htmlPtr->nInput;
+ zWin = MakeWindowName(htmlPtr, pElem);
+ Tcl_DStringAppend(&cmd, zWin, -1);
+ Tcl_DStringStartSublist(&cmd);
+ HtmlAppendArglist(&cmd, pElem);
+ Tcl_DStringEndSublist(&cmd);
+ HtmlLock(htmlPtr);
+ result = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&cmd));
+ Tcl_DStringFree(&cmd);
+ if( !HtmlUnlock(htmlPtr) ){
+ SizeAndLink(htmlPtr, zWin, pElem);
+ }
+ HtmlFree(zWin);
+ break;
+ }
+ default: {
+ CANT_HAPPEN;
+ pElem->base.flags &= ~HTML_Visible;
+ pElem->base.style.flags |= STY_Invisible;
+ pElem->input.tkwin = 0;
+ break;
+ }
+ }
+ return incomplete;
+}
+
+#if 0
+/*
+** The following array determines which characters can be put directly
+** in a query string and which must be escaped.
+*/
+static char needEscape[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1,
+};
+#define NeedToEscape(C) ((C)>0 && (C)<127 && needEscape[(int)(C)])
+
+/*
+** Append to the given DString, an encoded version of the given
+** text.
+*/
+static void EncodeText(Tcl_DString *str, char *z){
+ int i;
+ while( *z ){
+ for(i=0; z[i] && !NeedToEscape(z[i]); i++){ TestPoint(0); }
+ if( i>0 ){ TestPoint(0); Tcl_DStringAppend(str, z, i); }
+ z += i;
+ while( *z && NeedToEscape(*z) ){
+ if( *z==' ' ){
+ Tcl_DStringAppend(str,"+",1);
+ TestPoint(0);
+ }else if( *z=='\n' ){
+ Tcl_DStringAppend(str, "%0D%0A", 6);
+ TestPoint(0);
+ }else if( *z=='\r' ){
+ /* Ignore it... */
+ TestPoint(0);
+ }else{
+ char zBuf[5];
+ sprintf(zBuf,"%%%02X",0xff & *z);
+ Tcl_DStringAppend(str, zBuf, 3);
+ TestPoint(0);
+ }
+ z++;
+ }
+ }
+}
+#endif