月別アーカイブ: 2015年2月

stdin ? command : pipe

コマンドからパイプで渡されたデータはどう処理するのだろう?
どうせ stdin だろう、サクッと Python で実験

#!/usr/bin/env python3

# if stdin != pipe:
#     Press Ctrl+D

import sys
print(sys.argv)
print(sys.stdin.read())

pypipe

普通に stdin に入ってくるので値を得るのは簡単。
だけどうっかり単独起動すると当然のように入力待ちになる。
なので強制終了するしかない、cat コマンドもそうなるね。

でも bc コマンドなんかはパイプ経由だと計算結果を出力のみ。
単独起動だとインタラクティブシェルにと振り分けされる。
何か方法はあるのだろう、検索検索。

シェルスクリプトでパイプからの入力とキーボード入力を区別する

シェルスクリプトなら上記リンク先の方法で振り分けできた。
ファイルディスクプリタで見分けるのか、おぉワカラン。

LinuxやUNIXでパイプで渡されたデータをC言語で適切に処理するには? – Yahoo!知恵袋

やっぱりファイルディスクリプタか。
Non-blocking I/O がどうかでなく振り分けがしたいだけなんですが。
これはこれで勉強になるのでブックマークと。

面倒だ、bc のソースを読んでしまえ。
結構利用しているけどもう 15 年もメンテされていなかったのか…
http://ftp.gnu.org/gnu/bc/

grep しまくって isatty という関数を見つけた。
UNIXの部屋 コマンド検索:isatty (*BSD/Linux)

コレだよコレ。
STDOUT_FILENO はどうせ enum だし in 側はゼロだろ、ならば。

#include <stdio.h>
#include <unistd.h>

int
main (int argc, char* argv[]) {
    if (isatty(0)) {
        printf("stdin == Console\n");
    } else {
        char pipe[256];
        fgets(pipe, 256, stdin);
        printf(pipe);
    }
    return 0;
}

isatty

こんなにアッサリと振り分けできるじゃない。
マネしただけなんですが。
いやぁ GPL って本当に素晴らしいですね。

GOptionContext

コマンドラインオプションは Linux では重要。
とりあえずよく見かける実装手段を自分で整理、したけど…

#include <stdio.h>
#include <getopt.h>

/* 
 * optarg, optind については unistd.h で定義されている 
 * getopt.h によってインクルードされる
**/

static struct
option options[] = {
    {"help",   no_argument, 0, 'h'},
    {"list",   no_argument, 0, 'l'},
    {"num", required_argument, 0, 'n'},
    {0, 0, 0, 0}
};

int
main (int argc, char *argv[]) {

    int opt, i;
    int idx = 0; /* 使い道が無いので気にしないほうがいい */

    /* 第三引数にアルファベットを指定 */
    while ((opt = getopt_long(argc, argv, "hln:", options, &idx)) != -1) {
        switch (opt) {
        case 'l':
            /* こうやって捕まえる */
            printf("-l or --list オプションです\n");
            break;
        case 'n':
            /* コロンを付けると値を受け取れる */
            printf("%s 行表示します\n", optarg);
            break;
        case 'h':
            /* Usage は自分で用意する */
            printf("ヘルプが表示されるかも...\n");
            return 0;
        case '?':
            return 1;
        }
    }
    /* オプションを省いた部分を処理 */
    for (i=optind; i<argc; i++) {
        printf("%d %s\n", i, argv[i]);
    }
    return 0;
}

option 構造体の中、getopt_long の引数、そして case 文。
いったい何度同じアルファベット指定を書かせるのよ。
間違いの元というか、整理していて自分が間違いまくったYO!

それじゃイカンと思ったのかどうかは知らないが。
GLib の GOptionContext は一箇所のみの指定になっていた。

#include <glib.h>
#include <stdio.h> /* stderr */

static gboolean _bool = 0;     /* 値を受ける必要が無いとき */
static gint     _num  = 0;     /* getopt と違い数値として受け取り */
static gchar*   _str  = NULL;  /* 文字列は破棄が必要、日本語はダメだった */

static GOptionEntry entries[] = {
    {"bool", 'b', 0, G_OPTION_ARG_NONE,   &_bool, "Show", NULL},
    {"num",  'n', 0, G_OPTION_ARG_INT,    &_num,  "Size", "<num>"},
    {"str",  's', 0, G_OPTION_ARG_STRING, &_str,  "Text", "<string>"},
    {NULL}
};

