home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-11-19 | 41.2 KB | 1,085 lines |
- Newsgroups: comp.sources.misc
- From: karl@sugar.neosoft.com (Karl Lehenbauer)
- Subject: v26i013: tclx - extensions and on-line help for tcl 6.1, Part13/23
- Message-ID: <1991Nov19.135408.998@sparky.imd.sterling.com>
- X-Md4-Signature: a0f5b5f2bbff851835a5c1e82f59dae2
- Date: Tue, 19 Nov 1991 13:54:08 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: karl@sugar.neosoft.com (Karl Lehenbauer)
- Posting-number: Volume 26, Issue 13
- Archive-name: tclx/part13
- Environment: UNIX
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 13 (of 23)."
- # Contents: extended/man/CmdWrite.man extended/src/chmod.c
- # extended/tcllib/help/intro/expressions
- # Wrapped by karl@one on Wed Nov 13 21:50:26 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'extended/man/CmdWrite.man' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'extended/man/CmdWrite.man'\"
- else
- echo shar: Extracting \"'extended/man/CmdWrite.man'\" \(12815 characters\)
- sed "s/^X//" >'extended/man/CmdWrite.man' <<'END_OF_FILE'
- X.TH "Command Writing" TCL "" "Tcl"
- X.ad b
- X'@index: TclCommandWriting
- X.SH NAME
- XTclCommandWriting - Writing C language extensions to Tcl.
- X'
- X.SH OVERVIEW
- XThis document is intended to help the programmer who wishes to extend
- XTcl with C language routines. It should also be useful to someone
- Xwishing to add Tcl to an existing editor, comm program, etc. There
- Xis also programming information in the \fITcl.man\fR manual
- Xdirectory of the Berkeley distribution.
- X'
- X.SH WRITING TCL EXTENSIONS IN C
- XC extensions to Tcl must be written to receive their arguments in the
- Xmanner Tcl uses to pass them.
- X.PP
- XA C routine is called from Tcl with four arguments, a client data pointer,
- Xan interpreter pointer, an argument count and a pointer to an array of
- Xpointers to character strings containing the Tcl arguments to the routine.
- X.PP
- XA Tcl extension in C is now presented, and described below:
- X.sp
- X.nf
- X.ft CW
- X #include "tcl.h"
- X
- X int Tcl_EchoCmd(clientData, interp, argc, argv)
- X void *clientData;
- X Tcl_Interp *interp;
- X int argc;
- X char **argv;
- X {
- X int i;
- X
- X for (i = 1; i < argc; i++) {
- X printf("%s ",argv[i]);
- X }
- X printf("\\n");
- X return TCL_OK;
- X }
- X.ft R
- X.fi
- X.PP
- XThe client data pointer will be described later.
- X.PP
- XThe interpreter pointer is the ``key'' to an interpreter. It is returned by
- X\fITcl_CreateInterp\fR or \fITcl_CreateExtendedInterp\fR and is used within
- XTcl and by your C code. The structure pointed to by the interpreter pointer,
- Xand all of the subordinate structures that branch off of it, make up an
- Xinterpreter context, which includes all of the currently defined procedures,
- Xcommands, variables, arrays and the execution state of that interpreter.
- X.PP
- XThe argument count and pointer to an array of pointers to textual arguments
- Xis handled by your C code in the same manner that you would use in writing a
- XC \fImain\fR function -- the argument count and array of pointers
- Xworks the same
- Xas in a C \fImain\fR call; pointers to the arguments to the function are
- Xcontained
- Xin the \fIargv\fR array. Similar to a C main, the first argument
- X(\fIargv[0]\fR) is the
- Xname the routine was called as (in a main, the name the program
- Xwas invoked as).
- X.PP
- XIn the above example, all of the arguments are output with a space between
- Xeach one by looping through \fIargv\fR from one to the argument count,
- X\fIargc\fR, and a
- Xnewline terminates the line -- an echo command, although a ``real'' echo
- Xcommand would not add a trailing blank like this one does.
- X.PP
- XAll arguments from a Tcl call to a Tcl C extension are passed as strings.
- XIf your C routine expects certain numeric arguments, your routine must first
- Xconvert them using the \fITcl_GetInt\fR or \fITcl_GetDouble\fR
- Xfunction, or some other method
- Xof your own devising. If you program produces a numeric result, it should
- Xreturn a string equivalent to that numeric value. A common way of doing
- Xthis is something like...
- X.sp
- X.nf
- X.ft CW
- X sprintf(interp->result, "%ld", result);
- X.ft R
- X.fi
- X.PP
- XMore sophisticated commands should verify their arguments when possible,
- Xboth by examining the argument count, by verifying that numeric fields
- Xare really numeric, that values
- Xare in range when their ranges are known, and so forth.
- X.PP
- XTcl is designed to be as bullet-proof as possible, in the
- Xsense that Tcl programs should not be able to cause Tcl to dump core. Please
- Xdo the same with your C extensions by validating arguments as above.
- X.PP
- XIn the command below, two or more arguments are compared and the one with
- Xthe maximum value is returned, if all goes well. It is an error if there
- Xare fewer than three arguments (the pointer to the ``max'' command text itself,
- X\fIargv[0]\fR, and pointers to at least two arguments to compare the
- Xvalues of).
- X.PP
- XThis routine also shows the use of the programmer labor-saving
- X\fITcl_AppendResult\fR
- Xroutine. See the Tcl manual page, \fISetResult.man\fR, for details.
- XAlso examine the calls \fITcl_SetErrorCode\fR and \fITcl_UnixError\fR
- Xdocumented in the Tcl manual page \fIAddErrInfo.man\fR.
- X.sp
- X.nf
- X.ft CW
- X int
- X Tcl_MaxCmd (clientData, interp, argc, argv)
- X char *clientData;
- X Tcl_Interp *interp;
- X int argc;
- X char **argv;
- X {
- X int maxVal = MININT;
- X int maxIdx = 1;
- X int value, idx;
- X
- X
- X if (argc < 3) {
- X Tcl_AppendResult (interp, "bad # arg: ", argv[0],
- X " num1 num2 [..numN]", (char *)NULL);
- X return TCL_ERROR;
- X }
- X
- X for (idx = 1; idx < argc; idx++) {
- X if (Tcl_GetInt (argv[idx], 10, &Value) != TCL_OK)
- X return TCL_ERROR;
- X
- X if (value > maxVal) {
- X maxVal = value;
- X maxIdx = idx;
- X }
- X }
- X strcpy (interp->result, argv [maxIdx]);
- X return TCL_OK;
- X }
- X.ft R
- X.fi
- X.PP
- XWhen Tcl-callable functions complete, they should normally return
- X\fBTCL_OK\fR or \fBTCL_ERROR\fR.
- X\fBTCL_OK\fR is returned when the command succeeded and \fBTCL_ERROR\fR
- Xis returned when the command has failed rather drastically.
- X\fBTCL_ERROR\fR should
- Xbe returned for all syntax errors, non-numeric values where numeric ones
- Xwere expected, and so forth. Less clear in some cases is whether Tcl errors
- Xshould be returned or whether a function should just return a status value.
- XFor example, end-of-file during a \fIgets\fR returns a status,
- Xbut \fIopen\fR
- Xreturns an error if the open fails. Errors can be caught from
- XTcl programs using the \fIcatch\fR command.
- X.PP
- XLess common return values are
- X\fBTCL_RETURN\fR, \fBTCL_BREAK\fR and \fBTCL_CONTINUE\fR.
- XThese are used if you are adding new control and/or looping
- Xstructures to Tcl. To see these values in action, examine the source to
- Xthe \fIwhile\fR, \fIfor\fR, \fIif\fR and \fIloop\fR commands.
- X'
- X.SH INSTALLING YOUR COMMAND
- X.P
- XTo install your command into Tcl your must call
- X\fITcl_CreateCommand\fR, passing
- Xit the pointer into the interpreter you want to install the command into,
- Xthe name of the command, a pointer to the C function, a client data pointer,
- Xand a pointer to an optional callback routine.
- X.PP
- XThe client data pointer and the callback routine will be described later.
- X.PP
- XFor example, for the max function above (which incidentally comes from
- Xmath.c in the extend/src directory):
- X.sp
- X.nf
- X.ft CW
- X Tcl_CreateCommand (interp, "max", Tcl_MaxCmd, (ClientData)NULL,
- X (void (*)())NULL);
- X.ft R
- X.fi
- X.PP
- XIn the above example, the max function is added
- Xto the specified interpreter. The client data pointer and callback
- Xfunction pointer are NULL.
- X.PP
- X.SH CLIENT DATA
- X.PP
- XThe client data pointer provides a means for Tcl commands to have data
- Xassociated through them that is not global to the C program including
- Xthe Tcl core. It is essential in a multi-interpreter environment
- X(where a single program has created and is making use of multiple
- XTcl interpreters)
- Xfor the C routines to maintain any permanent data they need relative to
- Xeach interpreter being used, or there would be reentrancy problems.
- XTcl solves this through the client data mechanism. When you are about
- Xto call
- X\fITcl_CreateCommand\fR to add a new command to an interpreter, if that
- Xcommand needs to keep some read/write data from one invocation to another,
- Xyou should allocate the space, preferably using \fIckalloc\fR, then pass
- Xthe address of that space as the ClientData pointer to
- X\fITcl_CreateCommand\fR.
- X.PP
- XWhen your command is called from Tcl, the ClientData pointer you gave to
- X\fITcl_CreateCommand\fR when you added the command to that interpreter
- Xis passed
- Xto your C routine through the ClientData pointer calling argument.
- X.PP
- XCommands that need to share this data with one another can do so by using the
- Xsame ClientData pointer when the commands are added.
- X.PP
- XIt is important to note that the Tcl extensions in the extended/src
- Xdirectory have had all of their data set up in this way, so at
- Xthe time of this writing (release 6.1) the Tcl extensions support
- Xmultiple interpreters within one invocation of Tcl.
- X'
- X.SH INTEL '286 GOTCHAS
- X.P
- XThe '286 programmer who is not using an ANSI C standard compiler with
- Xfunction prototypes must be vigilant to ensure that anytime NULL is
- Xpassed to a function as a pointer it is explicitly cast to
- X\fB(void *)\fR or equivalent. Also remember that Tcl math within
- Xexpressions is carried out to 32 bits, so that you should usually use
- Xthe \fIlong\fR variable type for your integers, \fITcl_GetLong\fR (rather
- Xthan \fITcl_GetInt\fR) to convert strings to long integers, and remember
- Xto use \fB%ld\fR when printing results with \fIsprintf\fR, and so
- Xforth.
- X.PP
- XTo maintain '286 compatibility, all C programmers are asked to follow
- Xthese guidelines. I know you don't want to, but there are a lot of
- X286 machines out there and it is nice that they are able to run Tcl.
- X.SH THEORY OF HANDLES
- XSometimes you need to have a data element that isn't readily representable
- Xas a string within Tcl, for example a pointer to a complex C data structure.
- XWe do not think it is a good idea to try to pass pointers around within
- XTcl as strings by converting them to and from hex or integer representations,
- Xfor example. It is too easy to screw one up and the likely outcome of
- Xdoing that is a core dump.
- X.PP
- XInstead what we have done is developed and made use of the concept
- Xof \fIhandles\fR.
- XHandles are identifiers a C extension can pass to, and accept from,
- XTcl to make the transition between what your C code knows something as
- Xand what name Tcl knows it by to be as safe and painless as possible.
- XFor example,
- Xthe stdio package included in Tcl uses file handles. When you open a
- Xfile from Tcl, a handle is returned of the form \fBfile\fIn\fR where
- X\fIn\fR is a file number. When you pass the file handle back to \fIputs\fR,
- X\fIgets\fR, \fIseek\fR, \fIflush\fR and so forth, they validate the file
- Xhandle by checking the the \fBfile\fR text is present, then converting
- Xthe file number to an integer that they use to look into a data
- Xstructure of pointers
- Xto Tcl open file structures, which contain a Unix file descriptor, flags
- Xindicating whether or not the file is currently open, whether the file is
- Xa file or a pipe and so forth.
- X.PP
- XHandles have proven so useful that, as of release 6.1a, general support
- Xhas been added for them.
- XIf you need a similar capability, it would be best to use the handle
- Xroutines, documented in \fIHandles.man\fR.
- XWe recommend that you use a
- Xunique-to-your-package textual handle coupled with a specific identifier
- Xand let the handle management routines validate it when it's passed back.
- XIt is much easier to
- Xtrack down a bug with an implicated handle named something like \fBfile4\fR
- Xor \fBbitmap6\fR than just \fB6\fR.
- X.PP
- X.SH TRACKING MEMORY CORRUPTION PROBLEMS
- XOccasionally you may write code that scribbles past the end of an
- Xallocated piece of memory. The memory debugging
- Xroutines included in Tcl can help find these problems. See
- X\fIextended/man/Memory.man\fR for details.
- X.PP
- X.SH WRITING AN APPLICATION-SPECIFIC MAIN
- XFor those writing an application-specific main, for example, those adding
- XTcl to an existing application or including Tcl within a larger application,
- Xa few steps need to be taken to set up Tcl.
- X.PP
- XFor one thing, several \fIextern char *\fR definitions must be fulfilled,
- Xproviding data used by the \fIinfox\fR command. These definitions are
- X\fItclxVersion\fR, the Extended Tcl version number, \fItclxPatchlevel\fR,
- Xthe Extended Tcl patch level, \fItclAppName\fR, the name of the application,
- X\fItclAppLongname\fR, a description of the application, and
- X\fItclAppVersion\fR, the version number of the application.
- X.PP
- XA Tcl interpreter, including all of the extensions in Extended Tcl, is
- Xcreated with a call to \fITcl_CreateExtendedInterp\fR. Next, any
- Xapplication-specific commands are added by calls to \fITcl_CreateCommand\fR.
- XFinally, \fITcl_Startup\fR is called to load the Tcl startup code, pull
- Xin all of the Tcl procs and paths, do command line processing, handle
- Xautoloads, packages, and so forth. If the application writer wants
- Xdifferent startup behavior, they should write a different Tcl startup
- Xroutine. \fITcl_Startup\fR is defined in the file \fItclstartup.c\fR
- Xin the \fIextended/src\fR directory.
- X.PP
- XFinally, cleanup code is called to close down the application.
- X\fITcl_DeleteInterp\fR is called to free memory used by Tcl -- normally,
- Xthis is only called if \fBTCL_MEM_DEBUG\fR was defined, since Unix
- Xwill return all of the allocated memory back to the system, anyway.
- X.PP
- XThe writer of an application-specific main is invited to examine and use
- Xthe \fImain()\fR routine defined in \fIextended/src/main.c\fR
- Xas a template for their new main. There is a \fItcl++.C\fR, which is a
- Xmain for C++-based Tcl applications.
- END_OF_FILE
- if test 12815 -ne `wc -c <'extended/man/CmdWrite.man'`; then
- echo shar: \"'extended/man/CmdWrite.man'\" unpacked with wrong size!
- fi
- # end of 'extended/man/CmdWrite.man'
- fi
- if test -f 'extended/src/chmod.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'extended/src/chmod.c'\"
- else
- echo shar: Extracting \"'extended/src/chmod.c'\" \(12830 characters\)
- sed "s/^X//" >'extended/src/chmod.c' <<'END_OF_FILE'
- X/*
- X * chmod.c --
- X *
- X * Chmod, chown and chgrp Tcl commands.
- X *---------------------------------------------------------------------------
- X * Copyright 1991 Karl Lehenbauer and Mark Diekhans.
- X *
- X * Permission to use, copy, modify, and distribute this software and its
- X * documentation for any purpose and without fee is hereby granted, provided
- X * that the above copyright notice appear in all copies. Karl Lehenbauer and
- X * Mark Diekhans make no representations about the suitability of this
- X * software for any purpose. It is provided "as is" without express or
- X * implied warranty.
- X */
- X
- X#include "tclExtdInt.h"
- X
- X/*
- X * Prototypes of internal functions.
- X */
- Xint
- XTcl_ConvSymMode _ANSI_ARGS_((char *sysPerms,
- X int modeVal));
- X
- Xint
- XTcl_ConvAbsMode _ANSI_ARGS_((char *modeStr,
- X int assumeInt));
- X
- X
- X/*
- X *----------------------------------------------------------------------
- X *
- X * Tcl_ConvSymMode --
- X * Parse and convert symbolic file permissions as specified by chmod(C).
- X *
- X * Parameters:
- X * symPerms - The symbolic permissions to parse.
- X * modeVal - The existing permissions value on a file.
- X *
- X * Results:
- X * The new permissions, or -1 if invalid permissions where supplied.
- X *
- X *----------------------------------------------------------------------
- X */
- Xstatic int
- XTcl_ConvSymMode (sysPerms, modeVal)
- X char *sysPerms;
- X int modeVal;
- X
- X{
- X int user, group, other;
- X char operator;
- X int rwxMask, setUID, sticky, locking;
- X int newMode;
- X
- X while (*sysPerms != 0) {
- X user = group = other = FALSE;
- X
- X /*
- X * Scan who field.
- X */
- X while (! ((*sysPerms == '+') ||
- X (*sysPerms == '-') ||
- X (*sysPerms == '='))) {
- X switch (*sysPerms) {
- X case 'a':
- X user = group = other = TRUE;
- X break;
- X case 'u':
- X user = TRUE;
- X break;
- X case 'g':
- X group = TRUE;
- X break;
- X case 'o':
- X other = TRUE;
- X break;
- X default:
- X return -1; /* Error, not a recognized character or EOL */
- X }
- X sysPerms++;
- X }
- X
- X /*
- X * If none where specified, that means all.
- X */
- X
- X if (! (user || group || other))
- X user = group = other = TRUE;
- X
- X operator = *sysPerms++;
- X
- X /*
- X * Decode the permissions
- X */
- X
- X rwxMask = 0;
- X setUID = sticky = locking = FALSE;
- X
- X /*
- X * Scan permissions field
- X */
- X while (! ((*sysPerms == ',') || (*sysPerms == 0))) {
- X switch (*sysPerms) {
- X case 'r':
- X rwxMask |= 4;
- X break;
- X case 'w':
- X rwxMask |= 2;
- X break;
- X case 'x':
- X rwxMask |= 1;
- X break;
- X case 's':
- X setUID = TRUE;
- X break;
- X case 't':
- X sticky = TRUE;
- X break;
- X case 'l':
- X locking = TRUE;
- X break;
- X default:
- X return -1; /* Error, not a recognized character */
- X }
- X sysPerms++;
- X }
- X
- X /*
- X * Build mode map of specified values.
- X */
- X
- X newMode = 0;
- X if (user)
- X newMode |= rwxMask << 6;
- X if (group)
- X newMode |= rwxMask << 3;
- X if (other)
- X newMode |= rwxMask;
- X if (setUID && user)
- X newMode |= 04000;
- X if ((setUID || locking) && group)
- X newMode |= 02000;
- X if (sticky)
- X newMode |= 01000;
- X
- X /*
- X * Add to cumulative mode based on operator.
- X */
- X
- X if (operator == '+')
- X modeVal |= newMode;
- X else if (operator == '-')
- X modeVal &= ~newMode;
- X else if (operator == '=')
- X modeVal = newMode;
- X if (*sysPerms == ',')
- X sysPerms++;
- X }
- X
- X return modeVal;
- X
- X} /* Tcl_ConvSymMode */
- X
- X/*
- X *----------------------------------------------------------------------
- X *
- X * Tcl_ConvAbsMode --
- X * Convert a absolute file mode. If this fails, it might be a
- X * symbolic mode. Mode is assumed to be octal unless otherwise
- X * specified.
- X *
- X * Parameters:
- X * modeStr - The file mode string.
- X * assumeInt - Assume and integer (although a leading 0 will indicate
- X * octal.
- X * Results:
- X * The new permissions, or -1 if invalid permissions where supplied.
- X *
- X *----------------------------------------------------------------------
- X */
- Xint
- XTcl_ConvAbsMode (modeStr, assumeInt)
- X char *modeStr;
- X int assumeInt;
- X{
- X int mode;
- X
- X if (!Tcl_StrToInt (modeStr, (assumeInt) ? 0 : 8, &mode))
- X return -1; /* Not an octal number */
- X else
- X return mode;
- X
- X} /* Tcl_ConvAbsMode */
- X
- X/*
- X *----------------------------------------------------------------------
- X *
- X * Tcl_ChmodCmd --
- X * Implements the TCL chmod command:
- X * chmod [-i] mode filelist
- X *
- X * Results:
- X * Standard TCL results, may return the UNIX system error message.
- X *
- X *----------------------------------------------------------------------
- X */
- Xint
- XTcl_ChmodCmd (clientData, interp, argc, argv)
- X ClientData clientData;
- X Tcl_Interp *interp;
- X int argc;
- X char **argv;
- X{
- X int idx, modeVal, assumeInt, fileArgc, result = TCL_ERROR;
- X char **fileArgv, *modePtr;
- X struct stat fileStat;
- X
- X if (argc < 3)
- X goto wrongArgs;
- X if ((argv [1][0] == '-') && (argv [1][1] == 'i') && (argv [1][2] == '\0')){
- X if (argc < 4)
- X goto wrongArgs;
- X assumeInt = TRUE;
- X modePtr = argv [2];
- X } else {
- X assumeInt = FALSE;
- X modePtr = argv [1];
- X }
- X
- X if (Tcl_SplitList (interp, argv [argc - 1], &fileArgc,
- X &fileArgv) != TCL_OK)
- X return TCL_ERROR;
- X
- X for (idx = 0; idx < fileArgc; idx++) {
- X if ((modeVal = Tcl_ConvAbsMode (modePtr, assumeInt)) < 0) {
- X if (stat (fileArgv [idx], &fileStat) != 0)
- X goto fileError;
- X modeVal = Tcl_ConvSymMode (modePtr, fileStat.st_mode & 07777);
- X if (modeVal < 0) {
- X interp->result = "invalid file mode";
- X goto exitPoint;
- X }
- X if (assumeInt) {
- X Tcl_AppendResult (interp, argv [0], ": -i flag may not be",
- X " used with symbolic modes", (char *) NULL);
- X goto exitPoint;
- X }
- X }
- X if (chmod (fileArgv [idx], modeVal) < 0)
- X goto fileError;
- X }
- X
- X result = TCL_OK;
- XexitPoint:
- X ckfree ((char *) fileArgv);
- X return result;
- X
- XfileError:
- X /*
- X * Error accessing file, assumes file name is fileArgv [idx].
- X */
- X Tcl_AppendResult (interp, argv [0], ": ", fileArgv [idx], ": ",
- X Tcl_UnixError (interp), (char *) NULL);
- X ckfree ((char *) fileArgv);
- X return TCL_ERROR;
- X
- XwrongArgs:
- X Tcl_AppendResult (interp, "wrong # args: ", argv [0],
- X " [-i] mode filelist", (char *) NULL);
- X return TCL_ERROR;
- X}
- X
- X/*
- X *----------------------------------------------------------------------
- X *
- X * Tcl_ChownCmd --
- X * Implements the TCL chown command:
- X * chown owner filelist
- X * chown {owner group} filelist
- X *
- X * Results:
- X * Standard TCL results, may return the UNIX system error message.
- X *
- X *----------------------------------------------------------------------
- X */
- Xint
- XTcl_ChownCmd (clientData, interp, argc, argv)
- X ClientData clientData;
- X Tcl_Interp *interp;
- X int argc;
- X char **argv;
- X{
- X int idx, ownArgc, fileArgc;
- X char **ownArgv, **fileArgv = NULL;
- X struct stat fileStat;
- X int useOwnerGrp, chGroup, ownerId, groupId;
- X struct passwd *passwdPtr;
- X struct group *groupPtr;
- X int result = TCL_ERROR;
- X
- X if (argc != 3) {
- X Tcl_AppendResult (interp, "wrong # args: ", argv [0],
- X " owner|{owner group} filelist", (char *) NULL);
- X return TCL_ERROR;
- X }
- X
- X if (Tcl_SplitList (interp, argv[1], &ownArgc, &ownArgv) != TCL_OK)
- X return TCL_ERROR;
- X if ((ownArgc < 1) || (ownArgc > 2)) {
- X interp->result = "owner arg should be: owner or {owner group}";
- X goto exitPoint;
- X }
- X if (ownArgc == 2) {
- X useOwnerGrp = (ownArgv [1][0] == '\0');
- X chGroup = TRUE;
- X } else
- X chGroup = FALSE;
- X
- X /*
- X * Get the owner id, either convert the name or use it as an integer.
- X */
- X passwdPtr = getpwnam (ownArgv [0]);
- X if (passwdPtr != NULL)
- X ownerId = passwdPtr->pw_uid;
- X else {
- X if (!Tcl_StrToInt (ownArgv [0], 10, &ownerId)) {
- X Tcl_AppendResult (interp, "unknown user id: ", ownArgv [0],
- X (char *) NULL);
- X goto exitPoint;
- X }
- X }
- X /*
- X * Get the group id, this is either the specified id or name, or the
- X * if associated with the specified user.
- X */
- X if (chGroup) {
- X if (useOwnerGrp) {
- X if (passwdPtr == NULL) {
- X passwdPtr = getpwuid (ownerId);
- X if (passwdPtr != NULL) {
- X Tcl_AppendResult (interp, "unknown user id: ",
- X ownArgv [0], (char *) NULL);
- X goto exitPoint;
- X }
- X }
- X groupId = passwdPtr->pw_gid;
- X } else {
- X groupPtr = getgrnam (ownArgv [1]);
- X if (groupPtr != NULL)
- X groupId = groupPtr->gr_gid;
- X else {
- X if (!Tcl_StrToInt (ownArgv [1], 10, &groupId)) {
- X Tcl_AppendResult (interp, "unknown group id: ",
- X ownArgv [1], (char *) NULL);
- X goto exitPoint;
- X }
- X }
- X }
- X }
- X if (Tcl_SplitList (interp, argv [2], &fileArgc, &fileArgv) != TCL_OK)
- X goto exitPoint;
- X
- X for (idx = 0; idx < fileArgc; idx++) {
- X if (!chGroup) {
- X if (stat (fileArgv [idx], &fileStat) != 0) {
- X Tcl_AppendResult (interp, argv [0], ": ", fileArgv [idx], ": ",
- X Tcl_UnixError (interp), (char *) NULL);
- X goto exitPoint;
- X }
- X groupId = fileStat.st_gid;
- X }
- X
- X if (chown (fileArgv[idx], ownerId, groupId) < 0) {
- X Tcl_AppendResult (interp, argv [0], ": ", fileArgv [idx], ": ",
- X Tcl_UnixError (interp), (char *) NULL);
- X goto exitPoint;
- X }
- X
- X } /* Modify each file */
- X
- X result = TCL_OK;
- XexitPoint:
- X ckfree ((char *) ownArgv);
- X if (fileArgv != NULL)
- X ckfree ((char *) fileArgv);
- X return result;
- X}
- X
- X/*
- X *----------------------------------------------------------------------
- X *
- X * Tcl_ChgrpCmd --
- X * Implements the TCL chgrp command:
- X * chgrp group filelist
- X *
- X * Results:
- X * Standard TCL results, may return the UNIX system error message.
- X *
- X *----------------------------------------------------------------------
- X */
- Xint
- XTcl_ChgrpCmd (clientData, interp, argc, argv)
- X ClientData clientData;
- X Tcl_Interp *interp;
- X int argc;
- X char **argv;
- X{
- X int idx, fileArgc, groupId, result = TCL_ERROR;
- X char **fileArgv;
- X struct stat fileStat;
- X struct group *groupPtr;
- X
- X if (argc < 3) {
- X Tcl_AppendResult (interp, "wrong # args: ", argv [0],
- X " group filelist", (char *) NULL);
- X return TCL_ERROR;
- X }
- X
- X groupPtr = getgrnam (argv [1]);
- X if (groupPtr != NULL)
- X groupId = groupPtr->gr_gid;
- X else {
- X if (!Tcl_StrToInt (argv [1], 10, &groupId)) {
- X Tcl_AppendResult (interp, "unknown group id: ", argv [1],
- X (char *) NULL);
- X return TCL_ERROR;
- X }
- X }
- X if (Tcl_SplitList (interp, argv [2], &fileArgc, &fileArgv) != TCL_OK)
- X return TCL_ERROR;
- X
- X for (idx = 0; idx < fileArgc; idx++) {
- X if ((stat (fileArgv [idx], &fileStat) != 0) ||
- X (chown (fileArgv[idx], fileStat.st_uid, groupId) < 0)) {
- X Tcl_AppendResult (interp, argv [0], ": ", fileArgv [idx], ": ",
- X Tcl_UnixError (interp), (char *) NULL);
- X goto exitPoint;
- X }
- X } /* Modify each file */
- X
- X result = TCL_OK;
- XexitPoint:
- X ckfree ((char *) fileArgv);
- X return result;
- X}
- END_OF_FILE
- if test 12830 -ne `wc -c <'extended/src/chmod.c'`; then
- echo shar: \"'extended/src/chmod.c'\" unpacked with wrong size!
- fi
- # end of 'extended/src/chmod.c'
- fi
- if test -f 'extended/tcllib/help/intro/expressions' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'extended/tcllib/help/intro/expressions'\"
- else
- echo shar: Extracting \"'extended/tcllib/help/intro/expressions'\" \(12156 characters\)
- sed "s/^X//" >'extended/tcllib/help/intro/expressions' <<'END_OF_FILE'
- X EXPRESSIONS
- X The second major interpretation applied to strings in Tcl is
- X as expressions. Several commands, such as expr, for, and
- X if, treat one or more of their arguments as expressions and
- X call the Tcl expression processors (Tcl_ExprLong,
- X Tcl_ExprBoolean, etc.) to evaluate them. The operators
- X permitted in Tcl expressions are a subset of the operators
- X permitted in C expressions, and they have the same meaning
- X and precedence as the corresponding C operators.
- X
- X Expressions almost always yield numeric results (integer or
- X floating-point values). For example, the expression
- X
- X 8.2 + 6
- X
- X evaluates to 14.2. Tcl expressions differ from C
- X expressions in the way that operands are specified, and in
- X that Tcl expressions support non-numeric operands and string
- X comparisons.
- X
- X A Tcl expression consists of a combination of operands,
- X operators, and parentheses. White space may be used between
- X the operands and operators and parentheses; it is ignored by
- X the expression processor. Where possible, operands are
- X interpreted as integer values. Integer values may be
- X specified in decimal (the normal case), in octal (if the
- X first character of the operand is 0), or in hexadecimal (if
- X the first two characters of the operand are 0x). If an
- X operand does not have one of the integer formats given
- X above, then it is treated as a floating-point number if that
- X is possible. Floating-point numbers may be specified in any
- X of the ways accepted by an ANSI-compliant C compiler (except
- X that the ``f'', ``F'', ``l'', and ``L'' suffixes will not be
- X permitted in most installations). For example, all of the
- X following are valid floating-point numbers: 2.1, 3., 6e4,
- X 7.91e+16. If no numeric interpretation is possible, then an
- X operand is left as a string (and only a limited set of
- X operators may be applied to it).
- X
- X Operators may be specified in any of the following ways:
- X
- X [1]
- X As an numeric value, either integer or floating-point.
- X
- X [2]
- X As a Tcl variable, using standard $ notation. The
- X variable's value will be used as the operand.
- X
- X [3]
- X As a string enclosed in double-quotes. The expression
- X parser will perform backslash, variable, and command
- X substitutions on the information between the quotes,
- X and use the resulting value as the operand
- X
- X [4]
- X As a string enclosed in braces. The characters between
- X the open brace and matching close brace will be used as
- X the operand without any substitutions.
- X
- X [5]
- X As a Tcl command enclosed in brackets. The command
- X will be executed and its result will be used as the
- X operand.
- X
- X [6]
- X An unquoted string consisting of any number of letters,
- X digits, and underscores (but a digit may not be the
- X first character).
- X
- X Where substitutions occur above (e.g. inside quoted
- X strings), they are performed by the expression processor.
- X However, an additional layer of substitution may already
- X have been performed by the command parser before the
- X expression processor was called. As discussed below, it is
- X usually best to enclose expressions in braces to prevent the
- X command parser from performing substitutions on the
- X contents.
- X
- X For some examples of simple expressions, suppose the
- X variable a has the value 3 and the variable b has the value
- X 6. Then the expression on the left side of each of the
- X lines below will evaluate to the value on the right side of
- X the line:
- X
- X 3.1 + $a 6.1
- X 2 + "$a.$b" 5.6
- X 4*[length "6 2"] 8
- X {word one} < "word $a" 0
- X
- X
- X The valid operators are listed below, grouped in decreasing
- X order of precedence:
- X
- X - ~ !
- X Unary minus, bit-wise NOT, logical NOT.
- X None of these operands may be applied to
- X string operands, and bit-wise NOT may be
- X applied only to integers.
- X
- X * / %
- X Multiply, divide, remainder. None of
- X these operands may be applied to string
- X operands, and remainder may be applied
- X only to integers.
- X
- X + -
- X Add and subtract. Valid for any numeric
- X operands.
- X
- X << >>
- X Left and right shift. Valid for integer
- X operands only.
- X
- X < > <= >=
- X Boolean less, greater, less than or
- X equal, and greater than or equal. Each
- X operator produces 1 if the condition is
- X true, 0 otherwise. These operators may
- X be applied to strings as well as numeric
- X operands, in which case string
- X comparison is used.
- X
- X == !=
- X Boolean equal and not equal. Each
- X operator produces a zero/one result.
- X Valid for all operand types.
- X
- X &
- X Bit-wise AND. Valid for integer
- X operands only.
- X
- X ^
- X Bit-wise exclusive OR. Valid for
- X integer operands only.
- X
- X |
- X Bit-wise OR. Valid for integer operands
- X only.
- X
- X &&
- X Logical AND. Produces a 1 result if
- X both operands are non-zero, 0 otherwise.
- X Valid for numeric operands only
- X (integers or floating-point).
- X
- X ||
- X Logical OR. Produces a 0 result if both
- X operands are zero, 1 otherwise. Valid
- X for numeric operands only (integers or
- X floating-point).
- X
- X x?y:z
- X If-then-else, as in C. If x evaluates
- X to non-zero, then the result is the
- X value of y. Otherwise the result is the
- X value of z. The x operand must have a
- X numeric value.
- X
- X See the C manual for more details on the results produced by
- X each operator. All of the binary operators group left-to-
- X right within the same precedence level. For example, the
- X expression
- X
- X 4*2 < 7
- X
- X evaluates to 0.
- X
- X The &&, ||, and ?: operators have ``lazy evaluation'', just
- X as in C, which means that operands are not evaluated if they
- X are not needed to determine the outcome. For example, in
- X
- X $v ? [a] : [b]
- X
- X only one of [a] or [b] will actually be evaluated, depending
- X on the value of $v.
- X
- X All internal computations involving integers are done with
- X the C type long, and all internal computations involving
- X floating-point are done with the C type double. When
- X converting a string to floating-point, exponent overflow is
- X detected and results in a Tcl error. For conversion to
- X integer from string, detection of overflow depends on the
- X behavior of some routines in the local C library, so it
- X should be regarded as unreliable. In any case, overflow and
- X underflow are generally not detected reliably for
- X intermediate results.
- X
- X Conversion among internal representations for integer,
- X floating-point, and string operands is done automatically as
- X needed. For arithmetic computations, integers are used
- X until some floating-point number is introduced, after which
- X floating-point is used. For example,
- X
- X 5 / 4
- X yields the result 1, while
- X
- X 5 / 4.0
- X 5 / ( [length "abcd" chars] + 0.0 )
- X
- X both yield the result 1.25.
- X
- X String values may be used as operands of the comparison
- X operators, although the expression evaluator tries to do
- X comparisons as integer or floating-point when it can. If
- X one of the operands of a comparison is a string and the
- X other has a numeric value, the numeric operand is converted
- X back to a string using the C sprintf format specifier %d for
- X integers and %g for floating-point values. For example, the
- X expressions
- X
- X "0x03" > "2"
- X "0y" < "0x12"
- X both evaluate to 1. The first comparison is done using
- X integer comparison, and the second is done using string
- X comparison after the second operand is converted to the
- X string ``18''.
- X
- X In general it is safest to enclose an expression in braces
- X when entering it in a command: otherwise, if the expression
- X contains any white space then the Tcl interpreter will split
- X it among several arguments. For example, the command
- X
- X expr $a + $b
- X
- X results in three arguments being passed to expr: $a, +, and
- X $b. In addition, if the expression isn't in braces then the
- X Tcl interpreter will perform variable and command
- X substitution immediately (it will happen in the command
- X parser rather than in the expression parser). In many cases
- X the expression is being passed to a command that will
- X evaluate the expression later (or even many times if, for
- X example, the expression is to be used to decide when to exit
- X a loop). Usually the desired goal is to re-do the variable
- X or command substitutions each time the expression is
- X evaluated, rather than once and for all at the beginning.
- X For example, the command
- X
- X for {set i 1} $i<=10 {incr i} {...}*** WRONG ***
- X
- X is probably intended to iterate over all values of i from 1
- X to 10. After each iteration of the body of the loop, for
- X will pass its second argument to the expression evaluator to
- X see whether or not to continue processing. Unfortunately,
- X in this case the value of i in the second argument will be
- X substituted once and for all when the for command is parsed.
- X If i was 0 before the for command was invoked then for's
- X second argument will be 0<=10 which will always evaluate to
- X 1, even though i's value eventually becomes greater than 10.
- X In the above case the loop will never terminate. Instead,
- X the expression should be placed in braces:
- X
- X for {set i 1} {$i<=10} {incr i} {...}*** RIGHT ***
- X This causes the substitution of i's value to be delayed; it
- X will be re-done each time the expression is evaluated, which
- X is the desired result.
- END_OF_FILE
- if test 12156 -ne `wc -c <'extended/tcllib/help/intro/expressions'`; then
- echo shar: \"'extended/tcllib/help/intro/expressions'\" unpacked with wrong size!
- fi
- # end of 'extended/tcllib/help/intro/expressions'
- fi
- echo shar: End of archive 13 \(of 23\).
- cp /dev/null ark13isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 23 archives.
- echo "Now cd to "extended", edit the makefile, then do a "make""
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-