Annotation of nono/host/comdriver_stdio.cpp, revision 1.1

1.1     ! root        1: //
        !             2: // nono
        !             3: // Copyright (C) 2021 nono project
        !             4: // Licensed under nono-license.txt
        !             5: //
        !             6: 
        !             7: //
        !             8: // シリアルポートの標準入出力ドライバ
        !             9: //
        !            10: 
        !            11: #include "comdriver_stdio.h"
        !            12: #include "hostcom.h"
        !            13: #include <csignal>
        !            14: 
        !            15: // コンストラクタ
        !            16: COMDriverStdio::COMDriverStdio(HostDevice *hostdev_)
        !            17:        : inherited(hostdev_, "Stdio")
        !            18: {
        !            19:        // 現在の端末属性を取得
        !            20:        tcgetattr(STDIN_FILENO, &oldtc);
        !            21: }
        !            22: 
        !            23: // デストラクタ
        !            24: COMDriverStdio::~COMDriverStdio()
        !            25: {
        !            26:        // 端末属性を元に戻す
        !            27:        tcsetattr(STDIN_FILENO, TCSANOW, &oldtc);
        !            28: }
        !            29: 
        !            30: // ドライバ初期化
        !            31: bool
        !            32: COMDriverStdio::InitDriver()
        !            33: {
        !            34:        struct termios tc;
        !            35:        int fds[2];
        !            36: 
        !            37:        // 端末の設定を変更
        !            38:        tc = oldtc;
        !            39: 
        !            40:        // 入力時の変換は無し
        !            41:        tc.c_iflag = 0;
        !            42: 
        !            43:        tc.c_lflag &= ~ECHO;    // エコーオフ
        !            44:        tc.c_lflag &= ~ICANON;  // 非カノニカルモード
        !            45:        tc.c_lflag &= ~IEXTEN;  // DISCARD(^O)と LNEXT をオフ?
        !            46:        tc.c_cc[VTIME] = 0;
        !            47:        tc.c_cc[VMIN] = 1;
        !            48: 
        !            49:        if (tcsetattr(STDIN_FILENO, TCSANOW, &tc) < 0) {
        !            50:                putmsg(0, "tcsetattr: %s", strerror(errno));
        !            51:                return false;
        !            52:        }
        !            53: 
        !            54:        // シグナルを受け取る
        !            55:        if (pipe(fds) < 0) {
        !            56:                putmsg(0, "pipe: %s", strerror(errno));
        !            57:                return false;
        !            58:        }
        !            59:        if (hostdev->AddSignal(fds[0], fds[1]) < 0) {
        !            60:                putmsg(0, "AddSignal: %s", strerror(errno));
        !            61:                close(fds[0]);
        !            62:                close(fds[1]);
        !            63:                return false;
        !            64:        }
        !            65:        sigfd = fds[0];
        !            66: 
        !            67:        if (hostdev->AddOuter(STDIN_FILENO) < 0) {
        !            68:                putmsg(0, "AddOuter: %s", strerror(errno));
        !            69:                sigfd.Close();
        !            70:                close(fds[1]);
        !            71:                return false;
        !            72:        }
        !            73: 
        !            74:        char_from_signal = 0;
        !            75: 
        !            76:        return true;
        !            77: }
        !            78: 
        !            79: // Driver の Dispatch() は udata を返す。
        !            80: int
        !            81: COMDriverStdio::Dispatch(int udata)
        !            82: {
        !            83:        if (udata == HostDevice::DATA_FROM_SIGNAL) {
        !            84:                char buf[1];
        !            85:                if (read(sigfd, buf, sizeof(buf)) < 0) {
        !            86:                        putmsg(0, "read(sigfd=%d): %s", (int)sigfd, strerror(errno));
        !            87:                        return HostDevice::DONE;
        !            88:                }
        !            89:                int signo = buf[0];
        !            90:                switch (signo) {
        !            91:                 case SIGINT:
        !            92:                        // ^C が入力されたのでシリアルに '\x03' を送り込む
        !            93:                        char_from_signal = 0x03;
        !            94:                        break;
        !            95:                 case SIGTSTP:
        !            96:                        // ^Z が入力されたのでシリアルに '\x1a' を送り込む
        !            97:                        char_from_signal = 0x1a;
        !            98:                        break;
        !            99:                 case SIGQUIT:
        !           100:                        // ^\ が入力されたのでシリアルに '\x1e' を送り込む
        !           101:                        char_from_signal = 0x1e;
        !           102:                        break;
        !           103:                 default:
        !           104:                        return HostDevice::DONE;
        !           105:                }
        !           106: 
        !           107:                // シグナルで来た文字を Read で読める文字が外から来たことにする
        !           108:                return HostDevice::DATA_FROM_OUTER;
        !           109:        }
        !           110: 
        !           111:        return udata;
        !           112: }
        !           113: 
        !           114: // 外部への1バイト書き出し
        !           115: void
        !           116: COMDriverStdio::Write(uint32 data)
        !           117: {
        !           118:        uint8 buf[1];
        !           119:        int r;
        !           120: 
        !           121:        buf[0] = data;
        !           122:        r = write(STDOUT_FILENO, buf, sizeof(buf));
        !           123:        if (r < 0) {
        !           124:                putmsg(0, "write: %s", strerror(errno));
        !           125:                return;
        !           126:        }
        !           127:        if (r < sizeof(buf)) {
        !           128:                putmsg(0, "write: short");
        !           129:                return;
        !           130:        }
        !           131: }
        !           132: 
        !           133: // 外部からの1バイト読み込み
        !           134: int
        !           135: COMDriverStdio::Read()
        !           136: {
        !           137:        uint8 buf[1];
        !           138:        int r;
        !           139: 
        !           140:        // シグナルで来た文字があればそちらを返す
        !           141:        if (char_from_signal) {
        !           142:                r = char_from_signal;
        !           143:                char_from_signal = 0;
        !           144:                return r;
        !           145:        }
        !           146: 
        !           147:        r = read(STDIN_FILENO, buf, sizeof(buf));
        !           148:        if (r < 0) {
        !           149:                putmsg(0, "read: %s", strerror(errno));
        !           150:                return NODATA;
        !           151:        }
        !           152:        if (r == 0) {
        !           153:                return NODATA;
        !           154:        }
        !           155:        return buf[0];
        !           156: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.