zoukankan      html  css  js  c++  java
  • 终端I/O之终端标识

    历史沿袭至今,在大多数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 ", isatty(0) ? "tty" : "not a tty");

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

        printf("fd 2: %s ", 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 ", name);

     

        if(isatty(1))

        {

            name = ttyname(1);

            if(name == NULL)

                name = "undefined";

        }

        else

        {

            name = "not a tty";

        }

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

     

        if(isatty(2))

        {

            name = ttyname(2);

            if(name == NULL)

                name = "undefined";

        }

        else

        {

            name = "not a tty";

        }

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

        

        exit(0);

    }

     

    运行该程序得到:

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

  • 相关阅读:
    sqlserver2012附加数据库2005版本时出现的问题
    jQuery实现评论还剩多少个字
    在mvc3中经常使用身份验证实现
    Windows Phone学习(1):棋子未动,先观全局
    使用jquery.pagination.js实现无刷新分页
    Javascript和JQuery中常用的随机数产生函数(很好用)
    网页打印样式设置(页眉,页脚,页边距)
    rdlc到设置宽度后自动换行(转)
    VSS忘记Admin密码和修改默认登陆用户
    解决jquery 修改onclick事件后IE兼容模式下立刻执行的问题
  • 原文地址:https://www.cnblogs.com/nufangrensheng/p/3577037.html
Copyright © 2011-2022 走看看