]>
git.zerfleddert.de Git - micropolis/blob - src/tclx/src/tclxfcmd.c
4 * Extended Tcl pipe, copyfile and fstat commands.
5 *-----------------------------------------------------------------------------
6 * Copyright 1992 Karl Lehenbauer and Mark Diekhans.
8 * Permission to use, copy, modify, and distribute this software and its
9 * documentation for any purpose and without fee is hereby granted, provided
10 * that the above copyright notice appear in all copies. Karl Lehenbauer and
11 * Mark Diekhans make no representations about the suitability of this
12 * software for any purpose. It is provided "as is" without express or
14 *-----------------------------------------------------------------------------
15 * $Id: tclXfilecmds.c,v 2.0 1992/10/16 04:50:41 markd Rel $
16 *-----------------------------------------------------------------------------
22 * Prototypes of internal functions.
25 GetFileType
_ANSI_ARGS_((struct stat
*statBufPtr
));
28 ReturnStatList
_ANSI_ARGS_((Tcl_Interp
*interp
,
30 struct stat
*statBufPtr
));
33 ReturnStatArray
_ANSI_ARGS_((Tcl_Interp
*interp
,
35 struct stat
*statBufPtr
,
39 ReturnStatItem
_ANSI_ARGS_((Tcl_Interp
*interp
,
41 struct stat
*statBufPtr
,
45 ParseLockUnlockArgs
_ANSI_ARGS_((Tcl_Interp
*interp
,
49 OpenFile
**filePtrPtr
,
50 struct flock
*lockInfoPtr
));
54 *-----------------------------------------------------------------------------
57 * Implements the pipe TCL command:
58 * pipe [handle_var_r handle_var_w]
61 * Standard TCL result.
64 * Locates and creates entries in the handles table
66 *-----------------------------------------------------------------------------
70 ClientData clientData
,
76 Interp
*iPtr
= (Interp
*) interp
;
80 if (!((argc
== 1) || (argc
== 3))) {
81 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0],
82 " [handle_var_r handle_var_w]", (char*) NULL
);
86 if (pipe (fileIds
) < 0) {
87 interp
->result
= Tcl_UnixError (interp
);
91 if (Tcl_SetupFileEntry (interp
, fileIds
[0], TRUE
, FALSE
) != TCL_OK
)
93 if (Tcl_SetupFileEntry (interp
, fileIds
[1], FALSE
, TRUE
) != TCL_OK
)
97 sprintf (interp
->result
, "file%d file%d", fileIds
[0], fileIds
[1]);
99 sprintf (fHandle
, "file%d", fileIds
[0]);
100 if (Tcl_SetVar (interp
, argv
[1], fHandle
, TCL_LEAVE_ERR_MSG
) == NULL
)
103 sprintf (fHandle
, "file%d", fileIds
[1]);
104 if (Tcl_SetVar (interp
, argv
[2], fHandle
, TCL_LEAVE_ERR_MSG
) == NULL
)
117 *-----------------------------------------------------------------------------
120 * Implements the copyfile TCL command:
121 * copyfile handle1 handle2 [lines]
124 * Nothing if it worked, else an error.
126 *-----------------------------------------------------------------------------
130 ClientData clientData
,
136 OpenFile
*fromFilePtr
, *toFilePtr
;
137 char transferBuffer
[2048];
141 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0],
142 " fromfilehandle tofilehandle", (char *) NULL
);
146 if (TclGetOpenFile (interp
, argv
[1], &fromFilePtr
) != TCL_OK
)
148 if (TclGetOpenFile (interp
, argv
[2], &toFilePtr
) != TCL_OK
)
151 if (!fromFilePtr
->readable
) {
152 interp
->result
= "Source file is not open for read access";
155 if (!toFilePtr
->writable
) {
156 interp
->result
= "Target file is not open for write access";
161 bytesRead
= fread (transferBuffer
, sizeof (char),
162 sizeof (transferBuffer
), fromFilePtr
->f
);
163 if (bytesRead
<= 0) {
164 if (feof (fromFilePtr
->f
))
169 if (fwrite (transferBuffer
, sizeof (char), bytesRead
, toFilePtr
->f
) !=
177 interp
->result
= Tcl_UnixError (interp
);
182 *-----------------------------------------------------------------------------
186 * Looks at stat mode and returns a text string indicating what type of
190 * o statBufPtr (I) - Pointer to a buffer initialized by stat or fstat.
192 * A pointer static text string representing the type of the file.
193 *-----------------------------------------------------------------------------
197 struct stat
*statBufPtr
203 * Get a string representing the type of the file.
205 if (S_ISREG (statBufPtr
->st_mode
)) {
207 } else if (S_ISDIR (statBufPtr
->st_mode
)) {
208 typeStr
= "directory";
209 } else if (S_ISCHR (statBufPtr
->st_mode
)) {
210 typeStr
= "characterSpecial";
211 } else if (S_ISBLK (statBufPtr
->st_mode
)) {
212 typeStr
= "blockSpecial";
213 } else if (S_ISFIFO (statBufPtr
->st_mode
)) {
215 } else if (S_ISLNK (statBufPtr
->st_mode
)) {
217 } else if (S_ISSOCK (statBufPtr
->st_mode
)) {
227 *-----------------------------------------------------------------------------
231 * Return file stat infomation as a keyed list.
234 * o interp (I) - The list is returned in result.
235 * o filePtr (I) - Pointer to the Tcl open file structure.
236 * o statBufPtr (I) - Pointer to a buffer initialized by stat or fstat.
237 *-----------------------------------------------------------------------------
243 struct stat
*statBufPtr
249 "{atime %d} {ctime %d} {dev %d} {gid %d} {ino %d} {mode %d} ",
250 statBufPtr
->st_atime
, statBufPtr
->st_ctime
, statBufPtr
->st_dev
,
251 statBufPtr
->st_gid
, statBufPtr
->st_ino
, statBufPtr
->st_mode
);
252 Tcl_AppendResult (interp
, statList
, (char *) NULL
);
255 "{mtime %d} {nlink %d} {size %d} {uid %d} {tty %d} {type %s}",
256 statBufPtr
->st_mtime
, statBufPtr
->st_nlink
, statBufPtr
->st_size
,
257 statBufPtr
->st_uid
, isatty (fileno (filePtr
->f
)),
258 GetFileType (statBufPtr
));
259 Tcl_AppendResult (interp
, statList
, (char *) NULL
);
264 *-----------------------------------------------------------------------------
268 * Return file stat infomation in an array.
271 * o interp (I) - Current interpreter, error return in result.
272 * o filePtr (I) - Pointer to the Tcl open file structure.
273 * o statBufPtr (I) - Pointer to a buffer initialized by stat or fstat.
274 * o arrayName (I) - The name of the array to return the info in.
276 * TCL_OK or TCL_ERROR.
277 *-----------------------------------------------------------------------------
283 struct stat
*statBufPtr
,
289 sprintf (numBuf
, "%d", statBufPtr
->st_dev
);
290 if (Tcl_SetVar2 (interp
, arrayName
, "dev", numBuf
,
291 TCL_LEAVE_ERR_MSG
) == NULL
)
294 sprintf (numBuf
, "%d", statBufPtr
->st_ino
);
295 if (Tcl_SetVar2 (interp
, arrayName
, "ino", numBuf
,
296 TCL_LEAVE_ERR_MSG
) == NULL
)
299 sprintf (numBuf
, "%d", statBufPtr
->st_mode
);
300 if (Tcl_SetVar2 (interp
, arrayName
, "mode", numBuf
,
301 TCL_LEAVE_ERR_MSG
) == NULL
)
304 sprintf (numBuf
, "%d", statBufPtr
->st_nlink
);
305 if (Tcl_SetVar2 (interp
, arrayName
, "nlink", numBuf
,
306 TCL_LEAVE_ERR_MSG
) == NULL
)
309 sprintf (numBuf
, "%d", statBufPtr
->st_uid
);
310 if (Tcl_SetVar2 (interp
, arrayName
, "uid", numBuf
,
311 TCL_LEAVE_ERR_MSG
) == NULL
)
314 sprintf (numBuf
, "%d", statBufPtr
->st_gid
);
315 if (Tcl_SetVar2 (interp
, arrayName
, "gid", numBuf
,
316 TCL_LEAVE_ERR_MSG
) == NULL
)
319 sprintf (numBuf
, "%d", statBufPtr
->st_size
);
320 if (Tcl_SetVar2 (interp
, arrayName
, "size", numBuf
,
321 TCL_LEAVE_ERR_MSG
) == NULL
)
324 sprintf (numBuf
, "%d", statBufPtr
->st_atime
);
325 if (Tcl_SetVar2 (interp
, arrayName
, "atime", numBuf
,
326 TCL_LEAVE_ERR_MSG
) == NULL
)
329 sprintf (numBuf
, "%d", statBufPtr
->st_mtime
);
330 if (Tcl_SetVar2 (interp
, arrayName
, "mtime", numBuf
,
331 TCL_LEAVE_ERR_MSG
) == NULL
)
334 sprintf (numBuf
, "%d", statBufPtr
->st_ctime
);
335 if (Tcl_SetVar2 (interp
, arrayName
, "ctime", numBuf
,
336 TCL_LEAVE_ERR_MSG
) == NULL
)
339 if (Tcl_SetVar2 (interp
, arrayName
, "tty",
340 isatty (fileno (filePtr
->f
)) ? "1" : "0",
341 TCL_LEAVE_ERR_MSG
) == NULL
)
344 if (Tcl_SetVar2 (interp
, arrayName
, "type", GetFileType (statBufPtr
),
345 TCL_LEAVE_ERR_MSG
) == NULL
)
353 *-----------------------------------------------------------------------------
357 * Return a single file status item.
360 * o interp (I) - Item or error returned in result.
361 * o filePtr (I) - Pointer to the Tcl open file structure.
362 * o statBufPtr (I) - Pointer to a buffer initialized by stat or fstat.
363 * o itemName (I) - The name of the desired item.
365 * TCL_OK or TCL_ERROR.
366 *-----------------------------------------------------------------------------
372 struct stat
*statBufPtr
,
376 if (STREQU (itemName
, "dev"))
377 sprintf (interp
->result
, "%d", statBufPtr
->st_dev
);
378 else if (STREQU (itemName
, "ino"))
379 sprintf (interp
->result
, "%d", statBufPtr
->st_ino
);
380 else if (STREQU (itemName
, "mode"))
381 sprintf (interp
->result
, "%d", statBufPtr
->st_mode
);
382 else if (STREQU (itemName
, "nlink"))
383 sprintf (interp
->result
, "%d", statBufPtr
->st_nlink
);
384 else if (STREQU (itemName
, "uid"))
385 sprintf (interp
->result
, "%d", statBufPtr
->st_uid
);
386 else if (STREQU (itemName
, "gid"))
387 sprintf (interp
->result
, "%d", statBufPtr
->st_gid
);
388 else if (STREQU (itemName
, "size"))
389 sprintf (interp
->result
, "%d", statBufPtr
->st_size
);
390 else if (STREQU (itemName
, "atime"))
391 sprintf (interp
->result
, "%d", statBufPtr
->st_atime
);
392 else if (STREQU (itemName
, "mtime"))
393 sprintf (interp
->result
, "%d", statBufPtr
->st_mtime
);
394 else if (STREQU (itemName
, "ctime"))
395 sprintf (interp
->result
, "%d", statBufPtr
->st_ctime
);
396 else if (STREQU (itemName
, "type"))
397 interp
->result
= GetFileType (statBufPtr
);
398 else if (STREQU (itemName
, "tty"))
399 interp
->result
= isatty (fileno (filePtr
->f
)) ? "1" : "0";
401 Tcl_AppendResult (interp
, "Got \"", itemName
, "\", expected one of ",
402 "\"atime\", \"ctime\", \"dev\", \"gid\", \"ino\", ",
403 "\"mode\", \"mtime\", \"nlink\", \"size\", ",
404 "\"tty\", \"type\", \"uid\"", (char *) NULL
);
414 *-----------------------------------------------------------------------------
417 * Implements the fstat TCL command:
418 * fstat handle [item]|[stat arrayvar]
420 *-----------------------------------------------------------------------------
424 ClientData clientData
,
433 if ((argc
< 2) || (argc
> 4)) {
434 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0],
435 " handle [item]|[stat arrayVar]", (char *) NULL
);
439 if (TclGetOpenFile (interp
, argv
[1], &filePtr
) != TCL_OK
)
442 if (fstat (fileno (filePtr
->f
), &statBuf
)) {
443 interp
->result
= Tcl_UnixError (interp
);
448 * Return data in the requested format.
451 if (!STREQU (argv
[2], "stat")) {
452 Tcl_AppendResult (interp
, "expected item name of \"stat\" when ",
453 "using array name", (char *) NULL
);
456 return ReturnStatArray (interp
, filePtr
, &statBuf
, argv
[3]);
459 return ReturnStatItem (interp
, filePtr
, &statBuf
, argv
[2]);
461 ReturnStatList (interp
, filePtr
, &statBuf
);
467 *-----------------------------------------------------------------------------
471 * Implements the `lgets' Tcl command:
472 * lgets fileId [varName]
475 * A standard Tcl result.
478 * See the user documentation.
480 *-----------------------------------------------------------------------------
492 int bracesDepth
, inQuotes
, inChar
;
495 if ((argc
!= 2) && (argc
!= 3)) {
496 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0],
497 " fileId [varName]", (char *) NULL
);
500 if (TclGetOpenFile(interp
, argv
[1], &filePtr
) != TCL_OK
) {
503 if (!filePtr
->readable
) {
504 Tcl_AppendResult (interp
, "\"", argv
[1],
505 "\" wasn't opened for reading", (char *) NULL
);
509 Tcl_DynBufInit (&dynBuf
);
516 * Read in characters, keeping trace of if we are in the middle of a {}
517 * or "" part of the list.
521 if (dynBuf
.len
+ 1 == dynBuf
.size
)
522 Tcl_ExpandDynBuf (&dynBuf
, 0);
523 inChar
= getc (filePtr
->f
);
525 if (ferror (filePtr
->f
))
529 if (prevChar
!= '\\') {
535 if (bracesDepth
== 0)
540 if (bracesDepth
== 0)
541 inQuotes
= !inQuotes
;
546 if ((inChar
== '\n') && (bracesDepth
== 0) && !inQuotes
)
548 dynBuf
.ptr
[dynBuf
.len
++] = inChar
;
551 dynBuf
.ptr
[dynBuf
.len
] = '\0';
553 if ((bracesDepth
!= 0) || inQuotes
) {
554 Tcl_AppendResult (interp
, "miss-matched ",
555 (bracesDepth
!= 0) ? "braces" : "quote",
556 " in inputed list: ", dynBuf
.ptr
, (char *) NULL
);
561 Tcl_DynBufReturn (interp
, &dynBuf
);
563 if (Tcl_SetVar (interp
, argv
[2], dynBuf
.ptr
,
564 TCL_LEAVE_ERR_MSG
) == NULL
)
566 if (feof (filePtr
->f
) && (dynBuf
.len
== 0))
567 interp
->result
= "-1";
569 sprintf (interp
->result
, "%d", dynBuf
.len
);
570 Tcl_DynBufFree (&dynBuf
);
575 Tcl_ResetResult (interp
);
576 interp
->result
= Tcl_UnixError (interp
);
577 clearerr (filePtr
->f
);
581 Tcl_DynBufFree (&dynBuf
);
586 #ifndef TCL_NO_FILE_LOCKING
589 *-----------------------------------------------------------------------------
591 * ParseLockUnlockArgs --
593 * Parse the positional arguments common to both the flock and funlock
595 * ... handle [start] [length] [origin]
598 * o interp (I) - Pointer to the interpreter, errors returned in result.
599 * o argc (I) - Count of arguments supplied to the comment.
600 * o argv (I) - Commant argument vector.
601 * o argIdx (I) - Index of the first common agument to parse.
602 * o filePtrPtr (O) - Pointer to the open file structure returned here.
603 * o lockInfoPtr (O) - Fcntl info structure, start, length and whence
604 * are initialized by this routine.
606 * TCL_OK if all is OK, TCL_ERROR and an error message is result.
608 *-----------------------------------------------------------------------------
611 ParseLockUnlockArgs (Tcl_Interp
*interp
, int argc
, char **argv
, int argIdx
, OpenFile
**filePtrPtr
, struct flock
*lockInfoPtr
)
614 lockInfoPtr
->l_start
= 0;
615 lockInfoPtr
->l_len
= 0;
616 lockInfoPtr
->l_whence
= 0;
618 if (TclGetOpenFile (interp
, argv
[argIdx
], filePtrPtr
) != TCL_OK
)
622 if ((argIdx
< argc
) && (argv
[argIdx
][0] != '\0')) {
623 if (Tcl_GetLong (interp
, argv
[argIdx
],
624 &lockInfoPtr
->l_start
) != TCL_OK
)
629 if ((argIdx
< argc
) && (argv
[argIdx
][0] != '\0')) {
630 if (Tcl_GetLong (interp
, argv
[argIdx
], &lockInfoPtr
->l_len
) != TCL_OK
)
636 if (STREQU (argv
[argIdx
], "start"))
637 lockInfoPtr
->l_whence
= 0;
638 else if (STREQU (argv
[argIdx
], "current"))
639 lockInfoPtr
->l_whence
= 1;
640 else if (STREQU (argv
[argIdx
], "end"))
641 lockInfoPtr
->l_whence
= 2;
649 Tcl_AppendResult(interp
, "bad origin \"", argv
[argIdx
],
650 "\": should be \"start\", \"current\", or \"end\"",
657 *-----------------------------------------------------------------------------
661 * Implements the `flock' Tcl command:
662 * flock [-read|-write] [-nowait] handle [start] [length] [origin]
665 * A standard Tcl result.
667 *-----------------------------------------------------------------------------
678 int readLock
= FALSE
, writeLock
= FALSE
, noWaitLock
= FALSE
;
680 struct flock lockInfo
;
686 * Parse off the options.
689 for (argIdx
= 1; (argIdx
< argc
) && (argv
[argIdx
][0] == '-'); argIdx
++) {
690 if (STREQU (argv
[argIdx
], "-read")) {
694 if (STREQU (argv
[argIdx
], "-write")) {
698 if (STREQU (argv
[argIdx
], "-nowait")) {
705 if (readLock
&& writeLock
)
706 goto bothReadAndWrite
;
707 if (!(readLock
|| writeLock
))
711 * Make sure there are enough arguments left and then parse the
714 if ((argIdx
> argc
- 1) || (argIdx
< argc
- 4))
717 if (ParseLockUnlockArgs (interp
, argc
, argv
, argIdx
, &filePtr
,
718 &lockInfo
) != TCL_OK
)
721 if (readLock
&& !filePtr
->readable
)
723 if (writeLock
&& !filePtr
->writable
)
726 lockInfo
.l_type
= writeLock
? F_WRLCK
: F_RDLCK
;
728 stat
= fcntl (fileno (filePtr
->f
), noWaitLock
? F_SETLK
: F_SETLKW
,
730 if ((stat
< 0) && (errno
!= EACCES
)) {
731 interp
->result
= Tcl_UnixError (interp
);
736 interp
->result
= (stat
< 0) ? "0" : "1";
741 * Code to return error messages.
745 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0], " [-read|-write] ",
746 "[-nowait] handle [start] [length] [origin]",
751 * Invalid option found at argv [argIdx].
754 Tcl_AppendResult (interp
, "invalid option \"", argv
[argIdx
],
755 "\" expected one of \"-read\", \"-write\", or ",
756 "\"-nowait\"", (char *) NULL
);
760 interp
->result
= "can not specify both \"-read\" and \"-write\"";
764 interp
->result
= "file not open for reading";
768 interp
->result
= "file not open for writing";
773 *-----------------------------------------------------------------------------
777 * Implements the `funlock' Tcl command:
778 * funlock handle [start] [length] [origin]
781 * A standard Tcl result.
783 *-----------------------------------------------------------------------------
794 struct flock lockInfo
;
796 if ((argc
< 2) || (argc
> 5))
799 if (ParseLockUnlockArgs (interp
, argc
, argv
, 1, &filePtr
,
800 &lockInfo
) != TCL_OK
)
803 lockInfo
.l_type
= F_UNLCK
;
805 if (fcntl (fileno(filePtr
->f
), F_SETLK
, &lockInfo
) < 0) {
806 interp
->result
= Tcl_UnixError (interp
);
813 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0],
814 " handle [start] [length] [origin]", (char *) NULL
);
821 *-----------------------------------------------------------------------------
825 * Version of the command that always returns an error on systems that
826 * don't have file locking.
828 *-----------------------------------------------------------------------------
831 Tcl_FlockCmd (notUsed
, interp
, argc
, argv
)
837 interp
->result
= "File locking is not available on this system";
842 *-----------------------------------------------------------------------------
846 * Version of the command that always returns an error on systems that
847 * don't have file locking/
849 *-----------------------------------------------------------------------------
852 Tcl_FunlockCmd (notUsed
, interp
, argc
, argv
)
858 return Tcl_FlockCmd (notUsed
, interp
, argc
, argv
);