]>
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 *-----------------------------------------------------------------------------
69 Tcl_PipeCmd (clientData
, interp
, argc
, argv
)
70 ClientData clientData
;
75 Interp
*iPtr
= (Interp
*) interp
;
79 if (!((argc
== 1) || (argc
== 3))) {
80 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0],
81 " [handle_var_r handle_var_w]", (char*) NULL
);
85 if (pipe (fileIds
) < 0) {
86 interp
->result
= Tcl_UnixError (interp
);
90 if (Tcl_SetupFileEntry (interp
, fileIds
[0], TRUE
, FALSE
) != TCL_OK
)
92 if (Tcl_SetupFileEntry (interp
, fileIds
[1], FALSE
, TRUE
) != TCL_OK
)
96 sprintf (interp
->result
, "file%d file%d", fileIds
[0], fileIds
[1]);
98 sprintf (fHandle
, "file%d", fileIds
[0]);
99 if (Tcl_SetVar (interp
, argv
[1], fHandle
, TCL_LEAVE_ERR_MSG
) == NULL
)
102 sprintf (fHandle
, "file%d", fileIds
[1]);
103 if (Tcl_SetVar (interp
, argv
[2], fHandle
, TCL_LEAVE_ERR_MSG
) == NULL
)
116 *-----------------------------------------------------------------------------
119 * Implements the copyfile TCL command:
120 * copyfile handle1 handle2 [lines]
123 * Nothing if it worked, else an error.
125 *-----------------------------------------------------------------------------
128 Tcl_CopyfileCmd (clientData
, interp
, argc
, argv
)
129 ClientData clientData
;
134 OpenFile
*fromFilePtr
, *toFilePtr
;
135 char transferBuffer
[2048];
139 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0],
140 " fromfilehandle tofilehandle", (char *) NULL
);
144 if (TclGetOpenFile (interp
, argv
[1], &fromFilePtr
) != TCL_OK
)
146 if (TclGetOpenFile (interp
, argv
[2], &toFilePtr
) != TCL_OK
)
149 if (!fromFilePtr
->readable
) {
150 interp
->result
= "Source file is not open for read access";
153 if (!toFilePtr
->writable
) {
154 interp
->result
= "Target file is not open for write access";
159 bytesRead
= fread (transferBuffer
, sizeof (char),
160 sizeof (transferBuffer
), fromFilePtr
->f
);
161 if (bytesRead
<= 0) {
162 if (feof (fromFilePtr
->f
))
167 if (fwrite (transferBuffer
, sizeof (char), bytesRead
, toFilePtr
->f
) !=
175 interp
->result
= Tcl_UnixError (interp
);
180 *-----------------------------------------------------------------------------
184 * Looks at stat mode and returns a text string indicating what type of
188 * o statBufPtr (I) - Pointer to a buffer initialized by stat or fstat.
190 * A pointer static text string representing the type of the file.
191 *-----------------------------------------------------------------------------
194 GetFileType (statBufPtr
)
195 struct stat
*statBufPtr
;
200 * Get a string representing the type of the file.
202 if (S_ISREG (statBufPtr
->st_mode
)) {
204 } else if (S_ISDIR (statBufPtr
->st_mode
)) {
205 typeStr
= "directory";
206 } else if (S_ISCHR (statBufPtr
->st_mode
)) {
207 typeStr
= "characterSpecial";
208 } else if (S_ISBLK (statBufPtr
->st_mode
)) {
209 typeStr
= "blockSpecial";
210 } else if (S_ISFIFO (statBufPtr
->st_mode
)) {
212 } else if (S_ISLNK (statBufPtr
->st_mode
)) {
214 } else if (S_ISSOCK (statBufPtr
->st_mode
)) {
224 *-----------------------------------------------------------------------------
228 * Return file stat infomation as a keyed list.
231 * o interp (I) - The list is returned in result.
232 * o filePtr (I) - Pointer to the Tcl open file structure.
233 * o statBufPtr (I) - Pointer to a buffer initialized by stat or fstat.
234 *-----------------------------------------------------------------------------
237 ReturnStatList (interp
, filePtr
, statBufPtr
)
240 struct stat
*statBufPtr
;
245 "{atime %d} {ctime %d} {dev %d} {gid %d} {ino %d} {mode %d} ",
246 statBufPtr
->st_atime
, statBufPtr
->st_ctime
, statBufPtr
->st_dev
,
247 statBufPtr
->st_gid
, statBufPtr
->st_ino
, statBufPtr
->st_mode
);
248 Tcl_AppendResult (interp
, statList
, (char *) NULL
);
251 "{mtime %d} {nlink %d} {size %d} {uid %d} {tty %d} {type %s}",
252 statBufPtr
->st_mtime
, statBufPtr
->st_nlink
, statBufPtr
->st_size
,
253 statBufPtr
->st_uid
, isatty (fileno (filePtr
->f
)),
254 GetFileType (statBufPtr
));
255 Tcl_AppendResult (interp
, statList
, (char *) NULL
);
260 *-----------------------------------------------------------------------------
264 * Return file stat infomation in an array.
267 * o interp (I) - Current interpreter, error return in result.
268 * o filePtr (I) - Pointer to the Tcl open file structure.
269 * o statBufPtr (I) - Pointer to a buffer initialized by stat or fstat.
270 * o arrayName (I) - The name of the array to return the info in.
272 * TCL_OK or TCL_ERROR.
273 *-----------------------------------------------------------------------------
276 ReturnStatArray (interp
, filePtr
, statBufPtr
, arrayName
)
279 struct stat
*statBufPtr
;
284 sprintf (numBuf
, "%d", statBufPtr
->st_dev
);
285 if (Tcl_SetVar2 (interp
, arrayName
, "dev", numBuf
,
286 TCL_LEAVE_ERR_MSG
) == NULL
)
289 sprintf (numBuf
, "%d", statBufPtr
->st_ino
);
290 if (Tcl_SetVar2 (interp
, arrayName
, "ino", numBuf
,
291 TCL_LEAVE_ERR_MSG
) == NULL
)
294 sprintf (numBuf
, "%d", statBufPtr
->st_mode
);
295 if (Tcl_SetVar2 (interp
, arrayName
, "mode", numBuf
,
296 TCL_LEAVE_ERR_MSG
) == NULL
)
299 sprintf (numBuf
, "%d", statBufPtr
->st_nlink
);
300 if (Tcl_SetVar2 (interp
, arrayName
, "nlink", numBuf
,
301 TCL_LEAVE_ERR_MSG
) == NULL
)
304 sprintf (numBuf
, "%d", statBufPtr
->st_uid
);
305 if (Tcl_SetVar2 (interp
, arrayName
, "uid", numBuf
,
306 TCL_LEAVE_ERR_MSG
) == NULL
)
309 sprintf (numBuf
, "%d", statBufPtr
->st_gid
);
310 if (Tcl_SetVar2 (interp
, arrayName
, "gid", numBuf
,
311 TCL_LEAVE_ERR_MSG
) == NULL
)
314 sprintf (numBuf
, "%d", statBufPtr
->st_size
);
315 if (Tcl_SetVar2 (interp
, arrayName
, "size", numBuf
,
316 TCL_LEAVE_ERR_MSG
) == NULL
)
319 sprintf (numBuf
, "%d", statBufPtr
->st_atime
);
320 if (Tcl_SetVar2 (interp
, arrayName
, "atime", numBuf
,
321 TCL_LEAVE_ERR_MSG
) == NULL
)
324 sprintf (numBuf
, "%d", statBufPtr
->st_mtime
);
325 if (Tcl_SetVar2 (interp
, arrayName
, "mtime", numBuf
,
326 TCL_LEAVE_ERR_MSG
) == NULL
)
329 sprintf (numBuf
, "%d", statBufPtr
->st_ctime
);
330 if (Tcl_SetVar2 (interp
, arrayName
, "ctime", numBuf
,
331 TCL_LEAVE_ERR_MSG
) == NULL
)
334 if (Tcl_SetVar2 (interp
, arrayName
, "tty",
335 isatty (fileno (filePtr
->f
)) ? "1" : "0",
336 TCL_LEAVE_ERR_MSG
) == NULL
)
339 if (Tcl_SetVar2 (interp
, arrayName
, "type", GetFileType (statBufPtr
),
340 TCL_LEAVE_ERR_MSG
) == NULL
)
348 *-----------------------------------------------------------------------------
352 * Return a single file status item.
355 * o interp (I) - Item or error returned in result.
356 * o filePtr (I) - Pointer to the Tcl open file structure.
357 * o statBufPtr (I) - Pointer to a buffer initialized by stat or fstat.
358 * o itemName (I) - The name of the desired item.
360 * TCL_OK or TCL_ERROR.
361 *-----------------------------------------------------------------------------
364 ReturnStatItem (interp
, filePtr
, statBufPtr
, itemName
)
367 struct stat
*statBufPtr
;
370 if (STREQU (itemName
, "dev"))
371 sprintf (interp
->result
, "%d", statBufPtr
->st_dev
);
372 else if (STREQU (itemName
, "ino"))
373 sprintf (interp
->result
, "%d", statBufPtr
->st_ino
);
374 else if (STREQU (itemName
, "mode"))
375 sprintf (interp
->result
, "%d", statBufPtr
->st_mode
);
376 else if (STREQU (itemName
, "nlink"))
377 sprintf (interp
->result
, "%d", statBufPtr
->st_nlink
);
378 else if (STREQU (itemName
, "uid"))
379 sprintf (interp
->result
, "%d", statBufPtr
->st_uid
);
380 else if (STREQU (itemName
, "gid"))
381 sprintf (interp
->result
, "%d", statBufPtr
->st_gid
);
382 else if (STREQU (itemName
, "size"))
383 sprintf (interp
->result
, "%d", statBufPtr
->st_size
);
384 else if (STREQU (itemName
, "atime"))
385 sprintf (interp
->result
, "%d", statBufPtr
->st_atime
);
386 else if (STREQU (itemName
, "mtime"))
387 sprintf (interp
->result
, "%d", statBufPtr
->st_mtime
);
388 else if (STREQU (itemName
, "ctime"))
389 sprintf (interp
->result
, "%d", statBufPtr
->st_ctime
);
390 else if (STREQU (itemName
, "type"))
391 interp
->result
= GetFileType (statBufPtr
);
392 else if (STREQU (itemName
, "tty"))
393 interp
->result
= isatty (fileno (filePtr
->f
)) ? "1" : "0";
395 Tcl_AppendResult (interp
, "Got \"", itemName
, "\", expected one of ",
396 "\"atime\", \"ctime\", \"dev\", \"gid\", \"ino\", ",
397 "\"mode\", \"mtime\", \"nlink\", \"size\", ",
398 "\"tty\", \"type\", \"uid\"", (char *) NULL
);
408 *-----------------------------------------------------------------------------
411 * Implements the fstat TCL command:
412 * fstat handle [item]|[stat arrayvar]
414 *-----------------------------------------------------------------------------
417 Tcl_FstatCmd (clientData
, interp
, argc
, argv
)
418 ClientData clientData
;
426 if ((argc
< 2) || (argc
> 4)) {
427 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0],
428 " handle [item]|[stat arrayVar]", (char *) NULL
);
432 if (TclGetOpenFile (interp
, argv
[1], &filePtr
) != TCL_OK
)
435 if (fstat (fileno (filePtr
->f
), &statBuf
)) {
436 interp
->result
= Tcl_UnixError (interp
);
441 * Return data in the requested format.
444 if (!STREQU (argv
[2], "stat")) {
445 Tcl_AppendResult (interp
, "expected item name of \"stat\" when ",
446 "using array name", (char *) NULL
);
449 return ReturnStatArray (interp
, filePtr
, &statBuf
, argv
[3]);
452 return ReturnStatItem (interp
, filePtr
, &statBuf
, argv
[2]);
454 ReturnStatList (interp
, filePtr
, &statBuf
);
460 *-----------------------------------------------------------------------------
464 * Implements the `lgets' Tcl command:
465 * lgets fileId [varName]
468 * A standard Tcl result.
471 * See the user documentation.
473 *-----------------------------------------------------------------------------
476 Tcl_LgetsCmd (notUsed
, interp
, argc
, argv
)
484 int bracesDepth
, inQuotes
, inChar
;
487 if ((argc
!= 2) && (argc
!= 3)) {
488 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0],
489 " fileId [varName]", (char *) NULL
);
492 if (TclGetOpenFile(interp
, argv
[1], &filePtr
) != TCL_OK
) {
495 if (!filePtr
->readable
) {
496 Tcl_AppendResult (interp
, "\"", argv
[1],
497 "\" wasn't opened for reading", (char *) NULL
);
501 Tcl_DynBufInit (&dynBuf
);
508 * Read in characters, keeping trace of if we are in the middle of a {}
509 * or "" part of the list.
513 if (dynBuf
.len
+ 1 == dynBuf
.size
)
514 Tcl_ExpandDynBuf (&dynBuf
, 0);
515 inChar
= getc (filePtr
->f
);
517 if (ferror (filePtr
->f
))
521 if (prevChar
!= '\\') {
527 if (bracesDepth
== 0)
532 if (bracesDepth
== 0)
533 inQuotes
= !inQuotes
;
538 if ((inChar
== '\n') && (bracesDepth
== 0) && !inQuotes
)
540 dynBuf
.ptr
[dynBuf
.len
++] = inChar
;
543 dynBuf
.ptr
[dynBuf
.len
] = '\0';
545 if ((bracesDepth
!= 0) || inQuotes
) {
546 Tcl_AppendResult (interp
, "miss-matched ",
547 (bracesDepth
!= 0) ? "braces" : "quote",
548 " in inputed list: ", dynBuf
.ptr
, (char *) NULL
);
553 Tcl_DynBufReturn (interp
, &dynBuf
);
555 if (Tcl_SetVar (interp
, argv
[2], dynBuf
.ptr
,
556 TCL_LEAVE_ERR_MSG
) == NULL
)
558 if (feof (filePtr
->f
) && (dynBuf
.len
== 0))
559 interp
->result
= "-1";
561 sprintf (interp
->result
, "%d", dynBuf
.len
);
562 Tcl_DynBufFree (&dynBuf
);
567 Tcl_ResetResult (interp
);
568 interp
->result
= Tcl_UnixError (interp
);
569 clearerr (filePtr
->f
);
573 Tcl_DynBufFree (&dynBuf
);
578 #ifndef TCL_NO_FILE_LOCKING
581 *-----------------------------------------------------------------------------
583 * ParseLockUnlockArgs --
585 * Parse the positional arguments common to both the flock and funlock
587 * ... handle [start] [length] [origin]
590 * o interp (I) - Pointer to the interpreter, errors returned in result.
591 * o argc (I) - Count of arguments supplied to the comment.
592 * o argv (I) - Commant argument vector.
593 * o argIdx (I) - Index of the first common agument to parse.
594 * o filePtrPtr (O) - Pointer to the open file structure returned here.
595 * o lockInfoPtr (O) - Fcntl info structure, start, length and whence
596 * are initialized by this routine.
598 * TCL_OK if all is OK, TCL_ERROR and an error message is result.
600 *-----------------------------------------------------------------------------
603 ParseLockUnlockArgs (interp
, argc
, argv
, argIdx
, filePtrPtr
, lockInfoPtr
)
608 OpenFile
**filePtrPtr
;
609 struct flock
*lockInfoPtr
;
612 lockInfoPtr
->l_start
= 0;
613 lockInfoPtr
->l_len
= 0;
614 lockInfoPtr
->l_whence
= 0;
616 if (TclGetOpenFile (interp
, argv
[argIdx
], filePtrPtr
) != TCL_OK
)
620 if ((argIdx
< argc
) && (argv
[argIdx
][0] != '\0')) {
621 if (Tcl_GetLong (interp
, argv
[argIdx
],
622 &lockInfoPtr
->l_start
) != TCL_OK
)
627 if ((argIdx
< argc
) && (argv
[argIdx
][0] != '\0')) {
628 if (Tcl_GetLong (interp
, argv
[argIdx
], &lockInfoPtr
->l_len
) != TCL_OK
)
634 if (STREQU (argv
[argIdx
], "start"))
635 lockInfoPtr
->l_whence
= 0;
636 else if (STREQU (argv
[argIdx
], "current"))
637 lockInfoPtr
->l_whence
= 1;
638 else if (STREQU (argv
[argIdx
], "end"))
639 lockInfoPtr
->l_whence
= 2;
647 Tcl_AppendResult(interp
, "bad origin \"", argv
[argIdx
],
648 "\": should be \"start\", \"current\", or \"end\"",
655 *-----------------------------------------------------------------------------
659 * Implements the `flock' Tcl command:
660 * flock [-read|-write] [-nowait] handle [start] [length] [origin]
663 * A standard Tcl result.
665 *-----------------------------------------------------------------------------
668 Tcl_FlockCmd (notUsed
, interp
, argc
, argv
)
675 int readLock
= FALSE
, writeLock
= FALSE
, noWaitLock
= FALSE
;
677 struct flock lockInfo
;
683 * Parse off the options.
686 for (argIdx
= 1; (argIdx
< argc
) && (argv
[argIdx
][0] == '-'); argIdx
++) {
687 if (STREQU (argv
[argIdx
], "-read")) {
691 if (STREQU (argv
[argIdx
], "-write")) {
695 if (STREQU (argv
[argIdx
], "-nowait")) {
702 if (readLock
&& writeLock
)
703 goto bothReadAndWrite
;
704 if (!(readLock
|| writeLock
))
708 * Make sure there are enough arguments left and then parse the
711 if ((argIdx
> argc
- 1) || (argIdx
< argc
- 4))
714 if (ParseLockUnlockArgs (interp
, argc
, argv
, argIdx
, &filePtr
,
715 &lockInfo
) != TCL_OK
)
718 if (readLock
&& !filePtr
->readable
)
720 if (writeLock
&& !filePtr
->writable
)
723 lockInfo
.l_type
= writeLock
? F_WRLCK
: F_RDLCK
;
725 stat
= fcntl (fileno (filePtr
->f
), noWaitLock
? F_SETLK
: F_SETLKW
,
727 if ((stat
< 0) && (errno
!= EACCES
)) {
728 interp
->result
= Tcl_UnixError (interp
);
733 interp
->result
= (stat
< 0) ? "0" : "1";
738 * Code to return error messages.
742 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0], " [-read|-write] ",
743 "[-nowait] handle [start] [length] [origin]",
748 * Invalid option found at argv [argIdx].
751 Tcl_AppendResult (interp
, "invalid option \"", argv
[argIdx
],
752 "\" expected one of \"-read\", \"-write\", or ",
753 "\"-nowait\"", (char *) NULL
);
757 interp
->result
= "can not specify both \"-read\" and \"-write\"";
761 interp
->result
= "file not open for reading";
765 interp
->result
= "file not open for writing";
770 *-----------------------------------------------------------------------------
774 * Implements the `funlock' Tcl command:
775 * funlock handle [start] [length] [origin]
778 * A standard Tcl result.
780 *-----------------------------------------------------------------------------
783 Tcl_FunlockCmd (notUsed
, interp
, argc
, argv
)
790 struct flock lockInfo
;
792 if ((argc
< 2) || (argc
> 5))
795 if (ParseLockUnlockArgs (interp
, argc
, argv
, 1, &filePtr
,
796 &lockInfo
) != TCL_OK
)
799 lockInfo
.l_type
= F_UNLCK
;
801 if (fcntl (fileno(filePtr
->f
), F_SETLK
, &lockInfo
) < 0) {
802 interp
->result
= Tcl_UnixError (interp
);
809 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0],
810 " handle [start] [length] [origin]", (char *) NULL
);
817 *-----------------------------------------------------------------------------
821 * Version of the command that always returns an error on systems that
822 * don't have file locking.
824 *-----------------------------------------------------------------------------
827 Tcl_FlockCmd (notUsed
, interp
, argc
, argv
)
833 interp
->result
= "File locking is not available on this system";
838 *-----------------------------------------------------------------------------
842 * Version of the command that always returns an error on systems that
843 * don't have file locking/
845 *-----------------------------------------------------------------------------
848 Tcl_FunlockCmd (notUsed
, interp
, argc
, argv
)
854 return Tcl_FlockCmd (notUsed
, interp
, argc
, argv
);