home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume26 / tclx / part13 < prev    next >
Encoding:
Text File  |  1991-11-19  |  41.2 KB  |  1,085 lines

  1. Newsgroups: comp.sources.misc
  2. From: karl@sugar.neosoft.com (Karl Lehenbauer)
  3. Subject:  v26i013:  tclx - extensions and on-line help for tcl 6.1, Part13/23
  4. Message-ID: <1991Nov19.135408.998@sparky.imd.sterling.com>
  5. X-Md4-Signature: a0f5b5f2bbff851835a5c1e82f59dae2
  6. Date: Tue, 19 Nov 1991 13:54:08 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: karl@sugar.neosoft.com (Karl Lehenbauer)
  10. Posting-number: Volume 26, Issue 13
  11. Archive-name: tclx/part13
  12. Environment: UNIX
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 13 (of 23)."
  21. # Contents:  extended/man/CmdWrite.man extended/src/chmod.c
  22. #   extended/tcllib/help/intro/expressions
  23. # Wrapped by karl@one on Wed Nov 13 21:50:26 1991
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f 'extended/man/CmdWrite.man' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'extended/man/CmdWrite.man'\"
  27. else
  28. echo shar: Extracting \"'extended/man/CmdWrite.man'\" \(12815 characters\)
  29. sed "s/^X//" >'extended/man/CmdWrite.man' <<'END_OF_FILE'
  30. X.TH "Command Writing" TCL "" "Tcl"
  31. X.ad b
  32. X'@index: TclCommandWriting
  33. X.SH NAME
  34. XTclCommandWriting - Writing C language extensions to Tcl.
  35. X'
  36. X.SH OVERVIEW
  37. XThis document is intended to help the programmer who wishes to extend
  38. XTcl with C language routines.  It should also be useful to someone
  39. Xwishing to add Tcl to an existing editor, comm program, etc.  There
  40. Xis also programming information in the \fITcl.man\fR manual
  41. Xdirectory of the Berkeley distribution.
  42. X'
  43. X.SH WRITING TCL EXTENSIONS IN C
  44. XC extensions to Tcl must be written to receive their arguments in the
  45. Xmanner Tcl uses to pass them.
  46. X.PP
  47. XA C routine is called from Tcl with four arguments, a client data pointer,
  48. Xan interpreter pointer, an argument count and a pointer to an array of
  49. Xpointers to character strings containing the Tcl arguments to the routine.
  50. X.PP
  51. XA Tcl extension in C is now presented, and described below:
  52. X.sp
  53. X.nf
  54. X.ft CW
  55. X    #include "tcl.h"
  56. X
  57. X    int Tcl_EchoCmd(clientData, interp, argc, argv)
  58. X    void *clientData;
  59. X    Tcl_Interp *interp;
  60. X    int argc;
  61. X    char **argv;
  62. X    {
  63. X            int i;
  64. X
  65. X            for (i = 1; i < argc; i++) {
  66. X                    printf("%s ",argv[i]);
  67. X            }
  68. X            printf("\\n");
  69. X            return TCL_OK;
  70. X    }
  71. X.ft R
  72. X.fi
  73. X.PP      
  74. XThe client data pointer will be described later.
  75. X.PP
  76. XThe interpreter pointer is the ``key'' to an interpreter.  It is returned by
  77. X\fITcl_CreateInterp\fR or \fITcl_CreateExtendedInterp\fR and is used within
  78. XTcl and by your C code.  The structure pointed to by the interpreter pointer,
  79. Xand all of the subordinate structures that branch off of it, make up an
  80. Xinterpreter context, which includes all of the currently defined procedures,
  81. Xcommands, variables, arrays and the execution state of that interpreter.
  82. X.PP
  83. XThe argument count and pointer to an array of pointers to textual arguments
  84. Xis handled by your C code in the same manner that you would use in writing a
  85. XC \fImain\fR function -- the argument count and array of pointers
  86. Xworks the same
  87. Xas in a C \fImain\fR call; pointers to the arguments to the function are
  88. Xcontained
  89. Xin the \fIargv\fR array.  Similar to a C main, the first argument
  90. X(\fIargv[0]\fR) is the
  91. Xname the routine was called as (in a main, the name the program
  92. Xwas invoked as).
  93. X.PP
  94. XIn the above example, all of the arguments are output with a space between
  95. Xeach one by looping through \fIargv\fR from one to the argument count,
  96. X\fIargc\fR, and a
  97. Xnewline terminates the line -- an echo command, although a ``real'' echo
  98. Xcommand would not add a trailing blank like this one does.
  99. X.PP
  100. XAll arguments from a Tcl call to a Tcl C extension are passed as strings.
  101. XIf your C routine expects certain numeric arguments, your routine must first
  102. Xconvert them using the \fITcl_GetInt\fR or \fITcl_GetDouble\fR
  103. Xfunction, or some other method
  104. Xof your own devising.  If you program produces a numeric result, it should
  105. Xreturn a string equivalent to that numeric value.  A common way of doing
  106. Xthis is something like...
  107. X.sp
  108. X.nf
  109. X.ft CW
  110. X    sprintf(interp->result, "%ld", result);
  111. X.ft R
  112. X.fi
  113. X.PP      
  114. XMore sophisticated commands should verify their arguments when possible,
  115. Xboth by examining the argument count, by verifying that numeric fields
  116. Xare really numeric, that values
  117. Xare in range when their ranges are known, and so forth.
  118. X.PP
  119. XTcl is designed to be as bullet-proof as possible, in the
  120. Xsense that Tcl programs should not be able to cause Tcl to dump core.  Please
  121. Xdo the same with your C extensions by validating arguments as above.
  122. X.PP
  123. XIn the command below, two or more arguments are compared and the one with
  124. Xthe maximum value is returned, if all goes well.  It is an error if there
  125. Xare fewer than three arguments (the pointer to the ``max'' command text itself,
  126. X\fIargv[0]\fR, and pointers to at least two arguments to compare the
  127. Xvalues of).
  128. X.PP
  129. XThis routine also shows the use of the programmer labor-saving
  130. X\fITcl_AppendResult\fR
  131. Xroutine.  See the Tcl manual page, \fISetResult.man\fR, for details.
  132. XAlso examine the calls \fITcl_SetErrorCode\fR and \fITcl_UnixError\fR
  133. Xdocumented in the Tcl manual page \fIAddErrInfo.man\fR.
  134. X.sp
  135. X.nf
  136. X.ft CW
  137. X    int
  138. X    Tcl_MaxCmd (clientData, interp, argc, argv)
  139. X        char       *clientData;
  140. X        Tcl_Interp *interp;
  141. X        int         argc;
  142. X        char      **argv;
  143. X    {
  144. X        int maxVal = MININT;
  145. X        int maxIdx = 1;
  146. X        int value, idx;
  147. X
  148. X
  149. X        if (argc < 3) {
  150. X            Tcl_AppendResult (interp, "bad # arg: ", argv[0],
  151. X                              " num1 num2 [..numN]", (char *)NULL);
  152. X            return TCL_ERROR;
  153. X        }
  154. X
  155. X        for (idx = 1; idx < argc; idx++) {
  156. X            if (Tcl_GetInt (argv[idx], 10, &Value) != TCL_OK)
  157. X                return TCL_ERROR;
  158. X
  159. X            if (value > maxVal) {
  160. X                maxVal = value;
  161. X                maxIdx = idx;
  162. X            }
  163. X        }
  164. X        strcpy (interp->result, argv [maxIdx]);
  165. X        return TCL_OK;
  166. X    }
  167. X.ft R
  168. X.fi
  169. X.PP      
  170. XWhen Tcl-callable functions complete, they should normally return
  171. X\fBTCL_OK\fR or \fBTCL_ERROR\fR.
  172. X\fBTCL_OK\fR is returned when the command succeeded and \fBTCL_ERROR\fR
  173. Xis returned when the command has failed rather drastically.  
  174. X\fBTCL_ERROR\fR should
  175. Xbe returned for all syntax errors, non-numeric values where numeric ones
  176. Xwere expected, and so forth.  Less clear in some cases is whether Tcl errors
  177. Xshould be returned or whether a function should just return a status value.
  178. XFor example, end-of-file during a \fIgets\fR returns a status,
  179. Xbut \fIopen\fR
  180. Xreturns an error if the open fails.  Errors can be caught from
  181. XTcl programs using the \fIcatch\fR command.
  182. X.PP
  183. XLess common return values are 
  184. X\fBTCL_RETURN\fR, \fBTCL_BREAK\fR and \fBTCL_CONTINUE\fR.
  185. XThese are used if you are adding new control and/or looping
  186. Xstructures to Tcl.  To see these values in action, examine the source to
  187. Xthe \fIwhile\fR, \fIfor\fR, \fIif\fR and \fIloop\fR commands.
  188. X'
  189. X.SH INSTALLING YOUR COMMAND
  190. X.P
  191. XTo install your command into Tcl your must call 
  192. X\fITcl_CreateCommand\fR, passing
  193. Xit the pointer into the interpreter you want to install the command into,
  194. Xthe name of the command, a pointer to the C function, a client data pointer,
  195. Xand a pointer to an optional callback routine.
  196. X.PP
  197. XThe client data pointer and the callback routine will be described later.
  198. X.PP
  199. XFor example, for the max function above (which incidentally comes from
  200. Xmath.c in the extend/src directory):
  201. X.sp
  202. X.nf
  203. X.ft CW
  204. X    Tcl_CreateCommand (interp, "max", Tcl_MaxCmd, (ClientData)NULL, 
  205. X                      (void (*)())NULL);
  206. X.ft R
  207. X.fi
  208. X.PP
  209. XIn the above example, the max function is added
  210. Xto the specified interpreter.  The client data pointer and callback
  211. Xfunction pointer are NULL.
  212. X.PP
  213. X.SH CLIENT DATA
  214. X.PP
  215. XThe client data pointer provides a means for Tcl commands to have data
  216. Xassociated through them that is not global to the C program including
  217. Xthe Tcl core.  It is essential in a multi-interpreter environment
  218. X(where a single program has created and is making use of multiple
  219. XTcl interpreters)
  220. Xfor the C routines to maintain any permanent data they need relative to
  221. Xeach interpreter being used, or there would be reentrancy problems.
  222. XTcl solves this through the client data mechanism.  When you are about
  223. Xto call 
  224. X\fITcl_CreateCommand\fR to add a new command to an interpreter, if that
  225. Xcommand needs to keep some read/write data from one invocation to another,
  226. Xyou should allocate the space, preferably using \fIckalloc\fR, then pass
  227. Xthe address of that space as the ClientData pointer to
  228. X\fITcl_CreateCommand\fR.
  229. X.PP
  230. XWhen your command is called from Tcl, the ClientData pointer you gave to 
  231. X\fITcl_CreateCommand\fR when you added the command to that interpreter
  232. Xis passed
  233. Xto your C routine through the ClientData pointer calling argument.
  234. X.PP
  235. XCommands that need to share this data with one another can do so by using the
  236. Xsame ClientData pointer when the commands are added.
  237. X.PP
  238. XIt is important to note that the Tcl extensions in the extended/src
  239. Xdirectory have had all of their data set up in this way, so at
  240. Xthe time of this writing (release 6.1) the Tcl extensions support
  241. Xmultiple interpreters within one invocation of Tcl.
  242. X'
  243. X.SH INTEL '286 GOTCHAS
  244. X.P
  245. XThe '286 programmer who is not using an ANSI C standard compiler with
  246. Xfunction prototypes must be vigilant to ensure that anytime NULL is
  247. Xpassed to a function as a pointer it is explicitly cast to
  248. X\fB(void *)\fR or equivalent.  Also remember that Tcl math within
  249. Xexpressions is carried out to 32 bits, so that you should usually use
  250. Xthe \fIlong\fR variable type for your integers, \fITcl_GetLong\fR (rather
  251. Xthan \fITcl_GetInt\fR) to convert strings to long integers, and remember
  252. Xto use \fB%ld\fR when printing results with \fIsprintf\fR, and so
  253. Xforth.
  254. X.PP
  255. XTo maintain '286 compatibility, all C programmers are asked to follow
  256. Xthese guidelines.  I know you don't want to, but there are a lot of
  257. X286 machines out there and it is nice that they are able to run Tcl.
  258. X.SH THEORY OF HANDLES
  259. XSometimes you need to have a data element that isn't readily representable
  260. Xas a string within Tcl, for example a pointer to a complex C data structure.
  261. XWe do not think it is a good idea to try to pass pointers around within
  262. XTcl as strings by converting them to and from hex or integer representations,
  263. Xfor example.  It is too easy to screw one up and the likely outcome of
  264. Xdoing that is a core dump.
  265. X.PP
  266. XInstead what we have done is developed and made use of the concept 
  267. Xof \fIhandles\fR.
  268. XHandles are identifiers a C extension can pass to, and accept from,
  269. XTcl to make the transition between what your C code knows something as
  270. Xand what name Tcl knows it by to be as safe and painless as possible.  
  271. XFor example,
  272. Xthe stdio package included in Tcl uses file handles.  When you open a
  273. Xfile from Tcl, a handle is returned of the form \fBfile\fIn\fR where
  274. X\fIn\fR is a file number.  When you pass the file handle back to \fIputs\fR,
  275. X\fIgets\fR, \fIseek\fR, \fIflush\fR and so forth, they validate the file
  276. Xhandle by checking the the \fBfile\fR text is present, then converting
  277. Xthe file number to an integer that they use to look into a data
  278. Xstructure of pointers
  279. Xto Tcl open file structures, which contain a Unix file descriptor, flags
  280. Xindicating whether or not the file is currently open, whether the file is
  281. Xa file or a pipe and so forth.
  282. X.PP
  283. XHandles have proven so useful that, as of release 6.1a, general support
  284. Xhas been added for them.
  285. XIf you need a similar capability, it would be best to use the handle
  286. Xroutines, documented in \fIHandles.man\fR.
  287. XWe recommend that you use a
  288. Xunique-to-your-package textual handle coupled with a specific identifier
  289. Xand let the handle management routines validate it when it's passed back.
  290. XIt is much easier to
  291. Xtrack down a bug with an implicated handle named something like \fBfile4\fR
  292. Xor \fBbitmap6\fR than just \fB6\fR.
  293. X.PP
  294. X.SH TRACKING MEMORY CORRUPTION PROBLEMS
  295. XOccasionally you may write code that scribbles past the end of an
  296. Xallocated piece of memory.  The memory debugging
  297. Xroutines included in Tcl can help find these problems.  See
  298. X\fIextended/man/Memory.man\fR for details.
  299. X.PP
  300. X.SH WRITING AN APPLICATION-SPECIFIC MAIN
  301. XFor those writing an application-specific main, for example, those adding
  302. XTcl to an existing application or including Tcl within a larger application,
  303. Xa few steps need to be taken to set up Tcl.
  304. X.PP
  305. XFor one thing, several \fIextern char *\fR definitions must be fulfilled,
  306. Xproviding data used by the \fIinfox\fR command.  These definitions are
  307. X\fItclxVersion\fR, the Extended Tcl version number, \fItclxPatchlevel\fR,
  308. Xthe Extended Tcl patch level, \fItclAppName\fR, the name of the application,
  309. X\fItclAppLongname\fR, a description of the application, and
  310. X\fItclAppVersion\fR, the version number of the application.
  311. X.PP
  312. XA Tcl interpreter, including all of the extensions in Extended Tcl, is
  313. Xcreated with a call to \fITcl_CreateExtendedInterp\fR.  Next, any
  314. Xapplication-specific commands are added by calls to \fITcl_CreateCommand\fR.
  315. XFinally, \fITcl_Startup\fR is called to load the Tcl startup code, pull
  316. Xin all of the Tcl procs and paths, do command line processing, handle
  317. Xautoloads, packages, and so forth.  If the application writer wants
  318. Xdifferent startup behavior, they should write a different Tcl startup
  319. Xroutine.  \fITcl_Startup\fR is defined in the file \fItclstartup.c\fR
  320. Xin the \fIextended/src\fR directory.
  321. X.PP
  322. XFinally, cleanup code is called to close down the application.
  323. X\fITcl_DeleteInterp\fR is called to free memory used by Tcl -- normally,
  324. Xthis is only called if \fBTCL_MEM_DEBUG\fR was defined, since Unix
  325. Xwill return all of the allocated memory back to the system, anyway.
  326. X.PP
  327. XThe writer of an application-specific main is invited to examine and use
  328. Xthe \fImain()\fR routine defined in \fIextended/src/main.c\fR
  329. Xas a template for their new main.  There is a \fItcl++.C\fR, which is a
  330. Xmain for C++-based Tcl applications.
  331. END_OF_FILE
  332. if test 12815 -ne `wc -c <'extended/man/CmdWrite.man'`; then
  333.     echo shar: \"'extended/man/CmdWrite.man'\" unpacked with wrong size!
  334. fi
  335. # end of 'extended/man/CmdWrite.man'
  336. fi
  337. if test -f 'extended/src/chmod.c' -a "${1}" != "-c" ; then 
  338.   echo shar: Will not clobber existing file \"'extended/src/chmod.c'\"
  339. else
  340. echo shar: Extracting \"'extended/src/chmod.c'\" \(12830 characters\)
  341. sed "s/^X//" >'extended/src/chmod.c' <<'END_OF_FILE'
  342. X/* 
  343. X * chmod.c --
  344. X *
  345. X *    Chmod, chown and chgrp Tcl commands.
  346. X *---------------------------------------------------------------------------
  347. X * Copyright 1991 Karl Lehenbauer and Mark Diekhans.
  348. X *
  349. X * Permission to use, copy, modify, and distribute this software and its
  350. X * documentation for any purpose and without fee is hereby granted, provided
  351. X * that the above copyright notice appear in all copies.  Karl Lehenbauer and
  352. X * Mark Diekhans make no representations about the suitability of this
  353. X * software for any purpose.  It is provided "as is" without express or
  354. X * implied warranty.
  355. X */
  356. X
  357. X#include "tclExtdInt.h"
  358. X
  359. X/*
  360. X * Prototypes of internal functions.
  361. X */
  362. Xint
  363. XTcl_ConvSymMode _ANSI_ARGS_((char *sysPerms,
  364. X                             int   modeVal));
  365. X
  366. Xint
  367. XTcl_ConvAbsMode _ANSI_ARGS_((char *modeStr,
  368. X                             int   assumeInt));
  369. X
  370. X
  371. X/*
  372. X *----------------------------------------------------------------------
  373. X *
  374. X * Tcl_ConvSymMode --
  375. X *      Parse and convert symbolic file permissions as specified by chmod(C).
  376. X *
  377. X * Parameters:
  378. X *      symPerms - The symbolic permissions to parse.
  379. X *      modeVal - The existing permissions value on a file.
  380. X *
  381. X * Results:
  382. X *      The new permissions, or -1 if invalid permissions where supplied.
  383. X *
  384. X *----------------------------------------------------------------------
  385. X */
  386. Xstatic int
  387. XTcl_ConvSymMode (sysPerms, modeVal)
  388. X    char *sysPerms;
  389. X    int   modeVal;
  390. X
  391. X{
  392. X    int  user, group, other;
  393. X    char operator;
  394. X    int  rwxMask, setUID, sticky, locking;
  395. X    int  newMode;
  396. X
  397. X    while (*sysPerms != 0) {
  398. X        user = group = other = FALSE;
  399. X
  400. X        /* 
  401. X         * Scan who field.
  402. X         */
  403. X        while (! ((*sysPerms == '+') || 
  404. X                  (*sysPerms == '-') || 
  405. X                  (*sysPerms == '='))) {
  406. X            switch (*sysPerms) {
  407. X                case 'a':
  408. X                    user = group = other = TRUE;
  409. X                    break;
  410. X                case 'u':
  411. X                    user = TRUE;
  412. X                    break;
  413. X                case 'g':
  414. X                    group = TRUE;
  415. X                    break;
  416. X                case 'o':
  417. X                    other = TRUE;
  418. X                    break;
  419. X                default:
  420. X                    return -1;  /* Error, not a recognized character or EOL */
  421. X            }
  422. X            sysPerms++;
  423. X        }
  424. X
  425. X        /*
  426. X         * If none where specified, that means all.
  427. X         */
  428. X
  429. X        if (! (user || group || other))
  430. X            user = group = other = TRUE;
  431. X
  432. X        operator = *sysPerms++;
  433. X
  434. X        /* 
  435. X         * Decode the permissions
  436. X         */
  437. X
  438. X        rwxMask = 0;
  439. X        setUID = sticky = locking = FALSE;
  440. X
  441. X        /* 
  442. X         * Scan permissions field
  443. X         */
  444. X        while (! ((*sysPerms == ',') || (*sysPerms == 0))) {
  445. X            switch (*sysPerms) {
  446. X                case 'r':
  447. X                    rwxMask |= 4;
  448. X                    break;
  449. X                case 'w':
  450. X                    rwxMask |= 2;
  451. X                    break;
  452. X                case 'x':
  453. X                    rwxMask |= 1;
  454. X                    break;
  455. X                case 's':
  456. X                    setUID = TRUE;
  457. X                    break;
  458. X                case 't':
  459. X                    sticky = TRUE;
  460. X                    break;
  461. X                case 'l':
  462. X                    locking = TRUE;
  463. X                    break;
  464. X                default:
  465. X                    return -1;  /* Error, not a recognized character */
  466. X            }
  467. X            sysPerms++;
  468. X        }
  469. X
  470. X        /*
  471. X         * Build mode map of specified values.
  472. X         */
  473. X
  474. X        newMode = 0;
  475. X        if (user)
  476. X            newMode |= rwxMask << 6;
  477. X        if (group)
  478. X            newMode |= rwxMask << 3;
  479. X        if (other)
  480. X            newMode |= rwxMask;
  481. X        if (setUID && user)
  482. X            newMode |= 04000;
  483. X        if ((setUID || locking) && group)
  484. X            newMode |= 02000;
  485. X        if (sticky)
  486. X            newMode |= 01000;
  487. X
  488. X        /* 
  489. X         * Add to cumulative mode based on operator.
  490. X         */
  491. X
  492. X        if (operator == '+')
  493. X            modeVal |= newMode;
  494. X        else if (operator == '-')
  495. X            modeVal &= ~newMode;
  496. X        else if (operator == '=')
  497. X            modeVal = newMode;
  498. X        if (*sysPerms == ',')
  499. X            sysPerms++;
  500. X    }
  501. X
  502. X    return modeVal;
  503. X
  504. X} /* Tcl_ConvSymMode */
  505. X
  506. X/*
  507. X *----------------------------------------------------------------------
  508. X *
  509. X * Tcl_ConvAbsMode --
  510. X *      Convert a absolute file mode.  If this fails, it might be a 
  511. X *      symbolic mode.  Mode is assumed to be octal unless otherwise
  512. X *      specified.
  513. X *
  514. X * Parameters:
  515. X *      modeStr - The file mode string.
  516. X *      assumeInt - Assume and integer (although a leading 0 will indicate
  517. X *                  octal.
  518. X * Results:
  519. X *      The new permissions, or -1 if invalid permissions where supplied.
  520. X *
  521. X *----------------------------------------------------------------------
  522. X */
  523. Xint
  524. XTcl_ConvAbsMode (modeStr, assumeInt)
  525. X    char *modeStr; 
  526. X    int   assumeInt;
  527. X{
  528. X    int   mode;
  529. X
  530. X    if (!Tcl_StrToInt (modeStr, (assumeInt) ? 0 : 8, &mode))
  531. X      return -1;  /* Not an octal number */ 
  532. X    else
  533. X      return mode;
  534. X
  535. X} /* Tcl_ConvAbsMode */
  536. X
  537. X/*
  538. X *----------------------------------------------------------------------
  539. X *
  540. X * Tcl_ChmodCmd --
  541. X *     Implements the TCL chmod command:
  542. X *     chmod [-i] mode filelist
  543. X *
  544. X * Results:
  545. X *  Standard TCL results, may return the UNIX system error message.
  546. X *
  547. X *----------------------------------------------------------------------
  548. X */
  549. Xint
  550. XTcl_ChmodCmd (clientData, interp, argc, argv)
  551. X    ClientData   clientData;
  552. X    Tcl_Interp  *interp;
  553. X    int          argc;
  554. X    char       **argv;
  555. X{
  556. X    int         idx, modeVal, assumeInt, fileArgc, result = TCL_ERROR;
  557. X    char      **fileArgv, *modePtr;
  558. X    struct stat fileStat;
  559. X
  560. X    if (argc < 3)
  561. X        goto wrongArgs;
  562. X    if ((argv [1][0] == '-') && (argv [1][1] == 'i') && (argv [1][2] == '\0')){
  563. X        if (argc < 4)
  564. X            goto wrongArgs;
  565. X        assumeInt = TRUE;
  566. X        modePtr = argv [2];
  567. X    } else {
  568. X        assumeInt = FALSE;
  569. X        modePtr = argv [1];
  570. X    }
  571. X
  572. X    if (Tcl_SplitList (interp, argv [argc - 1], &fileArgc,
  573. X                       &fileArgv) != TCL_OK)
  574. X        return TCL_ERROR;
  575. X
  576. X    for (idx = 0; idx < fileArgc; idx++) {
  577. X        if ((modeVal = Tcl_ConvAbsMode (modePtr, assumeInt)) < 0) {
  578. X            if (stat (fileArgv [idx], &fileStat) != 0)
  579. X                goto fileError;
  580. X            modeVal = Tcl_ConvSymMode (modePtr, fileStat.st_mode & 07777);
  581. X            if (modeVal < 0) {
  582. X                interp->result = "invalid file mode";
  583. X                goto exitPoint;
  584. X            }
  585. X            if (assumeInt) {
  586. X                Tcl_AppendResult (interp, argv [0], ": -i flag may not be",
  587. X                                  " used with symbolic modes", (char *) NULL);
  588. X                goto exitPoint;
  589. X            }
  590. X        }
  591. X        if (chmod (fileArgv [idx], modeVal) < 0)
  592. X            goto fileError;
  593. X    }
  594. X
  595. X    result = TCL_OK;
  596. XexitPoint:
  597. X    ckfree ((char *) fileArgv);
  598. X    return result;
  599. X
  600. XfileError:
  601. X    /*
  602. X     * Error accessing file, assumes file name is fileArgv [idx].
  603. X     */
  604. X    Tcl_AppendResult (interp, argv [0], ": ", fileArgv [idx], ": ",
  605. X                      Tcl_UnixError (interp), (char *) NULL);
  606. X    ckfree ((char *) fileArgv);
  607. X    return TCL_ERROR;
  608. X
  609. XwrongArgs:
  610. X    Tcl_AppendResult (interp, "wrong # args: ", argv [0], 
  611. X                      " [-i] mode filelist", (char *) NULL);
  612. X    return TCL_ERROR;
  613. X}
  614. X
  615. X/*
  616. X *----------------------------------------------------------------------
  617. X *
  618. X * Tcl_ChownCmd --
  619. X *     Implements the TCL chown command:
  620. X *     chown owner filelist
  621. X *     chown {owner group} filelist
  622. X *
  623. X * Results:
  624. X *  Standard TCL results, may return the UNIX system error message.
  625. X *
  626. X *----------------------------------------------------------------------
  627. X */
  628. Xint
  629. XTcl_ChownCmd (clientData, interp, argc, argv)
  630. X    ClientData   clientData;
  631. X    Tcl_Interp  *interp;
  632. X    int          argc;
  633. X    char       **argv;
  634. X{
  635. X    int            idx, ownArgc, fileArgc;
  636. X    char         **ownArgv, **fileArgv = NULL;
  637. X    struct stat    fileStat;
  638. X    int            useOwnerGrp, chGroup, ownerId, groupId;
  639. X    struct passwd *passwdPtr;
  640. X    struct group  *groupPtr;
  641. X    int            result = TCL_ERROR;
  642. X
  643. X    if (argc != 3) {
  644. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0], 
  645. X                          " owner|{owner group} filelist", (char *) NULL);
  646. X        return TCL_ERROR;
  647. X    }
  648. X
  649. X    if (Tcl_SplitList (interp, argv[1], &ownArgc, &ownArgv) != TCL_OK)
  650. X        return TCL_ERROR;
  651. X    if ((ownArgc < 1) || (ownArgc > 2)) {
  652. X        interp->result = "owner arg should be: owner or {owner group}";
  653. X        goto exitPoint;
  654. X    }
  655. X    if (ownArgc == 2) {
  656. X        useOwnerGrp = (ownArgv [1][0] == '\0');
  657. X        chGroup = TRUE;
  658. X    } else
  659. X        chGroup = FALSE;
  660. X
  661. X    /*
  662. X     * Get the owner id, either convert the name or use it as an integer.
  663. X     */
  664. X    passwdPtr = getpwnam (ownArgv [0]);
  665. X    if (passwdPtr != NULL)
  666. X        ownerId = passwdPtr->pw_uid;
  667. X    else {
  668. X        if (!Tcl_StrToInt (ownArgv [0], 10, &ownerId)) {
  669. X            Tcl_AppendResult (interp, "unknown user id: ", ownArgv [0],
  670. X                              (char *) NULL);
  671. X            goto exitPoint;
  672. X        }
  673. X    }
  674. X    /*
  675. X     * Get the group id, this is either the specified id or name, or the
  676. X     * if associated with the specified user.
  677. X     */
  678. X    if (chGroup) {
  679. X        if (useOwnerGrp) {
  680. X            if (passwdPtr == NULL) {
  681. X                passwdPtr = getpwuid (ownerId);
  682. X                if (passwdPtr != NULL) {
  683. X                    Tcl_AppendResult (interp, "unknown user id: ", 
  684. X                                      ownArgv [0], (char *) NULL);
  685. X                    goto exitPoint;
  686. X                }
  687. X            }
  688. X            groupId = passwdPtr->pw_gid;                        
  689. X        } else {
  690. X            groupPtr = getgrnam (ownArgv [1]);
  691. X            if (groupPtr != NULL)
  692. X                groupId = groupPtr->gr_gid;
  693. X            else {
  694. X                if (!Tcl_StrToInt (ownArgv [1], 10, &groupId)) {
  695. X                    Tcl_AppendResult (interp, "unknown group id: ", 
  696. X                                      ownArgv [1], (char *) NULL);
  697. X                    goto exitPoint;
  698. X                }
  699. X            }
  700. X        }
  701. X    }
  702. X    if (Tcl_SplitList (interp, argv [2], &fileArgc, &fileArgv) != TCL_OK)
  703. X        goto exitPoint;
  704. X
  705. X    for (idx = 0; idx < fileArgc; idx++) {
  706. X        if (!chGroup) {
  707. X            if (stat (fileArgv [idx], &fileStat) != 0) {
  708. X                Tcl_AppendResult (interp, argv [0], ": ", fileArgv [idx], ": ",
  709. X                                  Tcl_UnixError (interp), (char *) NULL);
  710. X                goto exitPoint;
  711. X            }
  712. X            groupId = fileStat.st_gid;
  713. X        }
  714. X
  715. X        if (chown (fileArgv[idx], ownerId, groupId) < 0) {
  716. X            Tcl_AppendResult (interp, argv [0], ": ", fileArgv [idx], ": ",
  717. X                              Tcl_UnixError (interp), (char *) NULL);
  718. X            goto exitPoint;
  719. X        }
  720. X
  721. X    } /* Modify each file */
  722. X
  723. X    result = TCL_OK;
  724. XexitPoint:
  725. X    ckfree ((char *) ownArgv);
  726. X    if (fileArgv != NULL)
  727. X        ckfree ((char *) fileArgv);
  728. X    return result;
  729. X}
  730. X
  731. X/*
  732. X *----------------------------------------------------------------------
  733. X *
  734. X * Tcl_ChgrpCmd --
  735. X *     Implements the TCL chgrp command:
  736. X *     chgrp group filelist
  737. X *
  738. X * Results:
  739. X *  Standard TCL results, may return the UNIX system error message.
  740. X *
  741. X *----------------------------------------------------------------------
  742. X */
  743. Xint
  744. XTcl_ChgrpCmd (clientData, interp, argc, argv)
  745. X    ClientData   clientData;
  746. X    Tcl_Interp  *interp;
  747. X    int          argc;
  748. X    char       **argv;
  749. X{
  750. X    int            idx, fileArgc, groupId, result = TCL_ERROR;
  751. X    char         **fileArgv;
  752. X    struct stat    fileStat;
  753. X    struct group  *groupPtr;
  754. X
  755. X    if (argc < 3) {
  756. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0], 
  757. X                          " group filelist", (char *) NULL);
  758. X        return TCL_ERROR;
  759. X    }
  760. X
  761. X    groupPtr = getgrnam (argv [1]);
  762. X    if (groupPtr != NULL)
  763. X        groupId = groupPtr->gr_gid;
  764. X    else {
  765. X        if (!Tcl_StrToInt (argv [1], 10, &groupId)) {
  766. X            Tcl_AppendResult (interp, "unknown group id: ", argv [1],
  767. X                              (char *) NULL);
  768. X            return TCL_ERROR;
  769. X        }
  770. X    }
  771. X    if (Tcl_SplitList (interp, argv [2], &fileArgc, &fileArgv) != TCL_OK)
  772. X        return TCL_ERROR;
  773. X
  774. X    for (idx = 0; idx < fileArgc; idx++) {
  775. X        if ((stat (fileArgv [idx], &fileStat) != 0) ||
  776. X                (chown (fileArgv[idx], fileStat.st_uid, groupId) < 0)) {
  777. X            Tcl_AppendResult (interp, argv [0], ": ", fileArgv [idx], ": ",
  778. X                              Tcl_UnixError (interp), (char *) NULL);
  779. X            goto exitPoint;
  780. X        }
  781. X    } /* Modify each file */
  782. X
  783. X    result = TCL_OK;
  784. XexitPoint:
  785. X    ckfree ((char *) fileArgv);
  786. X    return result;
  787. X}
  788. END_OF_FILE
  789. if test 12830 -ne `wc -c <'extended/src/chmod.c'`; then
  790.     echo shar: \"'extended/src/chmod.c'\" unpacked with wrong size!
  791. fi
  792. # end of 'extended/src/chmod.c'
  793. fi
  794. if test -f 'extended/tcllib/help/intro/expressions' -a "${1}" != "-c" ; then 
  795.   echo shar: Will not clobber existing file \"'extended/tcllib/help/intro/expressions'\"
  796. else
  797. echo shar: Extracting \"'extended/tcllib/help/intro/expressions'\" \(12156 characters\)
  798. sed "s/^X//" >'extended/tcllib/help/intro/expressions' <<'END_OF_FILE'
  799. X     EXPRESSIONS
  800. X          The second major interpretation applied to strings in Tcl is
  801. X          as  expressions.   Several  commands, such as expr, for, and
  802. X          if, treat one or more of their arguments as expressions  and
  803. X          call    the   Tcl   expression   processors   (Tcl_ExprLong,
  804. X          Tcl_ExprBoolean, etc.)  to  evaluate  them.   The  operators
  805. X          permitted  in  Tcl expressions are a subset of the operators
  806. X          permitted in C expressions, and they have the  same  meaning
  807. X          and   precedence   as   the   corresponding   C   operators.
  808. X
  809. X          Expressions almost always yield numeric results (integer  or
  810. X          floating-point values).  For example, the expression
  811. X
  812. X               8.2 + 6
  813. X
  814. X          evaluates  to  14.2.   Tcl   expressions   differ   from   C
  815. X          expressions  in  the way that operands are specified, and in
  816. X          that Tcl expressions support non-numeric operands and string
  817. X          comparisons.
  818. X
  819. X          A Tcl expression consists  of  a  combination  of  operands,
  820. X          operators, and parentheses.  White space may be used between
  821. X          the operands and operators and parentheses; it is ignored by
  822. X          the  expression  processor.   Where  possible,  operands are
  823. X          interpreted  as  integer  values.   Integer  values  may  be
  824. X          specified  in  decimal  (the  normal case), in octal (if the
  825. X          first character of the operand is 0), or in hexadecimal  (if
  826. X          the  first  two  characters  of  the operand are 0x).  If an
  827. X          operand does not have  one  of  the  integer  formats  given
  828. X          above, then it is treated as a floating-point number if that
  829. X          is possible.  Floating-point numbers may be specified in any
  830. X          of the ways accepted by an ANSI-compliant C compiler (except
  831. X          that the ``f'', ``F'', ``l'', and ``L'' suffixes will not be
  832. X          permitted  in  most installations).  For example, all of the
  833. X          following are valid floating-point numbers:  2.1,  3.,  6e4,
  834. X          7.91e+16.  If no numeric interpretation is possible, then an
  835. X          operand is left as a string  (and  only  a  limited  set  of
  836. X          operators may be applied to it).
  837. X
  838. X          Operators may be specified in any of the following ways:
  839. X
  840. X          [1]
  841. X               As an numeric value, either integer or floating-point.
  842. X
  843. X          [2]
  844. X               As  a  Tcl  variable,  using  standard $ notation.  The
  845. X               variable's value will be used as the operand.
  846. X
  847. X          [3]
  848. X               As  a string enclosed in double-quotes.  The expression
  849. X               parser will perform backslash,  variable,  and  command
  850. X               substitutions  on  the  information between the quotes,
  851. X               and use the resulting value as the operand
  852. X
  853. X          [4]
  854. X               As a string enclosed in braces.  The characters between
  855. X               the open brace and matching close brace will be used as
  856. X               the operand without any substitutions.
  857. X
  858. X          [5]
  859. X               As  a  Tcl  command  enclosed in brackets.  The command
  860. X               will be executed and its result will  be  used  as  the
  861. X               operand.
  862. X
  863. X          [6]
  864. X               An unquoted string consisting of any number of letters,
  865. X               digits, and underscores (but a digit  may  not  be  the
  866. X               first character).
  867. X
  868. X          Where  substitutions  occur  above   (e.g.   inside   quoted
  869. X          strings),  they  are  performed by the expression processor.
  870. X          However, an additional layer  of  substitution  may  already
  871. X          have  been  performed  by  the  command  parser  before  the
  872. X          expression processor was called.  As discussed below, it  is
  873. X          usually best to enclose expressions in braces to prevent the
  874. X          command  parser  from  performing   substitutions   on   the
  875. X          contents.
  876. X
  877. X          For  some  examples  of  simple  expressions,  suppose   the
  878. X          variable  a has the value 3 and the variable b has the value
  879. X          6.  Then the expression on the left  side  of  each  of  the
  880. X          lines  below will evaluate to the value on the right side of
  881. X          the line:
  882. X
  883. X               3.1 + $a                6.1
  884. X               2 + "$a.$b"             5.6
  885. X               4*[length "6 2"]        8
  886. X               {word one} < "word $a"  0
  887. X
  888. X
  889. X          The valid operators are listed below, grouped in  decreasing
  890. X          order of precedence:
  891. X
  892. X          -  ~  !
  893. X                              Unary  minus, bit-wise NOT, logical NOT.
  894. X                              None of these operands may be applied to
  895. X                              string operands, and bit-wise NOT may be
  896. X                              applied only to integers.
  897. X
  898. X          *  /  %
  899. X                              Multiply,  divide,  remainder.   None of
  900. X                              these operands may be applied to  string
  901. X                              operands,  and  remainder may be applied
  902. X                              only to integers.
  903. X
  904. X          +  -
  905. X                              Add and subtract.  Valid for any numeric
  906. X                              operands.
  907. X
  908. X          <<  >>
  909. X                              Left and right shift.  Valid for integer
  910. X                              operands only.
  911. X
  912. X          <  >  <=  >=
  913. X                              Boolean  less,  greater,  less  than  or
  914. X                              equal, and greater than or equal.   Each
  915. X                              operator  produces 1 if the condition is
  916. X                              true, 0 otherwise.  These operators  may
  917. X                              be applied to strings as well as numeric
  918. X                              operands,   in   which    case    string
  919. X                              comparison is used.
  920. X
  921. X          ==  !=
  922. X                              Boolean   equal  and  not  equal.   Each
  923. X                              operator  produces  a  zero/one  result.
  924. X                              Valid for all operand types.
  925. X
  926. X          &
  927. X                              Bit-wise   AND.    Valid   for   integer
  928. X                              operands only.
  929. X
  930. X          ^
  931. X                              Bit-wise   exclusive   OR.    Valid  for
  932. X                              integer operands only.
  933. X
  934. X          |
  935. X                              Bit-wise OR.  Valid for integer operands
  936. X                              only.
  937. X
  938. X          &&
  939. X                              Logical  AND.   Produces  a  1 result if
  940. X                              both operands are non-zero, 0 otherwise.
  941. X                              Valid    for   numeric   operands   only
  942. X                              (integers or floating-point).
  943. X
  944. X          ||
  945. X                              Logical OR.  Produces a 0 result if both
  946. X                              operands are zero, 1  otherwise.   Valid
  947. X                              for  numeric  operands only (integers or
  948. X                              floating-point).
  949. X
  950. X          x?y:z
  951. X                              If-then-else,  as  in C.  If x evaluates
  952. X                              to non-zero,  then  the  result  is  the
  953. X                              value of y.  Otherwise the result is the
  954. X                              value of z.  The x operand must  have  a
  955. X                              numeric value.
  956. X
  957. X          See the C manual for more details on the results produced by
  958. X          each  operator.   All of the binary operators group left-to-
  959. X          right within the same precedence level.   For  example,  the
  960. X          expression
  961. X
  962. X               4*2 < 7
  963. X
  964. X          evaluates to 0.
  965. X
  966. X          The &&, ||, and ?: operators have ``lazy evaluation'',  just
  967. X          as in C, which means that operands are not evaluated if they
  968. X          are not needed to determine the outcome.  For example, in
  969. X
  970. X               $v ? [a] : [b]
  971. X
  972. X          only one of [a] or [b] will actually be evaluated, depending
  973. X          on the value of $v.
  974. X
  975. X          All internal computations involving integers are  done  with
  976. X          the  C  type  long,  and all internal computations involving
  977. X          floating-point are  done  with  the  C  type  double.   When
  978. X          converting  a string to floating-point, exponent overflow is
  979. X          detected and results in a  Tcl  error.   For  conversion  to
  980. X          integer  from  string,  detection of overflow depends on the
  981. X          behavior of some routines in the  local  C  library,  so  it
  982. X          should be regarded as unreliable.  In any case, overflow and
  983. X          underflow  are   generally   not   detected   reliably   for
  984. X          intermediate results.
  985. X
  986. X          Conversion  among  internal  representations  for   integer,
  987. X          floating-point, and string operands is done automatically as
  988. X          needed.  For  arithmetic  computations,  integers  are  used
  989. X          until  some floating-point number is introduced, after which
  990. X          floating-point is used.  For example,
  991. X
  992. X               5 / 4
  993. X          yields the result 1, while
  994. X
  995. X               5 / 4.0
  996. X               5 / ( [length "abcd" chars] + 0.0 )
  997. X
  998. X          both yield the result 1.25.
  999. X
  1000. X          String values may be used  as  operands  of  the  comparison
  1001. X          operators,  although  the  expression  evaluator tries to do
  1002. X          comparisons as integer or floating-point when  it  can.   If
  1003. X          one  of  the  operands  of  a comparison is a string and the
  1004. X          other has a numeric value, the numeric operand is  converted
  1005. X          back to a string using the C sprintf format specifier %d for
  1006. X          integers and %g for floating-point values.  For example, the
  1007. X          expressions
  1008. X
  1009. X               "0x03" > "2"
  1010. X               "0y" < "0x12"
  1011. X          both evaluate to 1.  The  first  comparison  is  done  using
  1012. X          integer  comparison,  and  the  second  is done using string
  1013. X          comparison after the second  operand  is  converted  to  the
  1014. X          string ``18''.
  1015. X
  1016. X          In general it is safest to enclose an expression  in  braces
  1017. X          when entering it in a command:  otherwise, if the expression
  1018. X          contains any white space then the Tcl interpreter will split
  1019. X          it among several arguments.  For example, the command
  1020. X
  1021. X               expr $a + $b
  1022. X
  1023. X          results in three arguments being passed to expr:  $a, +, and
  1024. X          $b.  In addition, if the expression isn't in braces then the
  1025. X          Tcl  interpreter   will   perform   variable   and   command
  1026. X          substitution  immediately  (it  will  happen  in the command
  1027. X          parser rather than in the expression parser).  In many cases
  1028. X          the  expression  is  being  passed  to  a  command that will
  1029. X          evaluate the expression later (or even many  times  if,  for
  1030. X          example, the expression is to be used to decide when to exit
  1031. X          a loop).  Usually the desired goal is to re-do the  variable
  1032. X          or   command  substitutions  each  time  the  expression  is
  1033. X          evaluated, rather than once and for all  at  the  beginning.
  1034. X          For example, the command
  1035. X
  1036. X               for {set i 1} $i<=10 {incr i} {...}*** WRONG ***
  1037. X
  1038. X          is probably intended to iterate over all values of i from  1
  1039. X          to  10.   After  each iteration of the body of the loop, for
  1040. X          will pass its second argument to the expression evaluator to
  1041. X          see  whether  or not to continue processing.  Unfortunately,
  1042. X          in this case the value of i in the second argument  will  be
  1043. X          substituted once and for all when the for command is parsed.
  1044. X          If i was 0 before the for command  was  invoked  then  for's
  1045. X          second  argument will be 0<=10 which will always evaluate to
  1046. X          1, even though i's value eventually becomes greater than 10.
  1047. X          In  the  above case the loop will never terminate.  Instead,
  1048. X          the expression should be placed in braces:
  1049. X
  1050. X               for {set i 1} {$i<=10} {incr i} {...}*** RIGHT ***
  1051. X          This causes the substitution of i's value to be delayed;  it
  1052. X          will be re-done each time the expression is evaluated, which
  1053. X          is the desired result.
  1054. END_OF_FILE
  1055. if test 12156 -ne `wc -c <'extended/tcllib/help/intro/expressions'`; then
  1056.     echo shar: \"'extended/tcllib/help/intro/expressions'\" unpacked with wrong size!
  1057. fi
  1058. # end of 'extended/tcllib/help/intro/expressions'
  1059. fi
  1060. echo shar: End of archive 13 \(of 23\).
  1061. cp /dev/null ark13isdone
  1062. MISSING=""
  1063. 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
  1064.     if test ! -f ark${I}isdone ; then
  1065.     MISSING="${MISSING} ${I}"
  1066.     fi
  1067. done
  1068. if test "${MISSING}" = "" ; then
  1069.     echo You have unpacked all 23 archives.
  1070.     echo "Now cd to "extended", edit the makefile, then do a "make""
  1071.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1072. else
  1073.     echo You still need to unpack the following archives:
  1074.     echo "        " ${MISSING}
  1075. fi
  1076. ##  End of shell archive.
  1077. exit 0
  1078.  
  1079. exit 0 # Just in case...
  1080. -- 
  1081. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1082. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1083. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1084. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1085.