📄 tclunixchan.c
字号:
#endif /* USE_SGTTY */ ttyPtr->baud = baud; ttyPtr->parity = parity; ttyPtr->data = data; ttyPtr->stop = stop;}/* *--------------------------------------------------------------------------- * * TtySetAttributes -- * * Set the current attributes of the specified serial device. * * Results: * None. * * Side effects: * None. * *--------------------------------------------------------------------------- */static voidTtySetAttributes(fd, ttyPtr) int fd; /* Open file descriptor for serial port to * be modified. */ TtyAttrs *ttyPtr; /* Buffer containing new attributes for * serial port. */{ IOSTATE iostate;#ifdef USE_TERMIOS int parity, data, flag; GETIOSTATE(fd, &iostate); cfsetospeed(&iostate, TtyGetSpeed(ttyPtr->baud)); cfsetispeed(&iostate, TtyGetSpeed(ttyPtr->baud)); flag = 0; parity = ttyPtr->parity; if (parity != 'n') { flag |= PARENB;#ifdef PAREXT iostate.c_cflag &= ~PAREXT; if ((parity == 'm') || (parity == 's')) { flag |= PAREXT; }#endif /* PAREXT */ if ((parity == 'm') || (parity == 'o')) { flag |= PARODD; } } data = ttyPtr->data; flag |= (data == 5) ? CS5 : (data == 6) ? CS6 : (data == 7) ? CS7 : CS8; if (ttyPtr->stop == 2) { flag |= CSTOPB; } iostate.c_cflag &= ~(PARENB | PARODD | CSIZE | CSTOPB); iostate.c_cflag |= flag;#endif /* USE_TERMIOS */#ifdef USE_TERMIO int parity, data, flag; GETIOSTATE(fd, &iostate); iostate.c_cflag &= ~CBAUD; iostate.c_cflag |= TtyGetSpeed(ttyPtr->baud); flag = 0; parity = ttyPtr->parity; if (parity != 'n') { flag |= PARENB; if ((parity == 'm') || (parity == 's')) { flag |= PAREXT; } if ((parity == 'm') || (parity == 'o')) { flag |= PARODD; } } data = ttyPtr->data; flag |= (data == 5) ? CS5 : (data == 6) ? CS6 : (data == 7) ? CS7 : CS8; if (ttyPtr->stop == 2) { flag |= CSTOPB; } iostate.c_cflag &= ~(PARENB | PARODD | PAREXT | CSIZE | CSTOPB); iostate.c_cflag |= flag;#endif /* USE_TERMIO */#ifdef USE_SGTTY int parity; GETIOSTATE(fd, &iostate); iostate.sg_ospeed = TtyGetSpeed(ttyPtr->baud); iostate.sg_ispeed = TtyGetSpeed(ttyPtr->baud); parity = ttyPtr->parity; if (parity == 'e') { iostate.sg_flags &= ~ODDP; iostate.sg_flags |= EVENP; } else if (parity == 'o') { iostate.sg_flags &= ~EVENP; iostate.sg_flags |= ODDP; }#endif /* USE_SGTTY */ SETIOSTATE(fd, &iostate);}/* *--------------------------------------------------------------------------- * * TtyParseMode -- * * Parse the "-mode" argument to the fconfigure command. The argument * is of the form baud,parity,data,stop. * * Results: * The return value is TCL_OK if the argument was successfully * parsed, TCL_ERROR otherwise. If TCL_ERROR is returned, an * error message is left in the interp's result (if interp is non-NULL). * * Side effects: * None. * *--------------------------------------------------------------------------- */static intTtyParseMode(interp, mode, speedPtr, parityPtr, dataPtr, stopPtr) Tcl_Interp *interp; /* If non-NULL, interp for error return. */ CONST char *mode; /* Mode string to be parsed. */ int *speedPtr; /* Filled with baud rate from mode string. */ int *parityPtr; /* Filled with parity from mode string. */ int *dataPtr; /* Filled with data bits from mode string. */ int *stopPtr; /* Filled with stop bits from mode string. */{ int i, end; char parity; static char *bad = "bad value for -mode"; i = sscanf(mode, "%d,%c,%d,%d%n", speedPtr, &parity, dataPtr, stopPtr, &end); if ((i != 4) || (mode[end] != '\0')) { if (interp != NULL) { Tcl_AppendResult(interp, bad, ": should be baud,parity,data,stop", NULL); } return TCL_ERROR; } /* * Only allow setting mark/space parity on platforms that support it * Make sure to allow for the case where strchr is a macro. * [Bug: 5089] */ if (#if defined(PAREXT) || defined(USE_TERMIO) strchr("noems", parity) == NULL#else strchr("noe", parity) == NULL#endif /* PAREXT|USE_TERMIO */ ) { if (interp != NULL) { Tcl_AppendResult(interp, bad,#if defined(PAREXT) || defined(USE_TERMIO) " parity: should be n, o, e, m, or s",#else " parity: should be n, o, or e",#endif /* PAREXT|USE_TERMIO */ NULL); } return TCL_ERROR; } *parityPtr = parity; if ((*dataPtr < 5) || (*dataPtr > 8)) { if (interp != NULL) { Tcl_AppendResult(interp, bad, " data: should be 5, 6, 7, or 8", NULL); } return TCL_ERROR; } if ((*stopPtr < 0) || (*stopPtr > 2)) { if (interp != NULL) { Tcl_AppendResult(interp, bad, " stop: should be 1 or 2", NULL); } return TCL_ERROR; } return TCL_OK;}/* *--------------------------------------------------------------------------- * * TtyInit -- * * Given file descriptor that refers to a serial port, * initialize the serial port to a set of sane values so that * Tcl can talk to a device located on the serial port. * Note that no initialization happens if the initialize flag * is not set; this is necessary for the correct handling of * UNIX console TTYs at startup. * * Results: * A pointer to a FileState suitable for use with Tcl_CreateChannel * and the ttyChannelType structure. * * Side effects: * Serial device initialized to non-blocking raw mode, similar to * sockets (if initialize flag is non-zero.) All other modes can * be simulated on top of this in Tcl. * *--------------------------------------------------------------------------- */static FileState *TtyInit(fd, initialize) int fd; /* Open file descriptor for serial port to * be initialized. */ int initialize;{ TtyState *ttyPtr; ttyPtr = (TtyState *) ckalloc((unsigned) sizeof(TtyState)); GETIOSTATE(fd, &ttyPtr->savedState); ttyPtr->stateUpdated = 0; if (initialize) { IOSTATE iostate = ttyPtr->savedState;#if defined(USE_TERMIOS) || defined(USE_TERMIO) if (iostate.c_iflag != IGNBRK || iostate.c_oflag != 0 || iostate.c_lflag != 0 || iostate.c_cflag & CREAD || iostate.c_cc[VMIN] != 1 || iostate.c_cc[VTIME] != 0) { ttyPtr->stateUpdated = 1; } iostate.c_iflag = IGNBRK; iostate.c_oflag = 0; iostate.c_lflag = 0; iostate.c_cflag |= CREAD; iostate.c_cc[VMIN] = 1; iostate.c_cc[VTIME] = 0;#endif /* USE_TERMIOS|USE_TERMIO */#ifdef USE_SGTTY if ((iostate.sg_flags & (EVENP | ODDP)) || !(iostate.sg_flags & RAW)) { ttyPtr->stateUpdated = 1; } iostate.sg_flags &= (EVENP | ODDP); iostate.sg_flags |= RAW;#endif /* USE_SGTTY */ /* * Only update if we're changing anything to avoid possible * blocking. */ if (ttyPtr->stateUpdated) { SETIOSTATE(fd, &iostate); } } return &ttyPtr->fs;}#endif /* SUPPORTS_TTY *//* *---------------------------------------------------------------------- * * TclpOpenFileChannel -- * * Open an file based channel on Unix systems. * * Results: * The new channel or NULL. If NULL, the output argument * errorCodePtr is set to a POSIX error and an error message is * left in the interp's result if interp is not NULL. * * Side effects: * May open the channel and may cause creation of a file on the * file system. * *---------------------------------------------------------------------- */Tcl_ChannelTclpOpenFileChannel(interp, pathPtr, mode, permissions) Tcl_Interp *interp; /* Interpreter for error reporting; * can be NULL. */ Tcl_Obj *pathPtr; /* Name of file to open. */ int mode; /* POSIX open mode. */ int permissions; /* If the open involves creating a * file, with what modes to create * it? */{ int fd, channelPermissions; FileState *fsPtr; CONST char *native, *translation; char channelName[16 + TCL_INTEGER_SPACE]; Tcl_ChannelType *channelTypePtr;#ifdef SUPPORTS_TTY int ctl_tty;#endif /* SUPPORTS_TTY */#ifdef DEPRECATED ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);#endif /* DEPRECATED */ switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) { case O_RDONLY: channelPermissions = TCL_READABLE; break; case O_WRONLY: channelPermissions = TCL_WRITABLE; break; case O_RDWR: channelPermissions = (TCL_READABLE | TCL_WRITABLE); break; default: /* * This may occurr if modeString was "", for example. */ panic("TclpOpenFileChannel: invalid mode value"); return NULL; } native = Tcl_FSGetNativePath(pathPtr); if (native == NULL) { return NULL; } fd = TclOSopen(native, mode, permissions);#ifdef SUPPORTS_TTY ctl_tty = (strcmp (native, "/dev/tty") == 0);#endif /* SUPPORTS_TTY */ if (fd < 0) { if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "couldn't open \"", Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), (char *) NULL); } return NULL; } /* * Set close-on-exec flag on the fd so that child processes will not * inherit this fd. */ fcntl(fd, F_SETFD, FD_CLOEXEC); sprintf(channelName, "file%d", fd);#ifdef SUPPORTS_TTY if (!ctl_tty && isatty(fd)) { /* * Initialize the serial port to a set of sane parameters. * Especially important if the remote device is set to echo and * the serial port driver was also set to echo -- as soon as a char * were sent to the serial port, the remote device would echo it, * then the serial driver would echo it back to the device, etc. */ translation = "auto crlf"; channelTypePtr = &ttyChannelType; fsPtr = TtyInit(fd, 1); } else #endif /* SUPPORTS_TTY */ { translation = NULL; channelTypePtr = &fileChannelType; fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState)); }#ifdef DEPRECATED if (channelTypePtr == &fileChannelType) { fsPtr->nextPtr = tsdPtr->firstFilePtr; tsdPtr->firstFilePtr = fsPtr; }#endif /* DEPRECATED */ fsPtr->validMask = channelPermissions | TCL_EXCEPTION; fsPtr->fd = fd; fsPtr->channel = Tcl_CreateChannel(channelTypePtr, channelName, (ClientData) fsPtr, channelPermissions); if (translation != NULL) { /* * Gotcha. Most modems need a "\r" at the end of the command * sequence. If you just send "at\n", the modem will not respond * with "OK" because it never got a "\r" to actually invoke the * command. So, by default, newlines are translated to "\r\n" on * output to avoid "bug" reports that the serial port isn't working. */ if (Tcl_SetChannelOption(interp, fsPtr->channel, "-translation", translation) != TCL_OK) { Tcl_Close(NULL, fsPtr->channel); return NULL; } } return fsPtr->channel;}/* *---------------------------------------------------------------------- * * Tcl_MakeFileChannel -- * * Makes a Tcl_Channel from an existing OS level file handle. * * Results: * The Tcl_Channel created around the preexisting OS level file handle. * * Side effects: * None. * *---------------------------------------------------------------------- */Tcl_ChannelTcl_MakeFileChannel(handle, mode) ClientData handle; /* OS level handle. */ int mode; /* ORed combination of TCL_READABLE and * TCL_WRITABLE to indicate file mode. */{ FileState *fsPtr; char channelName[16 + TCL_INTEGER_SPACE]; int fd = (int) handle; Tcl_ChannelType *channelTypePtr;#ifdef DEPRECATED ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);#endif /* DEPRECATED */ int socketType = 0; socklen_t argLength = sizeof(int); if (mode == 0) { return NULL; } /* * Look to see if a channel with this fd and the same mode already exists. * If the fd is used, but the mode doesn't match, return NULL. */#ifdef DEPRECATED for (fsPtr = tsdPtr->firstFilePtr; fsPtr != NULL; fsPtr = fsPtr->nextPtr) { if (fsPtr->fd == fd) { return ((mode|TCL_EXCEPTION) == fsPtr->validMask) ? fsPtr->channel : NULL; } }#endif /* DEPRECATED */#ifdef SUPPORTS_TTY if (isatty(fd)) { fsPtr = TtyInit(fd, 0); channelTypePtr = &ttyChannelType; sprintf(channelName, "serial%d", fd); } else#endif /* SUPPORTS_TTY */ if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (VOID *)&socketType, &argLength) == 0 && socketType == SOCK_STREAM) { return MakeTcpClientChannelMode((ClientData) fd, mode); } else { channelTypePtr = &fileChannelType; fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState)); sprintf(channelName, "file%d", fd); }#ifdef DEPRECATED if (channelTypePtr == &fileChannelType) { fsPtr->nextPtr = tsdPtr->firstFilePtr; tsdPtr->firstFilePtr = fsPtr; }#endif /* DEPRECATED */ fsPtr->fd = fd;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -