历史沿袭至今,在大多数UNIX系统中,控制终端的名字是/dev/tty. POSIX.1提供了一个运行时函数,可被用来确定控制终端的名字。

#include <stdio.h>

char *ctermid(char *ptr);

返回值:若成功则返回指向控制终端名的指针,若出错则返回指向空字符串的指针

如果ptr非空,则它被认为是一个指针,指向长度至少为L_ctermid字节的数组,进程的控制终端名存放在该数组中。常量L_ctermid定义在<stdio.h>中。若ptr是一个空指针,则该函数为数组(通常作为静态变量)分配空间。同样,进程的控制终端名存放在该数组中。

在这两种情况中,该数组的起始地址被作为函数值返回。因为大多数UNIX系统都使用/dev/tty作为控制终端名,所以此函数的主要作用是帮助提高向其他操作系统的可移植性。

实例:ctermid函数

程序清单18-3 POSIX.1 ctermid函数的实现

#include <stdio.h>

#include <string.h>

static char ctermid_name[L_ctermid];

char *

ctermid(char *str)

{

if(str == NULL)

str = ctermid_name;

return(strcpy(str, "/dev/tty"));    /* strcpy() returns str */

}

注意,因为我们无法确定调用者缓冲区的大小,所以也就不能防止过度使用该缓冲区。

另外两个与终端标识有关的函数是isatty和ttyname。前者在文件描述符引用一个终端设备时返回真,而后者则返回在该文件描述符上打开的终端设备的路径名。

#include <unisd.h>

int isatty(int filedes);

返回值:若为终端设备则返回1(真),反则返回0(假)

char *ttyname(int filedes);

返回值:指向终端路径名的指针,若出错则返回NULL

实例:isatty函数

程序清单18-4 POSIX.1 isatty函数的实现

#include <termios.h>

int

isatty(int fd)

{

struct termios    ts;

return(tcgetattr(fd, &ts) != -1);    /* true if no error (is a tty) */

}

程序清单18-5测试isatty函数

#include "apue.h"

int

main(void)

{

printf("fd 0: %s\n", isatty(0) ? "tty" : "not a tty");

printf("fd 1: %s\n", isatty(1) ? "tty" : "not a tty");

printf("fd 2: %s\n", isatty(2) ? "tty" : "not a tty");

exit(0);

}

运行程序清单18-5中的程序时,我们可以得到下面的结果:

实例:ttyname函数

程序清单18-6 POSIX.1 ttyname函数的实现

#include <sys/stat.h>

#include <dirent.h>

#include <limits.h>

#include <string.h>

#include <termios.h>

#include <unistd.h>

#include <stdlib.h>

struct devdir {

struct devdir    *d_next;

char        *d_name;

};

static struct devdir    *head;

static struct devdir    *tail;

static char        pathname[_POSIX_PATH_MAX + 1];

static void

add(char *dirname)

{

struct devdir    *ddp;

int        len;

len = strlen(dirname);

/*

* Skip ., .., and /dev/fd.

*/

if((dirname[len - 1] == '.') && (dirname[len - 2] == '/' ||

(dirname[len - 2] == '.' && dirname[len-3] == '/')))

return;

if(strcmp(dirname, "dev/fd") == 0)

return;

ddp = malloc(sizeof(struct devdir));

if(ddp == NULL)

return;

ddp->d_name = strdup(dirname);

if(ddp->d_name == NULL)

{

free(ddp);

return;

}

ddp->d_next = NULL;

if(tail == NULL)

{

head = ddp;

tail = ddp;

}

else

{

tail->d_next = ddp;

tail = ddp;

}

}

static void

cleanup(void)

{

struct devdir    *ddp, *nddp;

ddp = head;

while(ddp != NULL)

{

nddp = ddp->d_next;

free(ddp->d_name);

free(ddp);

ddp = nddp;

}

head = NULL;

tail = NULL;

}

static char *

searchdir(char *dirname, struct stat *fdstatp)

