minibufferのフォントを大きくする

例1

minibufferにフォーカスが移ったときに一時的に大きくするようにする.

(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup)
(defun my-minibuffer-setup ()
  (setq-local face-remapping-alist '((default :height 2.0))))
イメージ

例2

minibuffer-promptという faceがあるが, これはプロンプトの部分だけなので微妙.
prompt以外は default faceなので, これを大きくすると全体が大きくなってしまい
目的とは少しずれてしまうかな.

(set-face-attribute 'minibuffer-prompt nil
		    :height 2.0)
イメージ

奇妙である.

おわりに

もっとうまい方法はないものだろうか ?

Emacs Lispで「ソフトウェアエンジニアならば1時間以内に解けなければいけない5つの問題」を解いてみた

http://mattn.kaoriya.net/software/vim/20150527121332.htm


ちょうど 1時間程度. 1-4はすぐに書けて, 5に時間を要した.
(追記: 2015年6月1日 問4に誤りがあり修正しました)

問題1

'for'の代わりに loopで.

(require 'cl-lib)

(defun problem1-for (lst)
  (cl-loop for i in lst
           sum i))

(defun problem1-while (lst)
  (let ((sum 0)
        (xs lst))
    (while xs
      (setq sum (+ sum (car xs))
            xs (cdr xs)))
    sum))

(defun problem1-recursive (lst)
  (if (null lst)
      0
    (+ (car lst) (problem1-recursive (cdr lst)))))

(defun problem1-tail-recursive (lst)
  (cl-labels ((func (lst acc)
                (if (null lst)
                    acc
                  (func (cdr lst) (+ acc (car lst))))))
    (func lst 0)))

(let ((input '(1 2 3 4 5 6 7 8 9 10)))
  (cl-assert (= 55
                (problem1-for input)
                (problem1-while input)
                (problem1-recursive input)
                (problem1-tail-recursive input))))

問題2

(require 'cl-lib)

(defun problem2 (xs ys)
  (cl-loop for x in xs
           for y in ys
           collect x
           collect y))

(cl-assert (equal '(a 1 b 2 c 3)
                  (problem2 '(a b c) '(1 2 3))))


他には mapcanを使うとかだろか.

(cl-mapcan (lambda (a b) (list a b)) '(1 2 3) '(a b c))

問題3

表現範囲の問題で, calcを使用. すぐ書けたものでは正しく表示できず.

(require 'cl-lib)
(require 'calc-arith)

(defun bignum-to-string (n)
  (let ((sign (if (eq (car n) 'bigpos) "" "-")))
    (concat sign
            (mapconcat #'number-to-string
                       (reverse (cdr n))
                       ""))))

(defun problem3 (n)
  (cond ((= n 1) '(0))
        ((= n 2) '(0 1))
        (t
         (cl-loop with acc = '(1 0)
                  repeat (- n 2)
                  do
                  (push (calcFunc-add (cl-first acc) (cl-second acc)) acc)
                  finally
                  return (reverse (mapcar (lambda (e)
                                            (if (listp e) (bignum-to-string e) e)) acc))))))

(cl-assert
 (string= (nth 99 (problem3 100)) "218922995834555169026"))

問題4

(1つめのコードは誤っています.)

(require 'cl-lib)

(defun problem4 (lst)
  (let ((xs (sort lst (lambda (a b)
                        (string< (number-to-string b) (number-to-string a))))))
    (string-to-number (mapconcat #'number-to-string xs ""))))

(cl-assert
 (= (problem4 '(50 2 1 9)) 95021))


追記: 2015/JUN/1 修正版

(require 'cl-lib)

(defun compare (a b)
  (let ((ab-val (string-to-number (format "%s%s" a b)))
        (ba-val (string-to-number (format "%s%s" b a))))
    (> ab-val ba-val)))

(defun problem4 (lst)
  (let ((xs (sort lst #'compare)))
    (string-to-number (mapconcat #'number-to-string xs ""))))

(cl-assert
 (= (problem4 '(420 42 423)) 42423420)
 (= (problem4 '(50 2 1 9)) 95021))

問題5

他はすぐに思いついたけど, これは時間がかかった.
evalは使わず. 演算子の全組み合わせを出せばすぐだなと思ったけど,
文字列連結を先にするのがうまくいかず, 苦労した.

(require 'cl-lib)

(defun concat-num (a b)
  (string-to-number (concat (number-to-string a) (number-to-string b))))

(defun permute-ops (n)
  (let ((accs nil))
    (cl-labels ((permute-ops- (n i acc)
                  (if (= n i)
                      (push (reverse acc) accs)
                    (cl-loop for op in '(+ - concat-num)
                             do
                             (permute-ops- n (1+ i) (cons op acc))))))
      (permute-ops- n 0 '())
      accs)))

(defun apply-concat (lst ops)
  (cl-loop with stack = (list (car lst))
           for e in (cdr lst)
           for op in ops
           if (eq op 'concat-num)
           do
           (let ((a (pop stack)))
             (push (concat-num a e) stack))
           else
           do
           (push e stack)
           finally return (reverse stack)))

(defun calc-ops (lst- ops-)
  (let ((lst (apply-concat lst- ops-))
        (ops (cl-loop for op in ops-
                      unless (eq op 'concat-num)
                      collect op)))
    (if (null ops) ;; all ops are concat
        (car lst)
      (cl-loop with acc = (funcall (car ops) (cl-first lst) (cl-second lst))
               for op in (cdr ops)
               for num in (cddr lst)
               do
               (setq acc (funcall op acc num))
               finally return acc))))

(defun format-ops (lst ops)
  (concat (number-to-string (car lst))
          (cl-loop for op in ops
                   for num in (cdr lst)
                   if (eq op 'concat-num)
                   concat (number-to-string num)
                   else
                   concat (format "%s%s" op num))))

(defun problem5 (lst)
  (let ((opss (permute-ops (1- (length lst)))))
    (cl-loop for ops in opss
             when (= (calc-ops lst ops) 100)
             collect (format-ops lst ops))))

(cl-assert
 (member "1+2+34-5+67-8+9" (problem5 '(1 2 3 4 5 6 7 8 9))))

FreeBSDの posix_spawnの実装

http://blog.kazuhooku.com/2015/05/how-to-properly-spawn-external-command.html


を見て, 再現コードFreeBSDで実行してみたとき, 期待される挙動になったので FreeBSDでの実装を確認してみました.

コード

FreeBSD r282608のソースコードを対象にしています.


posix_spawnは lib/libc/gen/posix_spawn.cで定義される.

int
posix_spawn(pid_t *pid, const char *path,
    const posix_spawn_file_actions_t *fa,
    const posix_spawnattr_t *sa,
    char * const argv[], char * const envp[])
{
        return do_posix_spawn(pid, path, fa, sa, argv, envp, 0);
}

do_posix_spawn関数を呼び出すだけ.

static int
do_posix_spawn(pid_t *pid, const char *path,
    const posix_spawn_file_actions_t *fa,
    const posix_spawnattr_t *sa,
    char * const argv[], char * const envp[], int use_env_path)
{
        pid_t p;
        volatile int error = 0;

        p = vfork();
        switch (p) {
        case -1:
                return (errno);
        case 0:
                if (sa != NULL) {
                        error = process_spawnattr(*sa);
                        if (error)
                                _exit(127);
                }
                if (fa != NULL) {
                        error = process_file_actions(*fa);
                        if (error)
                                _exit(127);
                }
                if (use_env_path)
                        _execvpe(path, argv, envp != NULL ? envp : environ);
                else
                        _execve(path, argv, envp != NULL ? envp : environ);
                error = errno;
                _exit(127);
        default:
                if (error != 0)
                        _waitpid(p, NULL, WNOHANG);
                else if (pid != NULL)
                        *pid = p;
                return (error);
        }
}

初めに vforkを呼び出しています. vforkは forkと違いメモリ空間がコピーされない,かつ親プロセスは子プロセスが execするか exitするまで待つという性質があります.このため子プロセスが先に動作し, _execveが呼ばれます(posix_spawnpの場合は _execvpe). このとき実在しないコマンドが指定されている等で execが失敗したとき, error変数にerrnoを書き込み _exitします.


execが成功 or execが失敗+exitの後, 親プロセスが動き出します. switchの defaultの部分が実行され, はじめに errorがチェックされます. 前述の通り vforkではメモリ空間がコピーされないので, 親プロセスから子プロセスでの変更が確認できます. (vforkでなく, forkを使う場合, h2oの実装のように pipe等を使う必要があります)
で, errorが発生していれば waitpidをして, errorを返します. このような実装になっているので, 子プロセスで execが失敗した場合エラーを返すことができるということになります.
(字面だけ見ると, default節の ifが真になることはないので, コンパイラに削除される可能性がある. そうならないように volatileがつけられている. コンパイラはfork/vforkの挙動など知らない)

glibcでの実装

sysdeps/posix/spawni.cの __spawni関数です. 親プロセスが戻るところだけ示します.

  /* Generate the new process.  */
  if ((flags & POSIX_SPAWN_USEVFORK) != 0
      /* If no major work is done, allow using vfork.  Note that we
         might perform the path searching.  But this would be done by
         a call to execvp(), too, and such a call must be OK according
         to POSIX.  */
      || ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF
                    | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER
                    | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0
          && file_actions == NULL))
    new_pid = __vfork ();
  else
    new_pid = __fork ();

  if (new_pid != 0)
    {
      if (new_pid < 0)
        return errno;

      /* The call was successful.  Store the PID if necessary.  */
      if (pid != NULL)
        *pid = new_pid;

      return 0;
    }

vfork/forkが失敗した場合は errnoを返しますが, それ以外は 0を返しています.
なので子プロセスが execに失敗した場合でも 0(成功)が返っていたわけです.

vfork

vforkを使っている理由はわかりませんが, マルチスレッド下で呼ばれる可能性がある場合を考慮しているためと思われます(すぐに execすることが確定しているのでパフォーマンスを考えてのことかもしれませんが...)


マルチスレッド + forkの問題についてはこちらを参照してください


追記

  • POSIXでは posix_spawnは MMUなしの環境でも動作するように実装しないといけないとなっていました. そのための vforkかも.

Qemu ネットワーク周りリンク集

virtio-netを使ってインタフェースを生やす

AArch64関連のリンクまとめ

毎度毎度調べるのが面倒なので.

Openembeddedを ARMv8環境向けに構築する

Qemuで openembeddedのイメージを動かす方法

ARM Fast Model(armv8)で ARM KVMを動作させる方法

qemu + binfmt + chroot で AARCH64 環境を構築する 方法


binfmtを使い, ARM向けバイナリを qemuユーザモードエミュレーションで実行する. Debian AArch64用の root file systemに対して chrootを行うことと組み合わせることで擬似的な ARM環境を構築する.

ARMv8シミュレータの使い方