os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclFCmd.c
Update contrib.
4 * This file implements the generic portion of file manipulation
5 * subcommands of the "file" command.
7 * Copyright (c) 1996-1998 Sun Microsystems, Inc.
9 * See the file "license.terms" for information on usage and redistribution
10 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 * RCS: @(#) $Id: tclFCmd.c,v 1.20.2.2 2005/08/17 17:46:36 hobbs Exp $
19 * Declarations for local procedures defined in this file:
22 static int CopyRenameOneFile _ANSI_ARGS_((Tcl_Interp *interp,
23 Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr,
24 int copyFlag, int force));
25 static Tcl_Obj * FileBasename _ANSI_ARGS_((Tcl_Interp *interp,
27 static int FileCopyRename _ANSI_ARGS_((Tcl_Interp *interp,
28 int objc, Tcl_Obj *CONST objv[], int copyFlag));
29 static int FileForceOption _ANSI_ARGS_((Tcl_Interp *interp,
30 int objc, Tcl_Obj *CONST objv[], int *forcePtr));
33 *---------------------------------------------------------------------------
37 * This procedure implements the "rename" subcommand of the "file"
38 * command. Filename arguments need to be translated to native
39 * format before being passed to platform-specific code that
40 * implements rename functionality.
43 * A standard Tcl result.
46 * See the user documentation.
48 *---------------------------------------------------------------------------
52 TclFileRenameCmd(interp, objc, objv)
53 Tcl_Interp *interp; /* Interp for error reporting. */
54 int objc; /* Number of arguments. */
55 Tcl_Obj *CONST objv[]; /* Argument strings passed to Tcl_FileCmd. */
57 return FileCopyRename(interp, objc, objv, 0);
61 *---------------------------------------------------------------------------
65 * This procedure implements the "copy" subcommand of the "file"
66 * command. Filename arguments need to be translated to native
67 * format before being passed to platform-specific code that
68 * implements copy functionality.
71 * A standard Tcl result.
74 * See the user documentation.
76 *---------------------------------------------------------------------------
80 TclFileCopyCmd(interp, objc, objv)
81 Tcl_Interp *interp; /* Used for error reporting */
82 int objc; /* Number of arguments. */
83 Tcl_Obj *CONST objv[]; /* Argument strings passed to Tcl_FileCmd. */
85 return FileCopyRename(interp, objc, objv, 1);
89 *---------------------------------------------------------------------------
93 * Performs the work of TclFileRenameCmd and TclFileCopyCmd.
94 * See comments for those procedures.
102 *---------------------------------------------------------------------------
106 FileCopyRename(interp, objc, objv, copyFlag)
107 Tcl_Interp *interp; /* Used for error reporting. */
108 int objc; /* Number of arguments. */
109 Tcl_Obj *CONST objv[]; /* Argument strings passed to Tcl_FileCmd. */
110 int copyFlag; /* If non-zero, copy source(s). Otherwise,
113 int i, result, force;
117 i = FileForceOption(interp, objc - 2, objv + 2, &force);
122 if ((objc - i) < 2) {
123 Tcl_AppendResult(interp, "wrong # args: should be \"",
124 Tcl_GetString(objv[0]), " ", Tcl_GetString(objv[1]),
125 " ?options? source ?source ...? target\"",
131 * If target doesn't exist or isn't a directory, try the copy/rename.
132 * More than 2 arguments is only valid if the target is an existing
136 target = objv[objc - 1];
137 if (Tcl_FSConvertToPathType(interp, target) != TCL_OK) {
144 * Call Tcl_FSStat() so that if target is a symlink that points to a
145 * directory we will put the sources in that directory instead of
146 * overwriting the symlink.
149 if ((Tcl_FSStat(target, &statBuf) != 0) || !S_ISDIR(statBuf.st_mode)) {
150 if ((objc - i) > 2) {
152 Tcl_PosixError(interp);
153 Tcl_AppendResult(interp, "error ",
154 ((copyFlag) ? "copying" : "renaming"), ": target \"",
155 Tcl_GetString(target), "\" is not a directory",
160 * Even though already have target == translated(objv[i+1]),
161 * pass the original argument down, so if there's an error, the
162 * error message will reflect the original arguments.
165 result = CopyRenameOneFile(interp, objv[i], objv[i + 1], copyFlag,
172 * Move each source file into target directory. Extract the basename
173 * from each source, and append it to the end of the target path.
176 for ( ; i < objc - 1; i++) {
178 Tcl_Obj *source, *newFileName;
181 source = FileBasename(interp, objv[i]);
182 if (source == NULL) {
186 jargv[0] = objv[objc - 1];
188 temp = Tcl_NewListObj(2, jargv);
189 newFileName = Tcl_FSJoinPath(temp, -1);
190 Tcl_IncrRefCount(newFileName);
191 result = CopyRenameOneFile(interp, objv[i], newFileName, copyFlag,
193 Tcl_DecrRefCount(newFileName);
194 Tcl_DecrRefCount(temp);
195 Tcl_DecrRefCount(source);
197 if (result == TCL_ERROR) {
205 *---------------------------------------------------------------------------
209 * This procedure implements the "mkdir" subcommand of the "file"
210 * command. Filename arguments need to be translated to native
211 * format before being passed to platform-specific code that
212 * implements mkdir functionality.
215 * A standard Tcl result.
218 * See the user documentation.
220 *----------------------------------------------------------------------
223 TclFileMakeDirsCmd(interp, objc, objv)
224 Tcl_Interp *interp; /* Used for error reporting. */
225 int objc; /* Number of arguments */
226 Tcl_Obj *CONST objv[]; /* Argument strings passed to Tcl_FileCmd. */
229 int result, i, j, pobjc;
230 Tcl_Obj *split = NULL;
231 Tcl_Obj *target = NULL;
237 for (i = 2; i < objc; i++) {
238 if (Tcl_FSConvertToPathType(interp, objv[i]) != TCL_OK) {
243 split = Tcl_FSSplitPath(objv[i],&pobjc);
249 for (j = 0; j < pobjc; j++) {
250 target = Tcl_FSJoinPath(split, j + 1);
251 Tcl_IncrRefCount(target);
253 * Call Tcl_FSStat() so that if target is a symlink that
254 * points to a directory we will create subdirectories in
258 if (Tcl_FSStat(target, &statBuf) == 0) {
259 if (!S_ISDIR(statBuf.st_mode)) {
264 } else if (errno != ENOENT) {
266 * If Tcl_FSStat() failed and the error is anything
267 * other than non-existence of the target, throw the
272 } else if (Tcl_FSCreateDirectory(target) != TCL_OK) {
274 * Create might have failed because of being in a race
275 * condition with another process trying to create the
278 if (errno == EEXIST) {
279 if ((Tcl_FSStat(target, &statBuf) == 0)
280 && S_ISDIR(statBuf.st_mode)) {
282 * It is a directory that wasn't there before,
283 * so keep going without error.
285 Tcl_ResetResult(interp);
295 /* Forget about this sub-path */
296 Tcl_DecrRefCount(target);
299 Tcl_DecrRefCount(split);
304 if (errfile != NULL) {
305 Tcl_AppendResult(interp, "can't create directory \"",
306 Tcl_GetString(errfile), "\": ", Tcl_PosixError(interp),
311 Tcl_DecrRefCount(split);
313 if (target != NULL) {
314 Tcl_DecrRefCount(target);
320 *----------------------------------------------------------------------
324 * This procedure implements the "delete" subcommand of the "file"
328 * A standard Tcl result.
331 * See the user documentation.
333 *----------------------------------------------------------------------
337 TclFileDeleteCmd(interp, objc, objv)
338 Tcl_Interp *interp; /* Used for error reporting */
339 int objc; /* Number of arguments */
340 Tcl_Obj *CONST objv[]; /* Argument strings passed to Tcl_FileCmd. */
342 int i, force, result;
344 Tcl_Obj *errorBuffer = NULL;
346 i = FileForceOption(interp, objc - 2, objv + 2, &force);
351 if ((objc - i) < 1) {
352 Tcl_AppendResult(interp, "wrong # args: should be \"",
353 Tcl_GetString(objv[0]), " ", Tcl_GetString(objv[1]),
354 " ?options? file ?file ...?\"", (char *) NULL);
361 for ( ; i < objc; i++) {
365 if (Tcl_FSConvertToPathType(interp, objv[i]) != TCL_OK) {
371 * Call lstat() to get info so can delete symbolic link itself.
374 if (Tcl_FSLstat(objv[i], &statBuf) != 0) {
376 * Trying to delete a file that does not exist is not
377 * considered an error, just a no-op
380 if (errno != ENOENT) {
383 } else if (S_ISDIR(statBuf.st_mode)) {
385 * We own a reference count on errorBuffer, if it was set
386 * as a result of this call.
388 result = Tcl_FSRemoveDirectory(objv[i], force, &errorBuffer);
389 if (result != TCL_OK) {
390 if ((force == 0) && (errno == EEXIST)) {
391 Tcl_AppendResult(interp, "error deleting \"",
392 Tcl_GetString(objv[i]),
393 "\": directory not empty", (char *) NULL);
394 Tcl_PosixError(interp);
399 * If possible, use the untranslated name for the file.
402 errfile = errorBuffer;
403 /* FS supposed to check between translated objv and errfile */
404 if (Tcl_FSEqualPaths(objv[i], errfile)) {
409 result = Tcl_FSDeleteFile(objv[i]);
412 if (result != TCL_OK) {
415 * It is important that we break on error, otherwise we
416 * might end up owning reference counts on numerous
422 if (result != TCL_OK) {
423 if (errfile == NULL) {
425 * We try to accomodate poor error results from our
428 Tcl_AppendResult(interp, "error deleting unknown file: ",
429 Tcl_PosixError(interp), (char *) NULL);
431 Tcl_AppendResult(interp, "error deleting \"",
432 Tcl_GetString(errfile), "\": ",
433 Tcl_PosixError(interp), (char *) NULL);
437 if (errorBuffer != NULL) {
438 Tcl_DecrRefCount(errorBuffer);
444 *---------------------------------------------------------------------------
448 * Copies or renames specified source file or directory hierarchy
449 * to the specified target.
452 * A standard Tcl result.
455 * Target is overwritten if the force flag is set. Attempting to
456 * copy/rename a file onto a directory or a directory onto a file
457 * will always result in an error.
459 *----------------------------------------------------------------------
463 CopyRenameOneFile(interp, source, target, copyFlag, force)
464 Tcl_Interp *interp; /* Used for error reporting. */
465 Tcl_Obj *source; /* Pathname of file to copy. May need to
467 Tcl_Obj *target; /* Pathname of file to create/overwrite.
468 * May need to be translated. */
469 int copyFlag; /* If non-zero, copy files. Otherwise,
471 int force; /* If non-zero, overwrite target file if it
472 * exists. Otherwise, error if target already
476 Tcl_Obj *errfile, *errorBuffer;
477 /* If source is a link, then this is the real file/directory */
478 Tcl_Obj *actualSource = NULL;
479 Tcl_StatBuf sourceStatBuf, targetStatBuf;
481 if (Tcl_FSConvertToPathType(interp, source) != TCL_OK) {
484 if (Tcl_FSConvertToPathType(interp, target) != TCL_OK) {
493 * We want to copy/rename links and not the files they point to, so we
494 * use lstat(). If target is a link, we also want to replace the
495 * link and not the file it points to, so we also use lstat() on the
499 if (Tcl_FSLstat(source, &sourceStatBuf) != 0) {
503 if (Tcl_FSLstat(target, &targetStatBuf) != 0) {
504 if (errno != ENOENT) {
516 * Prevent copying or renaming a file onto itself. Under Windows,
517 * stat always returns 0 for st_ino. However, the Windows-specific
518 * code knows how to deal with copying or renaming a file on top of
519 * itself. It might be a good idea to write a stat that worked.
522 if ((sourceStatBuf.st_ino != 0) && (targetStatBuf.st_ino != 0)) {
523 if ((sourceStatBuf.st_ino == targetStatBuf.st_ino) &&
524 (sourceStatBuf.st_dev == targetStatBuf.st_dev)) {
531 * Prevent copying/renaming a file onto a directory and
532 * vice-versa. This is a policy decision based on the fact that
533 * existing implementations of copy and rename on all platforms
537 if (S_ISDIR(sourceStatBuf.st_mode)
538 && !S_ISDIR(targetStatBuf.st_mode)) {
540 Tcl_AppendResult(interp, "can't overwrite file \"",
541 Tcl_GetString(target), "\" with directory \"",
542 Tcl_GetString(source), "\"", (char *) NULL);
545 if (!S_ISDIR(sourceStatBuf.st_mode)
546 && S_ISDIR(targetStatBuf.st_mode)) {
548 Tcl_AppendResult(interp, "can't overwrite directory \"",
549 Tcl_GetString(target), "\" with file \"",
550 Tcl_GetString(source), "\"", (char *) NULL);
556 result = Tcl_FSRenameFile(source, target);
557 if (result == TCL_OK) {
561 if (errno == EINVAL) {
562 Tcl_AppendResult(interp, "error renaming \"",
563 Tcl_GetString(source), "\" to \"",
564 Tcl_GetString(target), "\": trying to rename a volume or ",
565 "move a directory into itself", (char *) NULL);
567 } else if (errno != EXDEV) {
573 * The rename failed because the move was across file systems.
574 * Fall through to copy file and then remove original. Note that
575 * the low-level Tcl_FSRenameFileProc in the filesystem is allowed
576 * to implement cross-filesystem moves itself, if it desires.
580 actualSource = source;
581 Tcl_IncrRefCount(actualSource);
585 * To add a flag to make 'copy' copy links instead of files, we could
586 * add a condition to ignore this 'if' here.
588 if (copyFlag && S_ISLNK(sourceStatBuf.st_mode)) {
590 * We want to copy files not links. Therefore we must follow the
591 * link. There are two purposes to this 'stat' call here. First
592 * we want to know if the linked-file/dir actually exists, and
593 * second, in the block of code which follows, some 20 lines
594 * down, we want to check if the thing is a file or directory.
596 if (Tcl_FSStat(source, &sourceStatBuf) != 0) {
597 /* Actual file doesn't exist */
598 Tcl_AppendResult(interp,
599 "error copying \"", Tcl_GetString(source),
600 "\": the target of this link doesn't exist",
606 Tcl_Obj *path = Tcl_FSLink(actualSource, NULL, 0);
610 Tcl_DecrRefCount(actualSource);
613 /* Arbitrary limit of 20 links to follow */
616 Tcl_SetErrno(EMLINK);
621 /* Now 'actualSource' is the correct file */
627 if (S_ISDIR(sourceStatBuf.st_mode)) {
628 result = Tcl_FSCopyDirectory(actualSource, target, &errorBuffer);
629 if (result != TCL_OK) {
630 if (errno == EXDEV) {
632 * The copy failed because we're trying to do a
633 * cross-filesystem copy. We do this through our Tcl
636 Tcl_SavedResult savedResult;
637 Tcl_Obj *copyCommand = Tcl_NewListObj(0,NULL);
638 Tcl_IncrRefCount(copyCommand);
639 Tcl_ListObjAppendElement(interp, copyCommand,
640 Tcl_NewStringObj("::tcl::CopyDirectory",-1));
642 Tcl_ListObjAppendElement(interp, copyCommand,
643 Tcl_NewStringObj("copying",-1));
645 Tcl_ListObjAppendElement(interp, copyCommand,
646 Tcl_NewStringObj("renaming",-1));
648 Tcl_ListObjAppendElement(interp, copyCommand, source);
649 Tcl_ListObjAppendElement(interp, copyCommand, target);
650 Tcl_SaveResult(interp, &savedResult);
651 result = Tcl_EvalObjEx(interp, copyCommand,
652 TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT);
653 Tcl_DecrRefCount(copyCommand);
654 if (result != TCL_OK) {
656 * There was an error in the Tcl-level copy.
657 * We will pass on the Tcl error message and
658 * can ensure this by setting errfile to NULL
660 Tcl_DiscardResult(&savedResult);
663 /* The copy was successful */
664 Tcl_RestoreResult(interp, &savedResult);
667 errfile = errorBuffer;
668 if (Tcl_FSEqualPaths(errfile, source)) {
670 } else if (Tcl_FSEqualPaths(errfile, target)) {
676 result = Tcl_FSCopyFile(actualSource, target);
677 if ((result != TCL_OK) && (errno == EXDEV)) {
678 result = TclCrossFilesystemCopy(interp, source, target);
680 if (result != TCL_OK) {
682 * We could examine 'errno' to double-check if the problem
683 * was with the target, but we checked the source above,
684 * so it should be quite clear
688 * We now need to reset the result, because the above call,
689 * if it failed, may have put an error message in place.
690 * (Ideally we would prefer not to pass an interpreter in
691 * above, but the channel IO code used by
692 * TclCrossFilesystemCopy currently requires one)
694 Tcl_ResetResult(interp);
697 if ((copyFlag == 0) && (result == TCL_OK)) {
698 if (S_ISDIR(sourceStatBuf.st_mode)) {
699 result = Tcl_FSRemoveDirectory(source, 1, &errorBuffer);
700 if (result != TCL_OK) {
701 if (Tcl_FSEqualPaths(errfile, source) == 0) {
706 result = Tcl_FSDeleteFile(source);
707 if (result != TCL_OK) {
711 if (result != TCL_OK) {
712 Tcl_AppendResult(interp, "can't unlink \"",
713 Tcl_GetString(errfile), "\": ",
714 Tcl_PosixError(interp), (char *) NULL);
720 if (errfile != NULL) {
721 Tcl_AppendResult(interp,
722 ((copyFlag) ? "error copying \"" : "error renaming \""),
723 Tcl_GetString(source), (char *) NULL);
724 if (errfile != source) {
725 Tcl_AppendResult(interp, "\" to \"", Tcl_GetString(target),
727 if (errfile != target) {
728 Tcl_AppendResult(interp, "\": \"", Tcl_GetString(errfile),
732 Tcl_AppendResult(interp, "\": ", Tcl_PosixError(interp),
735 if (errorBuffer != NULL) {
736 Tcl_DecrRefCount(errorBuffer);
738 if (actualSource != NULL) {
739 Tcl_DecrRefCount(actualSource);
745 *---------------------------------------------------------------------------
749 * Helps parse command line options for file commands that take
750 * the "-force" and "--" options.
753 * The return value is how many arguments from argv were consumed
754 * by this function, or -1 if there was an error parsing the
755 * options. If an error occurred, an error message is left in the
761 *---------------------------------------------------------------------------
765 FileForceOption(interp, objc, objv, forcePtr)
766 Tcl_Interp *interp; /* Interp, for error return. */
767 int objc; /* Number of arguments. */
768 Tcl_Obj *CONST objv[]; /* Argument strings. First command line
769 * option, if it exists, begins at 0. */
770 int *forcePtr; /* If the "-force" was specified, *forcePtr
771 * is filled with 1, otherwise with 0. */
776 for (i = 0; i < objc; i++) {
777 if (Tcl_GetString(objv[i])[0] != '-') {
780 if (strcmp(Tcl_GetString(objv[i]), "-force") == 0) {
782 } else if (strcmp(Tcl_GetString(objv[i]), "--") == 0) {
786 Tcl_AppendResult(interp, "bad option \"", Tcl_GetString(objv[i]),
787 "\": should be -force or --", (char *)NULL);
795 *---------------------------------------------------------------------------
799 * Given a path in either tcl format (with / separators), or in the
800 * platform-specific format for the current platform, return all the
801 * characters in the path after the last directory separator. But,
802 * if path is the root directory, returns no characters.
805 * Returns the string object that represents the basename. If there
806 * is an error, an error message is left in interp, and NULL is
812 *---------------------------------------------------------------------------
816 FileBasename(interp, pathPtr)
817 Tcl_Interp *interp; /* Interp, for error return. */
818 Tcl_Obj *pathPtr; /* Path whose basename to extract. */
822 Tcl_Obj *resultPtr = NULL;
824 splitPtr = Tcl_FSSplitPath(pathPtr, &objc);
827 if ((objc == 1) && (*Tcl_GetString(pathPtr) == '~')) {
828 Tcl_DecrRefCount(splitPtr);
829 if (Tcl_FSConvertToPathType(interp, pathPtr) != TCL_OK) {
832 splitPtr = Tcl_FSSplitPath(pathPtr, &objc);
836 * Return the last component, unless it is the only component, and it
837 * is the root of an absolute path.
841 Tcl_ListObjIndex(NULL, splitPtr, objc-1, &resultPtr);
843 (Tcl_FSGetPathType(resultPtr) != TCL_PATH_RELATIVE)) {
848 if (resultPtr == NULL) {
849 resultPtr = Tcl_NewObj();
851 Tcl_IncrRefCount(resultPtr);
852 Tcl_DecrRefCount(splitPtr);
857 *----------------------------------------------------------------------
861 * Sets or gets the platform-specific attributes of a file. The
862 * objc-objv points to the file name with the rest of the command
863 * line following. This routine uses platform-specific tables of
864 * option strings and callbacks. The callback to get the
865 * attributes take three parameters:
866 * Tcl_Interp *interp; The interp to report errors with.
867 * Since this is an object-based API,
868 * the object form of the result should
870 * CONST char *fileName; This is extracted using
871 * Tcl_TranslateFileName.
872 * TclObj **attrObjPtrPtr; A new object to hold the attribute
873 * is allocated and put here.
874 * The first two parameters of the callback used to write out the
875 * attributes are the same. The third parameter is:
876 * CONST *attrObjPtr; A pointer to the object that has
878 * They both return standard TCL errors; if the routine to get
879 * an attribute fails, no object is allocated and *attrObjPtrPtr
883 * Standard TCL error.
886 * May set file attributes for the file name.
888 *----------------------------------------------------------------------
892 TclFileAttrsCmd(interp, objc, objv)
893 Tcl_Interp *interp; /* The interpreter for error reporting. */
894 int objc; /* Number of command line arguments. */
895 Tcl_Obj *CONST objv[]; /* The command line objects. */
898 CONST char ** attributeStrings;
899 Tcl_Obj* objStrings = NULL;
900 int numObjStrings = -1;
904 Tcl_WrongNumArgs(interp, 2, objv,
905 "name ?option? ?value? ?option value ...?");
910 if (Tcl_FSConvertToPathType(interp, filePtr) != TCL_OK) {
918 attributeStrings = Tcl_FSFileAttrStrings(filePtr, &objStrings);
919 if (attributeStrings == NULL) {
922 if (objStrings == NULL) {
923 if (Tcl_GetErrno() != 0) {
925 * There was an error, probably that the filePtr is
926 * not accepted by any filesystem
928 Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
929 "could not read \"", Tcl_GetString(filePtr),
930 "\": ", Tcl_PosixError(interp),
936 /* We own the object now */
937 Tcl_IncrRefCount(objStrings);
938 /* Use objStrings as a list object */
939 if (Tcl_ListObjLength(interp, objStrings, &numObjStrings) != TCL_OK) {
942 attributeStrings = (CONST char **)
943 ckalloc ((1+numObjStrings) * sizeof(char*));
944 for (index = 0; index < numObjStrings; index++) {
945 Tcl_ListObjIndex(interp, objStrings, index, &objPtr);
946 attributeStrings[index] = Tcl_GetString(objPtr);
948 attributeStrings[index] = NULL;
952 * Get all attributes.
958 listPtr = Tcl_NewListObj(0, NULL);
959 for (index = 0; attributeStrings[index] != NULL; index++) {
960 Tcl_Obj *objPtr = Tcl_NewStringObj(attributeStrings[index], -1);
961 Tcl_ListObjAppendElement(interp, listPtr, objPtr);
962 /* We now forget about objPtr, it is in the list */
964 if (Tcl_FSFileAttrsGet(interp, index, filePtr,
965 &objPtr) != TCL_OK) {
966 Tcl_DecrRefCount(listPtr);
969 Tcl_ListObjAppendElement(interp, listPtr, objPtr);
971 Tcl_SetObjResult(interp, listPtr);
972 } else if (objc == 1) {
978 Tcl_Obj *objPtr = NULL;
980 if (numObjStrings == 0) {
981 Tcl_AppendResult(interp, "bad option \"",
982 Tcl_GetString(objv[0]), "\", there are no file attributes"
983 " in this filesystem.", (char *) NULL);
987 if (Tcl_GetIndexFromObj(interp, objv[0], attributeStrings,
988 "option", 0, &index) != TCL_OK) {
991 if (Tcl_FSFileAttrsGet(interp, index, filePtr,
992 &objPtr) != TCL_OK) {
995 Tcl_SetObjResult(interp, objPtr);
998 * Set option/value pairs.
1003 if (numObjStrings == 0) {
1004 Tcl_AppendResult(interp, "bad option \"",
1005 Tcl_GetString(objv[0]), "\", there are no file attributes"
1006 " in this filesystem.", (char *) NULL);
1010 for (i = 0; i < objc ; i += 2) {
1011 if (Tcl_GetIndexFromObj(interp, objv[i], attributeStrings,
1012 "option", 0, &index) != TCL_OK) {
1015 if (i + 1 == objc) {
1016 Tcl_AppendResult(interp, "value for \"",
1017 Tcl_GetString(objv[i]), "\" missing",
1021 if (Tcl_FSFileAttrsSet(interp, index, filePtr,
1022 objv[i + 1]) != TCL_OK) {
1030 if (numObjStrings != -1) {
1031 /* Free up the array we allocated */
1032 ckfree((char*)attributeStrings);
1034 * We don't need this object that was passed to us
1037 if (objStrings != NULL) {
1038 Tcl_DecrRefCount(objStrings);