{

struct stat    devstat;

DIR        *dp;

int        devlen;

struct dirent    *dirp;

strcpy(pathname, dirname);

if((dp = opendir(dirname)) == NULL)

return(NULL);

strcat(pathname, "/");

devlen = strlen(pathname);

while((dirp = readdir(dp)) != NULL)

{

strncpy(pathname + devlen, dirp->d_name,

_POSIX_PATH_MAX - devlen);

/*

* Skip aliases.

*/

if(strcmp(pathname, "/dev/stdin") == 0 ||

strcmp(pathname, "/dev/stdout") == 0 ||

strcmp(pathname, "/dev/stderr") == 0)

continue;

if(stat(pathname, &devstat) < 0)

continue;

if(S_ISDIR(devstat.st_mode))

{

add(pathname);

continue;

}

if(devstat.st_ino == fdstatp->st_ino &&

devstat.st_dev == fdstatp->st_dev)    /* found a match */

{

closedir(dp);

return(pathname);

}

}

closedir(dp);

return(NULL);

}

char *

ttyname(int fd)

{

struct stat    fdstat;

struct devdir    *ddp;

char        *rval;

if(isatty(fd) == 0)

return(NULL);

if(fstat(fd, &fdstat) < 0)

return(NULL);

if(S_ISCHR(fdstat.st_mode) == 0)

return(NULL);

rval = searchdir("/dev", &fdstat);

if(rval == NULL)

{

for(ddp = head; ddp != NULL; ddp = ddp->d_next)

if((rval = searchdir(ddp->d_name, &fdstat)) != NULL)

break;

}

cleanup();

return(rval);

}