int
main (int argc, char *argv[]) {

    GError* error = NULL;
    GOptionContext* context;

    context = g_option_context_new ("After GApplication ?");
    g_option_context_add_main_entries (context, entries, NULL);
    if (!g_option_context_parse (context, &argc, &argv, &error)) {
        g_fprintf(stderr, "Error parsing options, try --help.\n");
        return 1;
    }
    /* 値を確認 */
    g_printf("boolean=%d, int=%d, string=%s\n", _bool, _num, _str);

    /* 後は GApplication ? */

    g_free(_str);
    g_option_context_free(context);
    return 0;
}
/* output

$ ./a.out
boolean=0, int=0, string=(null)

$ ./a.out -b --num 675 -s Daytona
boolean=1, int=675, string=Daytona

$ ./a.out -h
Usage:
  a.out [OPTION...] After GApplication ?

Help Options:
  -h, --help             Show help options

Application Options:
  -b, --bool             Show
  -n, --num=<num>        Size
  -s, --str=<string>     Text

*/

GOptionEntry が少し面倒、と思ったら大間違いだった。
まさかの Usage 全自動生成、しかも細かい。
Python の optparse 同様に -h –help は勝手に作ってくれる。

変更したくなったら一箇所だけ書き換えればいいのは本当に嬉しい。
Usage にさえ反映されるので「やっちまった…」は確実に減る。

GOptionContext ってこんなに凄かったのか。
C 言語標準ライブラリでゴリゴリ書くなんてアホみたい。
せっかく整理したけどもう getopt を使うことは無いがや。

しかし別途というかオプション以外の引数や数を得る関数が何も無い。
そういうのは GApplication でヤレということでいいのかな?

dos2unix

改行コードの変換と上書きモードについて。あるいは iconv と nkf に見る思想の違い – 玉虫色に染まれ!

iconv と g_convert については以前書いたけど
そういえば改行コードを考えていなかった。
g_convert | PaePoi

SHIFT-JIS じゃなく CP932…
は置いておいて、コードでヤルなら自力しか無さそうだ。

しかし dos2unix なんて便利なコマンドがあったのね。

よくわかんないので早速 man を見てみる。
どうやら基本的に CRLF を LF に置き換えるコマンドらしい。
特定の文字コードは変換もするっぽいけど CP932 は当然無いな。

–remove-bom が default で有効のようだ。
うっ、コレも考えていなかった。
UTF-8 に BOM を付けるあの Windows の最悪仕様を忘れていた!
BOM を付けると PHP が動かないとか色々あるのよ。

本当に BOM を削除してくれるか試してみよう。
使い方はパイプで渡すと標準出力へ、引数に渡すと上書きみたい。

SeeMe というアプリを C# で作っていた頃のファイルを引っ張り出して。
そう、Visual Studio やメモ帳は勝手に BOM を付けてしまうんです。
特にメモ帳は BOM の有無のみで UTF-8 を見分ける糞っぷり。

dos2unix

見事 CRLF が LF になり BOM が削除された。
上書きなのでワイルドカードでまとめて変換も簡単、これはいい。
つか Windows はいいかげん BOM をヤメろよと。

しかし nkf ってマジで今でもメンテされているんですね。
nkf Network Kanji Filter プロジェクト日本語トップページ – SourceForge.JP

Numeric sort in GLib

ファイル名の数値優先ソート C 言語版を書いてみた。

というより、手元に溜まっている古い覚書ファイルを整理している。
昔書いたのって posix と glib が混在で自分がゲンナリするもので。
とにかく今の知識で限界まで整理して Web に書き出す。

Python の覚書でディレクトリ内容列挙とソートを別々に書いているけど
どうせ同時に使うのだからまとめたほうがよさそう。
ということでこんなコードになった。

#include <glib.h>
#include <gio/gio.h>

/*
 * Numeric sort in GLib (like a Nautilus)
 * gcc nautilus_sort.c `pkg-config --cflags --libs gio-2.0`
**/

gint
compare_main_func(gchar** a, gchar** b) {

    gint n;

    gchar* aaa = g_utf8_collate_key_for_filename (*a, -1);
    gchar* bbb = g_utf8_collate_key_for_filename (*b, -1);
    n = g_strcmp0(aaa, bbb);
    g_free(aaa);
    g_free(bbb);
    return n;
}

gint
compare_data_func(gconstpointer a, gconstpointer b) {
    return compare_main_func((gchar**)a, (gchar**)b);
}

void 
print_data(gpointer data, gpointer user_data) {
    g_printf("%s\n", data);
}

int
main (int argc, char *argv[]) {

    gchar* dir;
    GFile* file;
    GFileEnumerator* file_enum;
    GFileInfo* info;
    GPtrArray* array;

    dir = g_get_current_dir();
    file = g_file_new_for_path(dir);
    g_free(dir);
    /* Get the directory contents */
    array = g_ptr_array_new();
    file_enum = g_file_enumerate_children(file,
                                          G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
                                          G_FILE_QUERY_INFO_NONE,
                                          NULL,
                                          NULL);
    for (;;) {
        info = g_file_enumerator_next_file(file_enum, NULL, NULL);
        if (info == NULL) break;
        g_ptr_array_add(array, g_strdup(g_file_info_get_display_name(info)));
        g_object_unref(info);
    }
    g_object_unref(file_enum);
    /* Sort */
    g_ptr_array_sort(array, compare_data_func);
    /* print */
    g_ptr_array_foreach(array, print_data, NULL);
    /* free */
    g_ptr_array_free(array, TRUE);
    return 0;
}

