📄 tclecosaz.c
字号:
/*
* tclUnixAZ.c --
*
* This file contains the top-level command procedures for
* commands in the Tcl core that require UNIX facilities
* such as files and process execution. Much of the code
* in this file is based on earlier versions contributed
* by Karl Lehenbauer, Mark Diekhans and Peter da Silva.
*
* Copyright 1991 Regents of the University of California
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that this copyright
* notice appears in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*
* $Id: tclunxaz.c,v 1.1.1.1 2001/04/29 20:35:40 karll Exp $
*/
#include "tclInt.h"
#include "tclEcos.h"
uid_t geteuid(void) {return 666;}
/*
* The variable below caches the name of the current working directory
* in order to avoid repeated calls to getwd. The string is malloc-ed.
* NULL means the cache needs to be refreshed.
*/
static char *currentDir = NULL;
/*
* Prototypes for local procedures defined in this file:
*/
#if TCL_FORK_ENABLED
static int CleanupChildren _ANSI_ARGS_((Tcl_Interp *interp,
int numPids, int *pidPtr, int errorId));
#endif
static char * GetFileType _ANSI_ARGS_((int mode));
static int StoreStatData _ANSI_ARGS_((Tcl_Interp *interp,
char *varName, struct stat *statPtr));
/*
*----------------------------------------------------------------------
*
* Tcl_CdCmd --
*
* This procedure is invoked to process the "cd" Tcl command.
* See the user documentation for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
int
Tcl_CdCmd(dummy, interp, argc, argv)
ClientData dummy; /* Not used. */
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
char *dirName;
if (argc > 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" dirName\"", (char *) NULL);
return TCL_ERROR;
}
if (argc == 2) {
dirName = argv[1];
} else {
dirName = "~";
}
dirName = Tcl_TildeSubst(interp, dirName);
if (dirName == NULL) {
return TCL_ERROR;
}
if (currentDir != NULL) {
ckfree(currentDir);
currentDir = NULL;
}
if (chdir(dirName) != 0) {
Tcl_AppendResult(interp, "couldn't change working directory to \"",
dirName, "\": ", Tcl_UnixError(interp), (char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Tcl_CloseCmd --
*
* This procedure is invoked to process the "close" Tcl command.
* See the user documentation for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
int
Tcl_CloseCmd(dummy, interp, argc, argv)
ClientData dummy; /* Not used. */
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
OpenFile *filePtr;
int result = TCL_OK;
if (argc != 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" fileId\"", (char *) NULL);
return TCL_ERROR;
}
if (TclGetOpenFile(interp, argv[1], &filePtr) != TCL_OK) {
return TCL_ERROR;
}
((Interp *) interp)->filePtrArray[fileno(filePtr->f)] = NULL;
/*
* First close the file (in the case of a process pipeline, there may
* be two files, one for the pipe at each end of the pipeline).
*/
if (filePtr->f2 != NULL) {
if (fclose(filePtr->f2) == EOF) {
Tcl_AppendResult(interp, "error closing \"", argv[1],
"\": ", Tcl_UnixError(interp), "\n", (char *) NULL);
result = TCL_ERROR;
}
}
if (fclose(filePtr->f) == EOF) {
Tcl_AppendResult(interp, "error closing \"", argv[1],
"\": ", Tcl_UnixError(interp), "\n", (char *) NULL);
result = TCL_ERROR;
}
/*
* If the file was a connection to a pipeline, clean up everything
* associated with the child processes.
*/
#if TCL_FORK_ENABLED
if (filePtr->numPids > 0) {
if (CleanupChildren(interp, filePtr->numPids, filePtr->pidPtr,
filePtr->errorId) != TCL_OK) {
result = TCL_ERROR;
}
}
#endif
ckfree((char *) filePtr);
return result;
}
/*
*----------------------------------------------------------------------
*
* Tcl_EofCmd --
*
* This procedure is invoked to process the "eof" Tcl command.
* See the user documentation for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
int
Tcl_EofCmd(notUsed, interp, argc, argv)
ClientData notUsed; /* Not used. */
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
OpenFile *filePtr;
if (argc != 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" fileId\"", (char *) NULL);
return TCL_ERROR;
}
if (TclGetOpenFile(interp, argv[1], &filePtr) != TCL_OK) {
return TCL_ERROR;
}
if (feof(filePtr->f)) {
interp->result = "1";
} else {
interp->result = "0";
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Tcl_ExecCmd --
*
* This procedure is invoked to process the "exec" Tcl command.
* See the user documentation for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
#if TCL_FORK_ENABLED
/* ARGSUSED */
int
Tcl_ExecCmd(dummy, interp, argc, argv)
ClientData dummy; /* Not used. */
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
int outputId; /* File id for output pipe. -1
* means command overrode. */
int errorId; /* File id for temporary file
* containing error output. */
int *pidPtr;
int numPids, result;
/*
* See if the command is to be run in background; if so, create
* the command, detach it, and return.
*/
if ((argv[argc-1][0] == '&') && (argv[argc-1][1] == 0)) {
argc--;
argv[argc] = NULL;
numPids = Tcl_CreatePipeline(interp, argc-1, argv+1, &pidPtr,
(int *) NULL, (int *) NULL, (int *) NULL);
if (numPids < 0) {
return TCL_ERROR;
}
Tcl_DetachPids(numPids, pidPtr);
ckfree((char *) pidPtr);
return TCL_OK;
}
/*
* Create the command's pipeline.
*/
numPids = Tcl_CreatePipeline(interp, argc-1, argv+1, &pidPtr,
(int *) NULL, &outputId, &errorId);
if (numPids < 0) {
return TCL_ERROR;
}
/*
* Read the child's output (if any) and put it into the result.
*/
result = TCL_OK;
if (outputId != -1) {
while (1) {
# define BUFFER_SIZE 1000
char buffer[BUFFER_SIZE+1];
int count;
count = read(outputId, buffer, BUFFER_SIZE);
if (count == 0) {
break;
}
if (count < 0) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp,
"error reading from output pipe: ",
Tcl_UnixError(interp), (char *) NULL);
result = TCL_ERROR;
break;
}
buffer[count] = 0;
Tcl_AppendResult(interp, buffer, (char *) NULL);
}
close(outputId);
}
if (CleanupChildren(interp, numPids, pidPtr, errorId) != TCL_OK) {
result = TCL_ERROR;
}
return result;
}
#endif
/*
*----------------------------------------------------------------------
*
* Tcl_ExitCmd --
*
* This procedure is invoked to process the "exit" Tcl command.
* See the user documentation for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
#if 0 // We have another exit command in Mobitex Tcl for eCos.
/* ARGSUSED */
int
Tcl_ExitCmd(dummy, interp, argc, argv)
ClientData dummy; /* Not used. */
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
int value;
if ((argc != 1) && (argc != 2)) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ?returnCode?\"", (char *) NULL);
return TCL_ERROR;
}
if (argc == 1) {
exit(0);
}
if (Tcl_GetInt(interp, argv[1], &value) != TCL_OK) {
return TCL_ERROR;
}
exit(value);
return TCL_OK; /* Better not ever reach this! */
}
#endif
/*
*----------------------------------------------------------------------
*
* Tcl_FileCmd --
*
* This procedure is invoked to process the "file" Tcl command.
* See the user documentation for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
int
Tcl_FileCmd(dummy, interp, argc, argv)
ClientData dummy; /* Not used. */
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
char *p;
int length, statOp;
int mode = 0; /* Initialized only to prevent
* compiler warning message. */
struct stat statBuf;
char *fileName, c;
if (argc < 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" option name ?arg ...?\"", (char *) NULL);
return TCL_ERROR;
}
c = argv[1][0];
length = strlen(argv[1]);
/*
* First handle operations on the file name.
*/
fileName = Tcl_TildeSubst(interp, argv[2]);
if (fileName == NULL) {
return TCL_ERROR;
}
if ((c == 'd') && (strncmp(argv[1], "dirname", length) == 0)) {
if (argc != 3) {
argv[1] = "dirname";
not3Args:
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ", argv[1], " name\"", (char *) NULL);
return TCL_ERROR;
}
p = strrchr(fileName, '/');
if (p == NULL) {
interp->result = ".";
} else if (p == fileName) {
interp->result = "/";
} else {
*p = 0;
Tcl_SetResult(interp, fileName, TCL_VOLATILE);
*p = '/';
}
return TCL_OK;
} else if ((c == 'r') && (strncmp(argv[1], "rootname", length) == 0)
&& (length >= 2)) {
char *lastSlash;
if (argc != 3) {
argv[1] = "rootname";
goto not3Args;
}
p = strrchr(fileName, '.');
lastSlash = strrchr(fileName, '/');
if ((p == NULL) || ((lastSlash != NULL) && (lastSlash > p))) {
Tcl_SetResult(interp, fileName, TCL_VOLATILE);
} else {
*p = 0;
Tcl_SetResult(interp, fileName, TCL_VOLATILE);
*p = '.';
}
return TCL_OK;
} else if ((c == 'e') && (strncmp(argv[1], "extension", length) == 0)
&& (length >= 3)) {
char *lastSlash;
if (argc != 3) {
argv[1] = "extension";
goto not3Args;
}
p = strrchr(fileName, '.');
lastSlash = strrchr(fileName, '/');
if ((p != NULL) && ((lastSlash == NULL) || (lastSlash < p))) {
Tcl_SetResult(interp, p, TCL_VOLATILE);
}
return TCL_OK;
} else if ((c == 't') && (strncmp(argv[1], "tail", length) == 0)
&& (length >= 2)) {
if (argc != 3) {
argv[1] = "tail";
goto not3Args;
}
p = strrchr(fileName, '/');
if (p != NULL) {
Tcl_SetResult(interp, p+1, TCL_VOLATILE);
} else {
Tcl_SetResult(interp, fileName, TCL_VOLATILE);
}
return TCL_OK;
}
/*
* Next, handle operations that can be satisfied with the "access"
* kernel call.
*/
if (fileName == NULL) {
return TCL_ERROR;
}
if ((c == 'r') && (strncmp(argv[1], "readable", length) == 0)
&& (length >= 5)) {
if (argc != 3) {
argv[1] = "readable";
goto not3Args;
}
mode = R_OK;
checkAccess:
if (access(fileName, mode) == -1) {
interp->result = "0";
} else {
interp->result = "1";
}
return TCL_OK;
} else if ((c == 'w') && (strncmp(argv[1], "writable", length) == 0)) {
if (argc != 3) {
argv[1] = "writable";
goto not3Args;
}
mode = W_OK;
goto checkAccess;
} else if ((c == 'e') && (strncmp(argv[1], "executable", length) == 0)
&& (length >= 3)) {
if (argc != 3) {
argv[1] = "executable";
goto not3Args;
}
mode = X_OK;
goto checkAccess;
} else if ((c == 'e') && (strncmp(argv[1], "exists", length) == 0)
&& (length >= 3)) {
if (argc != 3) {
argv[1] = "exists";
goto not3Args;
}
mode = F_OK;
goto checkAccess;
}
/*
* Lastly, check stuff that requires the file to be stat-ed.
*/
if ((c == 'a') && (strncmp(argv[1], "atime", length) == 0)) {
if (argc != 3) {
argv[1] = "atime";
goto not3Args;
}
if (stat(fileName, &statBuf) == -1) {
goto badStat;
}
sprintf(interp->result, "%ld", (long)statBuf.st_atime);
return TCL_OK;
} else if ((c == 'i') && (strncmp(argv[1], "isdirectory", length) == 0)
&& (length >= 3)) {
if (argc != 3) {
argv[1] = "isdirectory";
goto not3Args;
}
statOp = 2;
} else if ((c == 'i') && (strncmp(argv[1], "isfile", length) == 0)
&& (length >= 3)) {
if (argc != 3) {
argv[1] = "isfile";
goto not3Args;
}
statOp = 1;
} else if ((c == 'l') && (strncmp(argv[1], "lstat", length) == 0)) {
if (argc != 4) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" lstat name varName\"", (char *) NULL);
return TCL_ERROR;
}
if (lstat(fileName, &statBuf) == -1) {
Tcl_AppendResult(interp, "couldn't lstat \"", argv[2],
"\": ", Tcl_UnixError(interp), (char *) NULL);
return TCL_ERROR;
}
return StoreStatData(interp, argv[3], &statBuf);
} else if ((c == 'm') && (strncmp(argv[1], "mtime", length) == 0)) {
if (argc != 3) {
argv[1] = "mtime";
goto not3Args;
}
if (stat(fileName, &statBuf) == -1) {
goto badStat;
}
sprintf(interp->result, "%ld", (long)statBuf.st_mtime);
return TCL_OK;
} else if ((c == 'o') && (strncmp(argv[1], "owned", length) == 0)) {
if (argc != 3) {
argv[1] = "owned";
goto not3Args;
}
statOp = 0;
#ifdef S_IFLNK
/*
* This option is only included if symbolic links exist on this system
* (in which case S_IFLNK should be defined).
*/
} else if ((c == 'r') && (strncmp(argv[1], "readlink", length) == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -