Programming」カテゴリーアーカイブ

g_strdup_printf

GLib には g_strdup_printf という関数があることを今頃知った。
strdup にに文字列成形機能を追加したということみたい。
ライブラリ関数として用意されているのだから利用しない手はない。

_strdup、_wcsdup、_mbsdup

strdup は _strdup とう名前で VisualStudio でも使えるようだ。
malloc して内容をコピーするだけなのでアッサリ自作できるとはいえ。

更に devhelp をよく見ると文字列は GPtrArray で配列にしている。
GArray で文字列でも問題ないみたいだけど。
とにかく前回のコードを上記で書き換えてみる。

#include <glib.h>

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

    GPtrArray* array;
    gchar*  str;
    gint    count, i;

    count = 3;
    array = g_ptr_array_new();
    i = 0;
    for (i; i<count; i++) {
        str = g_strdup_printf("GArray %03d", i);
        g_ptr_array_add(array, str);
    }
    /* printf */
    i = 0;
    for (i; i<array->len; i++) {
        g_print("%s\n", g_ptr_array_index(array, i));
    }
    /* free */
    g_ptr_array_free(array, TRUE);
    return 0;
}

g_strdup_printf ならこんなにスッキリ!
これは g_ptr_array_free が破棄してくれるけど通常は破棄を忘れずに。

GPtrArray なら一揆に簡単になった。
オブジェクト作成に引数は不要だし配列へのポインタ追加も代入不要。
中身の取り出しも型名指定する必要が無い、文字列なら絶対にコッチ。

ただ C 言語なので演算子のオーバーロードがない。
list[0] みたいにはできないんですね。

Arrays of Arrays

動的配列みたいなワード検索するとよく見かける C 言語コード

#include <stdio.h>

#define MAX_LENGTH 1024

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

    int count,i;
    char** arg;
    count = 3;
    /* 開始 */
    arg = (char**)malloc(sizeof(char*) * count);
    i = 0;
	for (i; i<count; i++) {
        arg[i] = (char*)malloc(sizeof(char) * MAX_LENGTH);
        sprintf(arg[i], "malloc %03d", i);
    }
    /* printf と破棄 */
    i = 0;
    for (i; i<count; i++) {
        printf("%s\n", arg[i]);
        free(arg[i]);
    }
    free(arg);
    return 0;
}

c_aoa

これだと gcc は盛大に Warning を吐いてくれるのね。
ポインタのポインタが配列の配列だと認識できないのかな?
先頭要素のポインタを一つ分オフセットすれば次の要素のポインタ…
って今なら普通に解るけどスゲェ理屈だよな。

minipoli で使っている C++ 式というか new でなら問題無い。
TCHAR を使っているし解りづらいので少し書き換えて。

#include <stdio.h>

const int MAX_LENGTH = 1024;

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

    int count = 3;
    // 開始
    char** arg = new char* [count];
	for (int i=0; i<count; i++) {
        arg[i] = new char[MAX_LENGTH];
        sprintf(arg[i], "new %03d", i);
    }
    // cout と破棄
    for (int i=0; i<count; i++) {
        printf("%s\n", arg[i]);
        delete[] arg[i];
    }
    delete[] arg;
    return 0;
}

C++ なのに何故 stdio なんだよとあの頃の自分にツッコミしたい。
VisualStudio でプログラミングを始めるとそうなっちゃうんだよなぁ。
Linux で C++ は実用面では避けたいんだが、gtkmm ワカンネエし。

GLib に GArray というものがあるので使ってみる。

#include <glib.h>

#define MAX_LENGTH 1024

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

    GArray* array;
    gchar   c[MAX_LENGTH];
    gint    count, i;

    count = 3;
    /* 開始 */
    array = g_array_new(TRUE, TRUE, sizeof (gchar*));
    i = 0;
    for (i; i<count; i++) {
        g_sprintf(c, "GArray %03d", i);
        gchar* temp;
        temp = g_strdup(c);
        g_array_append_val(array, temp);
    }
    /* printf 破棄は不要 */
    i = 0;
    for (i; i<array->len; i++) {
        g_print("%s\n", g_array_index(array, gchar*, i));
    }
    /* 第二引数 TRUE で中身も破棄 */
    g_array_free(array, TRUE);
    return 0;
}

