zsh completion macOS screencapture command
It is bundled neither zsh sources nor zsh-completions, so I wrote it.
#compdef screencapture __screencapture_files() { for ((i = 2;i < CURRENT;i++)) do if [[ $words[$i] == "-p" ]]; then return fi done _files } _arguments \ '-c[force screen capture to go to the clipboard]' \ '(-i -J -s -w -W)-b[capture touch bar only non interactive modes]' \ '(-b -i -J -s -w -W)-C[capture the cursor as well as the screen only in non interactive modes]' \ '-d[display errors to the user graphically]' \ '(-b -C)-i[capture screen interactively. ctrl clipboard, space toggle mode, escape cancel]' \ '-m[only capture the main monitor]' \ '-D[screen capture or record from the display specified]:display_number:' \ '(-b -s)-o[in window capture mode, do not capture the shadow of the window]' \ '-p[screen capture will use the default settings for capture]' \ '-M[screen capture output will go to a new Mail message]' \ '-P[screen capture output will open in Preview or QuickTime Player]' \ '-I[screen capture output will open in Messages]' \ '-B[screen capture output will open in app with bundle ID]:bundle_id:' \ '(-b -i -w -W)-s[only allow mouse selection mode]' \ '-S[in window capture mode, capture the screen not the window]' \ '-J+[sets the starting of interactive capture]:style:(selection window video)' \ '(-p)-t[image format to create default is png]:format:(pdf jpg tiff gif)' \ '-T+[take the picture after a delay of seconds]:seconds:' \ '(-b -i -s -W)-w[only allow window selection mode]::->interactive' \ '(-b -i -s -w)-W[start interaction in window selection mode]::->interactive' \ '-x[do not play sounds]' \ '-a[do not include windows attached to selected windows]' \ '-r[do not add dpi meta data to image]' \ '-l[capture this windows ID]:window_id:' \ '(-b -i -s -w -W)-R[capture screen rect]:rect:' \ '(-b)-v[capture video recording of the screen]::->video' \ '-V+[limits video capture to specified seconds]:seconds:' \ '-g[captures audio during a video recording using default input]' \ '-G[captures audio during a video recording using audio ID specified]' \ '-k[show clicks in video recording mode]' \ '-U[Show interactive toolbar in interactive mode]' \ '-u[present UI after screencapture is complete]' \ '*:files:__screencapture_files'
WFH雑感
完全 WFHを初めて早二ヶ月が過ぎた. 結論からいると成果はそれほど上がっていないのだが, その中で私が試したことについて示す. 今月半ばぐらいからぼちぼち改善しているような気はするので引き続き改善を行っていきたい
早寝早起き生活に変えた
オフィスに通っていた頃はひどいときだと朝 3 - 4時ぐらいに寝て, 10時頃に起きて, 1時間ぐらいで仕度してオフィスに行くということをしていたが, 家で仕事をするとなるとだらけてしまい 10時に起きたら仕事のやる気が出てくるのが 13時-14時になってしまってい, 焦りを生んでいたのでそれを改めるために早寝早起き生活にシフトした. 当然突然切り替えられるわけはなかったが, 1ヶ月ぐらいで徐々に早寝早起きできるようになり, 今では 1時までには寝て, 7時程度には起きられるようになった. これで朝だらけたいなぁと思っても 1-2時間の余裕があるので 10時程度には仕事モードに切り替えられるようになり気分的に楽になった.
slackのチャネルからひたすら leave
仕事に直接的に関係ないチャネルからほとんど leaveした. 会社の workspaceも privateで入っている workspaceも. times channel, 雑談チャネル, 会社の偉い人のチャネル, あまり興味ない技術チャネルなどなどひたすら leave. みんな WFHだと雑談チャネルとかオフィスにいたときでは出てこなかった話題がたくさん出て興味深く面白いわけだが, その手のものを見るといくらでも時間を潰せるし, いくらでも気が散るので見ないようにした. 最悪メンションなり DMが来るだろうの精神. 現状だらだらと slackチャネル巡りをするということはほぼなくなった
SNSの見直し
気が散るのもあるが, 時期が時期でありやたらと政治的な意見が増えた人がいる. 語るのは悪くないが, あの人そんな思想だったんだ, とか知りたくもことが多々ありメンタル的にもよくないので, その手の人は積極的に unfollow, blockするなどするようにした. 技術的な知見を得る機会は減るかもしれないが, メンタルがすり減らされるよりはよほどマシである.
ゲームを控える
オフィスに通っていた頃は, オフィスに行けば仕事モードに切り替えられるので, 家でゲームをしても会社でやりたいと思うことは皆無だったが, ずっと家にいると仕事中でも続きが気になるとなってしまい, 仕事が手につかない. 現在ワンルームのせまい部屋で生活しており, ゲーム環境 = 仕事環境であり, 眼の前に switch(+GCコン), PS4(アケコン)がある中で仕事をせざるを得ないのでなるべくゲームのことを考えなく済むようゲームを控えるようにした. (フィットボクシング, リングフィットアドベンチャー除く. FF7Rは買ってまで 2日かやっていないが特に禁断症状的なものは出ていない. 代わりにといってはあれだが, ここ数年間ろくに家で勉強していなかったが, 勉強時間を取るようにした.
その他
上記にあるように現状成果が十分でないことを認めないといけないと考えるが, いつまでもというわけにはいかないし, 自虐的な私は特にそういう状況にいつまでも耐えられると思えないので, 少しずつ改善していきたいと考える.
strlen for string literal
Environment
Sample code
#include <string.h> size_t string_const_size() { return strlen("hello world"); }
Compile with gcc -O0
gcc -O0 -c strlen.c objdump -S strlen.o
strlen.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <string_const_size>: 0: f3 0f 1e fa endbr64 4: 55 push %rbp 5: 48 89 e5 mov %rsp,%rbp 8: b8 0b 00 00 00 mov $0xb,%eax ;; 0xb=11 is string length of "hello world" d: 5d pop %rbp e: c3 retq
strlen
for string literal is calculated at compiling time even if optimization is disabled
Compile with clang -O0
I got same result as gcc
strlen.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <string_const_size>: 0: 55 push %rbp 1: 48 89 e5 mov %rsp,%rbp 4: b8 0b 00 00 00 mov $0xb,%eax ;; here 9: 5d pop %rbp a: c3 retq b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
Compile with gcc -O0 -fno-builtin
It looks strlen
is called
strlen.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <string_const_size>: 0: f3 0f 1e fa endbr64 4: 55 push %rbp 5: 48 89 e5 mov %rsp,%rbp 8: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # f <string_const_size+0xf> f: e8 00 00 00 00 callq 14 <string_const_size+0x14> 14: 5d pop %rbp 15: c3 retq
Summary
I suppose I can use strlen
for litaral string without runtime overhead and I don't need hack as below
const size_t some_length = sizeof("Hello World") -1;
Build GCC 4.9.4 x86_64 on Ubuntu 19.10
Apply patch
libgcc of gcc4.9.4 has issue on newer environment
diff -ur gcc-4.9.4/libgcc/config/i386/linux-unwind.h new-gcc-4.9.4/libgcc/config/i386/linux-unwind.h --- gcc-4.9.4/libgcc/config/i386/linux-unwind.h 2014-01-03 07:25:22.000000000 +0900 +++ new-gcc-4.9.4/libgcc/config/i386/linux-unwind.h 2020-04-17 11:25:54.600423882 +0900 @@ -58,7 +58,7 @@ if (*(unsigned char *)(pc+0) == 0x48 && *(unsigned long long *)(pc+1) == RT_SIGRETURN_SYSCALL) { - struct ucontext *uc_ = context->cfa; + ucontext_t *uc_ = context->cfa; /* The void * cast is necessary to avoid an aliasing warning. The aliasing warning is correct, but should not be a problem because it does not alias anything. */ @@ -138,7 +138,7 @@ siginfo_t *pinfo; void *puc; siginfo_t info; - struct ucontext uc; + ucontext_t ucontext uc; } *rt_ = context->cfa; /* The void * cast is necessary to avoid an aliasing warning. The aliasing warning is correct, but should not be a problem
Configure & make
# apply patch cd gcc-4.9.4 mkdir build cd build ../configure --prefix=$HOME/local/gcc-4.9 --enable-languages=c --disable-multilib --disable-libsanitizer make make install
libsanitaizer of gcc 4.9.4 cannot be built with recent glibc.
Minimum setup for node native module development with VScode
It is difficult to develop node native module without IDE. Because V8 API is difficult to use, complicated, often changed. node-gyp can generate Visual Studio solution file but other IDE is not supported well. I show how to setup writing native module on VScode
Install node headers
Install header files of node.js via node-gyp configure
node header is installed under user cache directory
Set include paths
Do C/C++: Edit configurations (JSON)
via command palette and open c_cpp_properties.json
.
Add above header path to includePath
list
{ "configurations": [ { "name": "Linux", "includePath": [ "${workspaceFolder}/**", "${env:HOME}/.cache/node-gyp/12.16.1/include/node" // 12.16.1 is node version, you need to change to your node version ], "defines": [], "compilerPath": "/usr/bin/clang", "cStandard": "c11", "cppStandard": "c++17", "intelliSenseMode": "clang-x64" } ], "version": 4 }
Screenshot
Enjoy
Disable Git-Bash case-insensitive completion
- Open git bash or command prompt as Admin
- Go to C:\Program Files\Git\etc
- Open inputrc file
- Change default completion-ignore-case value as below
--- inputrc.old 2019-12-13 20:32:51.577869500 +0900 +++ inputrc 2019-12-13 20:32:40.337057100 +0900 @@ -9,7 +9,7 @@ # Ignore case for the command-line-completion functionality # on: default on a Windows style console # off: default on a *nix style console -set completion-ignore-case on +set completion-ignore-case off # disable/enable 8bit input set input-meta on
zipパーサに関するメモ
仕事で zipファイルを展開せずバイナリのまま構造解析する可能性があったため, zipの仕様を調べていました. 仕様については Wikipedia(日本語版は今ひとつわからなかったところがあったので英語版をメインで見た方がよいと思います)等を参照してください. で, パース方法を調べると初めにファイル末尾にある End of central directory record(以下 EOCD)を探して, そこから Central directory file headerを探してごにょごにょするとあったのですが, EOCDには可変長なコメントフィールド(最大 0xffffバイト)があり, それを考慮した上で正しくパースするにはどうすればいいのだろうと思って, 各種言語の zipライブラリを調べてみました. これはそのメモです. 本記事は zip64の内容は含みません. ご注意ください
zip形式の仕様
問題となると考えたケース
- コメント部に別の zipを書き込んだ場合正しくパースできるのか
- validなファイルを invalidと解釈しないか
- 期待しないファイルを展開することはないか(今回未検証)
Go言語の archive/zip
zip.OpenReader
の大雑把な流れは以下のとおりです. 調べたのは Go 1.9の archive/zip
になります.
- EOCDを探す. 探すパターンが 2つあり, 末尾から 1024バイトの位置, 65 * 1024(=66560)バイトの位置から EOCDのマジックナンバを探す.
- マジックナンバが見つかったら, マジックナンバを除いた位置から始まるバイト列で directoryEnd構造体(EOCDに対応)を初期化する
- EOCDから Central directory file headerの先頭オフセットを取得し, 各ファイルの情報を zip.Fileに設定する
- 各ファイルの情報を取得するとき, Central directory file headerのマジックナンバをチェックし, 不正だと
zip.ErrFormat
を返す
特にコメントを意識していないようです.
テスト zipの作成
test.zip(aaa.txtを保持)のコメント部に別の incomment.zip(test.txtを保持)を書き込みます. 期待としては, aaa.txtが展開/名前が取得されます. (zipに含まれる名前が適当すぎますが, それっぽい名前にしてしまうとバイト列が変わってしまうためはじめに作ったこのスクリプトを利用しています)
#!/usr/bin/env python # -*- coding: utf-8 -*- import os import zipfile zip_file = 'test.zip' incomment_file = 'incomment.zip' for f in [zip_file, incomment_file]: if os.path.isfile(f): os.remove(f) with open('test.txt', 'wb') as f: f.write(os.urandom(2048)) # 1024バイト以上の長さになるようにする. incomment_zip = zipfile.ZipFile(incomment_file, mode='w') incomment_zip.write('test.txt') incomment_zip.close() with open('aaa.txt', 'wb') as f: f.write(b'aaa') zf = zipfile.ZipFile(zip_file, mode='w') zf.write('aaa.txt') with open(incomment_file, 'rb') as f: buf = f.read() zf.comment = buf zf.close()
作成した test.zipを archive/zipに与えてみる
以下のような zipに含まれるファイル一覧を表示する Goプログラムに test.zipを与えます.
package main import ( "archive/zip" "fmt" ) func main() { r, err := zip.OpenReader("test.zip") if err != nil { fmt.Println(err) return } for _, f := range r.File { fmt.Println(f.Name) } }
結果は以下のように validでないとエラーが返ります.
% go run main.go zip: not a valid zip file
原因はコメント中の別 zipの Central directory file headerの offsetを元ファイルの先頭から調べたとき, Central directory file headerのマジックナンバではないためです. コメントに関する制約は特にないようなので上で作成した zipは validだと思うのですが, invalidな zipとして判断されてしまいました.
この問題を回避するためにコメント中の zipの Central directory file headerの offsetに元の zipのコメント位置の offsetを加算した値を書き込みます. 下記のカーソル位置から始まる 2byteが Central directory file headerの offsetなのでバイナリエディタ等を使って書き換えます. (上の例だと 0x0826を 0x0899に書き換えます)
再度コマンドを実行してみます. 思惑通りコメント中に書き込んだ zipの方を対象の zipとして認識してくれて text.txtが出力されました.
% go run main.go test.txt
他の言語
中身までは見ていないですが, 試してみる. Goのような実装かもしれないので, 上の offset変更を適用した zipを喰わせます.
Python3(3.6.2)
import zipfile zf = zipfile.ZipFile('test.zip', 'r') print(zf.namelist())
% python3 test.py ['test.txt'] ## コメント中の zipを扱う
Perl(Archive::Zip 1.59)
use strict; use warnings; use Archive::Zip; my $zip = Archive::Zip->new(); $zip->read('test.zip'); print $_, "\n" for $zip->memberNames();
% perl test.pl test.txt ## コメント中の zipを扱う
unzipコマンド(6.00 Ubuntu版)
% unzip -l test.zip Archive: test.zip Length Date Time Name --------- ---------- ----- ---- 2048 2017-10-04 01:06 test.txt --------- ------- 2048 1 file
Goのようにコメント中の zipが扱われてしまうものが多いようです. 手元で正しく動いたのは, macOSの Finder(Archive Utility)だけでした.
なおこれらのプログラムは zip中のファイル名だけでファイルの中身を誤って(??)取得させようとすると Central directory file headerの offsetもそれぞれ修正する必要があるかと思います. これは未検証なので, もしかするとうまくいかないかもしれません. 余裕があれば確認しようかと思います.
最後に
- zipパーサにはコメントを考慮していないものがある.
- そうなっていないのはやはり速度重視だから ?
- ファイル末尾の min(コメントの最大長, ファイルサイズ)から状態(コメント中か否か等)を調べてマジックナンバを探索していけばよさそうなものだが..
- 最初に探すべきデータブロックに可変長なフィールドがあるのはどうなのか.