此处用到的方法是读/dev目录,寻找具有相同设备号和i节点编号的表项。每个文件系统有一个唯一的设备号(stat结构中的st_dev字段http://www.cnblogs.com/nufangrensheng/p/3501385.html),文件系统中的每个目录项有一个唯一的i节点号(stat结构中的st_ino字段)。在此函数中假定当找到一个匹配的设备号和匹配的i节点号时,就找到了所希望的目录项。

我们的终端名可能在/dev的子目录中。于是,需要搜索在/dev之下的整个文件系统子树。我们跳过了很多产生不正确或奇怪结果的目录,它们是/dev/.,/dev/..和/dev/fd。我么也跳过了一些别名,即/dev/stdin、/dev/stdout以及/dev/stderr,它们是对在/dev/fd目录中文件的符号链接。

程序清单18-7 测试ttyname函数

#include "apue.h"

int

main(void)

{

char *name;

if(isatty(0))

{

name = ttyname(0);

if(name == NULL)

name = "undefined";

}

else

{

name = "not a tty";

}

printf("fd 0: %s\n", name);

if(isatty(1))

{

name = ttyname(1);

if(name == NULL)

name = "undefined";

}

else

{

name = "not a tty";

}

printf("fd 1: %s\n", name);

if(isatty(2))

{

name = ttyname(2);

if(name == NULL)

name = "undefined";

}

else

{

name = "not a tty";

}

printf("fd 2: %s\n", name);

exit(0);

}

运行该程序得到:

文件描述符0、1和2都指向了同一终端/dev/tty1.

终端I/O之终端标识相关推荐

  1. ubuntu xfce下面两个终端合并为一个终端

    我们现在想把两个终端合并为一个终端,以便于管理 方法如下: ①左侧终端新开一个tab,如下: ②经过上述操作原来的终端就也变成tab了 我们不理会新开的"空白tab",鼠标拖动ta ...

  2. python打开伪终端_0xB:伪终端

    ##伪终端 这一章,我们来讲讲如何使用python做一个伪终端.不过在这之前你需要先了解一点伪终端的意思,还有一些技巧.这个我们会在下面讲到: 伪终端其实就是命令终端(cmd.exe,/bin/sh) ...

  3. DSM-830源网荷系统控制终端(源网荷智能互动终端)-新型电力负荷控制终端(电力负荷管理终端装置)-互动式需求侧管理终端-专变采集终端的功能。DSM-830交互式需求侧管理终端(需求侧管理互动式终端

    DSM-830源网荷系统控制终端(源网荷智能互动终端)-新型电力负荷控制终端(电力负荷管理终端装置)-互动式需求侧管理终端-专变采集终端的功能.DSM-830交互式需求侧管理终端(需求侧管理互动式终端 ...

  4. 北斗终端,北斗短报文终端,北斗指挥机,北斗终端,北斗通信卡的区分和定义

    北斗终端普通人基本都认为是用北斗卫星来定位的一种设备,爱陆通北斗终端指的是具备北斗定位和北斗短报文收发通信的专业设备,用于特殊地区和应用的一种通信设备.北斗终端和北斗短报文终端其实说的是一类设备,也叫 ...

  5. Windows 终端美化 PowerShell 默认终端修改

    Windows 终端美化 PowerShell 默认终端修改 安装 oh-my-posh 安装Powerline字体 安装ConEmu 美化powershell 设置ConEmu 把界面默认语言改为中 ...

  6. mac系统vsCode终端无法打开,终端打开自动关闭的问题

    mac系统vsCode终端无法打开,终端打开自动关闭的问题 产生问题的原因 遂: 解决方案 产生问题的原因 手欠+强迫症, 几乎每次vscode发布新版本,都会不自觉点下更新,因为小窗口实在难受 更新 ...

  7. source profile之后关闭终端,在打开终端nvcc -V和java -verson没有输出

    一点小笔记,也不知道为什么 我安装了cuda 然后在/etc/profile 里面配置了环境变量,执行source profile 再执行nvcc -V有输出,但是关闭当前终端之后再打开执行nvcc ...

  8. 开启xterm终端256色和终端下vim 256色

    相同的colorschema,vim和gvim的颜色差距还是很大的,因为gvim使用X的颜色,而vim只能使用终端提供的颜色,所以造成了二者的显示差异. xterm开启256色 现在的终端模拟器早就支 ...

  9. linux系统包括虚拟终端图形界面终端有,Linux的终端类型

    一.了解终端 在早期的年代,主机不是很多,都是一系列的大型主机,简单来说就是用户很多,但主机很少,不可能做到人手一台,但可以在主机上连接一个分屏器,在分屏器上可以连接鼠标键盘以及显示器,这些东西是没有 ...

最新文章

  1. 图像拼接--Robust image stitching with multiple registrations
  2. 吴恩达深度学习4.1笔记_Convolutional Neural Networks_卷积神经网络基础
  3. 雕虫晓技(十) Android超简单气泡效果
  4. Mongodb c#增删改查
  5. Illegal output or inout port connection (port 'out').
  6. 用Python自动发送邮件
  7. Javascript特效:普通轮播图
  8. macbook proc 如何设置touch bar 为F键
  9. windows 编程的学习次序
  10. 梦幻西游战斗中服务器维护,梦幻西游10月22日维护公告 连续战斗自动问题修复...
  11. 新海诚没有参与制作的作品_全能的新海诚,最初几部作品都是他一个人完成的!但是却有缺陷!...
  12. NS-3网络仿真平台搭建及可视化
  13. WPF输入框双向绑定Decimal类等数据无法输入小数点
  14. 怎么将pdf转换成excel
  15. MongoDB学习系列 -- 索引
  16. uni-app 上架应用商店踩坑过程
  17. 第15课:郭盛华课程_VB编程之图形与图像控件的使用方法
  18. Android中圆形图的几种实现方式
  19. UE4 材质UV纹理不随模型缩放拉伸
  20. vue webpack压缩代码_vue.js - 解决vue-cli打包后自动压缩代码

热门文章

  1. [树状数组+离散化] NamomoCamp Daily 6
  2. paperswithcode 论文阅读与代码复现
  3. Ipad各系列年代顺序
  4. 如何利用Web of Science进行科学研究
  5. Codeforces Round #657 (Div. 2) B. Dubious Cyrpto(思维,数学)
  6. 遥感图像去雾文章解读
  7. Unity VR学习:第一人称射击游戏(1)
  8. UE4像素流pixelstream的一些坑
  9. 阿里云商标注册快速上手笔记(新手图文教程)
  10. Java学完后就业方向有哪些呢?