]>
git.zerfleddert.de Git - micropolis/blob - src/tclx/src/tclxdup.c
4 * Extended Tcl dup command.
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: tclXdup.c,v 2.0 1992/10/16 04:50:36 markd Rel $
16 *-----------------------------------------------------------------------------
22 * Prototypes of internal functions.
25 DoNormalDup
_ANSI_ARGS_((Tcl_Interp
*interp
,
26 OpenFile
*oldFilePtr
));
29 DoSpecialDup
_ANSI_ARGS_((Tcl_Interp
*interp
,
31 char *newHandleName
));
35 *-----------------------------------------------------------------------------
38 * Process a normal dup command (i.e. the new file is not specified).
41 * o interp (I) - If an error occures, the error message is in result,
42 * otherwise the file handle is in result.
43 * o oldFilePtr (I) - Tcl file control block for the file to dup.
45 * A pointer to the open file structure for the new file, or NULL if an
47 *-----------------------------------------------------------------------------
50 DoNormalDup (interp
, oldFilePtr
)
54 Interp
*iPtr
= (Interp
*) interp
;
59 newFileId
= dup (fileno (oldFilePtr
->f
));
63 if (Tcl_SetupFileEntry (interp
, newFileId
,
65 oldFilePtr
->writable
) != TCL_OK
)
68 sprintf (interp
->result
, "file%d", newFileId
);
69 return iPtr
->filePtrArray
[newFileId
];
72 interp
->result
= Tcl_UnixError (interp
);
77 *-----------------------------------------------------------------------------
80 * Process a special dup command. This is the case were the file is
81 * dup-ed to stdin, stdout or stderr. The new file may or be open or
84 * o interp (I) - If an error occures, the error message is in result,
85 * otherwise nothing is returned.
86 * o oldFilePtr (I) - Tcl file control block for the file to dup.
87 * o newFileHandle (I) - The handle name for the new file.
89 * A pointer to the open file structure for the new file, or NULL if an
91 *-----------------------------------------------------------------------------
94 DoSpecialDup (interp
, oldFilePtr
, newHandleName
)
99 Interp
*iPtr
= (Interp
*) interp
;
102 OpenFile
*newFilePtr
;
105 * Duplicate the old file to the specified file id.
107 newFileId
= Tcl_ConvertFileHandle (interp
, newHandleName
);
111 Tcl_AppendResult (interp
, "target handle must be one of stdin, ",
112 "stdout, stderr, file0, file1, or file2: got \"",
113 newHandleName
, "\"", (char *) NULL
);
118 newFileCbPtr
= stdin
;
121 newFileCbPtr
= stdout
;
124 newFileCbPtr
= stderr
;
129 * If the specified id is not open, set up a stdio file descriptor.
131 TclMakeFileTable (iPtr
, newFileId
);
132 if (iPtr
->filePtrArray
[newFileId
] == NULL
) {
136 * Set up a stdio FILE control block for the new file.
138 if (oldFilePtr
->readable
&& oldFilePtr
->writable
) {
140 } else if (oldFilePtr
->writable
) {
145 if (freopen ("/dev/null", mode
, newFileCbPtr
) == NULL
)
150 * This functionallity may be obtained with dup2 on most systems. Being
155 if (fcntl (fileno (oldFilePtr
->f
), F_DUPFD
, newFileId
) < 0)
159 * Set up a Tcl OpenFile structure for the new file handle.
161 newFilePtr
= iPtr
->filePtrArray
[fileno (newFileCbPtr
)];
162 if (newFilePtr
== NULL
) {
163 newFilePtr
= (OpenFile
*) ckalloc (sizeof (OpenFile
));
164 iPtr
->filePtrArray
[fileno (newFileCbPtr
)] = newFilePtr
;
166 newFilePtr
->f
= newFileCbPtr
;
167 newFilePtr
->f2
= NULL
;
168 newFilePtr
->readable
= oldFilePtr
->readable
;
169 newFilePtr
->writable
= oldFilePtr
->writable
;
170 newFilePtr
->numPids
= 0;
171 newFilePtr
->pidPtr
= NULL
;
172 newFilePtr
->errorId
= -1;
177 iPtr
->result
= Tcl_UnixError (interp
);
182 *-----------------------------------------------------------------------------
185 * Implements the dup TCL command:
186 * dup filehandle [stdhandle]
189 * Returns TCL_OK and interp->result containing a filehandle
190 * if the requested file or pipe was successfully duplicated.
192 * Return TCL_ERROR and interp->result containing an
193 * explanation of what went wrong if an error occured.
196 * Locates and creates an entry in the handles table
198 *-----------------------------------------------------------------------------
201 Tcl_DupCmd (clientData
, interp
, argc
, argv
)
202 ClientData clientData
;
207 OpenFile
*oldFilePtr
, *newFilePtr
;
208 long seekOffset
= -1;
210 if ((argc
< 2) || (argc
> 3)) {
211 Tcl_AppendResult (interp
, tclXWrongArgs
, argv
[0],
212 " filehandle [stdhandle]", (char *) NULL
);
216 if (TclGetOpenFile(interp
, argv
[1], &oldFilePtr
) != TCL_OK
)
218 if (oldFilePtr
->numPids
> 0) { /*??????*/
219 Tcl_AppendResult (interp
, "can not `dup' a pipeline", (char *) NULL
);
224 * If writable, flush out the buffer. If readable, remember were we are
225 * so the we can set it up for the next stdio read to come from the same
226 * place. The location is only recorded if the file is a reqular file,
227 * since you cann't seek on other types of files.
229 if (oldFilePtr
->writable
) {
230 if (fflush (oldFilePtr
->f
) != 0)
233 if (oldFilePtr
->readable
) {
236 if (fstat (fileno (oldFilePtr
->f
), &statBuf
) < 0)
238 if ((statBuf
.st_mode
& S_IFMT
) == S_IFREG
) {
239 seekOffset
= ftell (oldFilePtr
->f
);
246 * Process the dup depending on if dup-ing to a new file or a target
250 newFilePtr
= DoNormalDup (interp
, oldFilePtr
);
252 newFilePtr
= DoSpecialDup (interp
, oldFilePtr
, argv
[2]);
254 if (newFilePtr
== NULL
)
257 if (seekOffset
>= 0) {
258 if (fseek (newFilePtr
->f
, seekOffset
, SEEK_SET
) != 0)
264 Tcl_ResetResult (interp
);
265 interp
->result
= Tcl_UnixError (interp
);