そうか、あらかじめポインタの領域が確保されているわけじゃないもんな。
一度新な領域を確保してポインタを入れる必要があるわけだ。
公式サンプルコードなら簡単だけど成形するとなると一手間掛かる。
GLib のほうが面倒臭いなんて初めて見た。

うーん、どれもイマイチだ。
次は GList でも調べるか。

Here Document

ヒアドキュメントが便利なのでもう少し調べる。
Y901x のインストールスクリプトで使っているから経験はあるのだが。

ヒアドキュメント – Wikipedia

シェルスクリプトはバッククォーテーションでコマンドも使えるのか。

#!/bin/sh

func() {
    echo バッククオートで関数も使える
}
shstr=シェルスクリプト
hdstr=ヒアドキュメント

cat << __EOS__
${shstr}で$hdstrは今更だけど
最初の改行は無視される、最後は echo や cat が改行する
エスケープ文字 \\ は有効
記号は\$とバッククオートを除いて <'"{[+=~ と普通に使える
`func`
__EOS__

自作関数でもいいようだ。

# output
シェルスクリプトでヒアドキュメントは今更だけど
最初の改行は無視される、最後は echo や cat が改行する
エスケープ文字 \ は有効
記号は$とバッククオートを除いて <'"{[+=~ と普通に使える
バッククオートで関数も使える

これはもしかして PHP でも関数が使えるかも。

<?php

function func() { return "関数"; }
$plstr = "Perl";
$shstr = "シェルスクリプト";

echo <<< __EOS__
PHP は${shstr}や $plstr 同様に利用できる
最初と最後の改行は無視されるので最後は一行開けるとよし
エスケープ文字 \\ は有効
記号は\$を除いて <'"{[+=~` と普通に使える
`func` って PHP にこんな機能はもともと無いよ!

__EOS__;
/* output
PHP はシェルスクリプトや Perl 同様に利用できる
最初と最後の改行は無視されるので最後は一行開けるとよし
エスケープ文字 \ は有効
記号は$を除いて <'"{[+=~` と普通に使える
`func` って PHP にこんな機能はもともと無いよ!
*/
?>

んなわけないか。
ところで PHP のヒアドキュメントは最後を改行しなくて最初戸惑った。
よく考えたら echo, cat, print() が改行していただけだった。
PHP の echo は改行しないもんね。

Perl や Lua って Fedora に最初から入っているけど使ったことが無いな。
余程のことがないかぎり今後も使うことは無いと思うけど。
GNOME は以前 JavaScript を押していたけど今はどうなんだろう?

// Gjs
// imports /usr/share/gjs-1.0/format.js

const Format = imports.format;

String.prototype.format = Format.format;

let jstr = "\
JavaScript はエスケープで強引な改行しか手段が無い\n\
更に%s機能は無い\n\
しかし %s ならこんなことができる\n\
%%s, %%d, %%x, %%f のみ";

print(jstr.format("文字列フォーマット", "Gjs"));
/*
JavaScript はエスケープで強引な改行しか手段が無い
更に文字列フォーマット機能は無い
しかし Gjs ならこんなことができる
%s, %d, %x, %f のみ
*/

これだものな。
面倒臭くなってブン投げたのは筆者だけではないと思う。

#include <stdio.h>

#define CSTR "\
%s は\n\
説明不要だよね\n"

int
main (int argc, char ** argv) {
	printf (CSTR, "C 言語");
	return 0;
}
/*
C 言語 は
説明不要だよね
*/

C のほうが簡単なんて洒落にもならん。
プラス記号で成形するのって最初は分かり易いのでいいと思うが。

#!/usr/bin/env python3

DOCSTR = """{0} はお馴染 {1}
最初と最後の改行も有効だけど print が最後を改行する
{2}
{1} は \\ エスケープが有効"""

def func():
    return "関数は format で実行すれば文字列さ"

print(DOCSTR.format("Python", "docstring", func()))

''' output
Python はお馴染 docstring
最初と最後の改行も有効だけど print が最後を改行する
関数は format で実行すれば文字列さ
docstring は \ エスケープが有効
'''

あぁ楽チン、やっぱりコレだよコレ!

