david@jpl-devvax.jpl.nasa.gov (David E. Smyth) (04/12/90)
Submitted-by: david@jpl-devvax.jpl.nasa.gov (David E. Smyth) Posting-number: Volume 6, Issue 69 Archive-name: mri/part03 # to unbundle, "sh" this file -- DO NOT use csh # SHAR archive format. Archive created Wed Apr 11 10:01:20 PDT 1990 echo x - MriReg.c sed 's/^X//' > MriReg.c <<'+FUNKY+STUFF+' X/* X******************************************************************************* X* X* SCCS_data: %Z%%M% %I%(%G%) X* X* Module_name: X* X* MriReg.c X* X* Subsystem_group: X* X* Motif Resource Interpreter, Registration Routines X* X* Related_keywords: X* X* Widget, Callback, Class, Constructor, Registration X* X* Module_description: X* X* This module contains the functions used to register callback X* functions, class names, and constructors with Mri. X* X* Since (for portability reasons) we can not assume runtime binding, X* all widget classes or creation routines (constructors) must be X* "registered" by the application BEFORE widget tree creation. X* X* Module_interface_summary: X* X* X* Xt Widget/Object Class Registration Routine: X* X* MriRegisterObjectClass( X* AppContext app, - application context X* String name, - class name, case insensitive X* WidgetClass class ) - class record pointer X* X* X* Motif Widget/Object Constructor Registration Routine: X* X* MriRegisterConstructor( X* AppContext app, - application context X* String name, - constructor name, case insens. X* (*Widget)() const ) - constructor function pointer X* X* X* Standard callback registration routine (all the following callbacks) X* X* MriRegisterMriCallbacks ( X* AppContext app ) - application context X* X* MriRegisterCallback( X* XtAppContext app, - application context X* String name, - register name, case insensitive X* Callback callback, - callback function pointer X* ClientData closure ) - default client data X* X* Module_history: X* X* mm/dd/yy initials function action X* -------- -------- -------- --------------------------------------------- X* 02/26/90 MarBru All Created X* 02/16/90 MarBru Create.. Limited creation to composite widgets/objects X* 04/05/90 d.smyth Dynamic Creation, rename to Mri X* X* Design_notes: X X* For VMS, we could have used LIB$FIND_IMAGE_SYMBOL and use dynamic X* (runtime) binding. But since most UNIX systems lack such capability, X* we stick to the concept of "registration" routines. X* X******************************************************************************* X*/ X/* X******************************************************************************* X* Include_files. X******************************************************************************* X*/ X X/* -- Operating system includes */ X#include <stdio.h> X#include <strings.h> X#include <ctype.h> X X/* -- X Window System includes */ X#include <X11/IntrinsicP.h> X#include <X11/StringDefs.h> X#include <X11/CoreP.h> X#include <XmP.h> X X/* -- Motif Resource Interpreter Includes */ X#include "Mri.h" X#include "MriP.h" X X/* X******************************************************************************* X* Private_data_definitions. X******************************************************************************* X The following cache/registry of known callbacks, constructors, and X classes, initially empty, is loaded by the application using X MriRegisterCallback(), MriRegisterConstructor(), and X MriRegisterObjectClass(). X Assuming small numbers of callbacks, the sequential search X of such cache is (initially) considered acceptable. X*/ X X/* -- Named callback procedures cache, intially empty */ X Xint callbacks_num = 0; Xint callbacks_max = 0; XCBCacheRec *callbacks_ptr = NULL; X X/* -- Named object classes cache, intially empty */ X Xint classes_num = 0; Xint classes_max = 0; XClCacheRec *classes_ptr = NULL; X X/* X******************************************************************************* X* Public_function_declarations. X******************************************************************************* X*/ X/* X -- Register Object Class X******************************************************************************* X This procedure adds object class name to our list of registered X classes/constructors. So far very simplistic ... without checking for X duplicate entries, no cache hashing scheme....no ties to app_context. X*/ Xvoid MriRegisterObjectClass ( app, name, class ) XXtAppContext app; /* not used (yet), must be present */ XString name; /* class name, case insensitive */ XWidgetClass class; /* Xt object class pointer */ X{ X char cr_name[MAX_XRMSTRING]; X register char *s; X register char *d; X X for ( d=cr_name, s=name; *s; s++) X *d++ = (isupper(*s)) ? tolower (*s) : *s; X *d = '\0'; X X if (classes_num >= classes_max ) X { X classes_max += ADD_CLASSES; X classes_ptr = (ClCacheRec*) XtRealloc((char*)classes_ptr, X sizeof(ClCacheRec) * classes_max); X } X classes_ptr[classes_num].quark = XrmStringToQuark ( cr_name ); X classes_ptr[classes_num].constructor = NULL; X classes_ptr[classes_num].class = class; X classes_num++; X} X X/* X -- Register constructor X******************************************************************************* X This procedure adds constructor procedure/name to our list of registered X classes/constructors. So far very simplistic ... without checking for X duplicate entries, no cache hashing scheme....no ties to app_context. X X Note the constructor is a "standard" widget creation routine X Widget XmCreateXyyyZyyy ( parent, name, args, nargs ) X*/ Xvoid MriRegisterConstructor ( app, name, constructor ) XXtAppContext app; /* not used (yet), must be present */ XString name; /* constructor name, case insensitive */ XWidget (*constructor) (); /* pointer to a widget creation routine */ X{ X char cr_name[MAX_XRMSTRING]; X register char *s; X register char *d; X X for ( d=cr_name, s=name; *s; s++) X *d++ = (isupper(*s)) ? tolower (*s) : *s; X *d = '\0'; X X if (classes_num >= classes_max ) X { X classes_max += ADD_CLASSES; X classes_ptr = (ClCacheRec*) XtRealloc((char*)classes_ptr, X sizeof(ClCacheRec) * classes_max); X } X classes_ptr[classes_num].quark = XrmStringToQuark ( cr_name ); X classes_ptr[classes_num].constructor = constructor; X classes_ptr[classes_num].class = NULL; X classes_num++; X} X X/* X -- Register callback X******************************************************************************* X This procedure adds callback procedure/name to our list of registered X callbacks. So far very simplistic ... without checking for duplicate X entries, no cache hashing scheme, no ties to app_context. X*/ Xvoid MriRegisterCallback ( app, name, callback, closure ) XXtAppContext app; /* not used (yet), must be present */ XString name; /* callback name, case insensitive */ XXtCallbackProc callback; /* callback function pointer */ Xcaddr_t closure; /* default closure (client data) */ X{ X char cb_name[MAX_XRMSTRING]; X register char *s; X register char *d; X X for ( d=cb_name, s=name; *s; s++) X *d++ = (isupper(*s)) ? tolower (*s) : *s; X *d = '\0'; X X if (callbacks_num >= callbacks_max ) X { X callbacks_max += ADD_CALLBACKS; X callbacks_ptr = (CBCacheRec*) XtRealloc((char*)callbacks_ptr, X sizeof(CBCacheRec) * callbacks_max); X } X callbacks_ptr[callbacks_num].quark = XrmStringToQuark ( cb_name ); X callbacks_ptr[callbacks_num].callback = callback; X callbacks_ptr[callbacks_num].closure = closure; X callbacks_num++; X} X X/* X -- MriRegisterXrmCallbacks X******************************************************************************* X*/ Xvoid MriRegisterMriCallbacks ( app ) XXtAppContext app; X{ X#define REG( name, cb, cl ) MriRegisterCallback ( app, name, cb, cl ) X X REG("CreateDynamicWidgetCB", MriCreateDynamicWidgetCB, NULL ); X REG("ManageNamedChildrenCB", MriManageNamedChildrenCB, NULL ); X REG("UnmanageNamedChildrenCB", MriUnmanageNamedChildrenCB, NULL ); X REG("SetResourceOnWidgetCB", MriSetResourceOnWidgetCB, NULL ); X REG("QuitApplicationCB", MriQuitApplicationCB, NULL ); X X#undef REG X} +FUNKY+STUFF+ echo '-rw-r--r-- 1 david 8262 Apr 11 07:46 MriReg.c (as sent)' chmod u=rw,g=r,o=r MriReg.c ls -l MriReg.c echo x - Application.c sed 's/^X//' > Application.c <<'+FUNKY+STUFF+' X#include <Xm/Xm.h> X#include "Mri.h" X X/* X -- Application Specific Information X******************************************************************************* X These data and functions must be declared and X initialized. The functions may be null functions. X*/ X Xchar appName[] = "tot"; Xchar appClass[] = "Tot"; XXrmOptionDescRec appOptions[] = NULL; XCardinal numOptions = 0; X Xvoid UserInitialization(); Xvoid RegisterApplicationCallbacks(); X X/* X -- UserInitialization() X******************************************************************************* X Allows the application to perform initialization, including X manipulation of the argv. Note that it is generally alot X easier to process the argument vector using application X resources, if such initialization can safely be performed X after the Xt toolkit is initialized. If an application wishes X to take advantage of the Xt processing of argv based on the X XrmOptionDescRec appOptions, the initialization code which X uses argv information should be performed in the function X RegisterApplicationCallbacks(). X*/ X Xvoid XUserInitialization( argc, argv ) X int *argc; /* note: this gets returned! */ X char *argv[]; X{ X} X X/* X -- Register application specific callbacks X******************************************************************************* X Allows the application to register application specific X callbacks. This function is called after the toolkit is X initialized and the XrmOptionDescRec appOptions is processed, X and before any widgets are created from the Xrm database. X Note, therefore, that the argc, argv passed in have already X been processed by XtInitialize: Xt arguments have been removed X (like geometry specifications) as well as application arguments X specified in the application's appOptions[]. Frequently, X an application would choose to print a usage message if *argc X is not zero, due to the existance of the unrecognized command X line options. X*/ X Xvoid XRegisterApplicationCallbacks( argc, argv, app ) X int *argc; /* note: this gets returned! */ X char *argv[]; X XtAppContext app; X{ X static void pushCB(); X static void destroyCB(); X X MriRegisterCallback ( app, "push", pushCB, NULL ); X MriRegisterCallback ( app, "destroy", destroyCB, NULL ); X} X X/* X -- Push callback X******************************************************************************* X This callback is a state machine; the first invocation loads the text X specified as client data into XmNlabelString resource of invoking widget; X the next invocation exits the application. X*/ Xstatic void XpushCB ( w, client, call ) X Widget w; X caddr_t client; X caddr_t call; X{ X static Boolean first = TRUE; X X if ( first ) X { X static Arg arg; X String text = ( client ) ? (String) client : "No text in Xrdb" ; X XmString val = XmStringCreateLtoR(text,XmSTRING_DEFAULT_CHARSET); X XtSetArg( arg, XmNlabelString, val ); X X XtSetValues ( w, &arg, 1); X X first = FALSE; X } X else X { X exit(); X } X} X X/* X -- Quit callback X******************************************************************************* X Terminate application without saving anything. Assume user really X means it! X*/ Xstatic void XquitCB ( w, client, call ) X Widget w; X caddr_t client; X caddr_t call; X{ X exit(); X} X X/* X -- Destroy callback X******************************************************************************* X destroy the widget. X*/ Xstatic void XdestroyCB ( w, client, call ) X Widget w; X caddr_t client; X caddr_t call; X{ X XtDestroyWidget(w); X} X +FUNKY+STUFF+ echo '-rw-r--r-- 1 david 3741 Apr 11 07:50 Application.c (as sent)' chmod u=rw,g=r,o=r Application.c ls -l Application.c echo x - R_1 sed 's/^X//' > R_1 <<'+FUNKY+STUFF+' X# HelloWorld - global resources X# X*fontList: -*-Times-Medium-R-Normal--14* X# X# shell X# XApp.managedChild_0: box,xmRowColumn X# X# box - the main container X# XApp.box.spacing: 2 XApp.box.background: red XApp.box.marginWidth: 4 XApp.box.marginHeight: 4 XApp.box.entryAlignment: alignment_center XApp.box.managedChild_0: label,xmlabel XApp.box.managedChild_1: push,xmpushbutton X# X# label X# XApp.box.label.background: white XApp.box.label.foreground: blue XApp.box.label.labelString: Hello, WORLD ! XApp.box.label.fontList: -*-Times-Bold-R-Normal--14* X# X# push X# XApp.box.push.background: bluE XApp.box.push.foreground: white XApp.box.push.location: center XApp.box.push.labelString: Push ME XApp.box.push.activateCallback: SetResourceOnWidgetCB( \ X activateCallback, push(To Go...), this) ,\ X SetResourceOnWidgetCB( \ X fontList, *times-bold*240*, this) +FUNKY+STUFF+ echo '-rw-r--r-- 1 david 886 Apr 4 16:48 R_1 (as sent)' chmod u=rw,g=r,o=r R_1 ls -l R_1 echo x - R_2 sed 's/^X//' > R_2 <<'+FUNKY+STUFF+' X# X# HelloWorld X# box main container X# lbl1 headline label - hello world X# box1 bulletin board for default button testing X# btn1 default button X# btn2 button controlling lbl2 X# btn3 button controlling lbl2 X# lbl2 footnote X# X# global resources X# X*fontList: -*-Helvetica-Medium-R-Normal--14* X# X# shell X# XTot.input: true XTot.managedChild_0: box,xmRowColumn X# X# box - the main container X# XTot.box.layout: column XTot.box.spacing: 8 XTot.box.background: red XTot.box.marginWidth: 0 XTot.box.marginHeight: 0 XTot.box.entryAlignment: alignment_center XTot.box.managedChild_0: lbl1,xmLabel XTot.box.managedChild_1: box1,xmBulletinBoard XTot.box.managedChild_2: btn2,xmPushButton XTot.box.managedChild_3: btn3,xmPushButton XTot.box.managedChild_4: lbl2,xmLabel X# X# lbl1 X# XTot.box.lbl1.background: white XTot.box.lbl1.foreground: blue XTot.box.lbl1.labelString: Hello, WORLD ! X# X# box1 X# XTot.box.box1.marginWidth: 8 XTot.box.box1.marginHeight: 8 XTot.box.box1.managedChild_0: btn1,xmPushButton X# X# btn1 X# XTot.box.box1.btn1.labelString: Push ME XTot.box.box1.btn1.background: lightBlue XTot.box.box1.btn1.foreground: red XTot.box.box1.btn1.showAsDefault: 2 XTot.box.box1.btn1.xrmCreateCallback: SetResourceOnWidgetCB(defaultButton,this,box.box1) XTot.box.box1.btn1.activateCallback: push(Push to EXIT !) X# X# btn2 X# XTot.box.btn2.background: lightBlue XTot.box.btn2.foreground: blue XTot.box.btn2.labelString: Remove Footnote XTot.box.btn2.activateCallback: UnmanageNamedChildrenCB(box.lbl2) X# X# btn3 X# XTot.box.btn3.background: lightBlue XTot.box.btn3.foreground: blue XTot.box.btn3.labelString: Add Footnote XTot.box.btn3.activateCallback: ManageNamedChildrenCB(box.lbl2) X# X# lbl2 X# XTot.box.lbl2.background: white XTot.box.lbl2.foreground: blue XTot.box.lbl2.labelString: Ain't it WONDERFULL ? X# +FUNKY+STUFF+ echo '-rw-r--r-- 1 david 1919 Apr 4 14:30 R_2 (as sent)' chmod u=rw,g=r,o=r R_2 ls -l R_2 echo x - R_3 sed 's/^X//' > R_3 <<'+FUNKY+STUFF+' X# X# TDS Output Tool "MacDraw" Style User Interface X# X# N.B. Many motif "XmCreate..." routines actually create a tree X# of widgets, and the root of that tree is often different from X# the "created" widget. For example, in this widget tree we have X# an XmMenuBar widget named menuBar, supposedly with the children X# fileMenu and helpMenu. However, this is really a fiction: since X# the type (really, constructor) specified for the fileMenu is X# XmPulldownMenu, what is really created is an XmMenuShell with X# two children: fileMenu and helpMenu. If either child gets X# mapped, then the XmMenuShell maps too. The name of this shell X# widget really cannot be safely assumed. It happens to be popup_fileMenu X# because the first menu pane it manages is named fileMenu. If X# the name of the first shell managed changes, then the name of X# the menu shell is different... Therefore, I've used wildcards X# for the names of the menu panes. You can't use wild cards for X# names passed to SetResourceOnWidgetCB(), so beware. X# X# Use the debug switch on the command line to dump the names of the X# widgets as they are created. This is very useful for debugging the X# resource file. E.g., App -D X# X# main Main Window X X# menuBar MenuBar X# file File Cascade button X# help Help Cascade button X# popup_fileMenu Pulldown Menu Shell for all pulldowns (magic) X# fileMenu Menu Pane - magically creates parent (popup_fileMenu) X# helpMenu Menu Pane X X# work Form work area X# c RoxCol, where all the controls go on the left X# dataproc rowColumn for data type and processing buttons X# chData RowCol for channel data buttons X# chProc RowCol for channel processing buttons X# frData RowCol for frame data buttons X# frProc RowCol for frame processing buttons X# sinks rowColumn on left below dataproc with buttons X# picture scrolledWindow for display of data and proc flows X# drawing drawingArea clipped by scrolledWindow (picture) X X########## X# Main Window: a MenuBar and a Work X########## X XTot.managedChild_0: main,xmMainWindow X X*main.managedChild_0: menuBar, XmMenuBar X*main.managedChild_1: com, XmRowColumn X*main.managedChild_2: work, XmForm X X########## X# Menu Bar, Cascade Buttons, and Pull Down Menus X########## X X*menuBar.xrmCreateCallback: SetResourceOnWidgetCB( menuBar, this, main ) X*menuBar.managedChild_0: file, XmCascadeButton X*menuBar.unmanagedChild_1: fileMenu, XmPulldownMenu X*menuBar.managedChild_2: help, XmCascadeButton X*menuBar.unmanagedChild_3: helpMenu, XmPulldownMenu X X########## X# File Cascade Button and PullDown Menu X########## X X*file.labelString: File X X*fileMenu.xrmCreateCallback: SetResourceOnWidgetCB( subMenuId, this, \ X main.menuBar.file ) X*fileMenu.managedChild_0: load, XmPushButton X*fileMenu.managedChild_1: sep1, XmSeparator X*fileMenu.managedChild_2: save, XmPushButton X*fileMenu.managedChild_3: saveAs, XmPushButton X*fileMenu.managedChild_4: sep2, XmSeparator X*fileMenu.managedChild_5: quit, XmPushButton X X*fileMenu.load.labelString: Load ... X X*fileMenu.save.labelString: Save X X*fileMenu.saveAs.labelString: Save As ... X X*fileMenu.quit.labelString: Quit !! X*fileMenu.quit.activateCallback: QuitApplicationCB() X X########## X# Help Cascade Button ane PullDown Menu X########## X X*help.labelString: Help X*help.xrmCreateCallback: SetResourceOnWidgetCB( menuHelpWidget, this, \ X main.menuBar ) X X*helpMenu.xrmCreateCallback: SetResourceOnWidgetCB( subMenuId, this, \ X main.menuBar.help ) X*helpMenu.managedChild_0: TBD, XmLabel X X########## X# Com: Common query params: comment, time X########## X X*com.xrmCreateCallback: SetResourceOnWidgetCB( commandWindow, this, main ) X*com.orientation: HORIZONTAL X*com.numColumns: 1 X*com.packing: PACK_COLUMN X*com.managedChild_0: zero_button, XmPushButton X*com.managedChild_1: one_button, XmPushButton X*com.managedChild_2: two_button, XmPushButton X*com.managedChild_3: three_button, XmPushButton X*com.managedChild_4: four_button, XmPushButton X*com.managedChild_5: five_button, XmPushButton X X########## X# Work: Control Panel down Left Side, Scrollable Picture to the Right X########## X X*work.xrmCreateCallback: SetResourceOnWidgetCB( workArea, this, main) X*work.managedChild_0: ctrls, XmRowColumn X*work.managedChild_1: picture, XmScrolledWindow X X*ctrls.managedChild_0: channel, XmRowColumn X*ctrls.managedChild_1: frame, XmRowColumn X*ctrls.managedChild_2: other, XmRowColumn X X*channel.orientation: HORIZONTAL X*channel.packing: PACK_COLUMN X*channel.managedChild_0: chData, XmRowColumn X*channel.managedChild_1: chProc, XmRowColumn X X*frame.orientation: HORIZONTAL X*frame.packing: PACK_COLUMN X*frame.managedChild_0: frData, XmRowColumn X*frame.managedChild_1: frProc, XmRowColumn X X*other.orientation: HORIZONTAL X*other.packing: PACK_COLUMN X*other.managedChild_0: sinkl, XmRowColumn X*other.managedChild_1: sinkr, XmRowColumn X X*chData.managedChild_0: b0, XmPushButton X*chData.managedChild_1: b1, XmPushButton X*chData.managedChild_2: b2, XmPushButton X*chData.managedChild_3: b3, XmPushButton X X*chData.b0.labelString: First Channel Set X*chData.b0.activateCallback: CreateDynamicWidgetCB( \ X main.work.picture.ScrolledWindowClipWindow.drawing.firstChSetIcon ) X*chData.b1.labelString: Second Channel Set X*chData.b2.labelString: Third Channel Set X*chData.b3.labelString: Specific Channels X X*chProc.managedChild_0: b0, XmPushButton X*chProc.managedChild_1: b1, XmPushButton X*chProc.managedChild_2: b2, XmPushButton X*chProc.managedChild_3: b3, XmPushButton X*chProc.managedChild_4: b4, XmPushButton X X*chProc.b0.labelString: ECDR Conversion (Std) X*chProc.b1.labelString: ECDR Conv (Specific) X*chProc.b2.labelString: Template Fmt (File) X*chProc.b3.labelString: Template Fmt (Proc) X*chProc.b4.labelString: Subset X X*frData.managedChild_0: b0, XmPushButton X*frData.managedChild_1: b1, XmPushButton X*frData.managedChild_2: b2, XmPushButton X*frData.managedChild_3: b3, XmPushButton X*frData.managedChild_4: b4, XmPushButton X*frData.managedChild_5: b5, XmPushButton X*frData.managedChild_6: b6, XmPushButton X X*frData.b0.labelString: Raw Frames X*frData.b1.labelString: Packets X*frData.b2.labelString: S/C Engineering X*frData.b3.labelString: MRO X*frData.b4.labelString: DSS Monitor X*frData.b5.labelString: QQC X*frData.b6.labelString: Science X X*frProc.managedChild_0: b0, XmPushButton X*frProc.managedChild_1: b1, XmPushButton X*frProc.managedChild_2: b2, XmPushButton X*frProc.managedChild_3: b3, XmPushButton X*frProc.managedChild_4: b4, XmPushButton X*frProc.managedChild_5: b5, XmPushButton X X*frProc.b0.labelString: ECDR Conversion (Std) X*frProc.b1.labelString: ECDR Conv (Specific) X*frProc.b2.labelString: Template Fmt (File) X*frProc.b3.labelString: Template Fmt (Proc) X*frProc.b4.labelString: Subset X*frProc.b5.labelString: Decommutation X X*sinkl.managedChild_0: b0, XmPushButton X*sinkl.managedChild_1: b1, XmPushButton X*sinkl.managedChild_2: b2, XmPushButton X X*sinkl.b0.labelString: UNIX File X*sinkl.b1.labelString: UNIX Pipe X*sinkl.b2.labelString: UNIX Socket X X*sinkr.managedChild_0: b0, XmPushButton X*sinkr.managedChild_1: b1, XmPushButton X*sinkr.managedChild_2: b2, XmPushButton X X*sinkr.b0.labelString: Spooler X*sinkr.b1.labelString: Virtual Circuit X*sinkr.b2.labelString: stdout X*sinkr.b2.activateCallback: CreateDynamicWidgetCB( \ X main.work.picture.ScrolledWindowClipWindow.drawing.stdoutIcon ) X X########## X# Picture: Drawing area within scrolled window X########## X X*picture.topAttachment: ATTACH_FORM X*picture.leftAttachment: ATTACH_WIDGET X*picture.leftWidget: main.work.ctrls X*picture.rightAttachment: ATTACH_FORM X*picture.bottomAttachment: ATTACH_FORM X*picture.scrollingPolicy: AUTOMATIC X*picture.scrollBarDisplayPolicy: AS_NEEDED X*picture.managedChild_0: drawing, XmForm X X*drawing.width: 200 X*drawing.height: 700 X*drawing.xrmCreateCallback: SetResourceOnWidgetCB( workWindow, this, \ X main.work.picture) X X*drawing.dynamicChild_0: stdoutIcon, XmPushButton, n X*drawing.dynamicChild_1: firstChSetIcon, XmPushButton X X*stdoutIcon.activateCallback: destroy() X*stdoutIcon.labelString: stdout X*stdoutIcon.fontList: *Times-Bold*140* X*stdoutIcon.rightAttachment: ATTACH_FORM X X*firstChSetIcon.activateCallback: destroy() X*firstChSetIcon.labelString: First Channel Set X*firstChSetIcon.fontList: *Times-Bold*140* X*firstChSetIcon.leftAttachment: ATTACH_FORM +FUNKY+STUFF+ echo '-rw-r--r-- 1 david 8404 Apr 11 07:50 R_3 (as sent)' chmod u=rw,g=r,o=r R_3 ls -l R_3 exit 0 dan ----------------------------------------------------------- O'Reilly && Associates argv@sun.com / argv@ora.com 632 Petaluma Ave, Sebastopol, CA 95472 800-338-NUTS, in CA: 800-533-NUTS, FAX 707-829-0104 Opinions expressed reflect those of the author only.