numeric_sort

pkg-config は gio ですのでお間違いなく。

Python では使わないので気が付かなかったけど
GCompareFunc の引数が gconstpointer になっている。
実際には const gchar** だ、コレにはまいった。

gchar* aaa = g_utf8_collate_key_for_filename (*((gchar**)a), -1);

とやれば一応関数に分離せずにビルドできる。
けど見た目が酷過ぎるので分離した、ドンだけキャストすればいいのよ。
ポインタが今一。。。な初心者がこんなの見たらブン投げるわ。

しかし GLib はループ用の int をまったく使わないで書けるんだな。
筆者はもう慣れたけどローカル変数も malloc も使わないって違和感スゲェ。
C より Python の経験があるほうが覚えるの早そう、破棄が必要なだけだし。

ついでに、今日電源を入れたら。

mouse

GNOME はこんなに親切だったのか、初めて見た。
いやマウスの LED がチカチカするから解るんですけど。

JavaScript Map to ComboBox

Javascript tips – 連想配列(ハッシュ)の要素取得

あれ、JavaScript の配列って普通に for in が使えたの?
Python 等と違ってキーが戻るってことなのね。

てっきりメソッド列挙しかできないと思いこんでいた。
ちと Gjs で試してみるか。

#!/usr/bin/env gjs

// Map
var map = {TOYOTA: "LEXUS", HONDA: "ACURA"};
map["NISSAN"] = "DATSUN";
for (var key in map) {
    print(key + " : " + map[key]);
}
print(" ");
// Array
var array = ["YAMAHA", "HONDA", "SUZUKI"];
array.push("KAWASAKI");
for (var key in array) {
    print(array[key]);
}
print(" ");
// Method
const Gtk = imports.gi.Gtk;
for (var s in Gtk.Window) {
    print(s);
}

gjs

うん Gjs でも問題無し、仕様のようだ。
forEach でも結果は同じだけどコッチのほうが違和感が少なくていい。

Array.forEach – JavaScript | MDN
Map.prototype.forEach() – JavaScript | MDN

ということで、JavaScript でコンボボックスを作る。
スマートフォンを考慮すると ListBox は使いたくない。

<form>
    <select>
        <option>KAWASAKI
        <option>SUZUKI
    </select>
</form>

実際の運用ではこういう HTML に直書きなんてほぼありえない。
データベースやファイルから読み込んで割り当てていくわけでして。
多分 Java か PHP で動的にタグを追加していくのが主流だと思う。

というか IE というゴミがさ。
それについては企業向けな人達にまかせてと。
IE をガン無視、スマートフォンはバッチリなサンプルコード。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<!-- for Smart Phone -->
<meta name="viewport" content="
    width=device-width,
    initial-scale=1.0,
    minimum-scale=1.0,
    maximum-scale=1.0,
    user-scalable=no" />
<title>コンボボックスを使う</title>
<style>
body {
	font-family: sans-serif;
	/*margin: 0;*/
	-webkit-text-size-adjust: 100%; /* iPhone */
}
</style>
<script type="text/javascript"><!--

    const truck = {
        "大好きな 4t トラックを選んでください": "未選択",
        "ISUZU":  "フォワード",
        "FUSO":   "ファイター",
        "TOYOTA": "トヨエース",
        "HINO":   "レンジャー"
    };

    var init = function() {
        var combobox = document.getElementById("ID_COMBOBOX");
        combobox.onchange = function() {
            var item = combobox.options[combobox.selectedIndex].value;
            var text = document.getElementById("ID_TEXT");
            text.innerHTML = item + " です";
        };
        for (var key in truck) {
            combobox.appendChild(new Option(key, truck[key]));
        };
    }
    //-->
</script>
</head>

<body onLoad="init()">

<form>
<select id="ID_COMBOBOX">
</select>
</form>

<p id="ID_TEXT">未選択</p>

<p><a href=".">Back</a></p>

</body>
</html>

コンボボックスを使う

連想配列を利用して動的にコンボボックスに追加してみました。
こうしておくと追加や並べ替えをしたくなった時に便利。
珍しくパソコンブラウザでも動くよ、IE は知らない。

ところで iPhone でコンボボックスを使うとこうなります。

iphone_combobox

小さい画面でも使い易いように工夫してますね。
wonder なんとかは小さいボタンに耐えられず削除しました。