しかしやっぱりヒアドキュメントに変数を直書きできたほうが便利。
それには $ 記号を変数に利用する言語しか無理なんだろうな。
と思っていました。

// Vala

const string DOCSTR = """Python と同じ
%s も使える、でも ''' は使えない
何故か \\ エスケープ\nは使えない
""";

string func() { return "無理"; }

int main (string[] args) {
    string one = "Vala";
    string tow = "ヒアドキュメント";
    stdout.printf(@"$one は実は@\"\"を使って$towもどきが利用できる
ですが$${one}みたいなブレース表記はダメみたい
最初と最後の改行も有効、エスケープ文字 \\ は有効
記号は$$と\"を除いて <'{[+=~` と普通に使える
`func` は当然不可能\n\n");
    //
    stdout.printf(DOCSTR, "docstring");
    return 0;
}
/* output
Vala は実は@""を使ってヒアドキュメントもどきが利用できる
ですが${one}みたいなブレース表記はダメみたい
最初と最後の改行も有効、エスケープ文字 \ は有効
記号は$と"を除いて <'{[+=~` と普通に使える
`func` は当然不可能

Python と同じ
docstring も使える、でも ''' は使えない
何故か \\ エスケープ\nは使えない
*/

Vala はやってくれました。
おかげで解った、滅茶苦茶使い辛いということを。
これなら docstring 方式のほうがいいや。

最後に、Gedit の色分けってスゴすぎる!

gedit

まさかこの Vala の $ 変数を見分けて色分けするとは思わなかった。
PHP 部分と HTML 部分をしっかり見分けるとかは知っていたが。
どの言語でもヒアドキュメント内でマズい記号を打つと即座に色が変わる。
これがデフォルトエディタって GNOME 恐るべしだよ。

GNOME Developer Platform Demos

GNOME Developer Platform Demos

ナイスなページ発見。
GNOME プロジェクトは何時の間かにこんなのを作っていた。

JavaScript はもう Gjs にしなさいみたい。
C, C++, Vala は Anjuta を使うのを前提にしているんだなぁ。

しかし Python だけ妙に詳しくて笑う。

インストールはこんな方法があるのか、autoreconf なんて知らなかった。
しかし print に括弧が無い、Python2 でまだいいよってことですか。
試したら本当にインストールできたけど…
先頭に #!/usr/bin/env python が無いので動かないwwwww
わざと?

Tutorial for beginners (Python)

アプリケーションメニュー(GMenu)はこうやればよかったのか。
GtkSwitch の notify::active なんて devhelp に載っていないんですけど…
とにかく参考になるわ、筆者はビギナー達の一人だったのか。

Python3 urllib

今日 Python3 で URI デコードをやろうとした。

Python 3 Porting Guide ? Porting to Python 3 v1 documentation
Python2 との違い一覧を作ってくれている人がいる、アリガトメルシー。
urllib.unquote は urllib.parse.unquote なのね。

#!/usr/bin/env python3

import urllib
print(dir(urllib))

''' output
['__builtins__', '__cached__', '__doc__', '__file__', '__initializing__', '__loader__', '__name__', '__package__', '__path__']
'''

import urllib.parse
print(dir(urllib))

''' output
['__builtins__', '__cached__', '__doc__', '__file__', '__initializing__', '__loader__', '__name__', '__package__', '__path__', 'parse']
'''

なんだこりゃ…

quote

当然そうなるよな、何故だ?
/usr/lib64/python3.3/urllib
を覗いてみると

urllib_zerobyte

__init__.py が 0 byte だとこういう動作になるってことなのか。
なるほど、多分どこかでこの知識が役に立つだろう。

#!/usr/bin/env python3

import urllib.parse
from gi.repository import GLib

uri = "file:///path/to/My%20Waifu.jpg"

path = urllib.parse.unquote(uri)
print(path) #=> file:///path/to/My Waifu.jpg

path, host = GLib.filename_from_uri(uri)
print(path) #=> /path/to/My Waifu.jpg

ただ unquote だと file:/// とかは普通に残るんだよな。
ホスト名があった場合(LAN 上ファイル等)も面倒だし。
Linux なら GLib を使ったほうがいいや。
こんな楽な手段を知っているので Python モジュールの知識が全然無いというのも考え物だな。