Windowsでslコマンドを使えるようにしたりなど


ピカチュウ!運用で回避だ!

DE-TEIUです。今日はslコマンドの話をします。

slコマンドとは

slはUnix系オペレーティングシステム (OS) のコマンドの一つ。コンソール画面をアスキーアートで描かれた蒸気機関車 (SL) が走り抜ける。

sl (UNIX) - Wikipediaより引用

ということで、実行するとこんな感じで機関車が右から左に走っていくアニメーションが再生されます。最高ですね。

slコマンド実行結果

unix系OSにはlsというコマンドがあり、これを使うとファイルの一覧を表示できます。このコマンドを呼ぶ際に、誤ってslと打ってしまうことがしばしばあったようで、それがきっかけでslコマンドが作られたそうです。

slコマンドをWindowsで実行できるようにしよう

WindowsでSLコマンドをビルド(sl.exe) #GCC - Qiitaという記事を参考にやってみます。

いろいろインストール

Chocolateyを導入

Chocolateyは、Windows向けのパッケージ管理システムです。Linux系OSで言うところのapt-getやyum、macOSのHomebrewみたいなものです。

公式サイトの導入手順に従って導入しましょう。

PowerShellを管理者権限で起動し、以下のコマンドを実行します。

Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

MinGWを導入

続いてMinGWを導入します。これは、Windows上でgccコンパイラ(など)を利用するためのツールです。 Chocolateyを導入したのでコマンド一発で入れられます。

choco install mingw

Makeを導入

次にMakeを導入します。これをいれると、複雑な手順のビルドを良い感じに自動化できるようになります。 これもChocolateyで入れましょう。

choco install make

Git for Windowsを導入

公式サイトからインストーラをダウンロードして実行しましょう。

ソースコードをダウンロードしてビルド

ビルドは先述のQiitaの記事と同じ手順でできました。

gitでプロジェクトをclone

以下のソースコードをGitHubからcloneします。

  • sl
  • PDCurses(cursesというライブラリの代用品らしい。ビルドに使用)
git clone https://github.com/mtoyoda/sl
cd sl
git clone https://github.com/wmcbrine/PDCurses

PDCursesをビルド

ビルド後、pdcurses.aというファイルをlibncurses.aにリネームする必要があるそうです。

cd PDCurses/wincon
make
rename pdcurses.a libncurses.a
cd ../.. # sl.cがあるディレクトリへ戻る

Makefileを編集

slディレクトリ直下のMakefileを一部変更します。10行目あたり。

# ----- before -----
CFLAGS=-O -Wall
# ----- after  -----
CFLAGS=-O -Wall -I./PDCurses -L./PDCurses/wincon

ビルドする

make

これでsl.exeが生成されると思います。実行したら機関車が走るはず。

何か作ってみる

せっかく良いソースコードがあるので、これを参考に自分でも何か作ってみようかと思いました。 ということで、私は古の個人サイトでよく使われていたmarqueeタグ(流れる文字を表示するやつ)を再現するアプリケーションを作ってみました。

marquee

アプリ実行時、引数に渡した文字列が流れます。以上。

ソースコード

文字をただ流すだけだと結構短くなりますね。

#include <curses.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>

static int add_text(int x);
static int my_mvaddstr(int y, int x, char *str);

static char *custom_text = "deforuto de nagareru moji !!!!!";

// 指定座標に文字列を描画する関数
static int my_mvaddstr(int y, int x, char *str)
{
    // 画面外の左側から文字列が入ってくる場合の処理
    for ( ; x < 0; ++x, ++str)
        if (*str == '\0')  return ERR;

    // 文字列を一文字ずつ描画
    for ( ; *str != '\0'; ++str, ++x)
        if (mvaddch(y, x, *str) == ERR)  return ERR;

    return OK;
}

// メイン関数
int main(int argc, char *argv[])
{
    int x;

    // コマンドライン引数からテキストを取得
    if (argc > 1) {
        custom_text = argv[1];  // 最初の引数を表示テキストとして使用
    }

    initscr();
    signal(SIGINT, SIG_IGN);    // Ctrl+C無効化
    noecho();                   // 入力文字非表示
    curs_set(0);               // カーソル非表示
    nodelay(stdscr, TRUE);     // 非ブロッキング入力
    leaveok(stdscr, TRUE);     // カーソル位置管理をncursesに委託
    scrollok(stdscr, FALSE);   // スクロール無効

    // アニメーションループ(右から左へ移動)
    for (x = COLS - 1; ; --x) {
        clear();                   // 画面クリア
        if (add_text(x) == ERR) break;  // テキスト描画
        getch();                   // 入力チェック(非ブロッキング)
        refresh();                 // 画面更新
        usleep(40000);            // 40ms待機
    }

    // ncurses終了処理
    mvcur(0, COLS - 1, LINES - 1, 0);
    endwin();

    return 0;
}


// テキストを画面中央に描画する関数
static int add_text(int x)
{
    int y, text_len = strlen(custom_text);
    if (x < -text_len)  return ERR;

    y = LINES / 2;
    my_mvaddstr(y, x, custom_text);

    return OK;
}