├── .circleci └── config.yml ├── .gitignore ├── ChangeLog ├── ChangeLog.ja ├── LICENSE ├── README.bsd ├── README.md ├── color.h ├── conf.h ├── ctrlseq ├── csi.h ├── dcs.h ├── esc.h └── osc.h ├── fb ├── common.h ├── freebsd.h ├── linux.h ├── netbsd.h └── openbsd.h ├── fonts ├── milkjf │ ├── README.1ST │ ├── milkjf_8x16.bdf │ ├── milkjf_8x16r.bdf │ └── milkjf_k16.bdf └── terminus │ ├── LICENSE │ └── ter-u16n.bdf ├── glyph_builder.sh ├── img ├── yaft-blue.png ├── yaft-gray.png └── yaft-screenshot.png ├── info ├── yaft.cap └── yaft.src ├── makefile ├── man └── yaft.1 ├── parse.h ├── table ├── ISO10646 ├── ISO8859 ├── JISX0201 ├── JISX0208 ├── X68000 └── alias ├── terminal.h ├── tools ├── bdf.h ├── mkfont_bdf.c ├── mkfont_bdf.h └── util.h ├── util.h ├── x ├── x.h └── yaftx.c ├── yaft.c ├── yaft.h └── yaft_wall /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | docker: 5 | - image: uobikiemukot/archlinux-circleci:latest 6 | steps: 7 | - checkout 8 | - run: 9 | name: build yaft 10 | command: make 11 | - run: 12 | name: build yaftx 13 | command: make yaftx 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.bk 2 | yaft 3 | yaftx 4 | glyph.h 5 | mkfont 6 | mkfont_bdf 7 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | ## 2012-06-19 2 | - version 0.1.0 3 | - initial release 4 | 5 | ## 2012-06-19 6 | - version 0.1.1 7 | - bug fix 8 | 9 | ## 2012-06-20 10 | - version 0.1.2 11 | - bug fix 12 | 13 | ## 2012-06-20 14 | - version 0.1.3 15 | - bug fix 16 | 17 | ## 2012-06-21 18 | - version 0.1.4 19 | - add eat_newline_glitch (xel) 20 | - remove auto_right_margin (bw) 21 | - remove OSC 4 (ccc, initc) 22 | 23 | ## 2012-06-24 24 | - version 0.1.5 25 | - change fonts format 26 | - fix glyph drawing 27 | - change effects of BOLD and REVERSE 28 | 29 | ## 2012-06-29 30 | - version 0.1.6 31 | - support more than one font 32 | - support glyph alias 33 | 34 | ## 2012-10-06 35 | - version 0.1.7 36 | - support following framebuffer types: 37 | - 15/16/24/32bpp true color (and maybe direct color) 38 | - 8bpp pseudo color 39 | 40 | ## 2012-10-17 41 | - version 0.1.8 42 | - add some opitons 43 | - yaft reads environment value, YAFT 44 | - wall: display wallpaper 45 | - w=N: set terminal width (pixel) 46 | - h=N: set terminal height (pixel) 47 | - x=N: set x offset 48 | - y=N: set y offset 49 | 50 | ~~~ 51 | $ export YAFT="wall w=640 h=384 x=32 y=32"; yaft 52 | ~~~ 53 | 54 | ## 2012-10-18 55 | - version 0.1.9 56 | - add some codes related to virtual console 57 | - remove all optios without "YAFT=wall" 58 | 59 | ## 2012-11-09 60 | - version 0.2.0 61 | - support BDF 62 | 63 | ~~~ 64 | $ ./mkfont alias-file your/favorite/bdf > glyph.h 65 | $ make yaft 66 | ~~~ 67 | 68 | ## 2012-11-30 69 | - version 0.2.1 70 | - bug fix 71 | - single CSI u (not following CSI s) causes Segmentation fault (reported by saitoha ([@kefir_])) 72 | 73 | [@kefir_]: http://saitoha.github.com/ 74 | 75 | ## 2012-12-02 76 | - version 0.2.2 77 | - improve UTF-8 parser (valid for [UTF-8 decoder capability and stress test]) 78 | - bug fix 79 | - not working glyph substitution 80 | 81 | [UTF-8 decoder capability and stress test]: http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt 82 | 83 | ## 2012-12-19 84 | - version 0.2.3 85 | - bug fix 86 | - wrong behavior of bce (ED, EL, DL, IL, ICH, DCH, ECH) (reported by IWAMOTO Kouichi ([@ttdoda])) 87 | 88 | [@ttdoda]: http://doda.teraterm.org/whoami.xhtm 89 | 90 | ## 2014-03-07 91 | - version 0.2.4 92 | - add some parameters in conf.h 93 | - ROTATE: NORMAL or CLOCKWISE or COUNTER_CLOCKWISE or UPSIDE_DOWN 94 | - LAZY_DRAW (reduce drawing) 95 | - BACKGROUND_DRAW (after vt switch, continue drawing) 96 | 97 | ## 2014-03-24 98 | - version 0.2.5 99 | - remove ROTATE, LAZY_DRAW, BACKGROUND_DRAW options 100 | - add some environment options 101 | - rotate: clockwise (cw), counter_clockwise (ccw), upside_down (ud) 102 | - background drawing: wallpaper (wall) 103 | ex) $ YAFT="wall cw ccw ud" yaft 104 | - framebuffer device: 105 | ex) $ FRAMEBUFFER="/dev/fb1" yaft 106 | - add OSC4/OSC104/OSC8900 (glyph width report) 107 | (ref: http://uobikiemukot.github.io/yaft/glyph_width_report.html) 108 | 109 | ## 2014-05-16 110 | - version 0.2.6 111 | - remove rotate option 112 | - support glyph width report rev.3 113 | (ref: http://uobikiemukot.github.io/yaft/glyph_width_report.html) 114 | - support DRCS/DRCSMMv1 115 | - bug fix 116 | - never refresh cmap at vt switch (8bpp mode) 117 | 118 | ## 2014-05-18 119 | - version 0.2.7 120 | - support xim (yaftx) 121 | 122 | ## 2014-08-27 123 | - version 0.2.8 124 | - support sixel 125 | - support copy/paste (yaftx) 126 | - support NetBSD/OpenBSD wscons 127 | - refer SHELL environment variable 128 | - remove WALLPAPER option (use YAFT="wall" environment variable) 129 | - add man page 130 | 131 | ## 2015-07-26 132 | - version 0.2.8 133 | - rewrite framebuffer code 134 | - support direct color 135 | - add some new options (conf.h) 136 | VT_CONTROL : don't handle vt-switching (vt-switching only works in linux) 137 | FORCE_TEXT_MODE: need this option for switching from X to yaft 138 | - various bug fixes 139 | - mkfont_bdf was broken (not affect SUBSTITUTE_WIDE/REPLACEMENT_CHAR) 140 | -------------------------------------------------------------------------------- /ChangeLog.ja: -------------------------------------------------------------------------------- 1 | 2012-06-19 haru 2 | * version 0.1.0 3 | * 試験的に公開 4 | 5 | 2012-06-19 haru 6 | * version 0.1.1 7 | * 細かなバグ修正 8 | * UCS_CHARSの値が要素数+1になってなかったのを修正 (common.h) 9 | * esc_func, csi_func, osc_funcも同様に配列の要素数が1足りなかったのを修正 (common.h) 10 | * parse_esc()の実体参照(*argc)がargcになってたのを修正 (parse.h) 11 | * dumpするときにstdoutのバッファリングを無効にするようにした (yaft.c) 12 | * delete_line(), erase_line()でスクロールが発生するときにDECSTBMの設定が反映されてなかったのを修正 (function.h) 13 | 14 | 2012-06-20 haru 15 | * version 0.1.2 16 | * 設定やフォントに不備があった場合に回避できないか頑張ってみることにした 17 | * 端末のサイズ(TERM_WIDTH/TERM_HEIGHT)が不正な場合にはフルスクリーンで起動する (yaft.c, terminal.h) 18 | * DEFAULT_CHARが見つからない場合にはSPACEを流用してみる (load.h) 19 | * コメントを追加 (common.h) 20 | * terminfoの別名を定義した (info/yaft.info) 21 | 22 | 2012-06-20 haru 23 | * version 0.1.3 24 | * 背景画像の表示方法をfbtermと同等のものに変更した (load.h, conf.h) 25 | * framebufferの書き込みアドレスがおかしかったのを修正した (framebuffer.h) 26 | * writeのエラー処理を真面目にやるようにした (util.h) 27 | * 色を定義する箇所が重複していたのをまとめた (color.h) 28 | * 端末のサイズとしてcell_sizeよりも小さなサイズは指定できないようにした (terminal.h) 29 | * 上記の修正に伴って色々変更.DEFAULT_CHARはSPACEにした (common.h) 30 | 31 | 2012-06-21 haru 32 | * version 0.1.4 33 | * indent -kr -ut -ts4 な感じのスタイルで書くことにした 34 | * gcc -std=c99 -pedantic -Wall -Os で通るように色々書き換えた 35 | * eat_newline_glitch(xel)を実装した (terminal.h) 36 | * auto_right_margin(bw)を廃止した (terminal.h, function.h) 37 | * OSCを廃止した (parse.h, function.h) 38 | * 上記の変更に伴ってterminfoを更新 (info/yaft.src) 39 | 40 | 2012-06-24 haru 41 | * version 0.1.5 42 | * スタイルはたぶん元に戻した 43 | * mplus fontをsampleとして追加 44 | * フォントの形式がおかしかったのでBDFと完全に互換なものに直した (load.h, framebuffer.h) 45 | * 8x16dotのフォント以外では正常に描画できていなかったのを修正した (load.h, framebuffer.h) 46 | * BOLD/REVERSEの処理方法を変更した (terminal.h, framebuffer.h) 47 | * 色の参照方法を変更した (function.h, framebuffer.h, conf.h) 48 | * その他色々? 49 | 50 | 2012-06-29 haru 51 | * version 0.1.6 52 | * フォントを複数指定できるようにした(load.h, terminal.h, conf.h) 53 | (一部のグリフしかない場合に使用するメモリが減った) 54 | * グリフの代用を指定できるようにした(load.h, terminal.h, conf.h) 55 | * その他ちょっとした修正等 56 | 57 | 2012-10-06 haru 58 | * version 0.1.7 59 | * 以下のframebuffer環境に対応した (framebuffer.h) 60 | 15/16/24/32bpp True Color(Direct Colorにもたぶん対応) 61 | 8bpp Pseudo Color 62 | 63 | 2012-10-17 haru 64 | * version 0.1.8 65 | * いくつかのoptionを追加 (yaft.c) 66 | 例) $ export YAFT="wall w=640 h=384 x=32 y=32"; yaft 67 | wall: display wallpaper 68 | w=N: set terminal width (pixel) 69 | h=N: set terminal height (pixel) 70 | x=N: set x offset 71 | y=N: set y offset 72 | 73 | 2012-10-18 haru 74 | * version 0.1.9 75 | * 仮想コンソールの切り替え時にyaftの停止・再描画を行う用にした (yaft.c) 76 | * 壁紙を表示するときの環境変数の設定の仕方がちょっと変わった (yaft.c) 77 | * 壁紙以外のoptionを廃止した 78 | * 他にもたぶん色々 79 | 80 | 2012-11-09 haru 81 | * version 0.2.0 82 | * 独自フォントを廃止してBDFを使うようにした 83 | ex) 84 | $ ./mkfont alias-file your/favorite/bdf > glyph.h 85 | $ make yaft 86 | 87 | 2012-11-30 88 | - version 0.2.1 89 | - bug fix 90 | - single CSI u (not following CSI s) causes Segmentation fault (reported by saitoha ([@kefir_])) 91 | 92 | [@kefir_]: http://saitoha.github.com/ 93 | 94 | 2012-12-02 95 | - version 0.2.2 96 | - improved UTF-8 parser (valid for [UTF-8 decoder capability and stress test]) 97 | - bug fix 98 | - not working glyph substitution 99 | 100 | [UTF-8 decoder capability and stress test]: http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt 101 | 102 | 2012-12-19 103 | - version 0.2.3 104 | - bug fix 105 | - wrong behavior of bce (ED, EL, DL, IL, ICH, DCH, ECH) (reported by IWAMOTO Kouichi ([@ttdoda])) 106 | 107 | [@ttdoda]: http://doda.teraterm.org/whoami.xhtm 108 | 109 | 2014-03-07 haru 110 | * version 0.2.4 111 | * conf.hにいくつかの設定を追加 112 | * ROTATE = NORMAL or CLOCKWISE or COUNTER_CLOCKWISE or UPSIDE_DOWN 113 | * LAZY_DRAW(データ量が多いときに描画を抑制する)を追加 114 | * BACKGROUND_DRAW(VT切り替え後も描画を続ける)を追加 115 | * struct terminalのoffsetを削除 116 | 117 | 2014-03-24 118 | * version 0.2.5 119 | * BACKGROUND_DRAW, ROTATEの設定をconf.hでなく環境変数YAFTでするようにした 120 | (実行時に変更する必要がないと思われるものは相変わらずconf.hで指定) 121 | * 環境変数YAFTで有効なオプション 122 | wall: 背景画像を有効にする 123 | background or bg: activeになっていないVTでも描画を続ける(2画面用) 124 | clockwise or cw: 90度描画を回転 125 | counter_clockwise or ccw: 270度描画を回転 126 | upside_down or ud: 180度描画を回転 127 | ex) YAFT="wall cw bg" yaft 128 | * 環境変数FRAMEBUFFER 129 | framebuffer deviceを指定する 130 | ex) FRAMEBUFFER="/dev/fb0" yaft 131 | * 幾つかのOSCを実装した 132 | OSC 4: color paletteの変更 133 | 色の設定(rgbの指定は1-4桁) 134 | OSC 4 ; c ; rgb:rr/gg/bb ST 135 | OSC 4 ; c ; #rrggbb ST 136 | c番目の色設定の応答 137 | request 138 | OSC 4 ; c ; ? ST 139 | response 140 | OSC 4 ; c ; rgb:rr/gg/bb ST 141 | OSC 104: color paletteの初期化 142 | c番目の色を初期化 143 | OSC 104 ; c ST 144 | 全ての色を初期化 145 | OSC 104 ST 146 | OSC 8900: glyph width report 147 | requestの際にwidth, from, toの指定を強制するようにした 148 | * request * 149 | OSC 8900 ; Ps ; ? : Pw : Pf : Pt ST 150 | Ps: reserved 151 | Pw: width (0 or 1 or 2) 152 | Pf: beginning of unicode code point 153 | Pt: end of unicode code point 154 | ST: BEL(0x07) or ESC(0x1B) BACKSLASH(0x5C) 155 | * answer * 156 | OSC 8900 ; Ps ; Pt ; Pf : Pt ; Pf : Pt ; ... ST 157 | Ps: responce code 158 | 0: ok (default) 159 | 1: recognized but not supported 160 | 2: not recognized 161 | Pt: reserved (maybe East Asian Width Version) 162 | 163 | Pf: beginning of unicode code point 164 | Pt: end of unicode code point 165 | ST: BEL(0x07) or ESC(0x1B) BACKSLASH(0x5C) 166 | (ref) 167 | http://uobikiemukot.github.io/yaft/glyph_width_report.html 168 | https://gist.github.com/saitoha/8767268 169 | * コードを色々整理した 170 | 171 | 2014-05-16 172 | * version 0.2.6 173 | * rorateオプションを消した 174 | * glyph.hの書式を変更 (フォントによってはyaftのバイナリがかなり小さく) 175 | * それに伴いtools/以下のソースを書き換え 176 | * glyph width report rev.3 に対応 (ref: http://uobikiemukot.github.io/yaft/glyph_width_report.html) 177 | * DRCSの領域(Unicode Private Area)の応答にはまだ未対応 178 | * DRCS/DRCSMMv1に試験的に対応 (無視しているパラメータが多いので注意) 179 | * yaftにはSCS(Select Character Set)が実装されていないので常にDRCSMMv1が有効 180 | * OSC/DCSはソースファイルを分離 (osc.h, dcs.h) 181 | * 8bpp時にVT switchが起きてもcmapを復元していなかったのを修正 182 | * その他にも色々コードを整理 183 | 184 | 2014-05-18 185 | * version 0.2.7 186 | * 主にX版(yaftx)の修正 187 | * ximが使えるようにした (scimのみで動作確認) 188 | * 描画の処理をfb版に合わせて修正 189 | * resizeの度にmalloc/freeをしていたのを止めた 190 | * ioctl(TIOCSWINSZ)の位置おかしかったのを修正 191 | * perror()の前にerrnoをちゃんと初期化するようにした (util.h) 192 | * forkpty(), openpty()を書き直した (util.h) 193 | * X版でMod1Mask(Alt)の修飾キーが効かなかったのを修正 (thanks to @H_Kobo) 194 | * Alt + [Up/Down/Left/Right]等の特殊キーに対応 195 | * XIMのinput styleの選択方法がバグってたのを修正 196 | * eopenpty()でcompilerのwarningが出る箇所を修正 (util.h) 197 | 198 | 2014-08-27 199 | * version 0.2.8 200 | * sixelのサポートを追加 201 | * マウスによるコピー/ペイストに対応 (yaftx) 202 | * NetBSD/OpenBSDのサポート 203 | * 環境変数SHELLを見るように (conf.hのshell_cmdよりも優先) 204 | * WALLPAPERオプションをconf.hから削除 (代わりにYAFT="wall"という環境変数を見るように) 205 | * man pageを作成 206 | 207 | 2015-07-26 208 | * version 0.2.8 209 | * フレームバッファ関連のコードを書き直した 210 | * direct colorをサポート (古いradeonのグラボ等で用いられる) 211 | * 幾つかのオプションを追加 212 | VT_CONTROL : vt switchingの処理を行わない (linux以外ではたぶん処理しなくても良い) 213 | FORCE_TEXT_MODE: KD_GRAPHICSへ変更しない (linux consoleの描画と競合するるが,Xとyaftを切り替える場合には必要) 214 | * 色々なバグ修正 215 | * mkfont_bdfによるフォント生成の不具合等 216 | * コードのrefine 217 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012 haru 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.bsd: -------------------------------------------------------------------------------- 1 | # yaft (yet another framebuffer terminal) 2 | 3 | ## test environment 4 | 5 | using qemu (i386, vga cirrus) 6 | 7 | - FreeBSD 10.1 8 | - OpenBSD 5.7 9 | - NetBSD 6.1.5 10 | 11 | ## FreeBSD 12 | 13 | ### kernel rebuild 14 | 15 | edit /usr/src/sys/i386/conf/GENERIC 16 | 17 | ~~~ 18 | options VESA 19 | options SC_PIXEL_MODE 20 | ~~~ 21 | 22 | build 23 | 24 | ~~~ 25 | # cd /usr/src 26 | # make buildkernel 27 | # make installkernel 28 | ~~~ 29 | 30 | ### module load (no kernel rebuild) 31 | 32 | ~~~ 33 | # kldload vesa 34 | # echo "vesa_load=\"YES\"" >> /boot/loader.conf 35 | ~~~ 36 | 37 | ### vesa mode 38 | 39 | check available mode 40 | 41 | ~~~ 42 | # vidcontrol -i mode 43 | ~~~ 44 | 45 | change mode 46 | 47 | ~~~ 48 | # vidcontrol MODE_XXX 49 | # echo "allscreens_flags=\"MODE_XXX\"" >> /etc/rc.conf 50 | ~~~ 51 | 52 | ### keyrepeat 53 | 54 | ~~~ 55 | # kbdcontrol -r fast 56 | ~~~ 57 | 58 | ### write-combine 59 | 60 | ~~~ 61 | # memcontrol set -b 0xe0000000 -l 0x10000000 -o SVGA write-combine 62 | ~~~ 63 | 64 | ## NetBSD 65 | 66 | ### vesa mode 67 | 68 | check available mode 69 | 70 | ~~~ 71 | (boot prompt) 72 | > vesa list 73 | ~~~ 74 | 75 | edit /boot.cfg 76 | 77 | ~~~ 78 | menu=Boot normally:rndseed /var/db/entropy-file;vesa 1024x768x32;boot netbsd 79 | ~~~ 80 | 81 | ### key repeat 82 | 83 | ~~~ 84 | # wsconsctl -w repeat.del1=200 repeat.deln=50 85 | ~~~ 86 | 87 | ~~~ 88 | # echo "setvar repeat.del1=200" >> /etc/wscons.conf 89 | # echo "setvar repeat.deln=50" >> /etc/wscons.conf 90 | ~~~ 91 | 92 | ## OpenBSD 93 | 94 | ### kernel 95 | 96 | - patch http://mlterm.sf.net/openbsd-5.3-fixvesa.patch 97 | 98 | edit /usr/src/sys/arch/i386/conf/GENERIC 99 | 100 | ~~~ 101 | vesabios0 at mainbus? 102 | option VESAFB 103 | ~~~ 104 | 105 | build 106 | 107 | ~~~ 108 | # cd /usr/src/sys/arch/i386/compile/GENERIC 109 | # make clean && make depend && make 110 | # make install 111 | # reboot 112 | ~~~ 113 | 114 | ### change vesa mode 115 | 116 | edit yaft/fb/openbsd.h 117 | 118 | ~~~ 119 | enum { 120 | FB_WIDTH = 640, 121 | FB_HEIGHT = 480, 122 | FB_DEPTH = 8, 123 | }; 124 | ~~~ 125 | 126 | ### key repeat 127 | 128 | ~~~ 129 | # wsconsctl -w repeat.del1=200 repeat.deln=50 130 | ~~~ 131 | 132 | ~~~ 133 | # echo "setvar repeat.del1=200" >> /etc/wscons.conf 134 | # echo "setvar repeat.deln=50" >> /etc/wscons.conf 135 | ~~~ 136 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # yaft (yet another framebuffer terminal) 2 | 3 | | Branch | Badge | 4 | | :--: | :--: | 5 | | master | [![CircleCI](https://circleci.com/gh/uobikiemukot/yaft.svg?style=svg)](https://circleci.com/gh/uobikiemukot/yaft) | 6 | | develop | [![CircleCI](https://circleci.com/gh/uobikiemukot/yaft/tree/develop.svg?style=svg)](https://circleci.com/gh/uobikiemukot/yaft/tree/develop) | 7 | 8 | Last update: Wed Mar 14 18:44:27 JST 2018 9 | 10 | ## description 11 | 12 | Yet Another Framebuffer Terminal (aka "yaft") is simple terminal emulator for minimalist. 13 | 14 | Features: 15 | 16 | + various framebuffer types (8/15/16/24/32bpp) 17 | + compatible with vt102 and Linux console ([detail](http://uobikiemukot.github.io/yaft/escape.html)) 18 | + UTF-8 encoding and UCS2 glyphs 19 | + 256 colors (same as xterm) 20 | + wallpaper 21 | + DRCS (DECDLD/DRCSMMv1) (experimental) 22 | + sixel (experimental) 23 | 24 | There are Several ports: 25 | 26 | - yaft for framebuffer console 27 | - Linux console 28 | - FreeBSD console 29 | - NetBSD/OpenBSD wscons (experimental) 30 | - yaftx for X Window System 31 | - [yaft-android](https://github.com/uobikiemukot/yaft-android) for Android 32 | 33 | ## download 34 | 35 | - [yaft-0.2.9.tar.gz](https://github.com/uobikiemukot/yaft/archive/v0.2.9.tar.gz) 36 | 37 | ## configuration 38 | 39 | If you want to change configuration, rewrite "conf.h". 40 | 41 | ## environment variables 42 | 43 | - FRAMEBUFFER=/dev/fb0: specify farmebuffer device 44 | - YAFT="wall": use current background as wallpaper (need [idump](https://github.com/uobikiemukot/idump) or fbv) 45 | 46 | ~~~ 47 | $ idump /path/to/wallpaper.png; tput civis; YAFT="wall" FRAMEBUFFER="/dev/fb1" yaft 48 | ~~~ 49 | 50 | ## how to use your favorite fonts 51 | 52 | You can use tools/mkfont_bdf to create "glyph.h". 53 | 54 | usage: tools/mkfont_bdf ALIAS_FILE BDF1 BDF2 BDF3 ... > glyph.h 55 | 56 | - ALIAS_FILE: glyph substitution rule file (see table/alias) 57 | - BDF1, BDF2, BDF3...: bdf files 58 | + yaft supports only "monospace" bdf font 59 | + you can specify mulitiple bdf fonts (but these fonts MUST be the same size) 60 | + If there is more than one glyph of the same codepoint, the glyph included in the FIRST bdf file is choosed 61 | 62 | ~~~ 63 | $ ./mkfont_bdf table/your_alias your/favorite/fonts.bdf > glyph.h 64 | ~~~ 65 | 66 | Or try glyph_builder.sh (bash script for creating yaft's glyph.h) 67 | 68 | - supported fonts: mplus, efont, milkjf, unifont, dina, terminus, profont, tamsyn 69 | 70 | ## build and install 71 | 72 | BSD users should check README.bsd 73 | 74 | ~~~ 75 | $ export LANG=en_US.UTF-8 # yaft uses libc's wcwidth for calculating glyph width 76 | $ make 77 | # make install 78 | or 79 | $ make yaftx 80 | # make installx 81 | ~~~ 82 | 83 | ## screenshot 84 | 85 | ![screenshot1](http://uobikiemukot.github.io/img/yaft-screenshot.png) 86 | 87 | ## license 88 | The MIT License (MIT) 89 | 90 | Copyright (c) 2012 haru (uobikiemukot at gmail dot com) 91 | 92 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 93 | 94 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 95 | 96 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 97 | -------------------------------------------------------------------------------- /color.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE for licence details. */ 2 | /* 3 | Standard VGA colors 4 | http://en.wikipedia.org/wiki/ANSI_escape_code 5 | 6 | xterm 256color 7 | http://www.calmar.ws/vim/256-xterm-24bit-rgb-color-chart.html 8 | http://jonasjacek.github.io/colors/ 9 | 10 | byte order: (MSB) RR GG BB (LSB) 11 | */ 12 | enum { 13 | COLORS = 256, /* number of color palette */ 14 | BITS_PER_RGB = 8, 15 | }; 16 | 17 | const uint32_t color_list[COLORS] = { 18 | /* system color: 16 */ 19 | 0x000000, 0xAA0000, 0x00AA00, 0xAA5500, 0x0000AA, 0xAA00AA, 0x00AAAA, 0xAAAAAA/* 0xAAAAAA */, 20 | 0x555555, 0xFF5555, 0x55FF55, 0xFFFF55, 0x5555FF, 0xFF55FF, 0x55FFFF, 0xDFDFDF/* 0xFFFFFF */, 21 | /* color cube: 216 */ 22 | 0x000000, 0x00005F, 0x000087, 0x0000AF, 0x0000D7, 0x0000FF, 0x005F00, 0x005F5F, 23 | 0x005F87, 0x005FAF, 0x005FD7, 0x005FFF, 0x008700, 0x00875F, 0x008787, 0x0087AF, 24 | 0x0087D7, 0x0087FF, 0x00AF00, 0x00AF5F, 0x00AF87, 0x00AFAF, 0x00AFD7, 0x00AFFF, 25 | 0x00D700, 0x00D75F, 0x00D787, 0x00D7AF, 0x00D7D7, 0x00D7FF, 0x00FF00, 0x00FF5F, 26 | 0x00FF87, 0x00FFAF, 0x00FFD7, 0x00FFFF, 0x5F0000, 0x5F005F, 0x5F0087, 0x5F00AF, 27 | 0x5F00D7, 0x5F00FF, 0x5F5F00, 0x5F5F5F, 0x5F5F87, 0x5F5FAF, 0x5F5FD7, 0x5F5FFF, 28 | 0x5F8700, 0x5F875F, 0x5F8787, 0x5F87AF, 0x5F87D7, 0x5F87FF, 0x5FAF00, 0x5FAF5F, 29 | 0x5FAF87, 0x5FAFAF, 0x5FAFD7, 0x5FAFFF, 0x5FD700, 0x5FD75F, 0x5FD787, 0x5FD7AF, 30 | 0x5FD7D7, 0x5FD7FF, 0x5FFF00, 0x5FFF5F, 0x5FFF87, 0x5FFFAF, 0x5FFFD7, 0x5FFFFF, 31 | 0x870000, 0x87005F, 0x870087, 0x8700AF, 0x8700D7, 0x8700FF, 0x875F00, 0x875F5F, 32 | 0x875F87, 0x875FAF, 0x875FD7, 0x875FFF, 0x878700, 0x87875F, 0x878787, 0x8787AF, 33 | 0x8787D7, 0x8787FF, 0x87AF00, 0x87AF5F, 0x87AF87, 0x87AFAF, 0x87AFD7, 0x87AFFF, 34 | 0x87D700, 0x87D75F, 0x87D787, 0x87D7AF, 0x87D7D7, 0x87D7FF, 0x87FF00, 0x87FF5F, 35 | 0x87FF87, 0x87FFAF, 0x87FFD7, 0x87FFFF, 0xAF0000, 0xAF005F, 0xAF0087, 0xAF00AF, 36 | 0xAF00D7, 0xAF00FF, 0xAF5F00, 0xAF5F5F, 0xAF5F87, 0xAF5FAF, 0xAF5FD7, 0xAF5FFF, 37 | 0xAF8700, 0xAF875F, 0xAF8787, 0xAF87AF, 0xAF87D7, 0xAF87FF, 0xAFAF00, 0xAFAF5F, 38 | 0xAFAF87, 0xAFAFAF, 0xAFAFD7, 0xAFAFFF, 0xAFD700, 0xAFD75F, 0xAFD787, 0xAFD7AF, 39 | 0xAFD7D7, 0xAFD7FF, 0xAFFF00, 0xAFFF5F, 0xAFFF87, 0xAFFFAF, 0xAFFFD7, 0xAFFFFF, 40 | 0xD70000, 0xD7005F, 0xD70087, 0xD700AF, 0xD700D7, 0xD700FF, 0xD75F00, 0xD75F5F, 41 | 0xD75F87, 0xD75FAF, 0xD75FD7, 0xD75FFF, 0xD78700, 0xD7875F, 0xD78787, 0xD787AF, 42 | 0xD787D7, 0xD787FF, 0xD7AF00, 0xD7AF5F, 0xD7AF87, 0xD7AFAF, 0xD7AFD7, 0xD7AFFF, 43 | 0xD7D700, 0xD7D75F, 0xD7D787, 0xD7D7AF, 0xD7D7D7, 0xD7D7FF, 0xD7FF00, 0xD7FF5F, 44 | 0xD7FF87, 0xD7FFAF, 0xD7FFD7, 0xD7FFFF, 0xFF0000, 0xFF005F, 0xFF0087, 0xFF00AF, 45 | 0xFF00D7, 0xFF00FF, 0xFF5F00, 0xFF5F5F, 0xFF5F87, 0xFF5FAF, 0xFF5FD7, 0xFF5FFF, 46 | 0xFF8700, 0xFF875F, 0xFF8787, 0xFF87AF, 0xFF87D7, 0xFF87FF, 0xFFAF00, 0xFFAF5F, 47 | 0xFFAF87, 0xFFAFAF, 0xFFAFD7, 0xFFAFFF, 0xFFD700, 0xFFD75F, 0xFFD787, 0xFFD7AF, 48 | 0xFFD7D7, 0xFFD7FF, 0xFFFF00, 0xFFFF5F, 0xFFFF87, 0xFFFFAF, 0xFFFFD7, 0xFFFFFF, 49 | /* gray scale: 24 */ 50 | 0x080808, 0x121212, 0x1C1C1C, 0x262626, 0x303030, 0x3A3A3A, 0x444444, 0x4E4E4E, 51 | 0x585858, 0x626262, 0x6C6C6C, 0x767676, 0x808080, 0x8A8A8A, 0x949494, 0x9E9E9E, 52 | 0xA8A8A8, 0xB2B2B2, 0xBCBCBC, 0xC6C6C6, 0xD0D0D0, 0xDADADA, 0xE4E4E4, 0xEEEEEE, 53 | }; 54 | -------------------------------------------------------------------------------- /conf.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE for licence details. */ 2 | /* conf.h: define custom variables */ 3 | 4 | /* color: index number of color_palette[] (see color.h) */ 5 | enum { 6 | DEFAULT_FG = 7, 7 | DEFAULT_BG = 0, 8 | ACTIVE_CURSOR_COLOR = 2, 9 | PASSIVE_CURSOR_COLOR = 1, 10 | }; 11 | 12 | /* misc */ 13 | enum { 14 | VERBOSE = false, /* write dump of input to stdout, debug message to stderr */ 15 | TABSTOP = 8, /* hardware tabstop */ 16 | LAZY_DRAW = true, /* don't draw when input data size is larger than BUFSIZE */ 17 | BACKGROUND_DRAW = false, /* always draw even if vt is not active */ 18 | VT_CONTROL = true, /* handle vt switching */ 19 | FORCE_TEXT_MODE = false, /* force KD_TEXT mode (not use KD_GRAPHICS mode) */ 20 | SUBSTITUTE_HALF = 0x0020, /* used for missing glyph(single width): U+0020 (SPACE) */ 21 | SUBSTITUTE_WIDE = 0x3000, /* used for missing glyph(double width): U+3000 (IDEOGRAPHIC SPACE) */ 22 | REPLACEMENT_CHAR = 0x003F, /* used for malformed UTF-8 sequence : U+003F (QUESTION MARK) */ 23 | }; 24 | 25 | /* TERM value */ 26 | const char *term_name = "yaft-256color"; 27 | 28 | /* framubuffer device */ 29 | #if defined(__linux__) 30 | const char *fb_path = "/dev/fb0"; 31 | #elif defined(__FreeBSD__) 32 | const char *fb_path = "/dev/ttyv0"; 33 | #elif defined(__NetBSD__) 34 | const char *fb_path = "/dev/ttyE0"; 35 | #elif defined(__OpenBSD__) 36 | const char *fb_path = "/dev/ttyC0"; 37 | #elif defined(__ANDROID__) 38 | const char *fb_path = "/dev/graphics/fb0"; 39 | #endif 40 | 41 | /* shell */ 42 | #if defined(__linux__) || defined(__MACH__) 43 | const char *shell_cmd = "/bin/bash"; 44 | #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) 45 | const char *shell_cmd = "/bin/csh"; 46 | #elif defined(__ANDROID__) 47 | const char *shell_cmd = "/system/bin/sh"; 48 | #endif 49 | -------------------------------------------------------------------------------- /ctrlseq/csi.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE for licence details. */ 2 | /* function for csi sequence */ 3 | void insert_blank(struct terminal_t *term, struct parm_t *parm) 4 | { 5 | int i, num = sum(parm); 6 | 7 | if (num <= 0) 8 | num = 1; 9 | 10 | for (i = term->cols - 1; term->cursor.x <= i; i--) { 11 | if (term->cursor.x <= (i - num)) 12 | copy_cell(term, term->cursor.y, i, term->cursor.y, i - num); 13 | else 14 | erase_cell(term, term->cursor.y, i); 15 | } 16 | } 17 | 18 | void curs_up(struct terminal_t *term, struct parm_t *parm) 19 | { 20 | int num = sum(parm); 21 | 22 | if (num <= 0) 23 | num = 1; 24 | 25 | move_cursor(term, -num, 0); 26 | } 27 | 28 | void curs_down(struct terminal_t *term, struct parm_t *parm) 29 | { 30 | int num = sum(parm); 31 | 32 | if (num <= 0) 33 | num = 1; 34 | 35 | move_cursor(term, num, 0); 36 | } 37 | 38 | void curs_forward(struct terminal_t *term, struct parm_t *parm) 39 | { 40 | int num = sum(parm); 41 | 42 | if (num <= 0) 43 | num = 1; 44 | 45 | move_cursor(term, 0, num); 46 | } 47 | 48 | void curs_back(struct terminal_t *term, struct parm_t *parm) 49 | { 50 | int num = sum(parm); 51 | 52 | if (num <= 0) 53 | num = 1; 54 | 55 | move_cursor(term, 0, -num); 56 | } 57 | 58 | void curs_nl(struct terminal_t *term, struct parm_t *parm) 59 | { 60 | int num = sum(parm); 61 | 62 | if (num <= 0) 63 | num = 1; 64 | 65 | move_cursor(term, num, 0); 66 | cr(term); 67 | } 68 | 69 | void curs_pl(struct terminal_t *term, struct parm_t *parm) 70 | { 71 | int num = sum(parm); 72 | 73 | if (num <= 0) 74 | num = 1; 75 | 76 | move_cursor(term, -num, 0); 77 | cr(term); 78 | } 79 | 80 | void curs_col(struct terminal_t *term, struct parm_t *parm) 81 | { 82 | int num; 83 | 84 | num = (parm->argc <= 0) ? 0: dec2num(parm->argv[parm->argc - 1]) - 1; 85 | set_cursor(term, term->cursor.y, num); 86 | } 87 | 88 | void curs_pos(struct terminal_t *term, struct parm_t *parm) 89 | { 90 | int line, col; 91 | 92 | if (parm->argc <= 0) { 93 | line = col = 0; 94 | } else if (parm->argc == 2) { 95 | line = dec2num(parm->argv[0]) - 1; 96 | col = dec2num(parm->argv[1]) - 1; 97 | } else { 98 | return; 99 | } 100 | 101 | if (line < 0) 102 | line = 0; 103 | if (col < 0) 104 | col = 0; 105 | 106 | set_cursor(term, line, col); 107 | } 108 | 109 | void curs_line(struct terminal_t *term, struct parm_t *parm) 110 | { 111 | int num; 112 | 113 | num = (parm->argc <= 0) ? 0: dec2num(parm->argv[parm->argc - 1]) - 1; 114 | set_cursor(term, num, term->cursor.x); 115 | } 116 | 117 | void erase_display(struct terminal_t *term, struct parm_t *parm) 118 | { 119 | int i, j, mode; 120 | 121 | mode = (parm->argc <= 0) ? 0: dec2num(parm->argv[parm->argc - 1]); 122 | 123 | if (mode < 0 || 2 < mode) 124 | return; 125 | 126 | if (mode == 0) { 127 | for (i = term->cursor.y; i < term->lines; i++) 128 | for (j = 0; j < term->cols; j++) 129 | if (i > term->cursor.y || (i == term->cursor.y && j >= term->cursor.x)) 130 | erase_cell(term, i, j); 131 | } else if (mode == 1) { 132 | for (i = 0; i <= term->cursor.y; i++) 133 | for (j = 0; j < term->cols; j++) 134 | if (i < term->cursor.y || (i == term->cursor.y && j <= term->cursor.x)) 135 | erase_cell(term, i, j); 136 | } else if (mode == 2) { 137 | for (i = 0; i < term->lines; i++) 138 | for (j = 0; j < term->cols; j++) 139 | erase_cell(term, i, j); 140 | } 141 | } 142 | 143 | void erase_line(struct terminal_t *term, struct parm_t *parm) 144 | { 145 | int i, mode; 146 | 147 | mode = (parm->argc <= 0) ? 0: dec2num(parm->argv[parm->argc - 1]); 148 | 149 | if (mode < 0 || 2 < mode) 150 | return; 151 | 152 | if (mode == 0) { 153 | for (i = term->cursor.x; i < term->cols; i++) 154 | erase_cell(term, term->cursor.y, i); 155 | } else if (mode == 1) { 156 | for (i = 0; i <= term->cursor.x; i++) 157 | erase_cell(term, term->cursor.y, i); 158 | } else if (mode == 2) { 159 | for (i = 0; i < term->cols; i++) 160 | erase_cell(term, term->cursor.y, i); 161 | } 162 | } 163 | 164 | void insert_line(struct terminal_t *term, struct parm_t *parm) 165 | { 166 | int num = sum(parm); 167 | 168 | if (term->mode & MODE_ORIGIN) { 169 | if (term->cursor.y < term->scroll.top 170 | || term->cursor.y > term->scroll.bottom) 171 | return; 172 | } 173 | 174 | if (num <= 0) 175 | num = 1; 176 | 177 | scroll(term, term->cursor.y, term->scroll.bottom, -num); 178 | } 179 | 180 | void delete_line(struct terminal_t *term, struct parm_t *parm) 181 | { 182 | int num = sum(parm); 183 | 184 | if (term->mode & MODE_ORIGIN) { 185 | if (term->cursor.y < term->scroll.top 186 | || term->cursor.y > term->scroll.bottom) 187 | return; 188 | } 189 | 190 | if (num <= 0) 191 | num = 1; 192 | 193 | scroll(term, term->cursor.y, term->scroll.bottom, num); 194 | } 195 | 196 | void delete_char(struct terminal_t *term, struct parm_t *parm) 197 | { 198 | int i, num = sum(parm); 199 | 200 | if (num <= 0) 201 | num = 1; 202 | 203 | for (i = term->cursor.x; i < term->cols; i++) { 204 | if ((i + num) < term->cols) 205 | copy_cell(term, term->cursor.y, i, term->cursor.y, i + num); 206 | else 207 | erase_cell(term, term->cursor.y, i); 208 | } 209 | } 210 | 211 | void erase_char(struct terminal_t *term, struct parm_t *parm) 212 | { 213 | int i, num = sum(parm); 214 | 215 | if (num <= 0) 216 | num = 1; 217 | else if (num + term->cursor.x > term->cols) 218 | num = term->cols - term->cursor.x; 219 | 220 | for (i = term->cursor.x; i < term->cursor.x + num; i++) 221 | erase_cell(term, term->cursor.y, i); 222 | } 223 | 224 | uint8_t rgb2index(uint8_t r, uint8_t g, uint8_t b) 225 | { 226 | /* SGR: Set Graphic Rendition (special case) 227 | * special color selection (from 256color index or as a 24bit color value) 228 | * 229 | * ESC [ 38 ; 5 ; Ps m 230 | * ESC [ 48 ; 5 ; Ps m 231 | * select foreground/background color from 256 color index 232 | * 233 | * ESC [ 38 ; 2 ; r ; g ; b m 234 | * ESC [ 48 ; 2 ; r ; g ; b m 235 | * select foreground/background color as a 24bit color value 236 | * 237 | * according to ITU T.416 (https://www.itu.int/rec/T-REC-T.416/en) 238 | * this format is valid (but most of terminals don't support) 239 | * ESC [ 38 : 5 : Ps m 240 | * ESC [ 48 : 5 : Ps m 241 | * 242 | * ESC [ 48 : 2 : r : g : b m 243 | * ESC [ 38 : 2 : r : g : b m 244 | */ 245 | int padding; 246 | uint8_t index; 247 | 248 | /* XXX: this calculation fails if color palette modified by OSC 4 */ 249 | /* 256 color palette is defined in color.h */ 250 | 251 | if (r == g && g == b) { 252 | /* 253 | search from grayscale 254 | index: 232 - 255 255 | value: 0x080808 - 0xEEEEEE 256 | inc : 0x0A 257 | */ 258 | padding = (r - 0x08) / 0x0A; 259 | 260 | if (padding >= 24) 261 | /* index 231 (0xFFFFFF) is the last color of 6x6x6 cube */ 262 | index = 231; 263 | else if (padding <= 0) 264 | index = 232; 265 | else 266 | index = 232 + padding; 267 | 268 | } else { 269 | /* 270 | search from 6x6x6 color cube 271 | index: 16 - 231 272 | each rgb takes 6 values: {0x00, 0x5F, 0x87, 0xAF, 0xD7, 0xFF} 273 | */ 274 | const uint8_t values[] = {0x0, 0x5F, 0x87, 0xAF, 0xD7, 0xFF}; 275 | const uint8_t rgb[] = {r, g, b}; 276 | uint8_t closest_index[3]; 277 | int small, big; 278 | 279 | for (int c = 0; c < 3; c++) { 280 | for (int i = 0; i < 5; i++) { 281 | if (values[i] <= rgb[c] && rgb[c] <= values[i + 1]) { 282 | small = abs(rgb[c] - values[i]); 283 | big = abs(rgb[c] - values[i + 1]); 284 | if (small < big) 285 | closest_index[c] = i; 286 | else 287 | closest_index[c] = i + 1; 288 | } 289 | } 290 | } 291 | index = 16 + closest_index[0] * 36 + closest_index[1] * 6 + closest_index[2]; 292 | } 293 | 294 | return index; 295 | } 296 | 297 | void set_attr(struct terminal_t *term, struct parm_t *parm) 298 | { 299 | /* SGR: Set Graphic Rendition 300 | * ESC [ Pm m 301 | * Pm: 302 | * 0: reset all attribute 303 | * 304 | * 1: brighten foreground color (only work for color index 0-7) 305 | * 4: underline 306 | * 5: brighten background color (only work for color index 0-7) 307 | * 7: reverse (swap foreground/background color) 308 | * 309 | * 21: reset brighten foreground color 310 | * 24: reset underline 311 | * 25: reset brighten background color 312 | * 27: reset reverse 313 | * 314 | * 30-37: select foreground color (color index 0-7) 315 | * 38: special foreground color selection: implemented in select_color_value() 316 | * 317 | * 40-47: select background color (color index 0-7) 318 | * 48: special foreground color selection: implemented in select_color_value() 319 | */ 320 | int i, num; 321 | 322 | if (parm->argc <= 0) { 323 | term->attribute = ATTR_RESET; 324 | term->color_pair.fg = DEFAULT_FG; 325 | term->color_pair.bg = DEFAULT_BG; 326 | return; 327 | } 328 | 329 | for (i = 0; i < parm->argc; i++) { 330 | num = dec2num(parm->argv[i]); 331 | //logging(DEBUG, "argc:%d num:%d\n", parm->argc, num); 332 | 333 | if (num == 0) { /* reset all attribute and color */ 334 | term->attribute = ATTR_RESET; 335 | term->color_pair.fg = DEFAULT_FG; 336 | term->color_pair.bg = DEFAULT_BG; 337 | } else if (1 <= num && num <= 7) { /* set attribute */ 338 | term->attribute |= attr_mask[num]; 339 | } else if (21 <= num && num <= 27) { /* reset attribute */ 340 | term->attribute &= ~attr_mask[num - 20]; 341 | } else if (30 <= num && num <= 37) { /* set foreground */ 342 | term->color_pair.fg = (num - 30); 343 | } else if (num == 38) { /* special foreground color selection */ 344 | /* select foreground color from 256 color index */ 345 | if ((i + 2) < parm->argc && dec2num(parm->argv[i + 1]) == 5) { 346 | term->color_pair.fg = dec2num(parm->argv[i + 2]); 347 | i += 2; 348 | /* select foreground color from specified rgb color */ 349 | } else if ((i + 4) < parm->argc && dec2num(parm->argv[i + 1]) == 2) { 350 | term->color_pair.fg = rgb2index(dec2num(parm->argv[i + 2]), 351 | dec2num(parm->argv[i + 3]), dec2num(parm->argv[i + 4])); 352 | i += 4; 353 | } 354 | } else if (num == 39) { /* reset foreground */ 355 | term->color_pair.fg = DEFAULT_FG; 356 | } else if (40 <= num && num <= 47) { /* set background */ 357 | term->color_pair.bg = (num - 40); 358 | } else if (num == 48) { /* special background color selection */ 359 | /* select background color from 256 color index */ 360 | if ((i + 2) < parm->argc && dec2num(parm->argv[i + 1]) == 5) { 361 | term->color_pair.bg = dec2num(parm->argv[i + 2]); 362 | i += 2; 363 | /* select background color from specified rgb color */ 364 | } else if ((i + 4) < parm->argc && dec2num(parm->argv[i + 1]) == 2) { 365 | term->color_pair.bg = rgb2index(dec2num(parm->argv[i + 2]), 366 | dec2num(parm->argv[i + 3]), dec2num(parm->argv[i + 4])); 367 | i += 4; 368 | } 369 | } else if (num == 49) { /* reset background */ 370 | term->color_pair.bg = DEFAULT_BG; 371 | } else if (90 <= num && num <= 97) { /* set bright foreground */ 372 | term->color_pair.fg = (num - 90) + BRIGHT_INC; 373 | } else if (100 <= num && num <= 107) { /* set bright background */ 374 | term->color_pair.bg = (num - 100) + BRIGHT_INC; 375 | } 376 | } 377 | } 378 | 379 | void status_report(struct terminal_t *term, struct parm_t *parm) 380 | { 381 | int i, num; 382 | char buf[BUFSIZE]; 383 | 384 | for (i = 0; i < parm->argc; i++) { 385 | num = dec2num(parm->argv[i]); 386 | if (num == 5) { /* terminal response: ready */ 387 | ewrite(term->fd, "\033[0n", 4); 388 | } else if (num == 6) { /* cursor position report */ 389 | snprintf(buf, BUFSIZE, "\033[%d;%dR", term->cursor.y + 1, term->cursor.x + 1); 390 | ewrite(term->fd, buf, strlen(buf)); 391 | } else if (num == 15) { /* terminal response: printer not connected */ 392 | ewrite(term->fd, "\033[?13n", 6); 393 | } 394 | } 395 | } 396 | 397 | void device_attribute(struct terminal_t *term, struct parm_t *parm) 398 | { 399 | /* TODO: refer VT525 DA */ 400 | (void) parm; 401 | ewrite(term->fd, "\033[?6c", 5); /* "I am a VT102" */ 402 | } 403 | 404 | void set_mode(struct terminal_t *term, struct parm_t *parm) 405 | { 406 | int i, mode; 407 | 408 | for (i = 0; i < parm->argc; i++) { 409 | mode = dec2num(parm->argv[i]); 410 | if (*(term->esc.buf + 1) != '?') 411 | continue; /* not supported */ 412 | 413 | if (mode == 6) { /* private mode */ 414 | term->mode |= MODE_ORIGIN; 415 | set_cursor(term, 0, 0); 416 | } else if (mode == 7) { 417 | term->mode |= MODE_AMRIGHT; 418 | } else if (mode == 25) { 419 | term->mode |= MODE_CURSOR; 420 | } else if (mode == 8901) { 421 | term->mode |= MODE_VWBS; 422 | } 423 | } 424 | 425 | } 426 | 427 | void reset_mode(struct terminal_t *term, struct parm_t *parm) 428 | { 429 | int i, mode; 430 | 431 | for (i = 0; i < parm->argc; i++) { 432 | mode = dec2num(parm->argv[i]); 433 | if (*(term->esc.buf + 1) != '?') 434 | continue; /* not supported */ 435 | 436 | if (mode == 6) { /* private mode */ 437 | term->mode &= ~MODE_ORIGIN; 438 | set_cursor(term, 0, 0); 439 | } else if (mode == 7) { 440 | term->mode &= ~MODE_AMRIGHT; 441 | term->wrap_occurred = false; 442 | } else if (mode == 25) { 443 | term->mode &= ~MODE_CURSOR; 444 | } else if (mode == 8901) { 445 | term->mode &= ~MODE_VWBS; 446 | } 447 | } 448 | 449 | } 450 | 451 | void set_margin(struct terminal_t *term, struct parm_t *parm) 452 | { 453 | int top, bottom; 454 | 455 | if (parm->argc <= 0) { /* CSI r */ 456 | top = 0; 457 | bottom = term->lines - 1; 458 | } else if (parm->argc == 2) { /* CSI ; r -> use default value */ 459 | top = (parm->argv[0] == NULL) ? 0: dec2num(parm->argv[0]) - 1; 460 | bottom = (parm->argv[1] == NULL) ? term->lines - 1: dec2num(parm->argv[1]) - 1; 461 | } else { 462 | return; 463 | } 464 | 465 | if (top < 0 || top >= term->lines) 466 | top = 0; 467 | if (bottom < 0 || bottom >= term->lines) 468 | bottom = term->lines - 1; 469 | 470 | if (top >= bottom) 471 | return; 472 | 473 | term->scroll.top = top; 474 | term->scroll.bottom = bottom; 475 | 476 | set_cursor(term, 0, 0); /* move cursor to home */ 477 | } 478 | 479 | void clear_tabstop(struct terminal_t *term, struct parm_t *parm) 480 | { 481 | int i, j, num; 482 | 483 | if (parm->argc <= 0) { 484 | term->tabstop[term->cursor.x] = false; 485 | } else { 486 | for (i = 0; i < parm->argc; i++) { 487 | num = dec2num(parm->argv[i]); 488 | if (num == 0) { 489 | term->tabstop[term->cursor.x] = false; 490 | } else if (num == 3) { 491 | for (j = 0; j < term->cols; j++) 492 | term->tabstop[j] = false; 493 | return; 494 | } 495 | } 496 | } 497 | } 498 | -------------------------------------------------------------------------------- /ctrlseq/dcs.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE for licence details. */ 2 | /* function for dcs sequence */ 3 | enum { 4 | RGBMAX = 255, 5 | HUEMAX = 360, 6 | LSMAX = 100, 7 | }; 8 | 9 | /* 10 | static inline void split_rgb(uint32_t color, uint8_t *r, uint8_t *g, uint8_t *b) 11 | { 12 | *r = bit_mask[8] & (color >> 16); 13 | *g = bit_mask[8] & (color >> 8); 14 | *b = bit_mask[8] & (color >> 0); 15 | } 16 | */ 17 | 18 | static inline int sixel_bitmap(struct terminal_t *term, struct sixel_canvas_t *sc, uint8_t bitmap) 19 | { 20 | int i, offset; 21 | //uint8_t r, g, b; 22 | 23 | logging(DEBUG, "sixel_bitmap()\nbitmap:%.2X point(%d, %d)\n", 24 | bitmap, sc->point.x, sc->point.y); 25 | 26 | if (sc->point.x >= term->width || sc->point.y >= term->height) 27 | return 1; 28 | 29 | offset = sc->point.x * BYTES_PER_PIXEL + sc->point.y * sc->line_length; 30 | 31 | for (i = 0; i < BITS_PER_SIXEL; i++) { 32 | if (offset >= BYTES_PER_PIXEL * term->width * term->height) 33 | break; 34 | 35 | if (bitmap & (0x01 << i)) { 36 | memcpy(sc->pixmap + offset, &sc->color_table[sc->color_index], BYTES_PER_PIXEL); 37 | /* 38 | split_rgb(sc->color_table[sc->color_index], &r, &g, &b); 39 | *(sc->pixmap + offset + 0) = b; 40 | *(sc->pixmap + offset + 1) = g; 41 | *(sc->pixmap + offset + 2) = r; 42 | */ 43 | } 44 | 45 | offset += sc->line_length; 46 | } 47 | sc->point.x++; 48 | 49 | if (sc->point.x > sc->width) 50 | sc->width = sc->point.x; 51 | 52 | return 1; 53 | } 54 | 55 | static inline int sixel_repeat(struct terminal_t *term, struct sixel_canvas_t *sc, char *buf) 56 | { 57 | int i, count; 58 | size_t length; 59 | char *cp, tmp[BUFSIZE]; 60 | uint8_t bitmap; 61 | 62 | cp = buf + 1; /* skip '!' itself */ 63 | while (isdigit(*cp)) /* skip non sixel bitmap character */ 64 | cp++; 65 | 66 | length = (cp - buf); 67 | strncpy(tmp, buf + 1, length - 1); 68 | *(tmp + length - 1) = '\0'; 69 | 70 | count = dec2num(tmp); 71 | 72 | logging(DEBUG, "sixel_repeat()\nbuf:%s length:%u\ncount:%d repeat:0x%.2X\n", 73 | tmp, (unsigned) length, count, *cp); 74 | 75 | if ('?' <= *cp && *cp <= '~') { 76 | bitmap = bit_mask[BITS_PER_SIXEL] & (*cp - '?'); 77 | for (i = 0; i < count; i++) 78 | sixel_bitmap(term, sc, bitmap); 79 | } 80 | 81 | return length + 1; 82 | } 83 | 84 | static inline int sixel_attr(struct sixel_canvas_t *sc, char *buf) 85 | { 86 | char *cp, tmp[BUFSIZE]; 87 | size_t length; 88 | struct parm_t parm; 89 | 90 | cp = buf + 1; 91 | while (isdigit(*cp) || *cp == ';') /* skip valid params */ 92 | cp++; 93 | 94 | length = (cp - buf); 95 | strncpy(tmp, buf + 1, length - 1); 96 | *(tmp + length - 1) = '\0'; 97 | 98 | reset_parm(&parm); 99 | parse_arg(tmp, &parm, ';', isdigit); 100 | 101 | if (parm.argc >= 4) { 102 | sc->width = dec2num(parm.argv[2]); 103 | sc->height = dec2num(parm.argv[3]); 104 | } 105 | 106 | logging(DEBUG, "sixel_attr()\nbuf:%s\nwidth:%d height:%d\n", 107 | tmp, sc->width, sc->height); 108 | 109 | return length; 110 | } 111 | 112 | static inline uint32_t hue2rgb(int n1, int n2, int hue) 113 | { 114 | if (hue < 0) 115 | hue += HUEMAX; 116 | 117 | if (hue > HUEMAX) 118 | hue -= HUEMAX; 119 | 120 | if (hue < (HUEMAX / 6)) 121 | return (n1 + (((n2 - n1) * hue + (HUEMAX / 12)) / (HUEMAX / 6))); 122 | if (hue < (HUEMAX / 2)) 123 | return n2; 124 | if (hue < ((HUEMAX * 2) / 3)) 125 | return (n1 + (((n2 - n1) * (((HUEMAX * 2) / 3) - hue) + (HUEMAX / 12)) / (HUEMAX / 6))); 126 | else 127 | return n1; 128 | } 129 | 130 | static inline uint32_t hls2rgb(int hue, int lum, int sat) 131 | { 132 | uint32_t r, g, b; 133 | int magic1, magic2; 134 | 135 | if (sat == 0) { 136 | r = g = b = (lum * RGBMAX) / LSMAX; 137 | } else { 138 | if (lum <= (LSMAX / 2) ) 139 | magic2 = (lum * (LSMAX + sat) + (LSMAX / 2)) / LSMAX; 140 | else 141 | magic2 = lum + sat - ((lum * sat) + (LSMAX / 2)) / LSMAX; 142 | magic1 = 2 * lum - magic2; 143 | 144 | r = (hue2rgb(magic1, magic2, hue + (HUEMAX / 3)) * RGBMAX + (LSMAX / 2)) / LSMAX; 145 | g = (hue2rgb(magic1, magic2, hue) * RGBMAX + (LSMAX / 2)) / LSMAX; 146 | b = (hue2rgb(magic1, magic2, hue - (HUEMAX / 3)) * RGBMAX + (LSMAX/2)) / LSMAX; 147 | } 148 | return (r << 16) + (g << 8) + b; 149 | } 150 | 151 | static inline int sixel_color(struct sixel_canvas_t *sc, char *buf) 152 | { 153 | char *cp, tmp[BUFSIZE]; 154 | int index, type; 155 | size_t length; 156 | uint16_t v1, v2, v3, r, g, b; 157 | uint32_t color; 158 | struct parm_t parm; 159 | 160 | cp = buf + 1; 161 | while (isdigit(*cp) || *cp == ';') /* skip valid params */ 162 | cp++; 163 | 164 | length = (cp - buf); 165 | strncpy(tmp, buf + 1, length - 1); /* skip '#' */ 166 | *(tmp + length - 1) = '\0'; 167 | 168 | reset_parm(&parm); 169 | parse_arg(tmp, &parm, ';', isdigit); 170 | 171 | if (parm.argc < 1) 172 | return length; 173 | 174 | index = dec2num(parm.argv[0]); 175 | if (index < 0) 176 | index = 0; 177 | else if (index >= COLORS) 178 | index = COLORS - 1; 179 | 180 | logging(DEBUG, "sixel_color()\nbuf:%s length:%u\nindex:%d\n", 181 | tmp, (unsigned) length, index); 182 | 183 | if (parm.argc == 1) { /* select color */ 184 | sc->color_index = index; 185 | return length; 186 | } 187 | 188 | if (parm.argc != 5) 189 | return length; 190 | 191 | type = dec2num(parm.argv[1]); 192 | v1 = dec2num(parm.argv[2]); 193 | v2 = dec2num(parm.argv[3]); 194 | v3 = dec2num(parm.argv[4]); 195 | 196 | if (type == 1) { /* HLS */ 197 | color = hls2rgb(v1, v2, v3); 198 | } else { 199 | r = bit_mask[8] & (0xFF * v1 / 100); 200 | g = bit_mask[8] & (0xFF * v2 / 100); 201 | b = bit_mask[8] & (0xFF * v3 / 100); 202 | color = (r << 16) | (g << 8) | b; 203 | } 204 | 205 | logging(DEBUG, "type:%d v1:%u v2:%u v3:%u color:0x%.8X\n", 206 | type, v1, v2, v3, color); 207 | 208 | sc->color_table[index] = color; 209 | 210 | return length; 211 | } 212 | 213 | static inline int sixel_cr(struct sixel_canvas_t *sc) 214 | { 215 | logging(DEBUG, "sixel_cr()\n"); 216 | 217 | sc->point.x = 0; 218 | 219 | return 1; 220 | } 221 | 222 | static inline int sixel_nl(struct sixel_canvas_t *sc) 223 | { 224 | logging(DEBUG, "sixel_nl()\n"); 225 | 226 | /* DECGNL moves active position to left margin 227 | and down one line of sixels: 228 | http://odl.sysworks.biz/disk$vaxdocdec963/decw$book/d3qsaaa1.p67.decw$book */ 229 | sc->point.y += BITS_PER_SIXEL; 230 | sc->point.x = 0; 231 | 232 | if (sc->point.y > sc->height) 233 | sc->height = sc->point.y; 234 | 235 | return 1; 236 | } 237 | 238 | void sixel_parse_data(struct terminal_t *term, struct sixel_canvas_t *sc, char *start_buf) 239 | { 240 | /* 241 | DECDLD sixel data 242 | '$': carriage return 243 | '-': new line 244 | '#': color 245 | # Pc: select color 246 | # Pc; Pu; Px; Py; Pz 247 | Pc : color index (0 to 255) 248 | Pu : color coordinate system 249 | 1: HLS (0 to 360 for Hue, 0 to 100 for others) 250 | 2: RGB (0 to 100 percent) (default) 251 | Px : Hue / Red 252 | Py : Lightness / Green 253 | Pz : Saturation / Blue 254 | '"': attr 255 | " Pan; Pad; Ph; Pv 256 | Pan, Pad: defines aspect ratio (Pan / Pad) (ignored) 257 | Ph, Pv : defines vertical/horizontal size of the image 258 | '!': repeat 259 | ! Pn ch 260 | Pn : repeat count ([0-9]+) 261 | ch : character to repeat ('?' to '~') 262 | sixel bitmap: 263 | range of ? (hex 3F) to ~ (hex 7E) 264 | ? (hex 3F) represents the binary value 00 0000. 265 | t (hex 74) represents the binary value 11 0101. 266 | ~ (hex 7E) represents the binary value 11 1111. 267 | */ 268 | int size = 0; 269 | char *cp, *end_buf; 270 | uint8_t bitmap; 271 | 272 | cp = start_buf; 273 | end_buf = cp + strlen(start_buf); 274 | 275 | while (cp < end_buf) { 276 | if (*cp == '!') { 277 | size = sixel_repeat(term, sc, cp); 278 | } else if (*cp == '"') { 279 | size = sixel_attr(sc, cp); 280 | } else if (*cp == '#') { 281 | size = sixel_color(sc, cp); 282 | } else if (*cp == '$') { 283 | size = sixel_cr(sc); 284 | } else if (*cp == '-') { 285 | size = sixel_nl(sc); 286 | } else if ('?' <= *cp && *cp <= '~') { 287 | bitmap = bit_mask[BITS_PER_SIXEL] & (*cp - '?'); 288 | size = sixel_bitmap(term, sc, bitmap); 289 | } else if (*cp == '\0') { /* end of sixel data */ 290 | break; 291 | } else { 292 | size = 1; 293 | } 294 | cp += size; 295 | } 296 | 297 | logging(DEBUG, "sixel_parse_data()\nwidth:%d height:%d\n", sc->width, sc->height); 298 | } 299 | 300 | void reset_sixel(struct sixel_canvas_t *sc, struct color_pair_t color_pair, int width, int height) 301 | { 302 | extern const uint32_t color_list[]; /* global */ 303 | int i; 304 | 305 | memset(sc->pixmap, 0, BYTES_PER_PIXEL * width * height); 306 | 307 | sc->width = 1; 308 | sc->height = 6; 309 | sc->point.x = 0; 310 | sc->point.y = 0; 311 | sc->line_length = BYTES_PER_PIXEL * width; 312 | sc->color_index = 0; 313 | 314 | /* 0 - 15: use vt340 or ansi color map */ 315 | /* VT340 VT340 Default Color Map 316 | ref: http://www.vt100.net/docs/vt3xx-gp/chapter2.html#T2-3 317 | */ 318 | sc->color_table[0] = 0x000000; sc->color_table[8] = 0x424242; 319 | sc->color_table[1] = 0x3333CC; sc->color_table[9] = 0x545499; 320 | sc->color_table[2] = 0xCC2121; sc->color_table[10] = 0x994242; 321 | sc->color_table[3] = 0x33CC33; sc->color_table[11] = 0x549954; 322 | sc->color_table[4] = 0xCC33CC; sc->color_table[12] = 0x995499; 323 | sc->color_table[5] = 0x33CCCC; sc->color_table[13] = 0x549999; 324 | sc->color_table[6] = 0xCCCC33; sc->color_table[14] = 0x999954; 325 | sc->color_table[7] = 0x878787; sc->color_table[15] = 0xCCCCCC; 326 | 327 | /* ANSI 16color table (but unusual order corresponding vt340 color map) 328 | sc->color_table[0] = color_list[0]; sc->color_table[8] = color_list[8]; 329 | sc->color_table[1] = color_list[4]; sc->color_table[9] = color_list[12]; 330 | sc->color_table[2] = color_list[1]; sc->color_table[10] = color_list[9]; 331 | sc->color_table[3] = color_list[2]; sc->color_table[11] = color_list[10]; 332 | sc->color_table[4] = color_list[5]; sc->color_table[12] = color_list[13]; 333 | sc->color_table[5] = color_list[6]; sc->color_table[13] = color_list[14]; 334 | sc->color_table[6] = color_list[3]; sc->color_table[14] = color_list[11]; 335 | sc->color_table[7] = color_list[7]; sc->color_table[15] = color_list[15]; 336 | */ 337 | /* change palette 0, because its often the same color as terminal background */ 338 | sc->color_table[0] = color_list[color_pair.fg]; 339 | 340 | /* 16 - 255: use xterm 256 color palette */ 341 | /* copy 256 color map */ 342 | for (i = 16; i < COLORS; i++) 343 | sc->color_table[i] = color_list[i]; 344 | } 345 | 346 | void sixel_copy2cell(struct terminal_t *term, struct sixel_canvas_t *sc) 347 | { 348 | int y, x, h, cols, lines; 349 | int src_offset, dst_offset; 350 | struct cell_t *cellp; 351 | 352 | if (sc->height > term->height) 353 | sc->height = term->height; 354 | 355 | cols = my_ceil(sc->width, CELL_WIDTH); 356 | lines = my_ceil(sc->height, CELL_HEIGHT); 357 | 358 | if (cols + term->cursor.x > term->cols) 359 | cols -= (cols + term->cursor.x - term->cols); 360 | 361 | for (y = 0; y < lines; y++) { 362 | for (x = 0; x < cols; x++) { 363 | erase_cell(term, term->cursor.y, term->cursor.x + x); 364 | cellp = &term->cells[term->cursor.y][term->cursor.x + x]; 365 | cellp->has_pixmap = true; 366 | for (h = 0; h < CELL_HEIGHT; h++) { 367 | src_offset = (y * CELL_HEIGHT + h) * sc->line_length + (CELL_WIDTH * x) * BYTES_PER_PIXEL; 368 | dst_offset = h * CELL_WIDTH * BYTES_PER_PIXEL; 369 | if (src_offset >= BYTES_PER_PIXEL * term->width * term->height) 370 | break; 371 | memcpy(cellp->pixmap + dst_offset, sc->pixmap + src_offset, CELL_WIDTH * BYTES_PER_PIXEL); 372 | } 373 | } 374 | move_cursor(term, 1, 0); 375 | //set_cursor(term, term->cursor.y + 1, term->cursor.x); 376 | } 377 | cr(term); 378 | } 379 | 380 | void sixel_parse_header(struct terminal_t *term, char *start_buf) 381 | { 382 | /* 383 | sixel format 384 | DSC P1; P2; P3; q; s...s; ST 385 | parameters 386 | DCS: ESC(0x1B) P (0x50) (8bit C1 character not recognized) 387 | P1 : pixel aspect ratio (force 0, 2:1) (ignored) 388 | P2 : background mode (ignored) 389 | 0 or 2: 0 stdands for current background color (default) 390 | 1 : 0 stands for remaining current color 391 | P3 : horizontal grid parameter (ignored) 392 | q : final character of sixel sequence 393 | s : see parse_sixel_data() 394 | ST : ESC (0x1B) '\' (0x5C) or BEL (0x07) 395 | */ 396 | char *cp; 397 | struct parm_t parm; 398 | 399 | /* replace final char of sixel header by NUL '\0' */ 400 | cp = strchr(start_buf, 'q'); 401 | *cp = '\0'; 402 | 403 | logging(DEBUG, "sixel_parse_header()\nbuf:%s\n", start_buf); 404 | 405 | /* split header by semicolon ';' */ 406 | reset_parm(&parm); 407 | parse_arg(start_buf, &parm, ';', isdigit); 408 | 409 | /* set canvas parameters */ 410 | reset_sixel(&term->sixel, term->color_pair, term->width, term->height); 411 | sixel_parse_data(term, &term->sixel, cp + 1); /* skip 'q' */ 412 | sixel_copy2cell(term, &term->sixel); 413 | } 414 | 415 | static inline void decdld_bitmap(struct glyph_t *glyph, uint8_t bitmap, uint8_t row, uint8_t column) 416 | { 417 | /* 418 | MSB LSB (glyph_t bitmap order, padding at LSB side) 419 | -> column 420 | sixel bit0 ->........ 421 | sixel bit1 ->........ 422 | sixel bit2 ->....@@.. 423 | sixel bit3 ->...@..@. 424 | sixel bit4 ->...@.... 425 | sixel bit5 ->...@.... 426 | .@@@@@.. 427 | ...@.... 428 | |...@.... 429 | row |...@.... 430 | v...@.... 431 | ...@.... 432 | ...@.... 433 | ...@.... 434 | ........ 435 | ........ 436 | */ 437 | int i, height_shift, width_shift; 438 | 439 | logging(DEBUG, "bit pattern:0x%.2X\n", bitmap); 440 | 441 | width_shift = CELL_WIDTH - 1 - column; 442 | if (width_shift < 0) 443 | return; 444 | 445 | for (i = 0; i < BITS_PER_SIXEL; i++) { 446 | if((bitmap >> i) & 0x01) { 447 | height_shift = row * BITS_PER_SIXEL + i; 448 | 449 | if (height_shift < CELL_HEIGHT) { 450 | logging(DEBUG, "height_shift:%d width_shift:%d\n", height_shift, width_shift); 451 | glyph->bitmap[height_shift] |= bit_mask[CELL_WIDTH] & (0x01 << width_shift); 452 | } 453 | } 454 | } 455 | } 456 | 457 | static inline void init_glyph(struct glyph_t *glyph) 458 | { 459 | int i; 460 | 461 | glyph->width = 1; /* drcs glyph must be HALF */ 462 | glyph->code = 0; /* this value not used: drcs call by DRCSMMv1 */ 463 | 464 | for (i = 0; i < CELL_HEIGHT; i++) 465 | glyph->bitmap[i] = 0; 466 | } 467 | 468 | void decdld_parse_data(char *start_buf, int start_char, struct glyph_t *chars) 469 | { 470 | /* 471 | DECDLD sixel data 472 | ';': glyph separator 473 | '/': line feed 474 | sixel bitmap: 475 | range of ? (hex 3F) to ~ (hex 7E) 476 | ? (hex 3F) represents the binary value 00 0000. 477 | t (hex 74) represents the binary value 11 0101. 478 | ~ (hex 7E) represents the binary value 11 1111. 479 | */ 480 | char *cp, *end_buf; 481 | uint8_t char_num = start_char; /* start_char == 0 means SPACE(0x20) */ 482 | uint8_t bitmap, row = 0, column = 0; 483 | 484 | init_glyph(&chars[char_num]); 485 | cp = start_buf; 486 | end_buf = cp + strlen(cp); 487 | 488 | while (cp < end_buf) { 489 | if ('?' <= *cp && *cp <= '~') { /* sixel bitmap */ 490 | logging(DEBUG, "char_num(ten):0x%.2X\n", char_num); 491 | /* remove offset '?' and use only 6bit */ 492 | bitmap = bit_mask[BITS_PER_SIXEL] & (*cp - '?'); 493 | decdld_bitmap(&chars[char_num], bitmap, row, column); 494 | column++; 495 | } else if (*cp == ';') { /* next char */ 496 | row = column = 0; 497 | char_num++; 498 | init_glyph(&chars[char_num]); 499 | } else if (*cp == '/') { /* sixel nl+cr */ 500 | row++; 501 | column = 0; 502 | } else if (*cp == '\0') { /* end of DECDLD sequence */ 503 | break; 504 | } 505 | cp++; 506 | } 507 | } 508 | 509 | void decdld_parse_header(struct terminal_t *term, char *start_buf) 510 | { 511 | /* 512 | DECDLD format 513 | DCS Pfn; Pcn; Pe; Pcmw; Pss; Pt; Pcmh; Pcss; f Dscs Sxbp1 ; Sxbp2 ; .. .; Sxbpn ST 514 | parameters 515 | DCS : ESC (0x1B) 'P' (0x50) (DCS(8bit C1 code) is not supported) 516 | Pfn : fontset (ignored) 517 | Pcn : start char (0 means SPACE 0x20) 518 | Pe : erase mode 519 | 0: clear selectet charset 520 | 1: clear only redefined glyph 521 | 2: clear all drcs charset 522 | Pcmw: max cellwidth (force CELL_WEDTH defined in glyph.h) 523 | Pss : screen size (ignored) 524 | Pt : defines the glyph as text or full cell or sixel (force full cell mode) 525 | (TODO: implement sixel/text mode) 526 | Pcmh: max cellheight (force CELL_HEIGHT defined in glyph.h) 527 | Pcss: character set size (force: 96) 528 | 0: 94 glyphs charset 529 | 1: 96 glyphs charset 530 | f : '{' (0x7B) 531 | Dscs: define character set 532 | Intermediate char: SPACE (0x20) to '/' (0x2F) 533 | final char : '0' (0x30) to '~' (0x7E) 534 | but allow chars between '@' (0x40) and '~' (0x7E) for DRCSMMv1 535 | (ref: https://github.com/saitoha/drcsterm/blob/master/README.rst) 536 | Sxbp: see parse_decdld_sixel() 537 | ST : ESC (0x1B) '\' (0x5C) or BEL (0x07) 538 | */ 539 | char *cp; 540 | int start_char, erase_mode, charset; 541 | struct parm_t parm; 542 | 543 | /* replace final char of DECDLD header by NUL '\0' */ 544 | cp = strchr(start_buf, '{'); 545 | *cp = '\0'; 546 | 547 | logging(DEBUG, "decdld_parse_header()\nbuf:%s\n", start_buf); 548 | 549 | /* split header by semicolon ';' */ 550 | reset_parm(&parm); 551 | parse_arg(start_buf, &parm, ';', isdigit); 552 | 553 | if (parm.argc != 8) /* DECDLD header must have 8 params */ 554 | return; 555 | 556 | /* set params */ 557 | start_char = dec2num(parm.argv[1]); 558 | erase_mode = dec2num(parm.argv[2]); 559 | 560 | /* parse Dscs */ 561 | cp++; /* skip final char (NUL) of DECDLD header */ 562 | while (SPACE <= *cp && *cp <= '/') /* skip intermediate char */ 563 | cp++; 564 | 565 | if (0x40 <= *cp && *cp <= 0x7E) /* final char of Dscs must be between 0x40 to 0x7E (DRCSMMv1) */ 566 | charset = *cp - 0x40; 567 | else 568 | charset = 0; 569 | 570 | logging(DEBUG, "charset(ku):0x%.2X start_char:%d erase_mode:%d\n", 571 | charset, start_char, erase_mode); 572 | 573 | /* reset previous glyph data */ 574 | if (erase_mode < 0 || erase_mode > 2) 575 | erase_mode = 0; 576 | 577 | if (erase_mode == 2) /* reset all drcs charset */ 578 | memset(term->drcs, 0, sizeof(struct glyph_t) * DRCS_CHARS); 579 | else if (erase_mode == 0) /* reset selected drcs charset */ 580 | memset(term->drcs + GLYPHS_PER_CHARSET * charset, 0, sizeof(struct glyph_t) * DRCS_CHARS); 581 | 582 | //if (term->drcs[charset] == NULL) /* always allocate 96 chars buffer */ 583 | //term->drcs[charset] = ecalloc(GLYPH_PER_CHARSET, sizeof(struct glyph_t)); 584 | 585 | decdld_parse_data(cp + 1, start_char, term->drcs + GLYPHS_PER_CHARSET * charset); /* skip final char */ 586 | } 587 | -------------------------------------------------------------------------------- /ctrlseq/esc.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE for licence details. */ 2 | /* function for control character */ 3 | void bs(struct terminal_t *term) 4 | { 5 | if (term->mode & MODE_VWBS 6 | && term->cursor.x - 1 >= 0 7 | && term->cells[term->cursor.y][term->cursor.x - 1].width == NEXT_TO_WIDE) 8 | move_cursor(term, 0, -2); 9 | else 10 | move_cursor(term, 0, -1); 11 | } 12 | 13 | void tab(struct terminal_t *term) 14 | { 15 | int i; 16 | 17 | for (i = term->cursor.x + 1; i < term->cols; i++) { 18 | if (term->tabstop[i]) { 19 | set_cursor(term, term->cursor.y, i); 20 | return; 21 | } 22 | } 23 | set_cursor(term, term->cursor.y, term->cols - 1); 24 | } 25 | 26 | void nl(struct terminal_t *term) 27 | { 28 | move_cursor(term, 1, 0); 29 | } 30 | 31 | void cr(struct terminal_t *term) 32 | { 33 | set_cursor(term, term->cursor.y, 0); 34 | } 35 | 36 | void enter_esc(struct terminal_t *term) 37 | { 38 | term->esc.state = STATE_ESC; 39 | } 40 | 41 | /* function for escape sequence */ 42 | void save_state(struct terminal_t *term) 43 | { 44 | term->state.mode = term->mode & MODE_ORIGIN; 45 | term->state.cursor = term->cursor; 46 | term->state.attribute = term->attribute; 47 | } 48 | 49 | void restore_state(struct terminal_t *term) 50 | { 51 | /* restore state */ 52 | if (term->state.mode & MODE_ORIGIN) 53 | term->mode |= MODE_ORIGIN; 54 | else 55 | term->mode &= ~MODE_ORIGIN; 56 | term->cursor = term->state.cursor; 57 | term->attribute = term->state.attribute; 58 | } 59 | 60 | void crnl(struct terminal_t *term) 61 | { 62 | cr(term); 63 | nl(term); 64 | } 65 | 66 | void set_tabstop(struct terminal_t *term) 67 | { 68 | term->tabstop[term->cursor.x] = true; 69 | } 70 | 71 | void reverse_nl(struct terminal_t *term) 72 | { 73 | move_cursor(term, -1, 0); 74 | } 75 | 76 | void identify(struct terminal_t *term) 77 | { 78 | ewrite(term->fd, "\033[?6c", 5); /* "I am a VT102" */ 79 | } 80 | 81 | void enter_csi(struct terminal_t *term) 82 | { 83 | term->esc.state = STATE_CSI; 84 | } 85 | 86 | void enter_osc(struct terminal_t *term) 87 | { 88 | term->esc.state = STATE_OSC; 89 | } 90 | 91 | void enter_dcs(struct terminal_t *term) 92 | { 93 | term->esc.state = STATE_DCS; 94 | } 95 | 96 | void ris(struct terminal_t *term) 97 | { 98 | reset(term); 99 | } 100 | -------------------------------------------------------------------------------- /ctrlseq/osc.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE for licence details. */ 2 | /* function for osc sequence */ 3 | int32_t parse_color1(char *seq) 4 | { 5 | /* 6 | format 7 | rgb:r/g/b 8 | rgb:rr/gg/bb 9 | rgb:rrr/ggg/bbb 10 | rgb:rrrr/gggg/bbbb 11 | */ 12 | int i, length, value; 13 | int32_t color; 14 | uint32_t rgb[3]; 15 | struct parm_t parm; 16 | 17 | reset_parm(&parm); 18 | parse_arg(seq, &parm, '/', isalnum); 19 | 20 | for (i = 0; i < parm.argc; i++) 21 | logging(DEBUG, "parm.argv[%d]: %s\n", i, parm.argv[i]); 22 | 23 | if (parm.argc != 3) 24 | return -1; 25 | 26 | length = strlen(parm.argv[0]); 27 | 28 | for (i = 0; i < 3; i++) { 29 | value = hex2num(parm.argv[i]); 30 | logging(DEBUG, "value:%d\n", value); 31 | 32 | if (length == 1) /* r/g/b/ */ 33 | rgb[i] = bit_mask[8] & (value * 0xFF / 0x0F); 34 | else if (length == 2) /* rr/gg/bb */ 35 | rgb[i] = bit_mask[8] & value; 36 | else if (length == 3) /* rrr/ggg/bbb */ 37 | rgb[i] = bit_mask[8] & (value * 0xFF / 0xFFF); 38 | else if (length == 4) /* rrrr/gggg/bbbb */ 39 | rgb[i] = bit_mask[8] & (value * 0xFF / 0xFFFF); 40 | else 41 | return -1; 42 | } 43 | 44 | color = (rgb[0] << 16) + (rgb[1] << 8) + rgb[2]; 45 | logging(DEBUG, "color:0x%.6X\n", color); 46 | 47 | return color; 48 | } 49 | 50 | int32_t parse_color2(char *seq) 51 | { 52 | /* 53 | format 54 | #rgb 55 | #rrggbb 56 | #rrrgggbbb 57 | #rrrrggggbbbb 58 | */ 59 | int i, length; 60 | uint32_t rgb[3]; 61 | int32_t color; 62 | char buf[BUFSIZE]; 63 | 64 | length = strlen(seq); 65 | memset(buf, '\0', BUFSIZE); 66 | 67 | if (length == 3) { /* rgb */ 68 | for (i = 0; i < 3; i++) { 69 | strncpy(buf, seq + i, 1); 70 | rgb[i] = bit_mask[8] & hex2num(buf) * 0xFF / 0x0F; 71 | } 72 | } else if (length == 6) { /* rrggbb */ 73 | for (i = 0; i < 3; i++) { /* rrggbb */ 74 | strncpy(buf, seq + i * 2, 2); 75 | rgb[i] = bit_mask[8] & hex2num(buf); 76 | } 77 | } else if (length == 9) { /* rrrgggbbb */ 78 | for (i = 0; i < 3; i++) { 79 | strncpy(buf, seq + i * 3, 3); 80 | rgb[i] = bit_mask[8] & hex2num(buf) * 0xFF / 0xFFF; 81 | } 82 | } else if (length == 12) { /* rrrrggggbbbb */ 83 | for (i = 0; i < 3; i++) { 84 | strncpy(buf, seq + i * 4, 4); 85 | rgb[i] = bit_mask[8] & hex2num(buf) * 0xFF / 0xFFFF; 86 | } 87 | } else { 88 | return -1; 89 | } 90 | 91 | color = (rgb[0] << 16) + (rgb[1] << 8) + rgb[2]; 92 | logging(DEBUG, "color:0x%.6X\n", color); 93 | 94 | return color; 95 | } 96 | 97 | void set_palette(struct terminal_t *term, void *arg) 98 | { 99 | /* 100 | OSC Ps ; Pt ST 101 | ref: http://invisible-island.net/xterm/ctlseqs/ctlseqs.html 102 | ref: http://ttssh2.sourceforge.jp/manual/ja/about/ctrlseq.html#OSC 103 | 104 | only recognize change color palette: 105 | Ps: 4 106 | Pt: c ; spec 107 | c: color index (from 0 to 255) 108 | spec: 109 | rgb:r/g/b 110 | rgb:rr/gg/bb 111 | rgb:rrr/ggg/bbb 112 | rgb:rrrr/gggg/bbbb 113 | #rgb 114 | #rrggbb 115 | #rrrgggbbb 116 | #rrrrggggbbbb 117 | this rgb format is "RGB Device String Specification" 118 | see http://xjman.dsl.gr.jp/X11R6/X11/CH06.html 119 | Pt: c ; ? 120 | response rgb color 121 | OSC 4 ; c ; rgb:rr/gg/bb ST 122 | 123 | TODO: this function only works in 32bpp mode 124 | */ 125 | struct parm_t *pt = (struct parm_t *) arg; 126 | int i, argc = pt->argc, index; 127 | int32_t color; 128 | uint8_t rgb[3]; 129 | char **argv = pt->argv; 130 | char buf[BUFSIZE]; 131 | 132 | if (argc != 3) 133 | return; 134 | 135 | index = dec2num(argv[1]); 136 | if (index < 0 || index >= COLORS) 137 | return; 138 | 139 | if (strncmp(argv[2], "rgb:", 4) == 0) { 140 | if ((color = parse_color1(argv[2] + 4)) != -1) { /* skip "rgb:" */ 141 | term->virtual_palette[index] = (uint32_t) color; 142 | term->palette_modified = true; 143 | } 144 | } else if (strncmp(argv[2], "#", 1) == 0) { 145 | if ((color = parse_color2(argv[2] + 1)) != -1) { /* skip "#" */ 146 | term->virtual_palette[index] = (uint32_t) color; 147 | term->palette_modified = true; 148 | } 149 | } else if (strncmp(argv[2], "?", 1) == 0) { 150 | for (i = 0; i < 3; i++) 151 | rgb[i] = bit_mask[8] & (term->virtual_palette[index] >> (8 * (2 - i))); 152 | 153 | snprintf(buf, BUFSIZE, "\033]4;%d;rgb:%.2X/%.2X/%.2X\033\\", 154 | index, rgb[0], rgb[1], rgb[2]); 155 | ewrite(term->fd, buf, strlen(buf)); 156 | } 157 | } 158 | 159 | void reset_palette(struct terminal_t *term, void *arg) 160 | { 161 | /* 162 | reset color c 163 | OSC 104 ; c ST 164 | c: index of color 165 | ST: BEL or ESC \ 166 | reset all color 167 | OSC 104 ST 168 | ST: BEL or ESC \ 169 | 170 | terminfo: oc=\E]104\E\\ 171 | */ 172 | struct parm_t *pt = (struct parm_t *) arg; 173 | int i, argc = pt->argc, c; 174 | char **argv = pt->argv; 175 | 176 | if (argc < 2) { /* reset all color palette */ 177 | for (i = 0; i < COLORS; i++) 178 | term->virtual_palette[i] = color_list[i]; 179 | term->palette_modified = true; 180 | } else if (argc == 2) { /* reset color_palette[c] */ 181 | c = dec2num(argv[1]); 182 | if (0 <= c && c < COLORS) { 183 | term->virtual_palette[c] = color_list[c]; 184 | term->palette_modified = true; 185 | } 186 | } 187 | } 188 | 189 | int isdigit_or_questionmark(int c) 190 | { 191 | if (isdigit(c) || c == '?') 192 | return 1; 193 | else 194 | return 0; 195 | } 196 | 197 | void glyph_width_report(struct terminal_t *term, void *arg) 198 | { 199 | /* 200 | glyph width report 201 | * request * 202 | OSC 8900 ; Ps ; Pw ; ? : Pf : Pt ST 203 | Ps: reserved 204 | Pw: width (0 or 1 or 2) 205 | Pfrom: beginning of unicode code point 206 | Pto: end of unicode code point 207 | ST: BEL(0x07) or ESC(0x1B) BACKSLASH(0x5C) 208 | * answer * 209 | OSC 8900 ; Ps ; Pv ; Pw ; Pf : Pt ; Pf : Pt ; ... ST 210 | Ps: responce code 211 | 0: ok (default) 212 | 1: recognized but not supported 213 | 2: not recognized 214 | Pv: reserved (maybe East Asian Width Version) 215 | Pw: width (0 or 1 or 2) 216 | Pfrom: beginning of unicode code point 217 | Pto: end of unicode code point 218 | ST: BEL(0x07) or ESC(0x1B) BACKSLASH(0x5C) 219 | ref 220 | http://uobikiemukot.github.io/yaft/glyph_width_report.html 221 | https://gist.github.com/saitoha/8767268 222 | */ 223 | struct parm_t *pt = (struct parm_t *) arg, sub_parm; 224 | int i, argc = pt->argc, width, from, to, left, right, w, wcw; //reserved 225 | char **argv = pt->argv, buf[BUFSIZE]; 226 | 227 | if (argc < 4) 228 | return; 229 | 230 | reset_parm(&sub_parm); 231 | parse_arg(argv[3], &sub_parm, ':', isdigit_or_questionmark); 232 | 233 | if (sub_parm.argc != 3 || *sub_parm.argv[0] != '?') 234 | return; 235 | 236 | //reserved = dec2num(argv[1]); 237 | width = dec2num(argv[2]); 238 | from = dec2num(sub_parm.argv[1]); 239 | to = dec2num(sub_parm.argv[2]); 240 | 241 | if ((width < 0) || (width > 2)) 242 | return; 243 | 244 | /* unicode private area: plane 16 (DRCSMMv1) is always half */ 245 | if ((from < 0) || (to >= UCS2_CHARS)) 246 | return; 247 | 248 | snprintf(buf, BUFSIZE, "\033]8900;0;0;%d;", width); /* OSC 8900 ; Ps; Pv ; Pw ; */ 249 | ewrite(term->fd, buf, strlen(buf)); 250 | 251 | left = right = -1; 252 | for (i = from; i <= to; i++) { 253 | wcw = wcwidth(i); 254 | if (wcw <= 0) /* zero width */ 255 | w = 0; 256 | else if (term->glyph[i] == NULL) /* missing glyph */ 257 | w = wcw; 258 | else 259 | w = term->glyph[i]->width; 260 | 261 | if (w != width) { 262 | if (right != -1) { 263 | snprintf(buf, BUFSIZE, "%d:%d;", left, right); 264 | ewrite(term->fd, buf, strlen(buf)); 265 | } else if (left != -1) { 266 | snprintf(buf, BUFSIZE, "%d:%d;", left, left); 267 | ewrite(term->fd, buf, strlen(buf)); 268 | } 269 | left = right = -1; 270 | } else { 271 | if (left == -1) 272 | left = i; 273 | else 274 | right = i; 275 | } 276 | } 277 | 278 | if (right != -1) { 279 | snprintf(buf, BUFSIZE, "%d:%d;", left, right); 280 | ewrite(term->fd, buf, strlen(buf)); 281 | } else if (left != -1) { 282 | snprintf(buf, BUFSIZE, "%d:%d;", left, left); 283 | ewrite(term->fd, buf, strlen(buf)); 284 | } 285 | 286 | ewrite(term->fd, "\033\\", 2); /* ST (ESC BACKSLASH) */ 287 | } 288 | -------------------------------------------------------------------------------- /fb/common.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE for licence details. */ 2 | /* common framebuffer struct/enum */ 3 | enum fb_type_t { 4 | YAFT_FB_TYPE_PACKED_PIXELS = 0, 5 | YAFT_FB_TYPE_PLANES, 6 | YAFT_FB_TYPE_UNKNOWN, 7 | }; 8 | 9 | enum fb_visual_t { 10 | YAFT_FB_VISUAL_TRUECOLOR = 0, 11 | YAFT_FB_VISUAL_DIRECTCOLOR, 12 | YAFT_FB_VISUAL_PSEUDOCOLOR, 13 | YAFT_FB_VISUAL_UNKNOWN, 14 | }; 15 | 16 | struct fb_info_t { 17 | struct bitfield_t { 18 | int length; 19 | int offset; 20 | } red, green, blue; 21 | int width, height; /* display resolution */ 22 | long screen_size; /* screen data size (byte) */ 23 | int line_length; /* line length (byte) */ 24 | int bytes_per_pixel; 25 | int bits_per_pixel; 26 | enum fb_type_t type; 27 | enum fb_visual_t visual; 28 | int reserved; /* os specific data */ 29 | }; 30 | 31 | /* os dependent typedef/include */ 32 | #if defined(__linux__) 33 | #include "linux.h" 34 | #elif defined(__FreeBSD__) 35 | #include "freebsd.h" 36 | #elif defined(__NetBSD__) 37 | #include "netbsd.h" 38 | #elif defined(__OpenBSD__) 39 | #include "openbsd.h" 40 | #endif 41 | 42 | struct framebuffer_t { 43 | int fd; /* file descriptor of framebuffer */ 44 | uint8_t *fp; /* pointer of framebuffer */ 45 | uint8_t *buf; /* copy of framebuffer */ 46 | uint8_t *wall; /* buffer for wallpaper */ 47 | uint32_t real_palette[COLORS]; /* hardware specific color palette */ 48 | struct fb_info_t info; 49 | cmap_t *cmap, *cmap_orig; 50 | }; 51 | 52 | /* common framebuffer functions */ 53 | uint8_t *load_wallpaper(uint8_t *fp, long screen_size) 54 | { 55 | uint8_t *ptr; 56 | 57 | if ((ptr = (uint8_t *) ecalloc(1, screen_size)) == NULL) { 58 | logging(ERROR, "couldn't allocate wallpaper buffer\n"); 59 | return NULL; 60 | } 61 | memcpy(ptr, fp, screen_size); 62 | 63 | return ptr; 64 | } 65 | 66 | void cmap_die(cmap_t *cmap) 67 | { 68 | if (cmap) { 69 | free(cmap->red); 70 | free(cmap->green); 71 | free(cmap->blue); 72 | //free(cmap->transp); 73 | free(cmap); 74 | } 75 | } 76 | 77 | cmap_t *cmap_create(int colors) 78 | { 79 | cmap_t *cmap; 80 | 81 | if ((cmap = (cmap_t *) ecalloc(1, sizeof(cmap_t))) == NULL) { 82 | logging(ERROR, "couldn't allocate cmap buffer\n"); 83 | return NULL; 84 | } 85 | 86 | /* init os specific */ 87 | alloc_cmap(cmap, colors); 88 | 89 | if (!cmap->red || !cmap->green || !cmap->blue) { 90 | logging(ERROR, "couldn't allocate red/green/blue buffer of cmap\n"); 91 | cmap_die(cmap); 92 | return NULL; 93 | } 94 | return cmap; 95 | } 96 | 97 | bool cmap_update(int fd, cmap_t *cmap) 98 | { 99 | if (cmap) { 100 | if (put_cmap(fd, cmap)) { 101 | logging(ERROR, "put_cmap failed\n"); 102 | return false; 103 | } 104 | } 105 | return true; 106 | } 107 | 108 | bool cmap_save(int fd, cmap_t *cmap) 109 | { 110 | if (get_cmap(fd, cmap)) { 111 | logging(WARN, "get_cmap failed\n"); 112 | return false; 113 | } 114 | return true; 115 | } 116 | 117 | bool cmap_init(int fd, struct fb_info_t *info, cmap_t *cmap, int colors, int length) 118 | { 119 | uint16_t r, g, b, r_index, g_index, b_index; 120 | 121 | for (int i = 0; i < colors; i++) { 122 | if (info->visual == YAFT_FB_VISUAL_DIRECTCOLOR) { 123 | r_index = (i >> (length - info->red.length)) & bit_mask[info->red.length]; 124 | g_index = (i >> (length - info->green.length)) & bit_mask[info->green.length]; 125 | b_index = (i >> (length - info->blue.length)) & bit_mask[info->blue.length]; 126 | 127 | /* XXX: maybe only upper order byte is used */ 128 | r = r_index << (CMAP_COLOR_LENGTH - info->red.length); 129 | g = g_index << (CMAP_COLOR_LENGTH - info->green.length); 130 | b = b_index << (CMAP_COLOR_LENGTH - info->blue.length); 131 | 132 | *(cmap->red + r_index) = r; 133 | *(cmap->green + g_index) = g; 134 | *(cmap->blue + b_index) = b; 135 | } else { /* YAFT_FB_VISUAL_PSEUDOCOLOR */ 136 | r_index = (i >> info->red.offset) & bit_mask[info->red.length]; 137 | g_index = (i >> info->green.offset) & bit_mask[info->green.length]; 138 | b_index = (i >> info->blue.offset) & bit_mask[info->blue.length]; 139 | 140 | r = r_index << (CMAP_COLOR_LENGTH - info->red.length); 141 | g = g_index << (CMAP_COLOR_LENGTH - info->green.length); 142 | b = b_index << (CMAP_COLOR_LENGTH - info->blue.length); 143 | 144 | *(cmap->red + i) = r; 145 | *(cmap->green + i) = g; 146 | *(cmap->blue + i) = b; 147 | } 148 | } 149 | 150 | if (!cmap_update(fd, cmap)) 151 | return false; 152 | 153 | return true; 154 | } 155 | 156 | static inline uint32_t color2pixel(struct fb_info_t *info, uint32_t color) 157 | { 158 | uint32_t r, g, b; 159 | 160 | r = bit_mask[BITS_PER_RGB] & (color >> (BITS_PER_RGB * 2)); 161 | g = bit_mask[BITS_PER_RGB] & (color >> BITS_PER_RGB); 162 | b = bit_mask[BITS_PER_RGB] & (color >> 0); 163 | 164 | r = r >> (BITS_PER_RGB - info->red.length); 165 | g = g >> (BITS_PER_RGB - info->green.length); 166 | b = b >> (BITS_PER_RGB - info->blue.length); 167 | 168 | return (r << info->red.offset) 169 | + (g << info->green.offset) 170 | + (b << info->blue.offset); 171 | } 172 | 173 | 174 | bool init_truecolor(struct fb_info_t *info, cmap_t **cmap, cmap_t **cmap_orig) 175 | { 176 | switch(info->bits_per_pixel) { 177 | case 15: /* XXX: 15 bpp is not tested */ 178 | case 16: 179 | case 24: 180 | case 32: 181 | break; 182 | default: 183 | logging(ERROR, "truecolor %d bpp not supported\n", info->bits_per_pixel); 184 | return false; 185 | } 186 | /* we don't use cmap in truecolor */ 187 | *cmap = *cmap_orig = NULL; 188 | 189 | return true; 190 | } 191 | 192 | bool init_indexcolor(int fd, struct fb_info_t *info, cmap_t **cmap, cmap_t **cmap_orig) 193 | { 194 | int colors, max_length; 195 | 196 | if (info->visual == YAFT_FB_VISUAL_DIRECTCOLOR) { 197 | switch(info->bits_per_pixel) { 198 | case 15: /* XXX: 15 bpp is not tested */ 199 | case 16: 200 | case 24: /* XXX: 24 bpp is not tested */ 201 | case 32: 202 | break; 203 | default: 204 | logging(ERROR, "directcolor %d bpp not supported\n", info->bits_per_pixel); 205 | return false; 206 | } 207 | logging(DEBUG, "red.length:%d gree.length:%d blue.length:%d\n", 208 | info->red.length, info->green.length, info->blue.length); 209 | 210 | max_length = (info->red.length > info->green.length) ? info->red.length: info->green.length; 211 | max_length = (max_length > info->blue.length) ? max_length: info->blue.length; 212 | } else { /* YAFT_FB_VISUAL_PSEUDOCOLOR */ 213 | switch(info->bits_per_pixel) { 214 | case 8: 215 | break; 216 | default: 217 | logging(ERROR, "pseudocolor %d bpp not supported\n", info->bits_per_pixel); 218 | return false; 219 | } 220 | 221 | /* in pseudo color, we use fixed palette (red/green: 3bit, blue: 2bit). 222 | this palette is not compatible with xterm 256 colors, 223 | but we can convert 24bit color into palette number easily. */ 224 | info->red.length = 3; 225 | info->green.length = 3; 226 | info->blue.length = 2; 227 | 228 | info->red.offset = 5; 229 | info->green.offset = 2; 230 | info->blue.offset = 0; 231 | 232 | /* XXX: not 3 but 8, each color has 256 colors palette */ 233 | max_length = 8; 234 | } 235 | 236 | colors = 1 << max_length; 237 | logging(DEBUG, "colors:%d max_length:%d\n", colors, max_length); 238 | 239 | *cmap = cmap_create(colors); 240 | *cmap_orig = cmap_create(colors); 241 | 242 | if (!(*cmap) || !(*cmap_orig)) 243 | goto cmap_init_err; 244 | 245 | if (!cmap_save(fd, *cmap_orig)) { 246 | logging(WARN, "couldn't save original cmap\n"); 247 | cmap_die(*cmap_orig); 248 | *cmap_orig = NULL; 249 | } 250 | 251 | if (!cmap_init(fd, info, *cmap, colors, max_length)) 252 | goto cmap_init_err; 253 | 254 | return true; 255 | 256 | cmap_init_err: 257 | cmap_die(*cmap); 258 | cmap_die(*cmap_orig); 259 | return false; 260 | } 261 | 262 | void fb_print_info(struct fb_info_t *info) 263 | { 264 | const char *type_str[] = { 265 | [YAFT_FB_TYPE_PACKED_PIXELS] = "YAFT_FB_TYPE_PACKED_PIXELS", 266 | [YAFT_FB_TYPE_PLANES] = "YAFT_FB_TYPE_PLANES", 267 | [YAFT_FB_TYPE_UNKNOWN] = "YAFT_FB_TYPE_UNKNOWN", 268 | }; 269 | 270 | const char *visual_str[] = { 271 | [YAFT_FB_VISUAL_TRUECOLOR] = "YAFT_FB_VISUAL_TRUECOLOR", 272 | [YAFT_FB_VISUAL_DIRECTCOLOR] = "YAFT_FB_VISUAL_DIRECTCOLOR", 273 | [YAFT_FB_VISUAL_PSEUDOCOLOR] = "YAFT_FB_VISUAL_PSEUDOCOLOR", 274 | [YAFT_FB_VISUAL_UNKNOWN] = "YAFT_FB_VISUAL_UNKNOWN", 275 | }; 276 | 277 | logging(DEBUG, "framebuffer info:\n"); 278 | logging(DEBUG, "\tred(off:%d len:%d) green(off:%d len:%d) blue(off:%d len:%d)\n", 279 | info->red.offset, info->red.length, info->green.offset, info->green.length, info->blue.offset, info->blue.length); 280 | logging(DEBUG, "\tresolution %dx%d\n", info->width, info->height); 281 | logging(DEBUG, "\tscreen size:%ld line length:%d\n", info->screen_size, info->line_length); 282 | logging(DEBUG, "\tbits_per_pixel:%d bytes_per_pixel:%d\n", info->bits_per_pixel, info->bytes_per_pixel); 283 | logging(DEBUG, "\ttype:%s\n", type_str[info->type]); 284 | logging(DEBUG, "\tvisual:%s\n", visual_str[info->visual]); 285 | } 286 | 287 | bool fb_init(struct framebuffer_t *fb) 288 | { 289 | extern const uint32_t color_list[COLORS]; /* defined in color.h */ 290 | extern const char *fb_path; /* defined in conf.h */ 291 | const char *path; 292 | char *env; 293 | 294 | /* open framebuffer device: check FRAMEBUFFER env at first */ 295 | path = ((env = getenv("FRAMEBUFFER")) == NULL) ? fb_path: env; 296 | if ((fb->fd = eopen(path, O_RDWR)) < 0) 297 | return false; 298 | 299 | /* os dependent initialize */ 300 | if (!set_fbinfo(fb->fd, &fb->info)) 301 | goto set_fbinfo_failed; 302 | 303 | if (VERBOSE) 304 | fb_print_info(&fb->info); 305 | 306 | /* allocate memory */ 307 | fb->fp = (uint8_t *) emmap(0, fb->info.screen_size, 308 | PROT_WRITE | PROT_READ, MAP_SHARED, fb->fd, 0); 309 | fb->buf = (uint8_t *) ecalloc(1, fb->info.screen_size); 310 | fb->wall = ((env = getenv("YAFT")) && strstr(env, "wall")) ? 311 | load_wallpaper(fb->fp, fb->info.screen_size): NULL; 312 | 313 | /* error check */ 314 | if (fb->fp == MAP_FAILED || !fb->buf) 315 | goto allocate_failed; 316 | 317 | if (fb->info.type != YAFT_FB_TYPE_PACKED_PIXELS) { 318 | /* TODO: support planes type */ 319 | logging(ERROR, "unsupport framebuffer type\n"); 320 | goto fb_init_failed; 321 | } 322 | 323 | if (fb->info.visual == YAFT_FB_VISUAL_TRUECOLOR) { 324 | if (!init_truecolor(&fb->info, &fb->cmap, &fb->cmap_orig)) 325 | goto fb_init_failed; 326 | } else if (fb->info.visual == YAFT_FB_VISUAL_DIRECTCOLOR 327 | || fb->info.visual == YAFT_FB_VISUAL_PSEUDOCOLOR) { 328 | if (!init_indexcolor(fb->fd, &fb->info, &fb->cmap, &fb->cmap_orig)) 329 | goto fb_init_failed; 330 | } else { 331 | /* TODO: support mono visual */ 332 | logging(ERROR, "unsupport framebuffer visual\n"); 333 | goto fb_init_failed; 334 | } 335 | 336 | /* init color palette */ 337 | for (int i = 0; i < COLORS; i++) 338 | fb->real_palette[i] = color2pixel(&fb->info, color_list[i]); 339 | 340 | return true; 341 | 342 | fb_init_failed: 343 | allocate_failed: 344 | free(fb->buf); 345 | free(fb->wall); 346 | if (fb->fp != MAP_FAILED) 347 | emunmap(fb->fp, fb->info.screen_size); 348 | set_fbinfo_failed: 349 | eclose(fb->fd); 350 | return false; 351 | } 352 | 353 | void fb_die(struct framebuffer_t *fb) 354 | { 355 | cmap_die(fb->cmap); 356 | if (fb->cmap_orig) { 357 | put_cmap(fb->fd, fb->cmap_orig); 358 | cmap_die(fb->cmap_orig); 359 | } 360 | free(fb->wall); 361 | free(fb->buf); 362 | emunmap(fb->fp, fb->info.screen_size); 363 | eclose(fb->fd); 364 | //fb_release(fb->fd, &fb->info); /* os specific */ 365 | } 366 | 367 | static inline void draw_sixel(struct framebuffer_t *fb, int line, int col, uint8_t *pixmap) 368 | { 369 | int h, w, src_offset, dst_offset; 370 | uint32_t pixel, color = 0; 371 | 372 | for (h = 0; h < CELL_HEIGHT; h++) { 373 | for (w = 0; w < CELL_WIDTH; w++) { 374 | src_offset = BYTES_PER_PIXEL * (h * CELL_WIDTH + w); 375 | memcpy(&color, pixmap + src_offset, BYTES_PER_PIXEL); 376 | 377 | dst_offset = (line * CELL_HEIGHT + h) * fb->info.line_length 378 | + (col * CELL_WIDTH + w) * fb->info.bytes_per_pixel; 379 | pixel = color2pixel(&fb->info, color); 380 | memcpy(fb->buf + dst_offset, &pixel, fb->info.bytes_per_pixel); 381 | } 382 | } 383 | } 384 | 385 | static inline void draw_line(struct framebuffer_t *fb, struct terminal_t *term, int line) 386 | { 387 | int pos, size, bdf_padding, glyph_width, margin_right; 388 | int col, w, h; 389 | uint32_t pixel; 390 | struct color_pair_t color_pair; 391 | struct cell_t *cellp; 392 | 393 | for (col = term->cols - 1; col >= 0; col--) { 394 | margin_right = (term->cols - 1 - col) * CELL_WIDTH; 395 | 396 | /* target cell */ 397 | cellp = &term->cells[line][col]; 398 | 399 | /* draw sixel pixmap */ 400 | if (cellp->has_pixmap) { 401 | draw_sixel(fb, line, col, cellp->pixmap); 402 | continue; 403 | } 404 | 405 | /* copy current color_pair (maybe changed) */ 406 | color_pair = cellp->color_pair; 407 | 408 | /* check wide character or not */ 409 | glyph_width = (cellp->width == HALF) ? CELL_WIDTH: CELL_WIDTH * 2; 410 | bdf_padding = my_ceil(glyph_width, BITS_PER_BYTE) * BITS_PER_BYTE - glyph_width; 411 | if (cellp->width == WIDE) 412 | bdf_padding += CELL_WIDTH; 413 | 414 | /* check cursor position */ 415 | if ((term->mode & MODE_CURSOR && line == term->cursor.y) 416 | && (col == term->cursor.x 417 | || (cellp->width == WIDE && (col + 1) == term->cursor.x) 418 | || (cellp->width == NEXT_TO_WIDE && (col - 1) == term->cursor.x))) { 419 | color_pair.fg = DEFAULT_BG; 420 | color_pair.bg = (!vt_active && BACKGROUND_DRAW) ? PASSIVE_CURSOR_COLOR: ACTIVE_CURSOR_COLOR; 421 | } 422 | 423 | for (h = 0; h < CELL_HEIGHT; h++) { 424 | /* if UNDERLINE attribute on, swap bg/fg */ 425 | if ((h == (CELL_HEIGHT - 1)) && (cellp->attribute & attr_mask[ATTR_UNDERLINE])) 426 | color_pair.bg = color_pair.fg; 427 | 428 | for (w = 0; w < CELL_WIDTH; w++) { 429 | pos = (term->width - 1 - margin_right - w) * fb->info.bytes_per_pixel 430 | + (line * CELL_HEIGHT + h) * fb->info.line_length; 431 | 432 | /* set color palette */ 433 | if (cellp->glyphp->bitmap[h] & (0x01 << (bdf_padding + w))) 434 | pixel = fb->real_palette[color_pair.fg]; 435 | else if (fb->wall && color_pair.bg == DEFAULT_BG) /* wallpaper */ 436 | memcpy(&pixel, fb->wall + pos, fb->info.bytes_per_pixel); 437 | else 438 | pixel = fb->real_palette[color_pair.bg]; 439 | 440 | /* update copy buffer only */ 441 | memcpy(fb->buf + pos, &pixel, fb->info.bytes_per_pixel); 442 | } 443 | } 444 | } 445 | 446 | /* actual display update (bit blit) */ 447 | pos = (line * CELL_HEIGHT) * fb->info.line_length; 448 | size = CELL_HEIGHT * fb->info.line_length; 449 | memcpy(fb->fp + pos, fb->buf + pos, size); 450 | 451 | /* TODO: page flip 452 | if fb_fix_screeninfo.ypanstep > 0, we can use hardware panning. 453 | set fb_fix_screeninfo.{yres_virtual,yoffset} and call ioctl(FBIOPAN_DISPLAY) 454 | but drivers of recent hardware (inteldrmfb, nouveaufb, radeonfb) don't support... 455 | (maybe we can use this by using libdrm) */ 456 | /* TODO: vertical synchronizing */ 457 | 458 | term->line_dirty[line] = ((term->mode & MODE_CURSOR) && term->cursor.y == line) ? true: false; 459 | } 460 | 461 | void refresh(struct framebuffer_t *fb, struct terminal_t *term) 462 | { 463 | if (term->palette_modified) { 464 | term->palette_modified = false; 465 | for (int i = 0; i < COLORS; i++) 466 | fb->real_palette[i] = color2pixel(&fb->info, term->virtual_palette[i]); 467 | } 468 | 469 | if (term->mode & MODE_CURSOR) 470 | term->line_dirty[term->cursor.y] = true; 471 | 472 | for (int line = 0; line < term->lines; line++) { 473 | if (term->line_dirty[line]) { 474 | draw_line(fb, term, line); 475 | } 476 | } 477 | } 478 | -------------------------------------------------------------------------------- /fb/freebsd.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE for licence details. */ 2 | /* XXX: _XOPEN_SOURCE >= 600 invalidates __BSD_VISIBLE 3 | so define some types manually */ 4 | typedef unsigned char u_char; 5 | typedef unsigned short u_short; 6 | typedef unsigned int u_int; 7 | typedef unsigned long u_long; 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | typedef struct fbcmap cmap_t; 15 | 16 | enum { 17 | CMAP_COLOR_LENGTH = sizeof(u_char) * BITS_PER_BYTE, 18 | }; 19 | 20 | /* os specific ioctl */ 21 | void alloc_cmap(cmap_t *cmap, int colors) 22 | { 23 | /* commond member included in struct fbcmap and video_color_palette_t */ 24 | cmap->index = 0; 25 | cmap->count = colors; 26 | cmap->red = (u_char *) ecalloc(colors, sizeof(u_char)); 27 | cmap->green = (u_char *) ecalloc(colors, sizeof(u_char)); 28 | cmap->blue = (u_char *) ecalloc(colors, sizeof(u_char)); 29 | /* not exist in struct fbcmap */ 30 | //cmap->transparent = NULL; 31 | } 32 | 33 | int put_cmap(int fd, cmap_t *cmap) 34 | { 35 | return ioctl(fd, FBIOPUTCMAP, cmap); 36 | } 37 | 38 | int get_cmap(int fd, cmap_t *cmap) 39 | { 40 | return ioctl(fd, FBIOGETCMAP, cmap); 41 | } 42 | 43 | /* initialize struct fb_info_t */ 44 | void set_bitfield(video_info_t *vinfo, 45 | struct bitfield_t *red, struct bitfield_t *green, struct bitfield_t *blue) 46 | { 47 | red->length = vinfo->vi_pixel_fsizes[0]; 48 | green->length = vinfo->vi_pixel_fsizes[1]; 49 | blue->length = vinfo->vi_pixel_fsizes[2]; 50 | 51 | red->offset = vinfo->vi_pixel_fields[0]; 52 | green->offset = vinfo->vi_pixel_fields[1]; 53 | blue->offset = vinfo->vi_pixel_fields[2]; 54 | } 55 | 56 | void set_type_visual(struct fb_info_t *info, int type, int visual) 57 | { 58 | /* ref: jfbterm-FreeBSD http://www.ac.auone-net.jp/~baba/jfbterm/ */ 59 | if (type == V_INFO_MM_PACKED || type == V_INFO_MM_DIRECT) 60 | info->type = YAFT_FB_TYPE_PACKED_PIXELS; 61 | else if (type == V_INFO_MM_PLANAR) 62 | info->type = YAFT_FB_TYPE_PLANES; 63 | else 64 | info->type = YAFT_FB_TYPE_UNKNOWN; 65 | 66 | /* in FreeBSD, Direct Color is not exist? */ 67 | if (type == V_INFO_MM_DIRECT && info->bits_per_pixel >= 15) 68 | info->visual = YAFT_FB_VISUAL_TRUECOLOR; 69 | else if (type == V_INFO_MM_PACKED && visual & V_ADP_PALETTE 70 | && info->bits_per_pixel == 8) 71 | info->visual = YAFT_FB_VISUAL_PSEUDOCOLOR; 72 | else 73 | info->visual = YAFT_FB_VISUAL_UNKNOWN; 74 | } 75 | 76 | bool set_fbinfo(int fd, struct fb_info_t *info) 77 | { 78 | int video_mode; 79 | video_info_t vinfo; 80 | video_adapter_info_t ainfo; 81 | 82 | if (ioctl(fd, FBIO_GETMODE, &video_mode)) { 83 | logging(ERROR, "ioctl: FBIO_GETMODE failed\n"); 84 | return false; 85 | } 86 | 87 | vinfo.vi_mode = video_mode; 88 | if (ioctl(fd, FBIO_MODEINFO, &vinfo)) { 89 | logging(ERROR, "ioctl: FBIO_MODEINFO failed\n"); 90 | return false; 91 | } 92 | 93 | if (ioctl(fd, FBIO_ADPINFO, &ainfo)) { 94 | logging(ERROR, "ioctl: FBIO_ADPINFO failed\n"); 95 | return false; 96 | } 97 | 98 | set_bitfield(&vinfo, &info->red, &info->green, &info->blue); 99 | 100 | info->width = vinfo.vi_width; 101 | info->height = vinfo.vi_height; 102 | info->screen_size = ainfo.va_window_size; 103 | info->line_length = ainfo.va_line_width; 104 | 105 | info->bits_per_pixel = vinfo.vi_depth; 106 | info->bytes_per_pixel = my_ceil(vinfo.vi_depth, BITS_PER_BYTE); 107 | 108 | logging(DEBUG, "mem_model:%d va_flags:0x%X\n", vinfo.vi_mem_model, ainfo.va_flags); 109 | set_type_visual(info, vinfo.vi_mem_model, ainfo.va_flags); 110 | 111 | return true; 112 | } 113 | -------------------------------------------------------------------------------- /fb/linux.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE for licence details. */ 2 | #include 3 | #include 4 | #include 5 | 6 | typedef struct fb_cmap cmap_t; 7 | 8 | enum { 9 | CMAP_COLOR_LENGTH = sizeof(__u16) * BITS_PER_BYTE, 10 | }; 11 | 12 | /* os specific ioctl */ 13 | void alloc_cmap(cmap_t *cmap, int colors) 14 | { 15 | cmap->start = 0; 16 | cmap->len = colors; 17 | cmap->red = (__u16 *) ecalloc(colors, sizeof(__u16)); 18 | cmap->green = (__u16 *) ecalloc(colors, sizeof(__u16)); 19 | cmap->blue = (__u16 *) ecalloc(colors, sizeof(__u16)); 20 | cmap->transp = NULL; 21 | } 22 | 23 | int put_cmap(int fd, cmap_t *cmap) 24 | { 25 | return ioctl(fd, FBIOPUTCMAP, cmap); 26 | } 27 | 28 | int get_cmap(int fd, cmap_t *cmap) 29 | { 30 | return ioctl(fd, FBIOGETCMAP, cmap); 31 | } 32 | 33 | /* initialize struct fb_info_t */ 34 | void set_bitfield(struct fb_var_screeninfo *vinfo, 35 | struct bitfield_t *red, struct bitfield_t *green, struct bitfield_t *blue) 36 | { 37 | red->length = vinfo->red.length; 38 | green->length = vinfo->green.length; 39 | blue->length = vinfo->blue.length; 40 | 41 | red->offset = vinfo->red.offset; 42 | green->offset = vinfo->green.offset; 43 | blue->offset = vinfo->blue.offset; 44 | } 45 | 46 | enum fb_type_t set_type(__u32 type) 47 | { 48 | if (type == FB_TYPE_PACKED_PIXELS) 49 | return YAFT_FB_TYPE_PACKED_PIXELS; 50 | else if (type == FB_TYPE_PLANES) 51 | return YAFT_FB_TYPE_PLANES; 52 | else 53 | return YAFT_FB_TYPE_UNKNOWN; 54 | } 55 | 56 | enum fb_visual_t set_visual(__u32 visual) 57 | { 58 | if (visual == FB_VISUAL_TRUECOLOR) 59 | return YAFT_FB_VISUAL_TRUECOLOR; 60 | else if (visual == FB_VISUAL_DIRECTCOLOR) 61 | return YAFT_FB_VISUAL_DIRECTCOLOR; 62 | else if (visual == FB_VISUAL_PSEUDOCOLOR) 63 | return YAFT_FB_VISUAL_PSEUDOCOLOR; 64 | else 65 | return YAFT_FB_VISUAL_UNKNOWN; 66 | } 67 | 68 | bool set_fbinfo(int fd, struct fb_info_t *info) 69 | { 70 | struct fb_fix_screeninfo finfo; 71 | struct fb_var_screeninfo vinfo; 72 | 73 | if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo)) { 74 | logging(ERROR, "ioctl: FBIOGET_FSCREENINFO failed\n"); 75 | return false; 76 | } 77 | 78 | if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo)) { 79 | logging(ERROR, "ioctl: FBIOGET_VSCREENINFO failed\n"); 80 | return false; 81 | } 82 | 83 | set_bitfield(&vinfo, &info->red, &info->green, &info->blue); 84 | 85 | info->width = vinfo.xres; 86 | info->height = vinfo.yres; 87 | info->screen_size = finfo.smem_len; 88 | info->line_length = finfo.line_length; 89 | 90 | info->bits_per_pixel = vinfo.bits_per_pixel; 91 | info->bytes_per_pixel = my_ceil(info->bits_per_pixel, BITS_PER_BYTE); 92 | 93 | info->type = set_type(finfo.type); 94 | info->visual = set_visual(finfo.visual); 95 | 96 | /* check screen [xy]offset and initialize because linux console changes these values */ 97 | if (vinfo.xoffset != 0 || vinfo.yoffset != 0) { 98 | vinfo.xoffset = vinfo.yoffset = 0; 99 | if (ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo)) 100 | logging(WARN, "couldn't reset offset (x:%d y:%d)\n", vinfo.xoffset, vinfo.yoffset); 101 | } 102 | 103 | return true; 104 | } 105 | -------------------------------------------------------------------------------- /fb/netbsd.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE for licence details. */ 2 | /* XXX: _XOPEN_SOURCE >= 600 invalidates __BSD_VISIBLE 3 | so define some types manually */ 4 | typedef unsigned char unchar; 5 | typedef unsigned char u_char; 6 | typedef unsigned short ushort; 7 | typedef unsigned int u_int; 8 | typedef unsigned long u_long; 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | typedef struct wsdisplay_cmap cmap_t; 15 | 16 | enum { 17 | CMAP_COLOR_LENGTH = sizeof(u_char) * BITS_PER_BYTE, 18 | }; 19 | 20 | void alloc_cmap(cmap_t *cmap, int colors) 21 | { 22 | cmap->index = 0; 23 | cmap->count = colors; 24 | cmap->red = (u_char *) ecalloc(colors, sizeof(u_char)); 25 | cmap->green = (u_char *) ecalloc(colors, sizeof(u_char)); 26 | cmap->blue = (u_char *) ecalloc(colors, sizeof(u_char)); 27 | } 28 | 29 | int put_cmap(int fd, cmap_t *cmap) 30 | { 31 | return ioctl(fd, WSDISPLAYIO_PUTCMAP, cmap); 32 | } 33 | 34 | int get_cmap(int fd, cmap_t *cmap) 35 | { 36 | return ioctl(fd, WSDISPLAYIO_GETCMAP, cmap); 37 | } 38 | 39 | void set_bitfield(int depth, struct bitfield_t *red, struct bitfield_t *green, struct bitfield_t *blue) 40 | { 41 | switch (depth) { 42 | case 15: 43 | red->offset = 10; green->offset = 5; blue->offset = 0; 44 | red->length = 5; green->length = 5; blue->length = 5; 45 | break; 46 | case 16: 47 | red->offset = 11; green->offset = 5; blue->offset = 0; 48 | red->length = 5; green->length = 6; blue->length = 5; 49 | break; 50 | case 24: 51 | case 32: 52 | red->offset = 16; green->offset = 8; blue->offset = 0; 53 | red->length = 8; green->length = 8; blue->length = 8; 54 | break; 55 | default: 56 | break; 57 | } 58 | } 59 | 60 | void set_type_visual(struct fb_info_t *info) 61 | { 62 | info->type = YAFT_FB_TYPE_PACKED_PIXELS; 63 | 64 | if (info->bits_per_pixel == 8) 65 | info->visual = YAFT_FB_VISUAL_PSEUDOCOLOR; 66 | else 67 | info->visual = YAFT_FB_VISUAL_TRUECOLOR; 68 | } 69 | 70 | bool set_fbinfo(int fd, struct fb_info_t *info) 71 | { 72 | int mode; 73 | struct wsdisplay_fbinfo finfo; 74 | 75 | mode = WSDISPLAYIO_MODE_DUMBFB; 76 | if (ioctl(fd, WSDISPLAYIO_SMODE, &mode)) { 77 | logging(ERROR, "ioctl: WSDISPLAYIO_SMODE failed\n"); 78 | return false; 79 | } 80 | 81 | if (ioctl(fd, WSDISPLAYIO_GINFO, &finfo)) { 82 | logging(ERROR, "ioctl: WSDISPLAYIO_GINFO failed\n"); 83 | return false; 84 | } 85 | logging(DEBUG, "width:%d height:%d depth:%d\n", finfo.width, finfo.height, finfo.depth); 86 | 87 | info->width = finfo.width; 88 | info->height = finfo.height; 89 | 90 | info->bits_per_pixel = finfo.depth; 91 | info->bytes_per_pixel = my_ceil(finfo.depth, BITS_PER_BYTE); 92 | 93 | info->line_length = info->bytes_per_pixel * info->width; 94 | info->screen_size = info->height * info->line_length; 95 | 96 | set_bitfield(info->bits_per_pixel, &info->red, &info->green, &info->blue); 97 | set_type_visual(info); 98 | 99 | return true; 100 | } 101 | -------------------------------------------------------------------------------- /fb/openbsd.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE for licence details. */ 2 | /* XXX: _XOPEN_SOURCE >= 600 invalidates __BSD_VISIBLE 3 | so define some types manually */ 4 | typedef unsigned char unchar; 5 | typedef unsigned char u_char; 6 | typedef unsigned short ushort; 7 | typedef unsigned int u_int; 8 | typedef unsigned long u_long; 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | typedef struct wsdisplay_cmap cmap_t; 15 | 16 | enum { 17 | CMAP_COLOR_LENGTH = sizeof(u_char) * BITS_PER_BYTE, 18 | FB_WIDTH = 640, 19 | FB_HEIGHT = 480, 20 | FB_DEPTH = 8, 21 | }; 22 | 23 | void alloc_cmap(cmap_t *cmap, int colors) 24 | { 25 | cmap->index = 0; 26 | cmap->count = colors; 27 | cmap->red = (u_char *) ecalloc(colors, sizeof(u_char)); 28 | cmap->green = (u_char *) ecalloc(colors, sizeof(u_char)); 29 | cmap->blue = (u_char *) ecalloc(colors, sizeof(u_char)); 30 | } 31 | 32 | int put_cmap(int fd, cmap_t *cmap) 33 | { 34 | return ioctl(fd, WSDISPLAYIO_PUTCMAP, cmap); 35 | } 36 | 37 | int get_cmap(int fd, cmap_t *cmap) 38 | { 39 | return ioctl(fd, WSDISPLAYIO_GETCMAP, cmap); 40 | } 41 | 42 | void set_bitfield(int depth, struct bitfield_t *red, struct bitfield_t *green, struct bitfield_t *blue) 43 | { 44 | switch (depth) { 45 | case 15: 46 | red->offset = 10; green->offset = 5; blue->offset = 0; 47 | red->length = 5; green->length = 5; blue->length = 5; 48 | break; 49 | case 16: 50 | red->offset = 11; green->offset = 5; blue->offset = 0; 51 | red->length = 5; green->length = 6; blue->length = 5; 52 | break; 53 | case 24: 54 | case 32: 55 | red->offset = 16; green->offset = 8; blue->offset = 0; 56 | red->length = 8; green->length = 8; blue->length = 8; 57 | break; 58 | default: 59 | break; 60 | } 61 | } 62 | 63 | void set_type_visual(struct fb_info_t *info) 64 | { 65 | info->type = YAFT_FB_TYPE_PACKED_PIXELS; 66 | 67 | if (info->bits_per_pixel == 8) 68 | info->visual = YAFT_FB_VISUAL_PSEUDOCOLOR; 69 | else 70 | info->visual = YAFT_FB_VISUAL_TRUECOLOR; 71 | } 72 | 73 | bool set_fbinfo(int fd, struct fb_info_t *info) 74 | { 75 | int mode; 76 | struct wsdisplay_fbinfo finfo; 77 | struct wsdisplay_gfx_mode gfx_mode = {.width = FB_WIDTH, .height = FB_HEIGHT, .depth = FB_DEPTH}; 78 | 79 | /* 80 | if (ioctl(fd, WSDISPLAYIO_GMODE, &info->reserved)) { 81 | logging(ERROR, "ioctl: WSDISPLAYIO_GMODE failed\n"); 82 | return false; 83 | } 84 | logging(DEBUG, "orig_mode:%d\n", info->reserved); 85 | */ 86 | 87 | if (ioctl(fd, WSDISPLAYIO_SETGFXMODE, &gfx_mode)) { 88 | logging(ERROR, "ioctl: WSDISPLAYIO_SETGFXMODE failed\n"); 89 | goto set_fbinfo_failed; 90 | } 91 | 92 | mode = WSDISPLAYIO_MODE_DUMBFB; 93 | if (ioctl(fd, WSDISPLAYIO_SMODE, &mode)) { 94 | logging(ERROR, "ioctl: WSDISPLAYIO_SMODE failed\n"); 95 | goto set_fbinfo_failed; 96 | } 97 | 98 | if (ioctl(fd, WSDISPLAYIO_GINFO, &finfo)) { 99 | logging(ERROR, "ioctl: WSDISPLAYIO_GINFO failed\n"); 100 | goto set_fbinfo_failed; 101 | } 102 | logging(DEBUG, "finfo width:%d height:%d depth:%d\n", finfo.width, finfo.height, finfo.depth); 103 | 104 | info->width = FB_WIDTH; 105 | info->height = FB_HEIGHT; 106 | 107 | info->bits_per_pixel = FB_DEPTH; 108 | info->bytes_per_pixel = my_ceil(FB_DEPTH, BITS_PER_BYTE); 109 | 110 | info->line_length = info->bytes_per_pixel * info->width; 111 | info->screen_size = info->height * info->line_length; 112 | 113 | set_bitfield(info->bits_per_pixel, &info->red, &info->green, &info->blue); 114 | set_type_visual(info); 115 | 116 | return true; 117 | 118 | set_fbinfo_failed: 119 | //ioctl(fd, WSDISPLAYIO_SMODE, &info->reserved); 120 | return false; 121 | } 122 | 123 | /* 124 | void fb_release(int fd, struct fb_info_t *info) 125 | { 126 | ioctl(fd, WSDISPLAYIO_SMODE, &info->reserved); 127 | } 128 | */ 129 | -------------------------------------------------------------------------------- /fonts/milkjf/README.1ST: -------------------------------------------------------------------------------- 1 | 《X Window BDF/PCF形式 16ドットフォントmilkjf》 2 | 3 | 製作 : 日本農園様 4 | −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 5 | 6 | X68000/X68030 シリーズ用に,日本農園様が製作された,milkjfフォ 7 | ント(全角非漢字部と半角)を,許可を得て X WindowのBDF形式に変換し, 8 | 配布する事が可能になりました(Public Domainです).なお,オリジナル 9 | の milkjfにない部分(特に漢字部)と, ギリシャ文字,ロシア文字は東 10 | 雲フォントを埋め込んでいます. 11 | フォントの一覧は以下の通りです.bold体はmkboldで作成したあと, 12 | 若干フォントエディタで修正を加えたものです. 13 | 14 | 15 | milkjf_8x16.bdf(.pcf) 16 | -milkjf-fixed-medium-r-normal--16-150-75-75-C-80-iso8859-1 17 | 18 | milkjf_8x16r.bdf(.pcf) 19 | -milkjf-fixed-medium-r-normal--16-150-75-75-C-80-jisx0201.1976-0 20 | 21 | milkjf_k16.bdf(.pcf) 22 | -milkjf-fixed-medium-r-normal--16-150-75-75-C-160-jisx0208.1990-0 23 | 24 | milkjf_8x16B.bdf(.pcf) 25 | -milkjf-fixed-bold-r-normal--16-150-75-75-C-80-iso8859-1 26 | 27 | milkjf_8x16rb.bdf(.pcf) 28 | -milkjf-fixed-bold-r-normal--16-150-75-75-C-80-jisx0201.1976-0 29 | 30 | milkjf_k16b.bdf(.pcf) 31 | -milkjf-fixed-bold-r-normal--16-150-75-75-C-160-jisx0208.1990-0 32 | 33 | 34 | −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 35 | X Window固有の問題等に関しては,以下にて. 36 | http://phe.phyas.aichi-edu.ac.jp/~cyamauch/xfonts.html 37 | 38 | cyamauch@hst.phyas.aichi-edu.ac.jp 山内千里 Oct.1,2001 39 | −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 40 | -------------------------------------------------------------------------------- /fonts/terminus/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Dimitar Toshkov Zhekov, 2 | with Reserved Font Name "Terminus Font". 3 | 4 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 5 | This license is copied below, and is also available with a FAQ at: 6 | http://scripts.sil.org/OFL 7 | 8 | 9 | ----------------------------------------------------------- 10 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 11 | ----------------------------------------------------------- 12 | 13 | PREAMBLE 14 | The goals of the Open Font License (OFL) are to stimulate worldwide 15 | development of collaborative font projects, to support the font creation 16 | efforts of academic and linguistic communities, and to provide a free and 17 | open framework in which fonts may be shared and improved in partnership 18 | with others. 19 | 20 | The OFL allows the licensed fonts to be used, studied, modified and 21 | redistributed freely as long as they are not sold by themselves. The 22 | fonts, including any derivative works, can be bundled, embedded, 23 | redistributed and/or sold with any software provided that any reserved 24 | names are not used by derivative works. The fonts and derivatives, 25 | however, cannot be released under any other type of license. The 26 | requirement for fonts to remain under this license does not apply 27 | to any document created using the fonts or their derivatives. 28 | 29 | DEFINITIONS 30 | "Font Software" refers to the set of files released by the Copyright 31 | Holder(s) under this license and clearly marked as such. This may 32 | include source files, build scripts and documentation. 33 | 34 | "Reserved Font Name" refers to any names specified as such after the 35 | copyright statement(s). 36 | 37 | "Original Version" refers to the collection of Font Software components as 38 | distributed by the Copyright Holder(s). 39 | 40 | "Modified Version" refers to any derivative made by adding to, deleting, 41 | or substituting -- in part or in whole -- any of the components of the 42 | Original Version, by changing formats or by porting the Font Software to a 43 | new environment. 44 | 45 | "Author" refers to any designer, engineer, programmer, technical 46 | writer or other person who contributed to the Font Software. 47 | 48 | PERMISSION & CONDITIONS 49 | Permission is hereby granted, free of charge, to any person obtaining 50 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 51 | redistribute, and sell modified and unmodified copies of the Font 52 | Software, subject to the following conditions: 53 | 54 | 1) Neither the Font Software nor any of its individual components, 55 | in Original or Modified Versions, may be sold by itself. 56 | 57 | 2) Original or Modified Versions of the Font Software may be bundled, 58 | redistributed and/or sold with any software, provided that each copy 59 | contains the above copyright notice and this license. These can be 60 | included either as stand-alone text files, human-readable headers or 61 | in the appropriate machine-readable metadata fields within text or 62 | binary files as long as those fields can be easily viewed by the user. 63 | 64 | 3) No Modified Version of the Font Software may use the Reserved Font 65 | Name(s) unless explicit written permission is granted by the corresponding 66 | Copyright Holder. This restriction only applies to the primary font name as 67 | presented to the users. 68 | 69 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 70 | Software shall not be used to promote, endorse or advertise any 71 | Modified Version, except to acknowledge the contribution(s) of the 72 | Copyright Holder(s) and the Author(s) or with their explicit written 73 | permission. 74 | 75 | 5) The Font Software, modified or unmodified, in part or in whole, 76 | must be distributed entirely under this license, and must not be 77 | distributed under any other license. The requirement for fonts to 78 | remain under this license does not apply to any document created 79 | using the Font Software. 80 | 81 | TERMINATION 82 | This license becomes null and void if any of the above conditions are 83 | not met. 84 | 85 | DISCLAIMER 86 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 87 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 88 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 89 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 90 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 91 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 92 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 93 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 94 | OTHER DEALINGS IN THE FONT SOFTWARE. 95 | -------------------------------------------------------------------------------- /glyph_builder.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # desc: bash script for creating yaft's glyph.h 3 | 4 | # settings 5 | YAFT_DIR=`pwd` 6 | WORK_DIR=/tmp/glyph_builder 7 | ALIAS_FILE=alias 8 | 9 | # infomation of each fonts 10 | # mplus 11 | MPLUS_VERSION=2.2.4 12 | MPLUS_NAME=mplus_bitmap_fonts-${MPLUS_VERSION} 13 | MPLUS_FILE=${MPLUS_NAME}.tar.gz 14 | MPLUS_URL=http://iij.dl.osdn.jp/mplus-fonts/5030/${MPLUS_FILE} 15 | 16 | # efont 17 | EFONT_VERSION=0.4.2 18 | EFONT_NAME=efont-unicode-bdf-${EFONT_VERSION} 19 | EFONT_FILE=${EFONT_NAME}.tar.bz2 20 | EFONT_URL=http://openlab.ring.gr.jp/efont/dist/unicode-bdf/${EFONT_FILE} 21 | 22 | # milkjf 23 | # already included in yaft 24 | 25 | # unifont 26 | UNIFONT_VERSION=11.0.02 27 | UNIFONT_NAME=unifont-${UNIFONT_VERSION} 28 | UNIFONT_FILE=${UNIFONT_NAME}.bdf.gz 29 | UNIFONT_URL=http://unifoundry.com/pub/unifont/${UNIFONT_NAME}/font-builds/${UNIFONT_FILE} 30 | 31 | # dina font (fetch from ProgrammingFonts repository) 32 | DINA_VERSION= 33 | DINA_NAME= 34 | DINA_FILE= 35 | DINA_DIR=ProgrammingFonts/Dina/BDF 36 | DINA_URL=https://github.com/ProgrammingFonts/ProgrammingFonts.git 37 | 38 | # terminus font 39 | TERMINUS_VERSION=4.39 40 | TERMINUS_NAME=terminus-font-${TERMINUS_VERSION} 41 | TERMINUS_FILE=${TERMINUS_NAME}.tar.gz 42 | TERMINUS_URL=http://sourceforge.net/projects/terminus-font/files/${TERMINUS_NAME}/${TERMINUS_FILE} 43 | 44 | # profont (pcf format) 45 | PROFONT_VERSION= 46 | PROFONT_NAME=profont-x11 47 | PROFONT_FILE=${PROFONT_NAME}.zip 48 | PROFONT_URL=http://tobiasjung.name/downloadfile.php?file=${PROFONT_FILE} 49 | 50 | # tamsyn font (pcf format) 51 | TAMSYN_VERSION=1.11 52 | TAMSYN_NAME=tamsyn-font-${TAMSYN_VERSION} 53 | TAMSYN_FILE=${TAMSYN_NAME}.tar.gz 54 | TAMSYN_URL=http://www.fial.com/~scott/tamsyn-font/download/${TAMSYN_FILE} 55 | 56 | # wqy-bitmapfont (mkfont_bdf cannot handle this font...) 57 | WQY_VERSION=1.0.0-RC1 58 | WQY_NAME=wqy-bitmapsong-bdf-${WQY_VERSION} 59 | WQY_FILE=${WQY_NAME}.tar.gz 60 | WQY_URL=http://jaist.dl.sourceforge.net/project/wqy/wqy-bitmapfont/${WQY_VERSION}/${WQY_FILE} 61 | 62 | # misc functions 63 | usage() 64 | { 65 | echo -e "usage: ./glyph_builder.sh FONTS VARIATIONS" 66 | echo -e "\tavalable fonts: mplus, efont, milkjf, unifont, dina, terminus, profont, tamsyn" 67 | echo -e "depends on: wget, pcf2bdf" 68 | } 69 | 70 | generate() 71 | { 72 | echo "./mkfont_bdf ./table/${ALIAS_FILE} ${@} > ${YAFT_DIR}/glyph.h" 73 | ./mkfont_bdf ./table/${ALIAS_FILE} ${@} > ${YAFT_DIR}/glyph.h 74 | } 75 | 76 | # each font generate function 77 | mplus_create_bdf() 78 | { 79 | # Install M+ BITMAP FONTS E 80 | echo -e "\nInstall M+ BITMAP FONTS E (iso8859-1)..." 81 | cd fonts_e 82 | 83 | awk '/^SWIDTH/{$2 += 80} /^DWIDTH/{$2 += 1} {print}' mplus_h12r.bdf \ 84 | | sed 's/hlv/hlvw/'> mplus_h12rw.bdf 85 | cd - 86 | 87 | # Install M+ BITMAP FONTS EURO 88 | echo -e "\nInstall M+ BITMAP FONTS EURO (iso8859-15)..." 89 | cd fonts_e/euro 90 | for f in mplus_*.diff 91 | do 92 | b=`basename $f .diff` 93 | echo "$f $b" 94 | cp ../$b.bdf ./ 95 | patch $b.bdf $b.diff 96 | mv $b.bdf $b-euro.bdf 97 | done 98 | 99 | awk '/^SWIDTH/{$2 += 80} /^DWIDTH/{$2 += 1} {print}' \ 100 | mplus_h12r-euro.bdf | sed 's/hlv/hlvw/' > mplus_h12rw-euro.bdf 101 | cd - 102 | 103 | echo -e "\nInstall M+ BITMAP FONTS J..." 104 | cd fonts_j 105 | 106 | echo "create: mplus_j10b.bdf" 107 | echo -n "wait a minute..." 108 | ../mkbold -r -R mplus_j10r.bdf | sed 's/medium/bold/' \ 109 | > mplus_j10b.bdf && 110 | echo " done" 111 | 112 | echo "create: mplus_j12b.bdf" 113 | echo -n "wait a minute..." 114 | ../mkbold -r -R mplus_j12r.bdf | sed 's/medium/bold/' \ 115 | > mplus_j12b.bdf && 116 | echo " done" 117 | 118 | cp mplus_j10r-iso-W4 mplus_j10r-iso.bdf 119 | echo "select: mplus_j10r-iso.bdf [W5]" 120 | patch mplus_j10r-iso.bdf mplus_j10r-iso-W5.diff 121 | #echo "select: mplus_j10r-iso.bdf [W4]" 122 | 123 | for f in mplus_[!j]*-jisx0201.diff 124 | do 125 | b=`basename $f -jisx0201.diff` 126 | echo "create: $b-jisx0201.bdf" 127 | cp ../fonts_e/$b.bdf ./ 128 | patch $b.bdf $b-jisx0201.diff 129 | mv $b.bdf $b-jisx0201.bdf 130 | done 131 | 132 | for f in mplus_j*-jisx0201.diff 133 | do 134 | b=`basename $f -jisx0201.diff` 135 | echo "create: $b-jisx0201.bdf" 136 | cp $b-iso.bdf $b-jisx0201.bdf 137 | patch $b-jisx0201.bdf $b-jisx0201.diff 138 | done 139 | 140 | # some bug fix 141 | sed -i 's|STARTCHAR 0x2455n|STARTCHAR 0x2455|' mplus_j12r.bdf 142 | sed -i 's|STARTCHAR 0x2455n|STARTCHAR 0x2455|' mplus_j12b.bdf 143 | 144 | cd - 145 | 146 | touch created 147 | } 148 | 149 | mplus() 150 | { 151 | echo -ne "creating glyph.h from mplus fonts...\n" 152 | wget -q -nc ${MPLUS_URL} 153 | 154 | if test ! -d ${MPLUS_NAME}; then 155 | bsdtar xf ${MPLUS_FILE} 156 | fi 157 | 158 | cd ${MPLUS_NAME} 159 | ln -sf ${YAFT_DIR}/mkfont_bdf . 160 | ln -sf ${YAFT_DIR}/table . 161 | 162 | if test ! -f created; then 163 | mplus_create_bdf > /dev/null 2>&1 164 | fi 165 | 166 | case "$1" in 167 | j10*) 168 | FILES=`find fonts_j -type f -name "*${1}*.bdf" | tr "\n" " "`;; 169 | j12*) 170 | PATTERN=`echo -n $1 | tail -c3` 171 | FILES=`find . -type f -name "*[fj]${PATTERN}*.bdf" | tr "\n" " "`;; 172 | f10*|f12*) 173 | FILES=`find fonts_e -type f -name "*${1}*.bdf" | tr "\n" " "`;; 174 | *) 175 | echo -ne "avalable font variations: [fj](10|12)[rb]\n" 176 | exit -1;; 177 | esac 178 | 179 | generate ${FILES} 180 | } 181 | 182 | efont() 183 | { 184 | echo -ne "creating glyph.h from efont unicode...\n" 185 | wget -q -nc ${EFONT_URL} 186 | 187 | if test ! -d ${EFONT_NAME}; then 188 | bsdtar xf ${EFONT_FILE} 189 | fi 190 | 191 | cd ${EFONT_NAME} 192 | ln -sf ${YAFT_DIR}/mkfont_bdf . 193 | ln -sf ${YAFT_DIR}/table . 194 | 195 | case "$1" in 196 | 1[0246]*|24*) 197 | FILES=`find . -type f -name "*${1}.bdf" | tr "\n" " "`;; 198 | *) 199 | echo -ne "avalable font variations: (10|12|14|16|24)(_b)?\n" 200 | exit -1;; 201 | esac 202 | 203 | generate ${FILES} 204 | } 205 | 206 | milkjf() 207 | { 208 | echo -ne "creating glyph.h from milkjf font...\n" 209 | 210 | ln -sf $YAFT_DIR/mkfont_bdf . 211 | ln -sf $YAFT_DIR/table . 212 | ln -sf $YAFT_DIR/fonts . 213 | 214 | FILES=`find -L fonts -type f -name "*.bdf" | tr "\n" " "` 215 | 216 | generate ${FILES} 217 | } 218 | 219 | unifont() 220 | { 221 | echo -ne "creating glyph.h from unifont...\n" 222 | wget -q -nc ${UNIFONT_URL} 223 | 224 | if test ! -f ${UNIFONT_NAME}.bdf; then 225 | gunzip ${UNIFONT_FILE} 226 | fi 227 | 228 | ln -sf $YAFT_DIR/mkfont_bdf . 229 | ln -sf $YAFT_DIR/table . 230 | 231 | FILES="${UNIFONT_NAME}.bdf" 232 | 233 | generate ${FILES} 234 | } 235 | 236 | dina() 237 | { 238 | echo -ne "creating glyph.h from dina font...\n" 239 | git clone ${DINA_URL} 240 | 241 | ln -sf $YAFT_DIR/mkfont_bdf . 242 | ln -sf $YAFT_DIR/table . 243 | 244 | case "$1" in 245 | r*) 246 | FILES=`find ${DINA_DIR} -type f -name "*${1}.bdf" | tr "\n" " "`;; 247 | *) 248 | echo -ne "avalable font variations: r400-(6|8|9|10), r700-(8|9|10)\n" 249 | exit -1;; 250 | esac 251 | 252 | generate ${FILES} 253 | } 254 | 255 | terminus() 256 | { 257 | echo -ne "creating glyph.h from terminus font...\n" 258 | wget -q -nc ${TERMINUS_URL} 259 | 260 | if test ! -d ${TERMINUS_NAME}; then 261 | bsdtar xf ${TERMINUS_FILE} 262 | fi 263 | 264 | cd ${TERMINUS_NAME} 265 | ln -sf $YAFT_DIR/mkfont_bdf . 266 | ln -sf $YAFT_DIR/table . 267 | 268 | case "$1" in 269 | u*) 270 | FILES=`find . -type f -name "*${1}.bdf" | tr "\n" " "`;; 271 | *) 272 | echo -ne "avalable font variations: u(14|16)v, u(12|14|16|18|20|22|24|28|32)[nb]\n" 273 | exit -1;; 274 | esac 275 | 276 | generate ${FILES} 277 | } 278 | 279 | profont() 280 | { 281 | echo -ne "creating glyph.h from profont...\n" 282 | wget -q -nc ${PROFONT_URL} -O ${PROFONT_FILE} 283 | 284 | if test ! -d ${PROFONT_NAME}; then 285 | bsdtar xf ${PROFONT_FILE} 286 | fi 287 | 288 | cd ${PROFONT_NAME} 289 | ln -sf $YAFT_DIR/mkfont_bdf . 290 | ln -sf $YAFT_DIR/table . 291 | 292 | if test ! -f created; then 293 | for i in *.pcf; do 294 | pcf2bdf -o `basename $i .pcf`.bdf $i 295 | done 296 | touch created 297 | fi 298 | 299 | case "$1" in 300 | 1*|2*) 301 | FILES=`find . -type f -name "*${1}.bdf" | tr "\n" " "`;; 302 | *) 303 | echo -ne "avalable font variations: (10|11|12|15|17|22|29)\n" 304 | exit -1;; 305 | esac 306 | 307 | generate ${FILES} 308 | } 309 | 310 | tamsyn() 311 | { 312 | echo -ne "creating glyph.h from tamsyn font...\n" 313 | wget -q -nc ${TAMSYN_URL} 314 | 315 | if test ! -d ${TAMSYN_NAME}; then 316 | bsdtar xf ${TAMSYN_FILE} 317 | fi 318 | 319 | cd ${TAMSYN_NAME} 320 | ln -sf $YAFT_DIR/mkfont_bdf . 321 | ln -sf $YAFT_DIR/table . 322 | 323 | if test ! -f created; then 324 | for i in *.pcf; do 325 | pcf2bdf -o `basename $i .pcf`.bdf $i 326 | done 327 | touch created 328 | fi 329 | 330 | case "$1" in 331 | *[rb]) 332 | FILES=`find . -type f -name "*${1}.bdf" | tr "\n" " "`;; 333 | *) 334 | echo -ne "avalable font variations: (5x9|6x12|7x13|7x14|8x15|8x16|10x20)[rb]\n" 335 | exit -1;; 336 | esac 337 | 338 | generate ${FILES} 339 | } 340 | 341 | wqy() 342 | { 343 | echo -ne "creating glyph.h from tamsyn font...\n" 344 | wget -q -nc ${WQY_URL} 345 | 346 | if test ! -d ${WQY_NAME}; then 347 | bsdtar xf ${WQY_FILE} 348 | fi 349 | 350 | cd wqy-bitmapsong 351 | ln -sf $YAFT_DIR/mkfont_bdf . 352 | ln -sf $YAFT_DIR/table . 353 | 354 | case "$1" in 355 | *pt|*px) 356 | FILES=`find . -type f -name "*${1}.bdf" | tr "\n" " "`;; 357 | *) 358 | echo -ne "avalable font variations: (9|10|11|12)pt, 13px\n" 359 | exit -1;; 360 | esac 361 | 362 | generate ${FILES} 363 | } 364 | 365 | # main 366 | echo "LANG: $LANG" 367 | mkdir -p $WORK_DIR 368 | cd $WORK_DIR 369 | 370 | case "$1" in 371 | "mplus") 372 | shift 373 | mplus $1;; 374 | "efont") 375 | shift 376 | efont $1;; 377 | "milkjf") 378 | milkjf;; 379 | "unifont") 380 | unifont;; 381 | "dina") 382 | shift 383 | dina $1;; 384 | "terminus") 385 | shift 386 | terminus $1;; 387 | "profont") 388 | shift 389 | profont $1;; 390 | "tamsyn") 391 | shift 392 | tamsyn $1;; 393 | *) 394 | usage;; 395 | esac 396 | -------------------------------------------------------------------------------- /img/yaft-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uobikiemukot/yaft/59ef091187736200e07ee1d67d6249ad4c691542/img/yaft-blue.png -------------------------------------------------------------------------------- /img/yaft-gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uobikiemukot/yaft/59ef091187736200e07ee1d67d6249ad4c691542/img/yaft-gray.png -------------------------------------------------------------------------------- /img/yaft-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uobikiemukot/yaft/59ef091187736200e07ee1d67d6249ad4c691542/img/yaft-screenshot.png -------------------------------------------------------------------------------- /info/yaft.cap: -------------------------------------------------------------------------------- 1 | # (untranslatable capabilities removed to fit entry within 1023 bytes) 2 | yaft-256color|yet another framebuffer terminal:\ 3 | :am:ms:ut:xn:\ 4 | :Co#256:co#80:it#8:li#24:pa#32767:\ 5 | :&7=^Z:@7=\E[4~:AB=\E[48;5;%dm:AF=\E[38;5;%dm:AL=\E[%dL:\ 6 | :DC=\E[%dP:DL=\E[%dM:DO=\E[%dB:F1=\E[23~:F2=\E[24~:\ 7 | :F3=\E[25~:F4=\E[26~:F5=\E[28~:F6=\E[29~:F7=\E[31~:\ 8 | :F8=\E[32~:F9=\E[33~:FA=\E[34~:IC=\E[%d@:K2=\E[G:Km=\E[M:\ 9 | :LE=\E[%dD:RA=\E[?7l:RI=\E[%dC:SA=\E[?7h:UP=\E[%dA:\ 10 | :al=\E[L:cb=\E[1K:cd=\E[J:ce=\E[K:ch=\E[%i%dG:cl=\E[H\E[J:\ 11 | :cm=\E[%i%d;%dH:cr=^M:cs=\E[%i%d;%dr:ct=\E[3g:\ 12 | :cv=\E[%i%dd:dc=\E[P:dl=\E[M:do=^J:ec=\E[%dX:ei=:ho=\E[H:\ 13 | :ic=\E[@:im=:is=\Ec:\ 14 | :k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:k5=\E[15~:k6=\E[17~:k7=\E[18~:k8=\E[19~:k9=\E[20~:\ 15 | :kD=\E[3~:kI=\E[2~:kN=\E[6~:kP=\E[5~:kb=^H:kd=\EOB:ke=\E[?1l\E>:kh=\EOH:kl=\EOD:kr=\EOC:ks=\E[?1h\E=:ku=\EOA:\ 16 | :le=^H:\ 17 | :mb=\E[5m:md=\E[1m:me=\E[m:mr=\E[7m:nd=\E[C:nw=\EE:\ 18 | :op=\E[39;49m:rc=\E8:rs=\Ec:sc=\E7:se=\E[27m:sf=^J:\ 19 | :so=\E[7m:sr=\EM:st=\EH:ta=^I:ue=\E[24m:up=\E[A:us=\E[4m:\ 20 | :ve=\E[?25h:vi=\E[?25l:\ 21 | :u6=\E[%d;%dR:u7=\E[6n: 22 | -------------------------------------------------------------------------------- /info/yaft.src: -------------------------------------------------------------------------------- 1 | yaft-256color|yet another framebuffer terminal, 2 | am, bce, msgr, xenl, 3 | 4 | cols#80, lines#24, it#8, colors#256, pairs#32767, 5 | 6 | clear=\E[H\E[J, 7 | 8 | nel=\EE, cr=^M, 9 | 10 | cuf=\E[%p1%dC, cuf1=\E[C, 11 | cub=\E[%p1%dD, cub1=^H, 12 | cuu=\E[%p1%dA, cuu1=\E[A, 13 | cud=\E[%p1%dB, cud1=^J, 14 | 15 | home=\E[H, 16 | cup=\E[%i%p1%d;%p2%dH, 17 | hpa=\E[%i%p1%dG, vpa=\E[%i%p1%dd, 18 | 19 | ind=^J, ri=\EM, 20 | csr=\E[%i%p1%d;%p2%dr, 21 | 22 | ed=\E[J, 23 | ech=\E[%p1%dX, 24 | dch=\E[%p1%dP, dch1=\E[P, 25 | dl=\E[%p1%dM, dl1=\E[M, 26 | el=\E[K, el1=\E[1K, 27 | 28 | il=\E[%p1%dL, il1=\E[L, 29 | ich=\E[%p1%d@, ich1=\E[@, 30 | 31 | civis=\E[?25l, cnorm=\E[?25h, 32 | 33 | ht=^I, hts=\EH, tbc=\E[3g, 34 | 35 | sc=\E7, rc=\E8, 36 | 37 | is2=\Ec, rs2=\Ec, 38 | 39 | op=\E[39;49m, 40 | 41 | setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m, 42 | setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m, 43 | 44 | sgr0=\E[m, 45 | sgr=\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;m, 46 | 47 | bold=\E[1m, rev=\E[7m, blink=\E[5m, 48 | smso=\E[7m, rmso=\E[27m, 49 | smul=\E[4m, rmul=\E[24m, 50 | smam=\E[?7h, rmam=\E[?7l, 51 | 52 | kf1=\E[[A, kf2=\E[[B, kf3=\E[[C, kf4=\E[[D, kf5=\E[[E, 53 | kf6=\E[17~, kf7=\E[18~, kf8=\E[19~, kf9=\E[20~, kf10=\E[21~, 54 | kf11=\E[23~, kf12=\E[24~, kf13=\E[25~, kf14=\E[26~, kf15=\E[28~, 55 | kf16=\E[29~, kf17=\E[31~, kf18=\E[32~, kf19=\E[33~, kf20=\E[34~, 56 | 57 | kcub1=\E[D, kcud1=\E[B, kcuf1=\E[C, kcuu1=\E[A, 58 | kb2=\E[G, kbs=\177, kcbt=\E[Z, 59 | khome=\E[1~, kich1=\E[2~, kdch1=\E[3~, kend=\E[4~, 60 | kmous=\E[M, knp=\E[6~, kpp=\E[5~, kspd=^Z, 61 | 62 | u6=\E[%i%d;%dR, u7=\E[6n, 63 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | CC ?= gcc 2 | #CC ?= clang 3 | 4 | CFLAGS ?= -std=c99 -pedantic -Wall -Wextra -O3 -s -pipe 5 | LDFLAGS ?= 6 | 7 | XCFLAGS ?= -std=c99 -pedantic -Wall -Wextra -I/usr/include/X11/ -O3 -s -pipe 8 | XLDFLAGS ?= -lX11 9 | 10 | HDR = glyph.h yaft.h conf.h color.h parse.h terminal.h util.h \ 11 | ctrlseq/esc.h ctrlseq/csi.h ctrlseq/osc.h ctrlseq/dcs.h \ 12 | fb/common.h fb/linux.h fb/freebsd.h fb/netbsd.h fb/openbsd.h \ 13 | x/x.h 14 | 15 | DESTDIR = 16 | PREFIX = $(DESTDIR)/usr 17 | MANPREFIX = $(DESTDIR)/usr/share/man 18 | 19 | all: yaft 20 | 21 | yaft: mkfont_bdf 22 | 23 | yaftx: mkfont_bdf 24 | 25 | mkfont_bdf: tools/mkfont_bdf.c tools/mkfont_bdf.h tools/bdf.h tools/util.h 26 | $(CC) -o $@ $< $(CFLAGS) $(LDFLAGS) 27 | 28 | glyph.h: mkfont_bdf 29 | # If you want to use your favorite fonts, please change following line 30 | # usage: mkfont_bdf ALIAS BDF1 BDF2 BDF3... > glyph.h 31 | # ALIAS: glyph substitution rule file (see table/alias for more detail) 32 | # BDF1 BDF2 BDF3...: monospace bdf files (must be the same size) 33 | # If there is more than one glyph of the same codepoint, the glyph included in the first bdf file is choosed 34 | ./mkfont_bdf table/alias fonts/milkjf/milkjf_k16.bdf fonts/milkjf/milkjf_8x16r.bdf fonts/milkjf/milkjf_8x16.bdf fonts/terminus/ter-u16n.bdf > glyph.h 35 | 36 | yaft: yaft.c $(HDR) 37 | # If you want to change configuration, please modify conf.h before make (see conf.h for more detail) 38 | $(CC) -o $@ $< $(CFLAGS) $(LDFLAGS) 39 | 40 | yaftx: x/yaftx.c $(HDR) 41 | # If you want to change configuration, please modify conf.h before make (see conf.h for more detail) 42 | $(CC) -o $@ $< $(XCFLAGS) $(XLDFLAGS) 43 | 44 | install: 45 | mkdir -p $(PREFIX)/share/terminfo 46 | tic -o $(PREFIX)/share/terminfo info/yaft.src 47 | mkdir -p $(PREFIX)/bin/ 48 | install -m755 ./yaft $(PREFIX)/bin/yaft 49 | install -m755 ./yaft_wall $(PREFIX)/bin/yaft_wall 50 | mkdir -p $(MANPREFIX)/man1/ 51 | install -m644 ./man/yaft.1 $(MANPREFIX)/man1/yaft.1 52 | 53 | installx: 54 | mkdir -p $(PREFIX)/share/terminfo 55 | tic -o $(PREFIX)/share/terminfo info/yaft.src 56 | mkdir -p $(PREFIX)/bin/ 57 | install -m755 ./yaftx $(PREFIX)/bin/yaftx 58 | 59 | uninstall: 60 | rm -f $(PREFIX)/bin/yaft 61 | rm -f $(PREFIX)/bin/yaft_wall 62 | 63 | uninstallx: 64 | rm -f $(PREFIX)/bin/yaftx 65 | 66 | clean: 67 | rm -f yaft yaftx mkfont_bdf glyph.h 68 | -------------------------------------------------------------------------------- /man/yaft.1: -------------------------------------------------------------------------------- 1 | .TH "YAFT" "1" "July 2014" "yaft 0.2.7" "yaft User Manual" 2 | .SH NAME 3 | .PP 4 | yaft \- yet another framebuffer terminal 5 | .SH SYNOPSIS 6 | .PP 7 | .B yaft 8 | .RB [ \-h ] 9 | .SH DESCRIPTION 10 | .PP 11 | .B yaft 12 | is simple framebuffer terminal emulator for minimalist (living without X). 13 | .SH OPTIONS 14 | .TP 15 | .B \-h 16 | Show help 17 | .RS 18 | .RE 19 | .SH CUSTOMIZATION 20 | .PP 21 | Rewrite conf.h before make. 22 | .SH CUSTOM FONTS 23 | .PP 24 | You can use tools/mkfont_bdf to create fonts file. See makefile and table/alias for detail. 25 | .SH ENVIRONMENT VARIABLES 26 | .TP 27 | .B FRAMEBUFFER 28 | Specify framebuffer device. 29 | .RS 30 | .RE 31 | .TP 32 | .B YAFT 33 | If this variable includes "wall", yaft enables wallpaper mode. See yaft_wall script for detail. 34 | .RS 35 | .RE 36 | .SH AUTHOR 37 | .PP 38 | haru 39 | .SH LICENSE 40 | .PP 41 | MIT LISENCE 42 | .SH "REPORTING BUGS" 43 | Please submit bug reports to <\fBhttps://github.com/uobikiemukot/yaft/issues\fR>. 44 | .SH SEE ALSO 45 | .PP 46 | .BR console_codes (4), 47 | .BR console_ioctl (4), 48 | .BR terminfo (5) 49 | -------------------------------------------------------------------------------- /parse.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE for licence details. */ 2 | void (*ctrl_func[CTRL_CHARS])(struct terminal_t *term) = { 3 | [BS] = bs, 4 | [HT] = tab, 5 | [LF] = nl, 6 | [VT] = nl, 7 | [FF] = nl, 8 | [CR] = cr, 9 | [ESC] = enter_esc, 10 | }; 11 | 12 | void (*esc_func[ESC_CHARS])(struct terminal_t *term) = { 13 | ['7'] = save_state, 14 | ['8'] = restore_state, 15 | ['D'] = nl, 16 | ['E'] = crnl, 17 | ['H'] = set_tabstop, 18 | ['M'] = reverse_nl, 19 | ['P'] = enter_dcs, 20 | ['Z'] = identify, 21 | ['['] = enter_csi, 22 | [']'] = enter_osc, 23 | ['c'] = ris, 24 | }; 25 | 26 | void (*csi_func[ESC_CHARS])(struct terminal_t *term, struct parm_t *) = { 27 | ['@'] = insert_blank, 28 | ['A'] = curs_up, 29 | ['B'] = curs_down, 30 | ['C'] = curs_forward, 31 | ['D'] = curs_back, 32 | ['E'] = curs_nl, 33 | ['F'] = curs_pl, 34 | ['G'] = curs_col, 35 | ['H'] = curs_pos, 36 | ['J'] = erase_display, 37 | ['K'] = erase_line, 38 | ['L'] = insert_line, 39 | ['M'] = delete_line, 40 | ['P'] = delete_char, 41 | ['X'] = erase_char, 42 | ['a'] = curs_forward, 43 | ['c'] = device_attribute, 44 | ['d'] = curs_line, 45 | ['e'] = curs_down, 46 | ['f'] = curs_pos, 47 | ['g'] = clear_tabstop, 48 | ['h'] = set_mode, 49 | ['l'] = reset_mode, 50 | ['m'] = set_attr, 51 | ['n'] = status_report, 52 | ['r'] = set_margin, 53 | /* XXX: not implemented because these sequences conflict DECSLRM/DECSHTS 54 | ['s'] = sco_save_state, 55 | ['u'] = sco_restore_state, 56 | */ 57 | ['`'] = curs_col, 58 | }; 59 | 60 | /* ctr char/esc sequence/charset function */ 61 | void control_character(struct terminal_t *term, uint8_t ch) 62 | { 63 | static const char *ctrl_char[] = { 64 | "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", 65 | "BS ", "HT ", "LF ", "VT ", "FF ", "CR ", "SO ", "SI ", 66 | "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", 67 | "CAN", "EM ", "SUB", "ESC", "FS ", "GS ", "RS ", "US ", 68 | }; 69 | 70 | *term->esc.bp = '\0'; 71 | 72 | logging(DEBUG, "ctl: %s\n", ctrl_char[ch]); 73 | 74 | if (ctrl_func[ch]) 75 | ctrl_func[ch](term); 76 | } 77 | 78 | void esc_sequence(struct terminal_t *term, uint8_t ch) 79 | { 80 | *term->esc.bp = '\0'; 81 | 82 | logging(DEBUG, "esc: ESC %s\n", term->esc.buf); 83 | 84 | if (strlen(term->esc.buf) == 1 && esc_func[ch]) 85 | esc_func[ch](term); 86 | 87 | /* not reset if csi/osc/dcs seqence */ 88 | if (ch == '[' || ch == ']' || ch == 'P') 89 | return; 90 | 91 | reset_esc(term); 92 | } 93 | 94 | void csi_sequence(struct terminal_t *term, uint8_t ch) 95 | { 96 | struct parm_t parm; 97 | 98 | *(term->esc.bp - 1) = '\0'; /* omit final character */ 99 | 100 | logging(DEBUG, "csi: CSI %s\n", term->esc.buf + 1); 101 | 102 | reset_parm(&parm); 103 | parse_arg(term->esc.buf + 1, &parm, ';', isdigit); /* skip '[' */ 104 | 105 | if (csi_func[ch]) 106 | csi_func[ch](term, &parm); 107 | 108 | reset_esc(term); 109 | } 110 | 111 | int is_osc_parm(int c) 112 | { 113 | if (isdigit(c) || isalpha(c) || 114 | c == '?' || c == ':' || c == '/' || c == '#') 115 | return true; 116 | else 117 | return false; 118 | } 119 | 120 | void omit_string_terminator(char *bp, uint8_t ch) 121 | { 122 | if (ch == BACKSLASH) /* ST: ESC BACKSLASH */ 123 | *(bp - 2) = '\0'; 124 | else /* ST: BEL */ 125 | *(bp - 1) = '\0'; 126 | } 127 | 128 | void osc_sequence(struct terminal_t *term, uint8_t ch) 129 | { 130 | int osc_mode; 131 | struct parm_t parm; 132 | 133 | omit_string_terminator(term->esc.bp, ch); 134 | 135 | logging(DEBUG, "osc: OSC %s\n", term->esc.buf); 136 | 137 | reset_parm(&parm); 138 | parse_arg(term->esc.buf + 1, &parm, ';', is_osc_parm); /* skip ']' */ 139 | 140 | if (parm.argc > 0) { 141 | osc_mode = dec2num(parm.argv[0]); 142 | logging(DEBUG, "osc_mode:%d\n", osc_mode); 143 | 144 | /* XXX: disable because this functions only work 24/32bpp 145 | -> support other bpp (including pseudo color) */ 146 | if (osc_mode == 4) 147 | set_palette(term, &parm); 148 | else if (osc_mode == 104) 149 | reset_palette(term, &parm); 150 | if (osc_mode == 8900) 151 | glyph_width_report(term, &parm); 152 | } 153 | reset_esc(term); 154 | } 155 | 156 | void dcs_sequence(struct terminal_t *term, uint8_t ch) 157 | { 158 | char *cp; 159 | 160 | omit_string_terminator(term->esc.bp, ch); 161 | 162 | logging(DEBUG, "dcs: DCS %s\n", term->esc.buf); 163 | 164 | /* check DCS header */ 165 | cp = term->esc.buf + 1; /* skip P */ 166 | while (cp < term->esc.bp) { 167 | if (*cp == '{' || *cp == 'q') /* DECDLD or sixel */ 168 | break; 169 | else if (*cp == ';' || ('0' <= *cp && *cp <= '9')) /* valid DCS header */ 170 | ; 171 | else /* invalid sequence */ 172 | cp = term->esc.bp; 173 | cp++; 174 | } 175 | 176 | if (cp != term->esc.bp) { /* header only or couldn't find final char */ 177 | /* parse DCS header */ 178 | if (*cp == 'q') 179 | sixel_parse_header(term, term->esc.buf + 1); 180 | else if (*cp == '{') 181 | decdld_parse_header(term, term->esc.buf + 1); 182 | } 183 | 184 | reset_esc(term); 185 | } 186 | 187 | void utf8_charset(struct terminal_t *term, uint8_t ch) 188 | { 189 | if (0x80 <= ch && ch <= 0xBF) { 190 | /* check illegal UTF-8 sequence 191 | * ? byte sequence: first byte must be between 0xC2 ~ 0xFD 192 | * 2 byte sequence: first byte must be between 0xC2 ~ 0xDF 193 | * 3 byte sequence: second byte following 0xE0 must be between 0xA0 ~ 0xBF 194 | * 4 byte sequence: second byte following 0xF0 must be between 0x90 ~ 0xBF 195 | * 5 byte sequence: second byte following 0xF8 must be between 0x88 ~ 0xBF 196 | * 6 byte sequence: second byte following 0xFC must be between 0x84 ~ 0xBF 197 | */ 198 | if ((term->charset.following_byte == 0) 199 | || (term->charset.following_byte == 1 && term->charset.count == 0 && term->charset.code <= 1) 200 | || (term->charset.following_byte == 2 && term->charset.count == 0 && term->charset.code == 0 && ch < 0xA0) 201 | || (term->charset.following_byte == 3 && term->charset.count == 0 && term->charset.code == 0 && ch < 0x90) 202 | || (term->charset.following_byte == 4 && term->charset.count == 0 && term->charset.code == 0 && ch < 0x88) 203 | || (term->charset.following_byte == 5 && term->charset.count == 0 && term->charset.code == 0 && ch < 0x84)) 204 | term->charset.is_valid = false; 205 | 206 | term->charset.code <<= 6; 207 | term->charset.code += ch & 0x3F; 208 | term->charset.count++; 209 | } else if (0xC0 <= ch && ch <= 0xDF) { 210 | term->charset.code = ch & 0x1F; 211 | term->charset.following_byte = 1; 212 | term->charset.count = 0; 213 | return; 214 | } else if (0xE0 <= ch && ch <= 0xEF) { 215 | term->charset.code = ch & 0x0F; 216 | term->charset.following_byte = 2; 217 | term->charset.count = 0; 218 | return; 219 | } else if (0xF0 <= ch && ch <= 0xF7) { 220 | term->charset.code = ch & 0x07; 221 | term->charset.following_byte = 3; 222 | term->charset.count = 0; 223 | return; 224 | } else if (0xF8 <= ch && ch <= 0xFB) { 225 | term->charset.code = ch & 0x03; 226 | term->charset.following_byte = 4; 227 | term->charset.count = 0; 228 | return; 229 | } else if (0xFC <= ch && ch <= 0xFD) { 230 | term->charset.code = ch & 0x01; 231 | term->charset.following_byte = 5; 232 | term->charset.count = 0; 233 | return; 234 | } else { /* 0xFE - 0xFF: not used in UTF-8 */ 235 | addch(term, REPLACEMENT_CHAR); 236 | reset_charset(term); 237 | return; 238 | } 239 | 240 | if (term->charset.count >= term->charset.following_byte) { 241 | /* illegal code point (ref: http://www.unicode.org/reports/tr27/tr27-4.html) 242 | 0xD800 ~ 0xDFFF : surrogate pair 243 | 0xFDD0 ~ 0xFDEF : noncharacter 244 | 0xnFFFE ~ 0xnFFFF: noncharacter (n: 0x00 ~ 0x10) 245 | 0x110000 ~ : invalid (unicode U+0000 ~ U+10FFFF) 246 | */ 247 | if (!term->charset.is_valid 248 | || (0xD800 <= term->charset.code && term->charset.code <= 0xDFFF) 249 | || (0xFDD0 <= term->charset.code && term->charset.code <= 0xFDEF) 250 | || ((term->charset.code & 0xFFFF) == 0xFFFE || (term->charset.code & 0xFFFF) == 0xFFFF) 251 | || (term->charset.code > 0x10FFFF)) 252 | addch(term, REPLACEMENT_CHAR); 253 | else 254 | addch(term, term->charset.code); 255 | 256 | reset_charset(term); 257 | } 258 | } 259 | 260 | void parse(struct terminal_t *term, uint8_t *buf, int size) 261 | { 262 | /* 263 | CTRL CHARS : 0x00 ~ 0x1F 264 | ASCII(printable): 0x20 ~ 0x7E 265 | CTRL CHARS(DEL) : 0x7F 266 | UTF-8 : 0x80 ~ 0xFF 267 | */ 268 | uint8_t ch; 269 | 270 | for (int i = 0; i < size; i++) { 271 | ch = buf[i]; 272 | if (term->esc.state == STATE_RESET) { 273 | /* interrupted by illegal byte */ 274 | if (term->charset.following_byte > 0 && (ch < 0x80 || ch > 0xBF)) { 275 | addch(term, REPLACEMENT_CHAR); 276 | reset_charset(term); 277 | } 278 | 279 | if (ch <= 0x1F) 280 | control_character(term, ch); 281 | else if (ch <= 0x7F) 282 | addch(term, ch); 283 | else 284 | utf8_charset(term, ch); 285 | } else if (term->esc.state == STATE_ESC) { 286 | if (push_esc(term, ch)) 287 | esc_sequence(term, ch); 288 | } else if (term->esc.state == STATE_CSI) { 289 | if (push_esc(term, ch)) 290 | csi_sequence(term, ch); 291 | } else if (term->esc.state == STATE_OSC) { 292 | if (push_esc(term, ch)) 293 | osc_sequence(term, ch); 294 | } else if (term->esc.state == STATE_DCS) { 295 | if (push_esc(term, ch)) 296 | dcs_sequence(term, ch); 297 | } 298 | } 299 | } 300 | -------------------------------------------------------------------------------- /table/ISO10646: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uobikiemukot/yaft/59ef091187736200e07ee1d67d6249ad4c691542/table/ISO10646 -------------------------------------------------------------------------------- /table/ISO8859: -------------------------------------------------------------------------------- 1 | # 2 | # Name: ISO/IEC 8859-1:1998 to Unicode 3 | # Unicode version: 3.0 4 | # Table version: 1.0 5 | # Table format: Format A 6 | # Date: 1999 July 27 7 | # Authors: Ken Whistler 8 | # 9 | # Copyright (c) 1991-1999 Unicode, Inc. All Rights reserved. 10 | # 11 | # This file is provided as-is by Unicode, Inc. (The Unicode Consortium). 12 | # No claims are made as to fitness for any particular purpose. No 13 | # warranties of any kind are expressed or implied. The recipient 14 | # agrees to determine applicability of information provided. If this 15 | # file has been provided on optical media by Unicode, Inc., the sole 16 | # remedy for any claim will be exchange of defective media within 90 17 | # days of receipt. 18 | # 19 | # Unicode, Inc. hereby grants the right to freely use the information 20 | # supplied in this file in the creation of products supporting the 21 | # Unicode Standard, and to make copies of this file in any form for 22 | # internal or external distribution as long as this notice remains 23 | # attached. 24 | # 25 | # General notes: 26 | # 27 | # This table contains the data the Unicode Consortium has on how 28 | # ISO/IEC 8859-1:1998 characters map into Unicode. 29 | # 30 | # Format: Three tab-separated columns 31 | # Column #1 is the ISO/IEC 8859-1 code (in hex as 0xXX) 32 | # Column #2 is the Unicode (in hex as 0xXXXX) 33 | # Column #3 the Unicode name (follows a comment sign, '#') 34 | # 35 | # The entries are in ISO/IEC 8859-1 order. 36 | # 37 | # Version history 38 | # 1.0 version updates 0.1 version by adding mappings for all 39 | # control characters. 40 | # 41 | # Updated versions of this file may be found in: 42 | # 43 | # 44 | # Any comments or problems, contact 45 | # Please note that is an archival address; 46 | # notices will be checked, but do not expect an immediate response. 47 | # 48 | 0x00 0x0000 # NULL 49 | 0x01 0x0001 # START OF HEADING 50 | 0x02 0x0002 # START OF TEXT 51 | 0x03 0x0003 # END OF TEXT 52 | 0x04 0x0004 # END OF TRANSMISSION 53 | 0x05 0x0005 # ENQUIRY 54 | 0x06 0x0006 # ACKNOWLEDGE 55 | 0x07 0x0007 # BELL 56 | 0x08 0x0008 # BACKSPACE 57 | 0x09 0x0009 # HORIZONTAL TABULATION 58 | 0x0A 0x000A # LINE FEED 59 | 0x0B 0x000B # VERTICAL TABULATION 60 | 0x0C 0x000C # FORM FEED 61 | 0x0D 0x000D # CARRIAGE RETURN 62 | 0x0E 0x000E # SHIFT OUT 63 | 0x0F 0x000F # SHIFT IN 64 | 0x10 0x0010 # DATA LINK ESCAPE 65 | 0x11 0x0011 # DEVICE CONTROL ONE 66 | 0x12 0x0012 # DEVICE CONTROL TWO 67 | 0x13 0x0013 # DEVICE CONTROL THREE 68 | 0x14 0x0014 # DEVICE CONTROL FOUR 69 | 0x15 0x0015 # NEGATIVE ACKNOWLEDGE 70 | 0x16 0x0016 # SYNCHRONOUS IDLE 71 | 0x17 0x0017 # END OF TRANSMISSION BLOCK 72 | 0x18 0x0018 # CANCEL 73 | 0x19 0x0019 # END OF MEDIUM 74 | 0x1A 0x001A # SUBSTITUTE 75 | 0x1B 0x001B # ESCAPE 76 | 0x1C 0x001C # FILE SEPARATOR 77 | 0x1D 0x001D # GROUP SEPARATOR 78 | 0x1E 0x001E # RECORD SEPARATOR 79 | 0x1F 0x001F # UNIT SEPARATOR 80 | 0x20 0x0020 # SPACE 81 | 0x21 0x0021 # EXCLAMATION MARK 82 | 0x22 0x0022 # QUOTATION MARK 83 | 0x23 0x0023 # NUMBER SIGN 84 | 0x24 0x0024 # DOLLAR SIGN 85 | 0x25 0x0025 # PERCENT SIGN 86 | 0x26 0x0026 # AMPERSAND 87 | 0x27 0x0027 # APOSTROPHE 88 | 0x28 0x0028 # LEFT PARENTHESIS 89 | 0x29 0x0029 # RIGHT PARENTHESIS 90 | 0x2A 0x002A # ASTERISK 91 | 0x2B 0x002B # PLUS SIGN 92 | 0x2C 0x002C # COMMA 93 | 0x2D 0x002D # HYPHEN-MINUS 94 | 0x2E 0x002E # FULL STOP 95 | 0x2F 0x002F # SOLIDUS 96 | 0x30 0x0030 # DIGIT ZERO 97 | 0x31 0x0031 # DIGIT ONE 98 | 0x32 0x0032 # DIGIT TWO 99 | 0x33 0x0033 # DIGIT THREE 100 | 0x34 0x0034 # DIGIT FOUR 101 | 0x35 0x0035 # DIGIT FIVE 102 | 0x36 0x0036 # DIGIT SIX 103 | 0x37 0x0037 # DIGIT SEVEN 104 | 0x38 0x0038 # DIGIT EIGHT 105 | 0x39 0x0039 # DIGIT NINE 106 | 0x3A 0x003A # COLON 107 | 0x3B 0x003B # SEMICOLON 108 | 0x3C 0x003C # LESS-THAN SIGN 109 | 0x3D 0x003D # EQUALS SIGN 110 | 0x3E 0x003E # GREATER-THAN SIGN 111 | 0x3F 0x003F # QUESTION MARK 112 | 0x40 0x0040 # COMMERCIAL AT 113 | 0x41 0x0041 # LATIN CAPITAL LETTER A 114 | 0x42 0x0042 # LATIN CAPITAL LETTER B 115 | 0x43 0x0043 # LATIN CAPITAL LETTER C 116 | 0x44 0x0044 # LATIN CAPITAL LETTER D 117 | 0x45 0x0045 # LATIN CAPITAL LETTER E 118 | 0x46 0x0046 # LATIN CAPITAL LETTER F 119 | 0x47 0x0047 # LATIN CAPITAL LETTER G 120 | 0x48 0x0048 # LATIN CAPITAL LETTER H 121 | 0x49 0x0049 # LATIN CAPITAL LETTER I 122 | 0x4A 0x004A # LATIN CAPITAL LETTER J 123 | 0x4B 0x004B # LATIN CAPITAL LETTER K 124 | 0x4C 0x004C # LATIN CAPITAL LETTER L 125 | 0x4D 0x004D # LATIN CAPITAL LETTER M 126 | 0x4E 0x004E # LATIN CAPITAL LETTER N 127 | 0x4F 0x004F # LATIN CAPITAL LETTER O 128 | 0x50 0x0050 # LATIN CAPITAL LETTER P 129 | 0x51 0x0051 # LATIN CAPITAL LETTER Q 130 | 0x52 0x0052 # LATIN CAPITAL LETTER R 131 | 0x53 0x0053 # LATIN CAPITAL LETTER S 132 | 0x54 0x0054 # LATIN CAPITAL LETTER T 133 | 0x55 0x0055 # LATIN CAPITAL LETTER U 134 | 0x56 0x0056 # LATIN CAPITAL LETTER V 135 | 0x57 0x0057 # LATIN CAPITAL LETTER W 136 | 0x58 0x0058 # LATIN CAPITAL LETTER X 137 | 0x59 0x0059 # LATIN CAPITAL LETTER Y 138 | 0x5A 0x005A # LATIN CAPITAL LETTER Z 139 | 0x5B 0x005B # LEFT SQUARE BRACKET 140 | 0x5C 0x005C # REVERSE SOLIDUS 141 | 0x5D 0x005D # RIGHT SQUARE BRACKET 142 | 0x5E 0x005E # CIRCUMFLEX ACCENT 143 | 0x5F 0x005F # LOW LINE 144 | 0x60 0x0060 # GRAVE ACCENT 145 | 0x61 0x0061 # LATIN SMALL LETTER A 146 | 0x62 0x0062 # LATIN SMALL LETTER B 147 | 0x63 0x0063 # LATIN SMALL LETTER C 148 | 0x64 0x0064 # LATIN SMALL LETTER D 149 | 0x65 0x0065 # LATIN SMALL LETTER E 150 | 0x66 0x0066 # LATIN SMALL LETTER F 151 | 0x67 0x0067 # LATIN SMALL LETTER G 152 | 0x68 0x0068 # LATIN SMALL LETTER H 153 | 0x69 0x0069 # LATIN SMALL LETTER I 154 | 0x6A 0x006A # LATIN SMALL LETTER J 155 | 0x6B 0x006B # LATIN SMALL LETTER K 156 | 0x6C 0x006C # LATIN SMALL LETTER L 157 | 0x6D 0x006D # LATIN SMALL LETTER M 158 | 0x6E 0x006E # LATIN SMALL LETTER N 159 | 0x6F 0x006F # LATIN SMALL LETTER O 160 | 0x70 0x0070 # LATIN SMALL LETTER P 161 | 0x71 0x0071 # LATIN SMALL LETTER Q 162 | 0x72 0x0072 # LATIN SMALL LETTER R 163 | 0x73 0x0073 # LATIN SMALL LETTER S 164 | 0x74 0x0074 # LATIN SMALL LETTER T 165 | 0x75 0x0075 # LATIN SMALL LETTER U 166 | 0x76 0x0076 # LATIN SMALL LETTER V 167 | 0x77 0x0077 # LATIN SMALL LETTER W 168 | 0x78 0x0078 # LATIN SMALL LETTER X 169 | 0x79 0x0079 # LATIN SMALL LETTER Y 170 | 0x7A 0x007A # LATIN SMALL LETTER Z 171 | 0x7B 0x007B # LEFT CURLY BRACKET 172 | 0x7C 0x007C # VERTICAL LINE 173 | 0x7D 0x007D # RIGHT CURLY BRACKET 174 | 0x7E 0x007E # TILDE 175 | 0x7F 0x007F # DELETE 176 | 0x80 0x0080 # 177 | 0x81 0x0081 # 178 | 0x82 0x0082 # 179 | 0x83 0x0083 # 180 | 0x84 0x0084 # 181 | 0x85 0x0085 # 182 | 0x86 0x0086 # 183 | 0x87 0x0087 # 184 | 0x88 0x0088 # 185 | 0x89 0x0089 # 186 | 0x8A 0x008A # 187 | 0x8B 0x008B # 188 | 0x8C 0x008C # 189 | 0x8D 0x008D # 190 | 0x8E 0x008E # 191 | 0x8F 0x008F # 192 | 0x90 0x0090 # 193 | 0x91 0x0091 # 194 | 0x92 0x0092 # 195 | 0x93 0x0093 # 196 | 0x94 0x0094 # 197 | 0x95 0x0095 # 198 | 0x96 0x0096 # 199 | 0x97 0x0097 # 200 | 0x98 0x0098 # 201 | 0x99 0x0099 # 202 | 0x9A 0x009A # 203 | 0x9B 0x009B # 204 | 0x9C 0x009C # 205 | 0x9D 0x009D # 206 | 0x9E 0x009E # 207 | 0x9F 0x009F # 208 | 0xA0 0x00A0 # NO-BREAK SPACE 209 | 0xA1 0x00A1 # INVERTED EXCLAMATION MARK 210 | 0xA2 0x00A2 # CENT SIGN 211 | 0xA3 0x00A3 # POUND SIGN 212 | 0xA4 0x00A4 # CURRENCY SIGN 213 | 0xA5 0x00A5 # YEN SIGN 214 | 0xA6 0x00A6 # BROKEN BAR 215 | 0xA7 0x00A7 # SECTION SIGN 216 | 0xA8 0x00A8 # DIAERESIS 217 | 0xA9 0x00A9 # COPYRIGHT SIGN 218 | 0xAA 0x00AA # FEMININE ORDINAL INDICATOR 219 | 0xAB 0x00AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK 220 | 0xAC 0x00AC # NOT SIGN 221 | 0xAD 0x00AD # SOFT HYPHEN 222 | 0xAE 0x00AE # REGISTERED SIGN 223 | 0xAF 0x00AF # MACRON 224 | 0xB0 0x00B0 # DEGREE SIGN 225 | 0xB1 0x00B1 # PLUS-MINUS SIGN 226 | 0xB2 0x00B2 # SUPERSCRIPT TWO 227 | 0xB3 0x00B3 # SUPERSCRIPT THREE 228 | 0xB4 0x00B4 # ACUTE ACCENT 229 | 0xB5 0x00B5 # MICRO SIGN 230 | 0xB6 0x00B6 # PILCROW SIGN 231 | 0xB7 0x00B7 # MIDDLE DOT 232 | 0xB8 0x00B8 # CEDILLA 233 | 0xB9 0x00B9 # SUPERSCRIPT ONE 234 | 0xBA 0x00BA # MASCULINE ORDINAL INDICATOR 235 | 0xBB 0x00BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK 236 | 0xBC 0x00BC # VULGAR FRACTION ONE QUARTER 237 | 0xBD 0x00BD # VULGAR FRACTION ONE HALF 238 | 0xBE 0x00BE # VULGAR FRACTION THREE QUARTERS 239 | 0xBF 0x00BF # INVERTED QUESTION MARK 240 | 0xC0 0x00C0 # LATIN CAPITAL LETTER A WITH GRAVE 241 | 0xC1 0x00C1 # LATIN CAPITAL LETTER A WITH ACUTE 242 | 0xC2 0x00C2 # LATIN CAPITAL LETTER A WITH CIRCUMFLEX 243 | 0xC3 0x00C3 # LATIN CAPITAL LETTER A WITH TILDE 244 | 0xC4 0x00C4 # LATIN CAPITAL LETTER A WITH DIAERESIS 245 | 0xC5 0x00C5 # LATIN CAPITAL LETTER A WITH RING ABOVE 246 | 0xC6 0x00C6 # LATIN CAPITAL LETTER AE 247 | 0xC7 0x00C7 # LATIN CAPITAL LETTER C WITH CEDILLA 248 | 0xC8 0x00C8 # LATIN CAPITAL LETTER E WITH GRAVE 249 | 0xC9 0x00C9 # LATIN CAPITAL LETTER E WITH ACUTE 250 | 0xCA 0x00CA # LATIN CAPITAL LETTER E WITH CIRCUMFLEX 251 | 0xCB 0x00CB # LATIN CAPITAL LETTER E WITH DIAERESIS 252 | 0xCC 0x00CC # LATIN CAPITAL LETTER I WITH GRAVE 253 | 0xCD 0x00CD # LATIN CAPITAL LETTER I WITH ACUTE 254 | 0xCE 0x00CE # LATIN CAPITAL LETTER I WITH CIRCUMFLEX 255 | 0xCF 0x00CF # LATIN CAPITAL LETTER I WITH DIAERESIS 256 | 0xD0 0x00D0 # LATIN CAPITAL LETTER ETH (Icelandic) 257 | 0xD1 0x00D1 # LATIN CAPITAL LETTER N WITH TILDE 258 | 0xD2 0x00D2 # LATIN CAPITAL LETTER O WITH GRAVE 259 | 0xD3 0x00D3 # LATIN CAPITAL LETTER O WITH ACUTE 260 | 0xD4 0x00D4 # LATIN CAPITAL LETTER O WITH CIRCUMFLEX 261 | 0xD5 0x00D5 # LATIN CAPITAL LETTER O WITH TILDE 262 | 0xD6 0x00D6 # LATIN CAPITAL LETTER O WITH DIAERESIS 263 | 0xD7 0x00D7 # MULTIPLICATION SIGN 264 | 0xD8 0x00D8 # LATIN CAPITAL LETTER O WITH STROKE 265 | 0xD9 0x00D9 # LATIN CAPITAL LETTER U WITH GRAVE 266 | 0xDA 0x00DA # LATIN CAPITAL LETTER U WITH ACUTE 267 | 0xDB 0x00DB # LATIN CAPITAL LETTER U WITH CIRCUMFLEX 268 | 0xDC 0x00DC # LATIN CAPITAL LETTER U WITH DIAERESIS 269 | 0xDD 0x00DD # LATIN CAPITAL LETTER Y WITH ACUTE 270 | 0xDE 0x00DE # LATIN CAPITAL LETTER THORN (Icelandic) 271 | 0xDF 0x00DF # LATIN SMALL LETTER SHARP S (German) 272 | 0xE0 0x00E0 # LATIN SMALL LETTER A WITH GRAVE 273 | 0xE1 0x00E1 # LATIN SMALL LETTER A WITH ACUTE 274 | 0xE2 0x00E2 # LATIN SMALL LETTER A WITH CIRCUMFLEX 275 | 0xE3 0x00E3 # LATIN SMALL LETTER A WITH TILDE 276 | 0xE4 0x00E4 # LATIN SMALL LETTER A WITH DIAERESIS 277 | 0xE5 0x00E5 # LATIN SMALL LETTER A WITH RING ABOVE 278 | 0xE6 0x00E6 # LATIN SMALL LETTER AE 279 | 0xE7 0x00E7 # LATIN SMALL LETTER C WITH CEDILLA 280 | 0xE8 0x00E8 # LATIN SMALL LETTER E WITH GRAVE 281 | 0xE9 0x00E9 # LATIN SMALL LETTER E WITH ACUTE 282 | 0xEA 0x00EA # LATIN SMALL LETTER E WITH CIRCUMFLEX 283 | 0xEB 0x00EB # LATIN SMALL LETTER E WITH DIAERESIS 284 | 0xEC 0x00EC # LATIN SMALL LETTER I WITH GRAVE 285 | 0xED 0x00ED # LATIN SMALL LETTER I WITH ACUTE 286 | 0xEE 0x00EE # LATIN SMALL LETTER I WITH CIRCUMFLEX 287 | 0xEF 0x00EF # LATIN SMALL LETTER I WITH DIAERESIS 288 | 0xF0 0x00F0 # LATIN SMALL LETTER ETH (Icelandic) 289 | 0xF1 0x00F1 # LATIN SMALL LETTER N WITH TILDE 290 | 0xF2 0x00F2 # LATIN SMALL LETTER O WITH GRAVE 291 | 0xF3 0x00F3 # LATIN SMALL LETTER O WITH ACUTE 292 | 0xF4 0x00F4 # LATIN SMALL LETTER O WITH CIRCUMFLEX 293 | 0xF5 0x00F5 # LATIN SMALL LETTER O WITH TILDE 294 | 0xF6 0x00F6 # LATIN SMALL LETTER O WITH DIAERESIS 295 | 0xF7 0x00F7 # DIVISION SIGN 296 | 0xF8 0x00F8 # LATIN SMALL LETTER O WITH STROKE 297 | 0xF9 0x00F9 # LATIN SMALL LETTER U WITH GRAVE 298 | 0xFA 0x00FA # LATIN SMALL LETTER U WITH ACUTE 299 | 0xFB 0x00FB # LATIN SMALL LETTER U WITH CIRCUMFLEX 300 | 0xFC 0x00FC # LATIN SMALL LETTER U WITH DIAERESIS 301 | 0xFD 0x00FD # LATIN SMALL LETTER Y WITH ACUTE 302 | 0xFE 0x00FE # LATIN SMALL LETTER THORN (Icelandic) 303 | 0xFF 0x00FF # LATIN SMALL LETTER Y WITH DIAERESIS 304 | -------------------------------------------------------------------------------- /table/alias: -------------------------------------------------------------------------------- 1 | # use WAVE DASH for FULLWIDTH TILDE 2 | 0xFF5E 0x301C 3 | # use TILDE for SMALL TILDE 4 | 0x02DC 0x007E 5 | # use HYPHEN-MINUS for MINUS SIGN 6 | 0x2212 0x002D 7 | -------------------------------------------------------------------------------- /terminal.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE for licence details. */ 2 | void erase_cell(struct terminal_t *term, int y, int x) 3 | { 4 | struct cell_t *cellp; 5 | 6 | cellp = &term->cells[y][x]; 7 | cellp->glyphp = term->glyph[DEFAULT_CHAR]; 8 | cellp->color_pair = term->color_pair; /* bce */ 9 | cellp->attribute = ATTR_RESET; 10 | cellp->width = HALF; 11 | cellp->has_pixmap = false; 12 | 13 | term->line_dirty[y] = true; 14 | } 15 | 16 | void copy_cell(struct terminal_t *term, int dst_y, int dst_x, int src_y, int src_x) 17 | { 18 | struct cell_t *dst, *src; 19 | 20 | dst = &term->cells[dst_y][dst_x]; 21 | src = &term->cells[src_y][src_x]; 22 | 23 | if (src->width == NEXT_TO_WIDE) { 24 | return; 25 | } else if (src->width == WIDE && dst_x == (term->cols - 1)) { 26 | erase_cell(term, dst_y, dst_x); 27 | } else { 28 | *dst = *src; 29 | if (src->width == WIDE) { 30 | *(dst + 1) = *src; 31 | (dst + 1)->width = NEXT_TO_WIDE; 32 | } 33 | term->line_dirty[dst_y] = true; 34 | } 35 | } 36 | 37 | int set_cell(struct terminal_t *term, int y, int x, const struct glyph_t *glyphp) 38 | { 39 | struct cell_t cell, *cellp; 40 | uint8_t color_tmp; 41 | 42 | cell.glyphp = glyphp; 43 | 44 | cell.color_pair.fg = (term->attribute & attr_mask[ATTR_BOLD] && term->color_pair.fg <= 7) ? 45 | term->color_pair.fg + BRIGHT_INC: term->color_pair.fg; 46 | cell.color_pair.bg = (term->attribute & attr_mask[ATTR_BLINK] && term->color_pair.bg <= 7) ? 47 | term->color_pair.bg + BRIGHT_INC: term->color_pair.bg; 48 | 49 | if (term->attribute & attr_mask[ATTR_REVERSE]) { 50 | color_tmp = cell.color_pair.fg; 51 | cell.color_pair.fg = cell.color_pair.bg; 52 | cell.color_pair.bg = color_tmp; 53 | } 54 | 55 | cell.attribute = term->attribute; 56 | cell.width = glyphp->width; 57 | cell.has_pixmap = false; 58 | 59 | cellp = &term->cells[y][x]; 60 | *cellp = cell; 61 | term->line_dirty[y] = true; 62 | 63 | if (cell.width == WIDE && x + 1 < term->cols) { 64 | cellp = &term->cells[y][x + 1]; 65 | *cellp = cell; 66 | cellp->width = NEXT_TO_WIDE; 67 | return WIDE; 68 | } 69 | 70 | if (cell.width == HALF /* isolated NEXT_TO_WIDE cell */ 71 | && x + 1 < term->cols 72 | && term->cells[y][x + 1].width == NEXT_TO_WIDE) { 73 | erase_cell(term, y, x + 1); 74 | } 75 | return HALF; 76 | } 77 | 78 | static inline void swap_lines(struct terminal_t *term, int i, int j) 79 | { 80 | struct cell_t *tmp; 81 | 82 | tmp = term->cells[i]; 83 | term->cells[i] = term->cells[j]; 84 | term->cells[j] = tmp; 85 | } 86 | 87 | void scroll(struct terminal_t *term, int from, int to, int offset) 88 | { 89 | int abs_offset, scroll_lines; 90 | 91 | if (offset == 0 || from >= to) 92 | return; 93 | 94 | logging(DEBUG, "scroll from:%d to:%d offset:%d\n", from, to, offset); 95 | 96 | for (int y = from; y <= to; y++) 97 | term->line_dirty[y] = true; 98 | 99 | abs_offset = abs(offset); 100 | scroll_lines = (to - from + 1) - abs_offset; 101 | 102 | if (offset > 0) { /* scroll down */ 103 | for (int y = from; y < from + scroll_lines; y++) 104 | swap_lines(term, y, y + offset); 105 | for (int y = (to - offset + 1); y <= to; y++) 106 | for (int x = 0; x < term->cols; x++) 107 | erase_cell(term, y, x); 108 | } 109 | else { /* scroll up */ 110 | for (int y = to; y >= from + abs_offset; y--) 111 | swap_lines(term, y, y - abs_offset); 112 | for (int y = from; y < from + abs_offset; y++) 113 | for (int x = 0; x < term->cols; x++) 114 | erase_cell(term, y, x); 115 | } 116 | } 117 | 118 | /* relative movement: cause scrolling */ 119 | void move_cursor(struct terminal_t *term, int y_offset, int x_offset) 120 | { 121 | int x, y, top, bottom; 122 | 123 | x = term->cursor.x + x_offset; 124 | y = term->cursor.y + y_offset; 125 | 126 | top = term->scroll.top; 127 | bottom = term->scroll.bottom; 128 | 129 | if (x < 0) { 130 | x = 0; 131 | } else if (x >= term->cols) { 132 | if (term->mode & MODE_AMRIGHT) 133 | term->wrap_occurred = true; 134 | x = term->cols - 1; 135 | } 136 | term->cursor.x = x; 137 | 138 | y = (y < 0) ? 0: 139 | (y >= term->lines) ? term->lines - 1: y; 140 | 141 | if (term->cursor.y == top && y_offset < 0) { 142 | y = top; 143 | scroll(term, top, bottom, y_offset); 144 | } else if (term->cursor.y == bottom && y_offset > 0) { 145 | y = bottom; 146 | scroll(term, top, bottom, y_offset); 147 | } 148 | term->cursor.y = y; 149 | } 150 | 151 | /* absolute movement: never scroll */ 152 | void set_cursor(struct terminal_t *term, int y, int x) 153 | { 154 | int top, bottom; 155 | 156 | if (term->mode & MODE_ORIGIN) { 157 | top = term->scroll.top; 158 | bottom = term->scroll.bottom; 159 | y += term->scroll.top; 160 | } else { 161 | top = 0; 162 | bottom = term->lines - 1; 163 | } 164 | 165 | x = (x < 0) ? 0: (x >= term->cols) ? term->cols - 1: x; 166 | y = (y < top) ? top: (y > bottom) ? bottom: y; 167 | 168 | term->cursor.x = x; 169 | term->cursor.y = y; 170 | term->wrap_occurred = false; 171 | } 172 | 173 | const struct glyph_t *drcs_glyph(struct terminal_t *term, uint32_t code) 174 | { 175 | /* DRCSMMv1 176 | ESC ( SP <\xXX> <\xYY> ESC ( B 177 | <===> U+10XXYY ( 0x40 <= 0xXX <=0x7E, 0x20 <= 0xYY <= 0x7F ) 178 | */ 179 | int row, cell; /* = ku, ten */ 180 | 181 | row = (0xFF00 & code) >> 8; 182 | cell = 0xFF & code; 183 | 184 | logging(DEBUG, "drcs row:0x%.2X cell:0x%.2X\n", row, cell); 185 | 186 | if ((0x40 <= row && row <= 0x7E) && (0x20 <= cell && cell <= 0x7F)) 187 | return &term->drcs[(row - 0x40) * GLYPHS_PER_CHARSET + (cell - 0x20)]; 188 | else 189 | return term->glyph[SUBSTITUTE_HALF]; 190 | } 191 | 192 | void addch(struct terminal_t *term, uint32_t code) 193 | { 194 | int width; 195 | const struct glyph_t *glyphp; 196 | 197 | logging(DEBUG, "addch: U+%.4X\n", code); 198 | 199 | width = wcwidth(code); 200 | 201 | if (width <= 0) /* zero width: not support combining characters */ 202 | return; 203 | else if (0x100000 <= code && code <= 0x10FFFD) /* unicode private area: plane 16 (DRCSMMv1) */ 204 | glyphp = drcs_glyph(term, code); 205 | else if (code >= UCS2_CHARS /* yaft support only UCS2 */ 206 | || term->glyph[code] == NULL /* missing glyph */ 207 | || term->glyph[code]->width != width) /* width unmatched */ 208 | glyphp = (width == 1) ? term->glyph[SUBSTITUTE_HALF]: term->glyph[SUBSTITUTE_WIDE]; 209 | else 210 | glyphp = term->glyph[code]; 211 | 212 | if ((term->wrap_occurred && term->cursor.x == term->cols - 1) /* folding */ 213 | || (glyphp->width == WIDE && term->cursor.x == term->cols - 1)) { 214 | set_cursor(term, term->cursor.y, 0); 215 | move_cursor(term, 1, 0); 216 | } 217 | term->wrap_occurred = false; 218 | 219 | move_cursor(term, 0, set_cell(term, term->cursor.y, term->cursor.x, glyphp)); 220 | } 221 | 222 | void reset_esc(struct terminal_t *term) 223 | { 224 | logging(DEBUG, "*esc reset*\n"); 225 | 226 | term->esc.bp = term->esc.buf; 227 | term->esc.state = STATE_RESET; 228 | } 229 | 230 | bool push_esc(struct terminal_t *term, uint8_t ch) 231 | { 232 | long offset; 233 | 234 | if ((term->esc.bp - term->esc.buf) >= term->esc.size) { /* buffer limit */ 235 | logging(DEBUG, "escape sequence length >= %d, term.esc.buf reallocated\n", term->esc.size); 236 | offset = term->esc.bp - term->esc.buf; 237 | term->esc.buf = erealloc(term->esc.buf, term->esc.size * 2); 238 | term->esc.bp = term->esc.buf + offset; 239 | term->esc.size *= 2; 240 | } 241 | 242 | /* ref: http://www.vt100.net/docs/vt102-ug/appendixd.html */ 243 | *term->esc.bp++ = ch; 244 | if (term->esc.state == STATE_ESC) { 245 | /* format: 246 | ESC I.......I F 247 | ' ' '/' '0' '~' 248 | 0x1B 0x20-0x2F 0x30-0x7E 249 | */ 250 | if ('0' <= ch && ch <= '~') /* final char */ 251 | return true; 252 | else if (SPACE <= ch && ch <= '/') /* intermediate char */ 253 | return false; 254 | } else if (term->esc.state == STATE_CSI) { 255 | /* format: 256 | CSI P.......P I.......I F 257 | ESC '[' '0' '?' ' ' '/' '@' '~' 258 | 0x1B 0x5B 0x30-0x3F 0x20-0x2F 0x40-0x7E 259 | */ 260 | if ('@' <= ch && ch <= '~') 261 | return true; 262 | else if (SPACE <= ch && ch <= '?') 263 | return false; 264 | } else { 265 | /* format: 266 | OSC I.....I F 267 | ESC ']' BEL or ESC '\' 268 | 0x1B 0x5D unknown 0x07 or 0x1B 0x5C 269 | DCS I....I F 270 | ESC 'P' BEL or ESC '\' 271 | 0x1B 0x50 unknown 0x07 or 0x1B 0x5C 272 | */ 273 | if (ch == BEL || (ch == BACKSLASH 274 | && (term->esc.bp - term->esc.buf) >= 2 && *(term->esc.bp - 2) == ESC)) 275 | return true; 276 | else if ((ch == ESC || ch == CR || ch == LF || ch == BS || ch == HT) 277 | || (SPACE <= ch && ch <= '~')) 278 | return false; 279 | } 280 | 281 | /* invalid sequence */ 282 | reset_esc(term); 283 | return false; 284 | } 285 | 286 | void reset_charset(struct terminal_t *term) 287 | { 288 | term->charset.code = term->charset.count = term->charset.following_byte = 0; 289 | term->charset.is_valid = true; 290 | } 291 | 292 | void reset(struct terminal_t *term) 293 | { 294 | term->mode = MODE_RESET; 295 | term->mode |= (MODE_CURSOR | MODE_AMRIGHT); 296 | term->wrap_occurred = false; 297 | 298 | term->scroll.top = 0; 299 | term->scroll.bottom = term->lines - 1; 300 | 301 | term->cursor.x = term->cursor.y = 0; 302 | 303 | term->state.mode = term->mode; 304 | term->state.cursor = term->cursor; 305 | term->state.attribute = ATTR_RESET; 306 | 307 | term->color_pair.fg = DEFAULT_FG; 308 | term->color_pair.bg = DEFAULT_BG; 309 | 310 | term->attribute = ATTR_RESET; 311 | 312 | for (int line = 0; line < term->lines; line++) { 313 | for (int col = 0; col < term->cols; col++) { 314 | erase_cell(term, line, col); 315 | if ((col % TABSTOP) == 0) 316 | term->tabstop[col] = true; 317 | else 318 | term->tabstop[col] = false; 319 | } 320 | term->line_dirty[line] = true; 321 | } 322 | 323 | reset_esc(term); 324 | reset_charset(term); 325 | } 326 | 327 | void redraw(struct terminal_t *term) 328 | { 329 | for (int i = 0; i < term->lines; i++) 330 | term->line_dirty[i] = true; 331 | } 332 | 333 | void term_die(struct terminal_t *term) 334 | { 335 | free(term->line_dirty); 336 | free(term->tabstop); 337 | free(term->esc.buf); 338 | free(term->sixel.pixmap); 339 | 340 | for (int i = 0; i < term->lines; i++) 341 | free(term->cells[i]); 342 | free(term->cells); 343 | } 344 | 345 | bool term_init(struct terminal_t *term, int width, int height) 346 | { 347 | extern const uint32_t color_list[COLORS]; /* global */ 348 | 349 | term->width = width; 350 | term->height = height; 351 | 352 | term->cols = term->width / CELL_WIDTH; 353 | term->lines = term->height / CELL_HEIGHT; 354 | 355 | term->esc.size = ESCSEQ_SIZE; 356 | 357 | logging(DEBUG, "terminal cols:%d lines:%d\n", term->cols, term->lines); 358 | 359 | /* allocate memory */ 360 | term->line_dirty = (bool *) ecalloc(term->lines, sizeof(bool)); 361 | term->tabstop = (bool *) ecalloc(term->cols, sizeof(bool)); 362 | term->esc.buf = (char *) ecalloc(1, term->esc.size); 363 | term->sixel.pixmap = (uint8_t *) ecalloc(width * height, BYTES_PER_PIXEL); 364 | 365 | term->cells = (struct cell_t **) ecalloc(term->lines, sizeof(struct cell_t *)); 366 | for (int i = 0; i < term->lines; i++) 367 | term->cells[i] = (struct cell_t *) ecalloc(term->cols, sizeof(struct cell_t)); 368 | 369 | if (!term->line_dirty || !term->tabstop || !term->cells 370 | || !term->esc.buf || !term->sixel.pixmap) { 371 | term_die(term); 372 | return false; 373 | } 374 | 375 | /* initialize palette */ 376 | for (int i = 0; i < COLORS; i++) 377 | term->virtual_palette[i] = color_list[i]; 378 | term->palette_modified = false; 379 | 380 | /* initialize glyph map */ 381 | for (uint32_t code = 0; code < UCS2_CHARS; code++) 382 | term->glyph[code] = NULL; 383 | 384 | for (uint32_t gi = 0; gi < sizeof(glyphs) / sizeof(struct glyph_t); gi++) 385 | term->glyph[glyphs[gi].code] = &glyphs[gi]; 386 | 387 | if (!term->glyph[DEFAULT_CHAR] 388 | || !term->glyph[SUBSTITUTE_HALF] 389 | || !term->glyph[SUBSTITUTE_WIDE]) { 390 | logging(ERROR, "couldn't find essential glyph:\ 391 | DEFAULT_CHAR(U+%.4X):%p SUBSTITUTE_HALF(U+%.4X):%p SUBSTITUTE_WIDE(U+%.4X):%p\n", 392 | DEFAULT_CHAR, term->glyph[DEFAULT_CHAR], 393 | SUBSTITUTE_HALF, term->glyph[SUBSTITUTE_HALF], 394 | SUBSTITUTE_WIDE, term->glyph[SUBSTITUTE_WIDE]); 395 | return false; 396 | } 397 | 398 | /* reset terminal */ 399 | reset(term); 400 | 401 | return true; 402 | } 403 | -------------------------------------------------------------------------------- /tools/bdf.h: -------------------------------------------------------------------------------- 1 | int pre_match(const char *buf, const char *str) { 2 | return !strncmp(buf, str, strlen(str)); 3 | } 4 | 5 | int bit2byte(int bits) 6 | { 7 | return (bits + BITS_PER_BYTE - 1) / BITS_PER_BYTE; 8 | } 9 | 10 | void shift_glyph(struct bdf_header_t *bdf_header, struct bdf_char_t *bdf_char) 11 | { 12 | int i, byte, shift; 13 | bitmap_width_t bitmap; 14 | 15 | for (i = 0; i < bdf_char->bbh; i++) { 16 | bitmap = bdf_char->bitmap[i]; 17 | byte = bit2byte(bdf_char->bbw); 18 | bitmap <<= (bit2byte(bdf_char->dwidth) - byte) * BITS_PER_BYTE; 19 | if (bdf_char->bbx >= 0) 20 | bitmap >>= bdf_char->bbx; 21 | else { 22 | logging(ERROR, "maybe overlapping (glpyh:%X bbx:%d)\n", bdf_char->encoding, bdf_char->bbx); 23 | bitmap <<= abs(bdf_char->bbx); 24 | } 25 | bdf_char->bitmap[i] = bitmap; 26 | } 27 | 28 | shift = bdf_header->ascent - (bdf_char->bbh + bdf_char->bby); 29 | if (shift >= 0) { 30 | memmove(bdf_char->bitmap + shift, bdf_char->bitmap, sizeof(bitmap_width_t) * bdf_char->bbh); 31 | memset(bdf_char->bitmap, 0, sizeof(bitmap_width_t) * shift); 32 | } 33 | else { 34 | logging(ERROR, "maybe overlapping (glpyh:%X vertical shift:%d)\n", bdf_char->encoding, shift); 35 | memmove(bdf_char->bitmap, bdf_char->bitmap + abs(shift), sizeof(bitmap_width_t) * bdf_char->bbh); 36 | } 37 | } 38 | 39 | void load_table(char *path, enum encode_t encode) 40 | { 41 | int i; 42 | char buf[BUFSIZE], *cp; 43 | FILE *fp; 44 | uint32_t from, to; 45 | 46 | fp = efopen(path, "r"); 47 | 48 | for (i = 0; i < UCS2_CHARS; i++) { 49 | if (encode == ISO10646) 50 | convert_table[i] = i; 51 | else 52 | convert_table[i] = -1; 53 | } 54 | 55 | while (fgets(buf, BUFSIZE, fp) != NULL) { 56 | if (strlen(buf) == 0 || buf[0] == '#') 57 | continue; 58 | 59 | if ((cp = strchr(buf, '\n')) != NULL) 60 | *cp = '\0'; 61 | 62 | sscanf(buf, "%X %X", (unsigned int *) &from, (unsigned int *) &to); 63 | convert_table[from] = to; 64 | } 65 | } 66 | 67 | int read_header(char *buf, struct bdf_header_t *bdf_header) 68 | { 69 | char *cp; 70 | 71 | if (pre_match(buf, "FONTBOUNDINGBOX ")) 72 | sscanf(buf + strlen("FONTBOUNDINGBOX "), "%d %d %d %d", 73 | &bdf_header->bbw, &bdf_header->bbh, &bdf_header->bbx, &bdf_header->bby); 74 | else if (pre_match(buf, "FONT_ASCENT ")) 75 | bdf_header->ascent = atoi(buf + strlen("FONT_ASCENT ")); 76 | else if (pre_match(buf, "FONT_DESCENT ")) 77 | bdf_header->descent = atoi(buf + strlen("FONT_DESCENT ")); 78 | else if (pre_match(buf, "DEFAULT_CHAR ")) 79 | bdf_header->default_char = atoi(buf + strlen("DEFAULT_CHAR ")); 80 | else if (pre_match(buf, "PIXEL_SIZE ")) 81 | bdf_header->pixel_size = atoi(buf + strlen("PIXEL_SIZE ")); 82 | else if (pre_match(buf, "CHARSET_REGISTRY ")) { 83 | strncpy(bdf_header->charset, buf + strlen("CHARSET_REGISTRY "), BUFSIZE - 1); 84 | logging(DEBUG, "%s\n", bdf_header->charset); 85 | 86 | for (cp = bdf_header->charset; *cp != '\0'; cp++) 87 | *cp = (char) toupper((int) *cp); 88 | 89 | if (strstr(bdf_header->charset, "X68000") != NULL 90 | || strstr(bdf_header->charset, "x68000") != NULL) 91 | load_table("./table/X68000", X68000); 92 | else if (strstr(bdf_header->charset, "JISX0201") != NULL 93 | || strstr(bdf_header->charset, "jisx0201") != NULL) 94 | load_table("./table/JISX0201", JISX0201); 95 | else if (strstr(bdf_header->charset, "JISX0208") != NULL 96 | || strstr(bdf_header->charset, "jisx0208") != NULL) 97 | load_table("./table/JISX0208", JISX0208); 98 | else if (strstr(bdf_header->charset, "ISO8859") != NULL 99 | || strstr(bdf_header->charset, "iso8859") != NULL) 100 | load_table("./table/ISO8859", ISO8859); 101 | else /* assume "ISO10646" */ 102 | load_table("./table/ISO10646", ISO10646); 103 | } 104 | else if (pre_match(buf, "CHARS ")) { 105 | bdf_header->chars = atoi(buf + strlen("CHARS ")); 106 | return BDF_CHAR; 107 | } 108 | 109 | return BDF_HEADER; 110 | } 111 | 112 | int read_char(char *buf, struct bdf_char_t *bdf_char) 113 | { 114 | if (pre_match(buf, "BBX ")) 115 | sscanf(buf + strlen("BBX "), "%d %d %d %d", 116 | &bdf_char->bbw, &bdf_char->bbh, &bdf_char->bbx, &bdf_char->bby); 117 | else if (pre_match(buf, "DWIDTH ")) 118 | bdf_char->dwidth = atoi(buf + strlen("DWIDTH ")); 119 | else if (pre_match(buf, "ENCODING ")) { 120 | bdf_char->encoding = atoi(buf + strlen("ENCODING ")); 121 | //logging(DEBUG, "reading char:%d\n", bdf_char->encoding); 122 | } 123 | else if (pre_match(buf, "BITMAP")) { 124 | return BDF_BITMAP; 125 | } 126 | 127 | return BDF_CHAR; 128 | } 129 | 130 | int read_bitmap(struct glyph_list_t **glist_head, struct glyph_t *default_glyph, 131 | char *buf, struct bdf_header_t *bdf_header, struct bdf_char_t *bdf_char) 132 | { 133 | static int count = 0; 134 | uint32_t code; 135 | uint8_t width, height; 136 | struct glyph_list_t *listp; 137 | struct glyph_t *glyph; 138 | 139 | if (pre_match(buf, "ENDCHAR")) { 140 | count = 0; 141 | 142 | shift_glyph(bdf_header, bdf_char); 143 | 144 | if (bdf_char->encoding < 0 || bdf_char->encoding >= UCS2_CHARS) 145 | return BDF_CHAR; 146 | 147 | code = convert_table[bdf_char->encoding]; 148 | width = bdf_char->dwidth; 149 | height = bdf_header->ascent + bdf_header->descent; 150 | 151 | //logging(DEBUG, "code:%d width:%d height:%d\n", code, width, height); 152 | 153 | if (code < UCS2_CHARS && width <= 64) { 154 | listp = ecalloc(1, sizeof(struct glyph_list_t)); 155 | glyph = ecalloc(1, sizeof(struct glyph_t)); 156 | 157 | glyph->width = width; 158 | glyph->height = height; 159 | /* XXX: max width 64 pixels (wide char) */ 160 | glyph->bitmap = (bitmap_width_t *) ecalloc(glyph->height, sizeof(bitmap_width_t)); 161 | 162 | for (int i = 0; i < glyph->height; i++) 163 | glyph->bitmap[i] = bdf_char->bitmap[i]; 164 | 165 | /* add new element to glyph list */ 166 | listp->code = code; 167 | listp->glyph = glyph; 168 | listp->next = *glist_head; 169 | *glist_head = listp; 170 | 171 | if (code == DEFAULT_CHAR) 172 | *default_glyph = *glyph; 173 | } 174 | memset(bdf_char, 0, sizeof(struct bdf_char_t)); 175 | return BDF_CHAR; 176 | } 177 | else 178 | sscanf(buf, "%X", (unsigned int *) &bdf_char->bitmap[count++]); 179 | 180 | return BDF_BITMAP; 181 | } 182 | 183 | bool load_bdf_glyph(struct glyph_list_t **glist_head, struct glyph_t *default_glyph, char *path) 184 | { 185 | int mode = BDF_HEADER; 186 | char lbuf[BUFSIZE], *cp; 187 | FILE *fp; 188 | struct bdf_header_t bdf_header; 189 | struct bdf_char_t bdf_char; 190 | 191 | if ((fp = efopen(path, "r")) == NULL) 192 | return false; 193 | 194 | memset(&bdf_header, 0, sizeof(struct bdf_header_t)); 195 | memset(&bdf_char, 0, sizeof(struct bdf_char_t)); 196 | 197 | logging(DEBUG, "read bdf: %s\n", path); 198 | 199 | while (fgets(lbuf, BUFSIZE, fp) != NULL) { 200 | if ((cp = strchr(lbuf, '\n')) != NULL) 201 | *cp = '\0'; 202 | 203 | //fprintf(stderr, "%s\n", lbuf); 204 | 205 | if (mode == BDF_HEADER) 206 | mode = read_header(lbuf, &bdf_header); 207 | else if (mode == BDF_CHAR) 208 | mode = read_char(lbuf, &bdf_char); 209 | else if (mode == BDF_BITMAP) 210 | mode = read_bitmap(glist_head, default_glyph, lbuf, &bdf_header, &bdf_char); 211 | } 212 | efclose(fp); 213 | return true; 214 | } 215 | -------------------------------------------------------------------------------- /tools/mkfont_bdf.c: -------------------------------------------------------------------------------- 1 | #include "mkfont_bdf.h" 2 | #include "../conf.h" 3 | #include "util.h" 4 | #include "bdf.h" 5 | 6 | /* mkfont_bdf functions */ 7 | bool map_glyph(struct glyph_t *font[], 8 | struct glyph_list_t *glist_head, struct glyph_t *default_glyph) 9 | { 10 | int width, cell_width = 0, cell_height = 0; 11 | struct glyph_t *glyph; 12 | struct glyph_list_t *listp; 13 | 14 | if (default_glyph->width == 0 || default_glyph->height == 0) { 15 | logging(ERROR, "default glyph(U+%.4X) not found\n", DEFAULT_CHAR); 16 | return false; 17 | } 18 | 19 | cell_width = default_glyph->width; 20 | cell_height = default_glyph->height; 21 | logging(DEBUG, "default glyph width:%d height:%d\n", 22 | default_glyph->width, default_glyph->height); 23 | 24 | for (listp = glist_head; listp != NULL; listp = listp->next) { 25 | if (listp->code >= UCS2_CHARS) 26 | continue; 27 | 28 | width = wcwidth(listp->code); 29 | glyph = listp->glyph; 30 | if ((width <= 0) /* not printable */ 31 | || (glyph->height != cell_height) /* invalid font height */ 32 | || (glyph->width != (cell_width * width))) /* invalid font width */ 33 | continue; 34 | 35 | font[listp->code] = glyph; 36 | } 37 | return true; 38 | } 39 | 40 | bool load_alias(struct glyph_t *font[], char *alias) 41 | { 42 | unsigned int dst, src; 43 | char buf[BUFSIZE]; 44 | FILE *fp; 45 | 46 | if ((fp = efopen(alias, "r")) == NULL) 47 | return false; 48 | 49 | while (fgets(buf, BUFSIZE, fp) != NULL) { 50 | if (strlen(buf) == 0 || buf[0] == '#') 51 | continue; 52 | 53 | sscanf(buf, "%X %X", &dst, &src); 54 | if ((dst >= UCS2_CHARS) || (src >= UCS2_CHARS)) 55 | continue; 56 | 57 | //if (font[src] != NULL && font[dst] != NULL) { 58 | if (font[src] != NULL) { 59 | logging(DEBUG, "swapped: use U+%.4X for U+%.4X\n", src, dst); 60 | font[dst] = font[src]; 61 | 62 | //free(font[dst]->bitmap); 63 | //font[dst]->width = font[src]->width; 64 | //font[dst]->height = font[src]->height; 65 | //font[dst]->bitmap = font[src]->bitmap; 66 | //memcpy(font[dst]->bitmap, font[src]->bitmap, sizeof(bitmap_width_t) * font[src]->height); 67 | } 68 | } 69 | efclose(fp); 70 | return true; 71 | } 72 | 73 | bool check_font(struct glyph_t **font, struct glyph_t *empty_half, struct glyph_t *empty_wide) 74 | { 75 | empty_half->bitmap = (bitmap_width_t *) ecalloc(font[DEFAULT_CHAR]->height, sizeof(bitmap_width_t)); 76 | empty_wide->bitmap = (bitmap_width_t *) ecalloc(font[DEFAULT_CHAR]->height, sizeof(bitmap_width_t)); 77 | 78 | if (!empty_half->bitmap || !empty_wide->bitmap) 79 | return false; 80 | 81 | empty_half->width = font[DEFAULT_CHAR]->width; 82 | empty_wide->width = font[DEFAULT_CHAR]->width * WIDE; 83 | empty_half->height = font[DEFAULT_CHAR]->height; 84 | empty_wide->height = font[DEFAULT_CHAR]->height; 85 | 86 | if (font[SUBSTITUTE_HALF] == NULL) { 87 | logging(WARN, "half substitute glyph(U+%.4X) not found, use empty glyph\n", SUBSTITUTE_HALF); 88 | font[SUBSTITUTE_HALF] = empty_half; 89 | } 90 | if (font[SUBSTITUTE_WIDE] == NULL) { 91 | logging(WARN, "wide substitute glyph(U+%.4X) not found, use empty glyph\n", SUBSTITUTE_WIDE); 92 | font[SUBSTITUTE_WIDE] = empty_wide; 93 | } 94 | if (font[REPLACEMENT_CHAR] == NULL) { 95 | logging(WARN, "replacement glyph(U+%.4X) not found, use empty glyph\n", REPLACEMENT_CHAR); 96 | font[REPLACEMENT_CHAR] = empty_half; 97 | } 98 | return true; 99 | } 100 | 101 | bool dump_font(struct glyph_t *font[]) 102 | { 103 | int i, j, width, int_type; 104 | uint8_t cell_width, cell_height; 105 | 106 | cell_width = font[DEFAULT_CHAR]->width; 107 | cell_height = font[DEFAULT_CHAR]->height; 108 | 109 | int_type = my_ceil(cell_width, BITS_PER_BYTE) /* minimum byte for containing half glyph */ 110 | * 2 /* minimum byte for containing wide glyph */ 111 | * BITS_PER_BYTE; /* minimum bits for containing wide glyph */ 112 | 113 | /* int_type: 16, 32, 48, 64, 80... */ 114 | if (int_type == 48) { /* uint48_t does not exist */ 115 | int_type = 64; 116 | } else if (int_type >= 80) { 117 | logging(ERROR, "BDF width too large (uint%d_t does not exist)\n", int_type); 118 | return false; 119 | } 120 | 121 | fprintf(stdout, 122 | "struct glyph_t {\n" 123 | "\tuint32_t code;\n" 124 | "\tuint8_t width;\n" 125 | "\tuint%d_t bitmap[%d];\n" 126 | "};\n\n", int_type, cell_height); 127 | 128 | fprintf(stdout, "enum {\n\tCELL_WIDTH = %d,\n\tCELL_HEIGHT = %d\n};\n\n", 129 | cell_width, cell_height); 130 | 131 | fprintf(stdout, "static const struct glyph_t glyphs[] = {\n"); 132 | for (i = 0; i < UCS2_CHARS; i++) { 133 | width = wcwidth(i); 134 | 135 | if (font[i] == NULL) /* glyph not found */ 136 | continue; 137 | 138 | fprintf(stdout, "\t{%d, %d, {", i, width); 139 | for (j = 0; j < cell_height; j++) 140 | fprintf(stdout, "0x%X%s", (unsigned int) font[i]->bitmap[j], (j == (cell_height - 1)) ? "": ", "); 141 | fprintf(stdout, "}},\n"); 142 | } 143 | fprintf(stdout, "};\n"); 144 | return true; 145 | } 146 | 147 | void cleanup(struct glyph_list_t *glist_head, struct glyph_t *empty_half, struct glyph_t *empty_wide) 148 | { 149 | struct glyph_list_t *listp, *next; 150 | 151 | for (listp = glist_head; listp != NULL; listp = next) { 152 | next = listp->next; 153 | 154 | free(listp->glyph->bitmap); 155 | free(listp->glyph); 156 | free(listp); 157 | } 158 | free(empty_half->bitmap); 159 | free(empty_wide->bitmap); 160 | } 161 | 162 | int main(int argc, char *argv[]) 163 | { 164 | struct glyph_list_t *glist_head = NULL; 165 | struct glyph_t *font[UCS2_CHARS], default_glyph, empty_wide, empty_half; 166 | 167 | if (!setlocale(LC_ALL, "")) /* set current locale for wcwidth() */ 168 | logging(WARN, "setlocale() failed\n"); 169 | 170 | if (argc < 3) { 171 | logging(FATAL, "usage: ./mkfont ALIAS BDF1 [BDF2] [BDF3] ...\n"); 172 | return EXIT_FAILURE; 173 | } 174 | 175 | for (int i = 0; i < UCS2_CHARS; i++) 176 | font[i] = NULL; 177 | 178 | for (int i = 2; i < argc; i++) 179 | load_bdf_glyph(&glist_head, &default_glyph, argv[i]); 180 | 181 | if (!map_glyph(font, glist_head, &default_glyph)) { 182 | logging(FATAL, "map_glyph() failed\n"); 183 | goto err_occurred; 184 | } 185 | 186 | if (!load_alias(font, argv[1])) 187 | logging(WARN, "font alias does not work\n"); 188 | 189 | if (!check_font(font, &empty_half, &empty_wide)) { 190 | logging(FATAL, "check_font() failed\n"); 191 | goto err_occurred; 192 | } 193 | 194 | if (!dump_font(font)) { 195 | logging(FATAL, "dump_font() failed\n"); 196 | goto err_occurred; 197 | } 198 | 199 | cleanup(glist_head, &empty_half, &empty_wide); 200 | return EXIT_SUCCESS; 201 | 202 | err_occurred: 203 | cleanup(glist_head, &empty_half, &empty_wide); 204 | return EXIT_FAILURE; 205 | } 206 | -------------------------------------------------------------------------------- /tools/mkfont_bdf.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE for licence details. */ 2 | #define _XOPEN_SOURCE 600 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | typedef uint64_t bitmap_width_t; 15 | 16 | enum char_code { 17 | /* 7 bit control char */ 18 | BEL = 0x07, BS = 0x08, HT = 0x09, 19 | LF = 0x0A, VT = 0x0B, FF = 0x0C, 20 | CR = 0x0D, ESC = 0x1B, DEL = 0x7F, 21 | /* others */ 22 | SPACE = 0x20, 23 | BACKSLASH = 0x5C, 24 | }; 25 | 26 | enum misc { 27 | BITS_PER_BYTE = 8, 28 | BUFSIZE = 1024, /* read, esc, various buffer size */ 29 | UCS2_CHARS = 0x10000, /* number of UCS2 glyph */ 30 | DEFAULT_CHAR = SPACE, /* used for erase char, cell_size */ 31 | MAX_HEIGHT = 64, 32 | BDF_HEADER = 0, 33 | BDF_CHAR = 1, 34 | BDF_BITMAP = 2, 35 | }; 36 | 37 | enum encode_t { 38 | X68000, 39 | JISX0208, 40 | JISX0201, 41 | /* 42 | JISX0212, 43 | JISX0213, 44 | */ 45 | ISO8859, 46 | ISO10646 47 | }; 48 | 49 | enum glyph_width_t { 50 | NEXT_TO_WIDE = 0, 51 | HALF, 52 | WIDE, 53 | }; 54 | 55 | struct glyph_t { 56 | uint8_t width, height; 57 | bitmap_width_t *bitmap; 58 | }; 59 | 60 | struct glyph_list_t { 61 | uint32_t code; 62 | struct glyph_t *glyph; 63 | struct glyph_list_t *next; 64 | }; 65 | 66 | struct bdf_header_t { 67 | int bbw, bbh, bbx, bby; 68 | int ascent, descent; 69 | int default_char; 70 | int chars; 71 | int pixel_size; 72 | char charset[BUFSIZE]; 73 | }; 74 | 75 | struct bdf_char_t { 76 | int bbw, bbh, bbx, bby; 77 | int dwidth; 78 | int encoding; 79 | bitmap_width_t bitmap[MAX_HEIGHT]; 80 | }; 81 | 82 | int convert_table[UCS2_CHARS]; 83 | -------------------------------------------------------------------------------- /tools/util.h: -------------------------------------------------------------------------------- 1 | /* wrapper of C functions */ 2 | enum loglevel_t { 3 | DEBUG = 0, 4 | WARN, 5 | ERROR, 6 | FATAL, 7 | }; 8 | 9 | void logging(enum loglevel_t loglevel, char *format, ...) 10 | { 11 | va_list arg; 12 | static const char *loglevel2str[] = { 13 | [DEBUG] = "DEBUG", 14 | [WARN] = "WARN", 15 | [ERROR] = "ERROR", 16 | [FATAL] = "FATAL", 17 | }; 18 | 19 | /* debug message is available on verbose mode */ 20 | if ((loglevel == DEBUG) && (VERBOSE == false)) 21 | return; 22 | 23 | fprintf(stderr, ">>%s<<\t", loglevel2str[loglevel]); 24 | 25 | va_start(arg, format); 26 | vfprintf(stderr, format, arg); 27 | va_end(arg); 28 | } 29 | 30 | FILE *efopen(const char *path, char *mode) 31 | { 32 | FILE *fp; 33 | errno = 0; 34 | 35 | if ((fp = fopen(path, mode)) == NULL) { 36 | logging(ERROR, "couldn't open \"%s\"\n", path); 37 | logging(ERROR, "fopen: %s\n", strerror(errno)); 38 | } 39 | return fp; 40 | } 41 | 42 | int efclose(FILE *fp) 43 | { 44 | int ret; 45 | errno = 0; 46 | 47 | if ((ret = fclose(fp)) < 0) 48 | logging(ERROR, "fclose: %s\n", strerror(errno)); 49 | 50 | return ret; 51 | } 52 | 53 | void *ecalloc(size_t nmemb, size_t size) 54 | { 55 | void *ptr; 56 | errno = 0; 57 | 58 | if ((ptr = calloc(nmemb, size)) == NULL) 59 | logging(ERROR, "calloc: %s\n", strerror(errno)); 60 | 61 | return ptr; 62 | } 63 | 64 | int my_ceil(int val, int div) 65 | { 66 | if (div == 0) 67 | //return 0; 68 | return -1; 69 | else 70 | return (val + div - 1) / div; 71 | } 72 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE for licence details. */ 2 | /* error functions */ 3 | enum loglevel_t { 4 | DEBUG = 0, 5 | WARN, 6 | ERROR, 7 | FATAL, 8 | }; 9 | 10 | void logging(enum loglevel_t loglevel, char *format, ...) 11 | { 12 | va_list arg; 13 | static const char *loglevel2str[] = { 14 | [DEBUG] = "DEBUG", 15 | [WARN] = "WARN", 16 | [ERROR] = "ERROR", 17 | [FATAL] = "FATAL", 18 | }; 19 | 20 | /* debug message is available on verbose mode */ 21 | if ((loglevel == DEBUG) && (VERBOSE == false)) 22 | return; 23 | 24 | fprintf(stderr, ">>%s<<\t", loglevel2str[loglevel]); 25 | 26 | va_start(arg, format); 27 | vfprintf(stderr, format, arg); 28 | va_end(arg); 29 | } 30 | 31 | /* wrapper of C functions */ 32 | int eopen(const char *path, int flag) 33 | { 34 | int fd; 35 | errno = 0; 36 | 37 | if ((fd = open(path, flag)) < 0) { 38 | logging(ERROR, "couldn't open \"%s\"\n", path); 39 | logging(ERROR, "open: %s\n", strerror(errno)); 40 | } 41 | return fd; 42 | } 43 | 44 | int eclose(int fd) 45 | { 46 | int ret; 47 | errno = 0; 48 | 49 | if ((ret = close(fd)) < 0) 50 | logging(ERROR, "close: %s\n", strerror(errno)); 51 | 52 | return ret; 53 | } 54 | 55 | FILE *efopen(const char *path, char *mode) 56 | { 57 | FILE *fp; 58 | errno = 0; 59 | 60 | if ((fp = fopen(path, mode)) == NULL) { 61 | logging(ERROR, "couldn't open \"%s\"\n", path); 62 | logging(ERROR, "fopen: %s\n", strerror(errno)); 63 | } 64 | return fp; 65 | } 66 | 67 | int efclose(FILE *fp) 68 | { 69 | int ret; 70 | errno = 0; 71 | 72 | if ((ret = fclose(fp)) < 0) 73 | logging(ERROR, "fclose: %s\n", strerror(errno)); 74 | 75 | return ret; 76 | } 77 | 78 | void *emmap(void *addr, size_t len, int prot, int flag, int fd, off_t offset) 79 | { 80 | void *fp; 81 | errno = 0; 82 | 83 | if ((fp = mmap(addr, len, prot, flag, fd, offset)) == MAP_FAILED) 84 | logging(ERROR, "mmap: %s\n", strerror(errno)); 85 | 86 | return fp; 87 | } 88 | 89 | int emunmap(void *ptr, size_t len) 90 | { 91 | int ret; 92 | errno = 0; 93 | 94 | if ((ret = munmap(ptr, len)) < 0) 95 | logging(ERROR, "munmap: %s\n", strerror(errno)); 96 | 97 | return ret; 98 | } 99 | 100 | void *ecalloc(size_t nmemb, size_t size) 101 | { 102 | void *ptr; 103 | errno = 0; 104 | 105 | if ((ptr = calloc(nmemb, size)) == NULL) 106 | logging(ERROR, "calloc: %s\n", strerror(errno)); 107 | 108 | return ptr; 109 | } 110 | 111 | void *erealloc(void *ptr, size_t size) 112 | { 113 | void *new; 114 | errno = 0; 115 | 116 | if ((new = realloc(ptr, size)) == NULL) 117 | logging(ERROR, "realloc: %s\n", strerror(errno)); 118 | 119 | return new; 120 | } 121 | 122 | int eselect(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *tv) 123 | { 124 | int ret; 125 | errno = 0; 126 | 127 | if ((ret = select(maxfd, readfds, writefds, errorfds, tv)) < 0) { 128 | if (errno == EINTR) 129 | return eselect(maxfd, readfds, writefds, errorfds, tv); 130 | else 131 | logging(ERROR, "select: %s\n", strerror(errno)); 132 | } 133 | return ret; 134 | } 135 | 136 | ssize_t ewrite(int fd, const void *buf, size_t size) 137 | { 138 | ssize_t ret; 139 | errno = 0; 140 | 141 | if ((ret = write(fd, buf, size)) < 0) { 142 | if (errno == EINTR) { 143 | logging(ERROR, "write: EINTR occurred\n"); 144 | return ewrite(fd, buf, size); 145 | } else if (errno == EAGAIN || errno == EWOULDBLOCK) { 146 | logging(ERROR, "write: EAGAIN or EWOULDBLOCK occurred, sleep %d usec\n", SLEEP_TIME); 147 | usleep(SLEEP_TIME); 148 | return ewrite(fd, buf, size); 149 | } else { 150 | logging(ERROR, "write: %s\n", strerror(errno)); 151 | return ret; 152 | } 153 | } else if (ret < (ssize_t) size) { 154 | logging(ERROR, "data size:%zu write size:%zd\n", size, ret); 155 | return ewrite(fd, (char *) buf + ret, size - ret); 156 | } 157 | return ret; 158 | } 159 | 160 | int esigaction(int signo, struct sigaction *act, struct sigaction *oact) 161 | { 162 | int ret; 163 | errno = 0; 164 | 165 | if ((ret = sigaction(signo, act, oact)) < 0) 166 | logging(ERROR, "sigaction: %s\n", strerror(errno)); 167 | 168 | return ret; 169 | } 170 | 171 | int etcgetattr(int fd, struct termios *tm) 172 | { 173 | int ret; 174 | errno = 0; 175 | 176 | if ((ret = tcgetattr(fd, tm)) < 0) 177 | logging(ERROR, "tcgetattr: %s\n", strerror(errno)); 178 | 179 | return ret; 180 | } 181 | 182 | int etcsetattr(int fd, int action, const struct termios *tm) 183 | { 184 | int ret; 185 | errno = 0; 186 | 187 | if ((ret = tcsetattr(fd, action, tm)) < 0) 188 | logging(ERROR, "tcgetattr: %s\n", strerror(errno)); 189 | 190 | return ret; 191 | } 192 | 193 | int eopenpty(int *amaster, int *aslave, char *aname, 194 | const struct termios *termp, const struct winsize *winsize) 195 | { 196 | int master; 197 | char *name = NULL; 198 | errno = 0; 199 | 200 | if ((master = posix_openpt(O_RDWR | O_NOCTTY)) < 0 201 | || grantpt(master) < 0 202 | || unlockpt(master) < 0 203 | || (name = ptsname(master)) == NULL) { 204 | logging(ERROR, "openpty: %s\n", strerror(errno)); 205 | return -1; 206 | } 207 | *amaster = master; 208 | *aslave = eopen(name, O_RDWR | O_NOCTTY); 209 | 210 | if (aname) 211 | /* XXX: we don't use the slave's name, do nothing */ 212 | (void) aname; 213 | //strncpy(aname, name, _POSIX_TTY_NAME_MAX - 1); 214 | //snprintf(aname, _POSIX_TTY_NAME_MAX, "%s", name); 215 | if (termp) 216 | etcsetattr(*aslave, TCSAFLUSH, termp); 217 | if (winsize) 218 | ioctl(*aslave, TIOCSWINSZ, winsize); 219 | 220 | return 0; 221 | } 222 | 223 | pid_t eforkpty(int *amaster, char *name, 224 | const struct termios *termp, const struct winsize *winsize) 225 | { 226 | int master, slave; 227 | pid_t pid; 228 | 229 | if (eopenpty(&master, &slave, name, termp, winsize) < 0) 230 | return -1; 231 | 232 | errno = 0; 233 | pid = fork(); 234 | if (pid < 0) { 235 | logging(ERROR, "fork: %s\n", strerror(errno)); 236 | return pid; 237 | } else if (pid == 0) { /* child */ 238 | close(master); 239 | setsid(); 240 | 241 | dup2(slave, STDIN_FILENO); 242 | dup2(slave, STDOUT_FILENO); 243 | dup2(slave, STDERR_FILENO); 244 | 245 | /* XXX: this ioctl may fail in Mac OS X 246 | ref http://www.opensource.apple.com/source/Libc/Libc-825.25/util/pty.c?txt */ 247 | if (ioctl(slave, TIOCSCTTY, NULL)) 248 | logging(WARN, "ioctl: TIOCSCTTY faild\n"); 249 | close(slave); 250 | 251 | return 0; 252 | } 253 | /* parent */ 254 | close(slave); 255 | *amaster = master; 256 | 257 | return pid; 258 | } 259 | 260 | int esetenv(const char *name, const char *value, int overwrite) 261 | { 262 | int ret; 263 | errno = 0; 264 | 265 | if ((ret = setenv(name, value, overwrite)) < 0) 266 | logging(ERROR, "setenv: %s\n", strerror(errno)); 267 | 268 | return ret; 269 | } 270 | 271 | int eexecvp(const char *file, char *const argv[]) 272 | { 273 | int ret; 274 | errno = 0; 275 | 276 | if ((ret = execvp(file, (char * const *) argv)) < 0) 277 | logging(ERROR, "execvp: %s\n", strerror(errno)); 278 | 279 | return ret; 280 | } 281 | 282 | int eexecl(const char *path) 283 | { 284 | int ret; 285 | errno = 0; 286 | 287 | /* XXX: assume only one argument is given */ 288 | if ((ret = execl(path, path, NULL)) < 0) 289 | logging(ERROR, "execl: %s\n", strerror(errno)); 290 | 291 | return ret; 292 | } 293 | 294 | long estrtol(const char *nptr, char **endptr, int base) 295 | { 296 | long int ret; 297 | errno = 0; 298 | 299 | ret = strtol(nptr, endptr, base); 300 | if (ret == LONG_MIN || ret == LONG_MAX) { 301 | logging(ERROR, "strtol: %s\n", strerror(errno)); 302 | return 0; 303 | } 304 | 305 | return ret; 306 | } 307 | 308 | /* parse_arg functions */ 309 | void reset_parm(struct parm_t *pt) 310 | { 311 | pt->argc = 0; 312 | for (int i = 0; i < MAX_ARGS; i++) 313 | pt->argv[i] = NULL; 314 | } 315 | 316 | void add_parm(struct parm_t *pt, char *cp) 317 | { 318 | if (pt->argc >= MAX_ARGS) 319 | return; 320 | 321 | logging(DEBUG, "argv[%d]: %s\n", pt->argc, (cp == NULL) ? "NULL": cp); 322 | 323 | pt->argv[pt->argc] = cp; 324 | pt->argc++; 325 | } 326 | 327 | void parse_arg(char *buf, struct parm_t *pt, int delim, int (is_valid)(int c)) 328 | { 329 | /* 330 | v..........v d v.....v d v.....v ... d 331 | (valid char) (delimiter) 332 | argv[0] argv[1] argv[2] ... argv[argc - 1] 333 | */ 334 | size_t length; 335 | char *cp, *vp; 336 | 337 | if (buf == NULL) 338 | return; 339 | 340 | length = strlen(buf); 341 | logging(DEBUG, "parse_arg() length:%u\n", (unsigned) length); 342 | 343 | vp = NULL; 344 | for (size_t i = 0; i < length; i++) { 345 | cp = buf + i; 346 | 347 | if (vp == NULL && is_valid(*cp)) 348 | vp = cp; 349 | 350 | if (*cp == delim) { 351 | *cp = '\0'; 352 | add_parm(pt, vp); 353 | vp = NULL; 354 | } 355 | 356 | if (i == (length - 1) && (vp != NULL || *cp == '\0')) 357 | add_parm(pt, vp); 358 | } 359 | 360 | logging(DEBUG, "argc:%d\n", pt->argc); 361 | } 362 | 363 | /* other functions */ 364 | int my_ceil(int val, int div) 365 | { 366 | if (div == 0) 367 | return 0; 368 | else 369 | return (val + div - 1) / div; 370 | } 371 | 372 | int dec2num(char *str) 373 | { 374 | if (str == NULL) 375 | return 0; 376 | 377 | return estrtol(str, NULL, 10); 378 | } 379 | 380 | int hex2num(char *str) 381 | { 382 | if (str == NULL) 383 | return 0; 384 | 385 | return estrtol(str, NULL, 16); 386 | } 387 | 388 | int sum(struct parm_t *parm) 389 | { 390 | int sum = 0; 391 | 392 | for (int i = 0; i < parm->argc; i++) 393 | sum += dec2num(parm->argv[i]); 394 | 395 | return sum; 396 | } 397 | -------------------------------------------------------------------------------- /x/x.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE for licence details. */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define XK_NO_MOD UINT_MAX 8 | 9 | enum { /* default terminal size 80x24 (8x16 dot font) */ 10 | TERM_WIDTH = 640, 11 | TERM_HEIGHT = 384, 12 | }; 13 | 14 | struct keymap_t { 15 | KeySym keysym; 16 | unsigned int mask; 17 | char str[BUFSIZE]; 18 | }; 19 | 20 | const struct keymap_t keymap[] = { 21 | {XK_BackSpace, XK_NO_MOD, "\177" }, 22 | {XK_Up, Mod1Mask, "\033\033[A"}, 23 | {XK_Up, XK_NO_MOD, "\033[A" }, 24 | {XK_Down, Mod1Mask, "\033\033[B"}, 25 | {XK_Down, XK_NO_MOD, "\033[B" }, 26 | {XK_Right, Mod1Mask, "\033\033[C"}, 27 | {XK_Right, XK_NO_MOD, "\033[C" }, 28 | {XK_Left, Mod1Mask, "\033\033[D"}, 29 | {XK_Left, XK_NO_MOD, "\033[D" }, 30 | {XK_Begin, XK_NO_MOD, "\033[G" }, 31 | {XK_Home, XK_NO_MOD, "\033[1~" }, 32 | {XK_Insert, XK_NO_MOD, "\033[2~" }, 33 | {XK_Delete, XK_NO_MOD, "\033[3~" }, 34 | {XK_End, XK_NO_MOD, "\033[4~" }, 35 | {XK_Prior, XK_NO_MOD, "\033[5~" }, 36 | {XK_Next, XK_NO_MOD, "\033[6~" }, 37 | {XK_F1, XK_NO_MOD, "\033[[A" }, 38 | {XK_F2, XK_NO_MOD, "\033[[B" }, 39 | {XK_F3, XK_NO_MOD, "\033[[C" }, 40 | {XK_F4, XK_NO_MOD, "\033[[D" }, 41 | {XK_F5, XK_NO_MOD, "\033[[E" }, 42 | {XK_F6, XK_NO_MOD, "\033[17~" }, 43 | {XK_F7, XK_NO_MOD, "\033[18~" }, 44 | {XK_F8, XK_NO_MOD, "\033[19~" }, 45 | {XK_F9, XK_NO_MOD, "\033[20~" }, 46 | {XK_F10, XK_NO_MOD, "\033[21~" }, 47 | {XK_F11, XK_NO_MOD, "\033[23~" }, 48 | {XK_F12, XK_NO_MOD, "\033[24~" }, 49 | {XK_F13, XK_NO_MOD, "\033[25~" }, 50 | {XK_F14, XK_NO_MOD, "\033[26~" }, 51 | {XK_F15, XK_NO_MOD, "\033[28~" }, 52 | {XK_F16, XK_NO_MOD, "\033[29~" }, 53 | {XK_F17, XK_NO_MOD, "\033[31~" }, 54 | {XK_F18, XK_NO_MOD, "\033[32~" }, 55 | {XK_F19, XK_NO_MOD, "\033[33~" }, 56 | {XK_F20, XK_NO_MOD, "\033[34~" }, 57 | }; 58 | 59 | /* not assigned: 60 | kcbt=\E[Z,kmous=\E[M,kspd=^Z, 61 | */ 62 | 63 | struct xwindow_t { 64 | Display *display; 65 | Window window; 66 | Pixmap pixbuf; 67 | Colormap cmap; 68 | GC gc; 69 | int width, height; 70 | int screen; 71 | unsigned long color_palette[COLORS]; 72 | }; 73 | 74 | #define PXCACHE_SIZE (1024) 75 | struct pxcache_entry { 76 | uint32_t color; 77 | unsigned long pixel; 78 | }; 79 | static struct pxcache_entry pxcache[PXCACHE_SIZE]; 80 | static int pxcache_top = 0; 81 | 82 | bool search_pxcache(uint32_t color, unsigned long *pixel) 83 | { 84 | int i; 85 | /* usually faster to search recently allocated colors first */ 86 | for (i = pxcache_top - 1; i >= 0; i--) { 87 | if (pxcache[i].color == color) { 88 | *pixel = pxcache[i].pixel; 89 | return true; 90 | } 91 | } 92 | return false; 93 | } 94 | 95 | unsigned long color2pixel(struct xwindow_t *xw, uint32_t color) 96 | { 97 | unsigned long pixel; 98 | if (search_pxcache(color, &pixel)) { 99 | return pixel; 100 | } else { 101 | XColor xc; 102 | 103 | xc.red = ((color >> 16) & bit_mask[8]) << 8; 104 | xc.green = ((color >> 8) & bit_mask[8]) << 8; 105 | xc.blue = ((color >> 0) & bit_mask[8]) << 8; 106 | 107 | if (!XAllocColor(xw->display, xw->cmap, &xc)) { 108 | logging(WARN, "could not allocate color\n"); 109 | return BlackPixel(xw->display, DefaultScreen(xw->display)); 110 | } else { 111 | if (pxcache_top == PXCACHE_SIZE) { 112 | logging(WARN, "pixel cache is full. starting over\n"); 113 | pxcache_top = 0; 114 | } 115 | pxcache[pxcache_top].color = color; 116 | pxcache[pxcache_top].pixel = xc.pixel; 117 | pxcache_top++; 118 | return xc.pixel; 119 | } 120 | } 121 | } 122 | 123 | bool xw_init(struct xwindow_t *xw) 124 | { 125 | XTextProperty xtext = {.value = (unsigned char *) "yaftx", 126 | .encoding = XA_STRING, .format = 8, .nitems = 5}; 127 | 128 | if ((xw->display = XOpenDisplay(NULL)) == NULL) { 129 | logging(ERROR, "XOpenDisplay() failed\n"); 130 | return false; 131 | } 132 | 133 | if (!XSupportsLocale()) 134 | logging(WARN, "X does not support locale\n"); 135 | 136 | if (XSetLocaleModifiers("") == NULL) 137 | logging(WARN, "cannot set locale modifiers\n"); 138 | 139 | xw->cmap = DefaultColormap(xw->display, xw->screen); 140 | for (int i = 0; i < COLORS; i++) 141 | xw->color_palette[i] = color2pixel(xw, color_list[i]); 142 | 143 | xw->screen = DefaultScreen(xw->display); 144 | xw->window = XCreateSimpleWindow(xw->display, DefaultRootWindow(xw->display), 145 | 0, 0, TERM_WIDTH, TERM_HEIGHT, 0, xw->color_palette[DEFAULT_FG], xw->color_palette[DEFAULT_BG]); 146 | XSetWMProperties(xw->display, xw->window, &xtext, NULL, NULL, 0, NULL, NULL, NULL); /* return void */ 147 | 148 | xw->gc = XCreateGC(xw->display, xw->window, 0, NULL); 149 | XSetGraphicsExposures(xw->display, xw->gc, False); 150 | 151 | xw->width = DisplayWidth(xw->display, xw->screen); 152 | xw->height = DisplayHeight(xw->display, xw->screen); 153 | xw->pixbuf = XCreatePixmap(xw->display, xw->window, 154 | xw->width, xw->height, XDefaultDepth(xw->display, xw->screen)); 155 | 156 | XSelectInput(xw->display, xw->window, 157 | ExposureMask | KeyPressMask | StructureNotifyMask); 158 | 159 | XMapWindow(xw->display, xw->window); 160 | 161 | return true; 162 | } 163 | 164 | void xw_die(struct xwindow_t *xw) 165 | { 166 | XFreeGC(xw->display, xw->gc); 167 | XFreePixmap(xw->display, xw->pixbuf); 168 | XDestroyWindow(xw->display, xw->window); 169 | XCloseDisplay(xw->display); 170 | } 171 | 172 | static inline void draw_sixel(struct xwindow_t *xw, int line, int col, struct cell_t *cellp) 173 | { 174 | int w, h; 175 | uint32_t color = 0; 176 | 177 | for (h = 0; h < CELL_HEIGHT; h++) { 178 | for (w = 0; w < CELL_WIDTH; w++) { 179 | memcpy(&color, cellp->pixmap + BYTES_PER_PIXEL * (h * CELL_WIDTH + w), BYTES_PER_PIXEL); 180 | 181 | if (color_list[DEFAULT_BG] != color) { 182 | XSetForeground(xw->display, xw->gc, color2pixel(xw, color)); 183 | XDrawPoint(xw->display, xw->pixbuf, xw->gc, 184 | col * CELL_WIDTH + w, line * CELL_HEIGHT + h); 185 | } 186 | } 187 | } 188 | } 189 | 190 | static inline void draw_line(struct xwindow_t *xw, struct terminal_t *term, int line) 191 | { 192 | int bdf_padding, glyph_width, margin_right; 193 | int col, w, h; 194 | struct color_pair_t color_pair; 195 | struct cell_t *cellp; 196 | const struct glyph_t *glyphp; 197 | 198 | /* at first, fill all pixels of line in background color */ 199 | XSetForeground(xw->display, xw->gc, xw->color_palette[DEFAULT_BG]); 200 | XFillRectangle(xw->display, xw->pixbuf, xw->gc, 0, line * CELL_HEIGHT, term->width, CELL_HEIGHT); 201 | 202 | for (col = term->cols - 1; col >= 0; col--) { 203 | margin_right = (term->cols - 1 - col) * CELL_WIDTH; 204 | 205 | /* draw sixel pixmap */ 206 | cellp = &term->cells[line][col]; 207 | if (cellp->has_pixmap) { 208 | draw_sixel(xw, line, col, cellp); 209 | continue; 210 | } 211 | 212 | /* get color and glyph */ 213 | color_pair = cellp->color_pair; 214 | glyphp = cellp->glyphp; 215 | 216 | /* check wide character or not */ 217 | glyph_width = (cellp->width == HALF) ? CELL_WIDTH: CELL_WIDTH * 2; 218 | bdf_padding = my_ceil(glyph_width, BITS_PER_BYTE) * BITS_PER_BYTE - glyph_width; 219 | if (cellp->width == WIDE) 220 | bdf_padding += CELL_WIDTH; 221 | 222 | /* check cursor position */ 223 | if ((term->mode & MODE_CURSOR && line == term->cursor.y) 224 | && (col == term->cursor.x 225 | || (cellp->width == WIDE && (col + 1) == term->cursor.x) 226 | || (cellp->width == NEXT_TO_WIDE && (col - 1) == term->cursor.x))) { 227 | color_pair.fg = DEFAULT_BG; 228 | color_pair.bg = (!vt_active && BACKGROUND_DRAW) ? PASSIVE_CURSOR_COLOR: ACTIVE_CURSOR_COLOR; 229 | } 230 | 231 | for (h = 0; h < CELL_HEIGHT; h++) { 232 | /* if UNDERLINE attribute on, swap bg/fg */ 233 | if ((h == (CELL_HEIGHT - 1)) && (cellp->attribute & attr_mask[ATTR_UNDERLINE])) 234 | color_pair.bg = color_pair.fg; 235 | 236 | for (w = 0; w < CELL_WIDTH; w++) { 237 | /* set color palette */ 238 | if (glyphp->bitmap[h] & (0x01 << (bdf_padding + w))) 239 | XSetForeground(xw->display, xw->gc, xw->color_palette[color_pair.fg]); 240 | else if (color_pair.bg != DEFAULT_BG) 241 | XSetForeground(xw->display, xw->gc, xw->color_palette[color_pair.bg]); 242 | else /* already draw */ 243 | continue; 244 | 245 | /* update copy buffer */ 246 | XDrawPoint(xw->display, xw->pixbuf, xw->gc, 247 | term->width - 1 - margin_right - w, line * CELL_HEIGHT + h); 248 | } 249 | } 250 | } 251 | 252 | term->line_dirty[line] = ((term->mode & MODE_CURSOR) && term->cursor.y == line) ? true: false; 253 | } 254 | 255 | void refresh(struct xwindow_t *xw, struct terminal_t *term) 256 | { 257 | int line, update_from, update_to; 258 | 259 | if (term->mode & MODE_CURSOR) 260 | term->line_dirty[term->cursor.y] = true; 261 | 262 | update_from = update_to = -1; 263 | for (line = 0; line < term->lines; line++) { 264 | if (term->line_dirty[line]) { 265 | draw_line(xw, term, line); 266 | 267 | if (update_from == -1) 268 | update_from = update_to = line; 269 | else 270 | update_to = line; 271 | } 272 | } 273 | 274 | /* actual display update: vertical synchronizing */ 275 | if (update_from != -1) 276 | XCopyArea(xw->display, xw->pixbuf, xw->window, xw->gc, 0, update_from * CELL_HEIGHT, 277 | term->width, (update_to - update_from + 1) * CELL_HEIGHT, 0, update_from * CELL_HEIGHT); 278 | } 279 | -------------------------------------------------------------------------------- /x/yaftx.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE for licence details. */ 2 | #include "../yaft.h" 3 | #include "../conf.h" 4 | #include "../util.h" 5 | #include "x.h" 6 | #include "../terminal.h" 7 | #include "../ctrlseq/esc.h" 8 | #include "../ctrlseq/csi.h" 9 | #include "../ctrlseq/osc.h" 10 | #include "../ctrlseq/dcs.h" 11 | #include "../parse.h" 12 | 13 | void sig_handler(int signo) 14 | { 15 | extern volatile sig_atomic_t child_alive; 16 | 17 | if (signo == SIGCHLD) { 18 | child_alive = false; 19 | wait(NULL); 20 | } 21 | } 22 | 23 | bool sig_set(int signo, void (*handler)(int signo), int flags) 24 | { 25 | struct sigaction sigact; 26 | 27 | memset(&sigact, 0, sizeof(struct sigaction)); 28 | sigact.sa_handler = handler; 29 | sigact.sa_flags = flags; 30 | 31 | if (esigaction(signo, &sigact, NULL) == -1) { 32 | logging(WARN, "sigaction: signo %d failed\n", signo); 33 | return false; 34 | } 35 | return true; 36 | } 37 | 38 | void check_fds(fd_set *fds, struct timeval *tv, int master) 39 | { 40 | FD_ZERO(fds); 41 | FD_SET(master, fds); 42 | tv->tv_sec = 0; 43 | tv->tv_usec = SELECT_TIMEOUT; 44 | eselect(master + 1, fds, NULL, NULL, tv); 45 | } 46 | 47 | char *keyremap(KeySym keysym, unsigned int state) 48 | { 49 | int length; 50 | unsigned int mask; 51 | 52 | length = sizeof(keymap) / sizeof(keymap[0]); 53 | 54 | for (int i = 0; i < length; i++) { 55 | mask = keymap[i].mask; 56 | if (keymap[i].keysym == keysym && 57 | ((state & mask) == mask || (mask == XK_NO_MOD && !state))) 58 | return (char *) keymap[i].str; 59 | } 60 | return NULL; 61 | } 62 | 63 | void xkeypress(struct xwindow_t *xw, struct terminal_t *term, XEvent *ev) 64 | { 65 | int size; 66 | char buf[BUFSIZE], *customkey; 67 | XKeyEvent *e = &ev->xkey; 68 | KeySym keysym; 69 | 70 | //size = XmbLookupString(xw->ic, e, buf, BUFSIZE, &keysym, NULL); 71 | (void) xw; 72 | 73 | size = XLookupString(e, buf, BUFSIZE, &keysym, NULL); 74 | if ((customkey = keyremap(keysym, e->state))) { 75 | ewrite(term->fd, customkey, strlen(customkey)); 76 | } else { 77 | if (size == 1 && (e->state & Mod1Mask)) { 78 | buf[1] = buf[0]; 79 | buf[0] = '\033'; 80 | size = 2; 81 | } 82 | ewrite(term->fd, buf, size); 83 | } 84 | } 85 | 86 | void xresize(struct xwindow_t *xw, struct terminal_t *term, XEvent *ev) 87 | { 88 | XConfigureEvent *e = &ev->xconfigure; 89 | struct winsize ws; 90 | 91 | logging(DEBUG, "xresize() term.width:%d term.height:%d width:%d height:%d\n", 92 | term->width, term->height, e->width, e->height); 93 | 94 | (void ) xw; /* unused */ 95 | 96 | if (e->width == term->width && e->height == term->height) 97 | return; 98 | 99 | term->width = e->width; 100 | term->height = e->height; 101 | 102 | term->cols = term->width / CELL_WIDTH; 103 | term->lines = term->height / CELL_HEIGHT; 104 | 105 | term->scroll.top = 0; 106 | term->scroll.bottom = term->lines - 1; 107 | 108 | ws.ws_col = term->cols; 109 | ws.ws_row = term->lines; 110 | ws.ws_xpixel = CELL_WIDTH * term->cols; 111 | ws.ws_ypixel = CELL_HEIGHT * term->lines; 112 | ioctl(term->fd, TIOCSWINSZ, &ws); 113 | } 114 | 115 | void xredraw(struct xwindow_t *xw, struct terminal_t *term, XEvent *ev) 116 | { 117 | XExposeEvent *e = &ev->xexpose; 118 | int i, lines, update_from; 119 | 120 | logging(DEBUG, "xredraw() count:%d x:%d y:%d width:%d height:%d\n", 121 | e->count, e->x, e->y, e->width, e->height); 122 | 123 | update_from = e->y / CELL_HEIGHT; 124 | lines = my_ceil(e->height, CELL_HEIGHT); 125 | 126 | for (i = 0; i < lines; i++) { 127 | if ((update_from + i) < term->lines) 128 | term->line_dirty[update_from + i] = true; 129 | } 130 | 131 | if (e->count == 0) 132 | refresh(xw, term); 133 | } 134 | 135 | void (*event_func[LASTEvent])(struct xwindow_t *xw, struct terminal_t *term, XEvent *ev) = { 136 | [KeyPress] = xkeypress, 137 | [ConfigureNotify] = xresize, 138 | [Expose] = xredraw, 139 | }; 140 | 141 | bool fork_and_exec(int *master, const char *cmd, char *const argv[], int lines, int cols) 142 | { 143 | pid_t pid; 144 | struct winsize ws = {.ws_row = lines, .ws_col = cols, 145 | /* XXX: this variables are UNUSED (man tty_ioctl), 146 | but useful for calculating terminal cell size */ 147 | .ws_ypixel = CELL_HEIGHT * lines, .ws_xpixel = CELL_WIDTH * cols}; 148 | 149 | pid = eforkpty(master, NULL, NULL, &ws); 150 | if (pid < 0) 151 | return false; 152 | else if (pid == 0) { /* child */ 153 | esetenv("TERM", term_name, 1); 154 | eexecvp(cmd, argv); 155 | /* never reach here */ 156 | exit(EXIT_FAILURE); 157 | } 158 | return true; 159 | } 160 | 161 | int main(int argc, char *const argv[]) 162 | { 163 | extern const char *shell_cmd; /* defined in conf.h */ 164 | const char *cmd; 165 | uint8_t buf[BUFSIZE]; 166 | ssize_t size; 167 | fd_set fds; 168 | struct timeval tv; 169 | struct xwindow_t xw; 170 | struct terminal_t term; 171 | XEvent ev; 172 | XConfigureEvent confev; 173 | extern volatile sig_atomic_t child_alive; 174 | 175 | /* init */ 176 | if (!setlocale(LC_ALL, "")) 177 | logging(WARN, "setlocale falied\n"); 178 | 179 | if (!sig_set(SIGCHLD, sig_handler, SA_RESTART)) 180 | logging(ERROR, "signal initialize failed\n"); 181 | 182 | if (!xw_init(&xw)) { 183 | logging(FATAL, "xwindow initialize failed\n"); 184 | goto xw_init_failed; 185 | } 186 | 187 | if (!term_init(&term, xw.width, xw.height)) { 188 | logging(FATAL, "terminal initialize failed\n"); 189 | goto term_init_failed; 190 | } 191 | 192 | /* fork and exec shell */ 193 | cmd = (argc < 2) ? shell_cmd: argv[1]; 194 | if (!fork_and_exec(&term.fd, cmd, argv + 1, term.lines, term.cols)) { 195 | logging(FATAL, "forkpty failed\n"); 196 | goto fork_failed; 197 | } 198 | child_alive = true; 199 | 200 | /* initial terminal size defined in x.h */ 201 | confev.width = TERM_WIDTH; 202 | confev.height = TERM_HEIGHT; 203 | xresize(&xw, &term, (XEvent *) &confev); 204 | 205 | /* main loop */ 206 | while (child_alive) { 207 | while(XPending(xw.display)) { 208 | XNextEvent(xw.display, &ev); 209 | if (XFilterEvent(&ev, None)) 210 | continue; 211 | if (event_func[ev.type]) 212 | event_func[ev.type](&xw, &term, &ev); 213 | } 214 | 215 | check_fds(&fds, &tv, term.fd); 216 | if (FD_ISSET(term.fd, &fds)) { 217 | size = read(term.fd, buf, BUFSIZE); 218 | if (size > 0) { 219 | if (DEBUG) 220 | ewrite(STDOUT_FILENO, buf, size); 221 | parse(&term, buf, size); 222 | refresh(&xw, &term); 223 | } 224 | } 225 | } 226 | 227 | /* die */ 228 | term_die(&term); 229 | xw_die(&xw); 230 | sig_set(SIGCHLD, SIG_DFL, 0); 231 | return EXIT_SUCCESS; 232 | 233 | fork_failed: 234 | term_die(&term); 235 | term_init_failed: 236 | xw_die(&xw); 237 | xw_init_failed: 238 | return EXIT_FAILURE; 239 | } 240 | -------------------------------------------------------------------------------- /yaft.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE for licence details. */ 2 | /* yaft.c: include main function */ 3 | #include "yaft.h" 4 | #include "conf.h" 5 | #include "util.h" 6 | #include "fb/common.h" 7 | #include "terminal.h" 8 | #include "ctrlseq/esc.h" 9 | #include "ctrlseq/csi.h" 10 | #include "ctrlseq/osc.h" 11 | #include "ctrlseq/dcs.h" 12 | #include "parse.h" 13 | 14 | void sig_handler(int signo) 15 | { 16 | sigset_t sigset; 17 | /* global */ 18 | extern volatile sig_atomic_t vt_active; 19 | extern volatile sig_atomic_t child_alive; 20 | extern volatile sig_atomic_t need_redraw; 21 | 22 | logging(DEBUG, "caught signal! no:%d\n", signo); 23 | 24 | if (signo == SIGCHLD) { 25 | child_alive = false; 26 | wait(NULL); 27 | } else if (signo == SIGUSR1) { /* vt activate */ 28 | vt_active = true; 29 | need_redraw = true; 30 | ioctl(STDIN_FILENO, VT_RELDISP, VT_ACKACQ); 31 | } else if (signo == SIGUSR2) { /* vt deactivate */ 32 | vt_active = false; 33 | ioctl(STDIN_FILENO, VT_RELDISP, 1); 34 | 35 | if (BACKGROUND_DRAW) { /* update passive cursor */ 36 | need_redraw = true; 37 | } else { /* sleep until next vt switching */ 38 | sigfillset(&sigset); 39 | sigdelset(&sigset, SIGUSR1); 40 | sigsuspend(&sigset); 41 | } 42 | } 43 | } 44 | 45 | void set_rawmode(int fd, struct termios *save_tm) 46 | { 47 | struct termios tm; 48 | 49 | tm = *save_tm; 50 | tm.c_iflag = tm.c_oflag = 0; 51 | tm.c_cflag &= ~CSIZE; 52 | tm.c_cflag |= CS8; 53 | tm.c_lflag &= ~(ECHO | ISIG | ICANON); 54 | tm.c_cc[VMIN] = 1; /* min data size (byte) */ 55 | tm.c_cc[VTIME] = 0; /* time out */ 56 | etcsetattr(fd, TCSAFLUSH, &tm); 57 | } 58 | 59 | bool tty_init(struct termios *termios_orig) 60 | { 61 | struct sigaction sigact; 62 | 63 | memset(&sigact, 0, sizeof(struct sigaction)); 64 | sigact.sa_handler = sig_handler; 65 | sigact.sa_flags = SA_RESTART; 66 | esigaction(SIGCHLD, &sigact, NULL); 67 | 68 | if (VT_CONTROL) { 69 | esigaction(SIGUSR1, &sigact, NULL); 70 | esigaction(SIGUSR2, &sigact, NULL); 71 | 72 | struct vt_mode vtm; 73 | vtm.mode = VT_PROCESS; 74 | vtm.waitv = 0; 75 | vtm.acqsig = SIGUSR1; 76 | vtm.relsig = SIGUSR2; 77 | vtm.frsig = 0; 78 | 79 | if (ioctl(STDIN_FILENO, VT_SETMODE, &vtm)) 80 | logging(WARN, "ioctl: VT_SETMODE failed (maybe here is not console)\n"); 81 | 82 | if (FORCE_TEXT_MODE == false) { 83 | if (ioctl(STDIN_FILENO, KDSETMODE, KD_GRAPHICS)) 84 | logging(WARN, "ioctl: KDSETMODE failed (maybe here is not console)\n"); 85 | } 86 | } 87 | 88 | etcgetattr(STDIN_FILENO, termios_orig); 89 | set_rawmode(STDIN_FILENO, termios_orig); 90 | ewrite(STDIN_FILENO, "\033[?25l", 6); /* make cusor invisible */ 91 | 92 | return true; 93 | } 94 | 95 | void tty_die(struct termios *termios_orig) 96 | { 97 | /* no error handling */ 98 | struct sigaction sigact; 99 | struct vt_mode vtm; 100 | 101 | memset(&sigact, 0, sizeof(struct sigaction)); 102 | sigact.sa_handler = SIG_DFL; 103 | sigaction(SIGCHLD, &sigact, NULL); 104 | 105 | if (VT_CONTROL) { 106 | sigaction(SIGUSR1, &sigact, NULL); 107 | sigaction(SIGUSR2, &sigact, NULL); 108 | 109 | vtm.mode = VT_AUTO; 110 | vtm.waitv = 0; 111 | vtm.relsig = vtm.acqsig = vtm.frsig = 0; 112 | 113 | ioctl(STDIN_FILENO, VT_SETMODE, &vtm); 114 | 115 | if (FORCE_TEXT_MODE == false) 116 | ioctl(STDIN_FILENO, KDSETMODE, KD_TEXT); 117 | } 118 | 119 | tcsetattr(STDIN_FILENO, TCSAFLUSH, termios_orig); 120 | fflush(stdout); 121 | ewrite(STDIN_FILENO, "\033[?25h", 6); /* make cursor visible */ 122 | } 123 | 124 | bool fork_and_exec(int *master, const char *cmd, char *const argv[], int lines, int cols) 125 | { 126 | pid_t pid; 127 | struct winsize ws = {.ws_row = lines, .ws_col = cols, 128 | /* XXX: this variables are UNUSED (man tty_ioctl), 129 | but useful for calculating terminal cell size */ 130 | .ws_ypixel = CELL_HEIGHT * lines, .ws_xpixel = CELL_WIDTH * cols}; 131 | 132 | pid = eforkpty(master, NULL, NULL, &ws); 133 | if (pid < 0) 134 | return false; 135 | else if (pid == 0) { /* child */ 136 | esetenv("TERM", term_name, 1); 137 | eexecvp(cmd, argv); 138 | /* never reach here */ 139 | exit(EXIT_FAILURE); 140 | } 141 | return true; 142 | } 143 | 144 | int check_fds(fd_set *fds, struct timeval *tv, int input, int master) 145 | { 146 | FD_ZERO(fds); 147 | FD_SET(input, fds); 148 | FD_SET(master, fds); 149 | tv->tv_sec = 0; 150 | tv->tv_usec = SELECT_TIMEOUT; 151 | return eselect(master + 1, fds, NULL, NULL, tv); 152 | } 153 | 154 | int main(int argc, char *const argv[]) 155 | { 156 | extern const char *shell_cmd; /* defined in conf.h */ 157 | const char *cmd; 158 | uint8_t buf[BUFSIZE]; 159 | ssize_t size; 160 | fd_set fds; 161 | struct timeval tv; 162 | struct framebuffer_t fb; 163 | struct terminal_t term; 164 | /* global */ 165 | extern volatile sig_atomic_t need_redraw; 166 | extern volatile sig_atomic_t child_alive; 167 | extern struct termios termios_orig; 168 | 169 | /* init */ 170 | if (setlocale(LC_ALL, "") == NULL) /* for wcwidth() */ 171 | logging(WARN, "setlocale falied\n"); 172 | 173 | if (!fb_init(&fb)) { 174 | logging(FATAL, "framebuffer initialize failed\n"); 175 | goto fb_init_failed; 176 | } 177 | 178 | if (!term_init(&term, fb.info.width, fb.info.height)) { 179 | logging(FATAL, "terminal initialize failed\n"); 180 | goto term_init_failed; 181 | } 182 | 183 | if (!tty_init(&termios_orig)) { 184 | logging(FATAL, "tty initialize failed\n"); 185 | goto tty_init_failed; 186 | } 187 | 188 | /* fork and exec shell */ 189 | cmd = (argc < 2) ? shell_cmd: argv[1]; 190 | if (!fork_and_exec(&term.fd, cmd, argv + 1, term.lines, term.cols)) { 191 | logging(FATAL, "forkpty failed\n"); 192 | goto tty_init_failed; 193 | } 194 | child_alive = true; 195 | 196 | /* main loop */ 197 | while (child_alive) { 198 | if (need_redraw) { 199 | need_redraw = false; 200 | cmap_update(fb.fd, fb.cmap); /* after VT switching, need to restore cmap (in 8bpp mode) */ 201 | redraw(&term); 202 | refresh(&fb, &term); 203 | } 204 | 205 | if (check_fds(&fds, &tv, STDIN_FILENO, term.fd) == -1) 206 | continue; 207 | 208 | if (FD_ISSET(STDIN_FILENO, &fds)) { 209 | if ((size = read(STDIN_FILENO, buf, BUFSIZE)) > 0) 210 | ewrite(term.fd, buf, size); 211 | } 212 | if (FD_ISSET(term.fd, &fds)) { 213 | if ((size = read(term.fd, buf, BUFSIZE)) > 0) { 214 | if (VERBOSE) 215 | ewrite(STDOUT_FILENO, buf, size); 216 | parse(&term, buf, size); 217 | if (LAZY_DRAW && size == BUFSIZE) 218 | continue; /* maybe more data arrives soon */ 219 | refresh(&fb, &term); 220 | } 221 | } 222 | } 223 | 224 | /* normal exit */ 225 | tty_die(&termios_orig); 226 | term_die(&term); 227 | fb_die(&fb); 228 | return EXIT_SUCCESS; 229 | 230 | /* error exit */ 231 | tty_init_failed: 232 | term_die(&term); 233 | term_init_failed: 234 | fb_die(&fb); 235 | fb_init_failed: 236 | return EXIT_FAILURE; 237 | } 238 | -------------------------------------------------------------------------------- /yaft.h: -------------------------------------------------------------------------------- 1 | /* See LICENSE for licence details. */ 2 | #define _XOPEN_SOURCE 600 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "glyph.h" 24 | #include "color.h" 25 | 26 | enum char_code { 27 | /* 7 bit */ 28 | BEL = 0x07, BS = 0x08, HT = 0x09, 29 | LF = 0x0A, VT = 0x0B, FF = 0x0C, 30 | CR = 0x0D, ESC = 0x1B, DEL = 0x7F, 31 | /* others */ 32 | SPACE = 0x20, 33 | BACKSLASH = 0x5C, 34 | }; 35 | 36 | enum misc { 37 | BUFSIZE = 1024, /* read, esc, various buffer size */ 38 | BITS_PER_BYTE = 8, /* bits per byte */ 39 | BYTES_PER_PIXEL = sizeof(uint32_t), /* pixel size of sixel pixmap data */ 40 | BITS_PER_SIXEL = 6, /* number of bits of a sixel */ 41 | ESCSEQ_SIZE = 1024, /* limit size of terminal escape sequence */ 42 | SELECT_TIMEOUT = 15000, /* used by select() */ 43 | SLEEP_TIME = 30000, /* sleep time at EAGAIN, EWOULDBLOCK (usec) */ 44 | MAX_ARGS = 16, /* max parameters of csi/osc sequence */ 45 | UCS2_CHARS = 0x10000, /* number of UCS2 glyphs */ 46 | CTRL_CHARS = 0x20, /* number of ctrl_func */ 47 | ESC_CHARS = 0x80, /* number of esc_func */ 48 | DRCS_CHARSETS = 63, /* number of charset of DRCS (according to DRCSMMv1) */ 49 | GLYPHS_PER_CHARSET = 96, /* number of glyph of each DRCS charset */ 50 | DRCS_CHARS = DRCS_CHARSETS * GLYPHS_PER_CHARSET, 51 | DEFAULT_CHAR = SPACE, /* used for erase char */ 52 | BRIGHT_INC = 8, /* value used for brightening color */ 53 | }; 54 | 55 | enum char_attr { 56 | ATTR_RESET = 0, 57 | ATTR_BOLD = 1, /* brighten foreground */ 58 | ATTR_UNDERLINE = 4, 59 | ATTR_BLINK = 5, /* brighten background */ 60 | ATTR_REVERSE = 7, 61 | }; 62 | 63 | const uint8_t attr_mask[] = { 64 | 0x00, 0x01, 0x00, 0x00, /* 0:none 1:bold 2:none 3:none */ 65 | 0x02, 0x04, 0x00, 0x08, /* 4:underline 5:blink 6:none 7:reverse */ 66 | }; 67 | 68 | const uint32_t bit_mask[] = { 69 | 0x00, 70 | 0x01, 0x03, 0x07, 0x0F, 71 | 0x1F, 0x3F, 0x7F, 0xFF, 72 | 0x1FF, 0x3FF, 0x7FF, 0xFFF, 73 | 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 74 | 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, 75 | 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, 76 | 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, 77 | 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF, 78 | }; 79 | 80 | enum osc { 81 | OSC_GWREPT = 8900, /* OSC Ps: mode number of yaft GWREPT */ 82 | }; 83 | 84 | enum term_mode { 85 | MODE_RESET = 0x00, 86 | MODE_ORIGIN = 0x01, /* origin mode: DECOM */ 87 | MODE_CURSOR = 0x02, /* cursor visible: DECTCEM */ 88 | MODE_AMRIGHT = 0x04, /* auto wrap: DECAWM */ 89 | MODE_VWBS = 0x08, /* variable-width backspace */ 90 | }; 91 | 92 | enum esc_state { 93 | STATE_RESET = 0x00, 94 | STATE_ESC = 0x01, /* 0x1B, \033, ESC */ 95 | STATE_CSI = 0x02, /* ESC [ */ 96 | STATE_OSC = 0x04, /* ESC ] */ 97 | STATE_DCS = 0x08, /* ESC P */ 98 | }; 99 | 100 | enum glyph_width { 101 | NEXT_TO_WIDE = 0, 102 | HALF, 103 | WIDE, 104 | }; 105 | 106 | struct margin_t { uint16_t top, bottom; }; 107 | struct point_t { uint16_t x, y; }; 108 | struct color_pair_t { uint8_t fg, bg; }; 109 | 110 | struct cell_t { 111 | const struct glyph_t *glyphp; /* pointer to glyph */ 112 | struct color_pair_t color_pair; /* color (fg, bg) */ 113 | enum char_attr attribute; /* bold, underscore, etc... */ 114 | enum glyph_width width; /* wide char flag: WIDE, NEXT_TO_WIDE, HALF */ 115 | bool has_pixmap; /* has sixel pixmap data or not */ 116 | /* sixel pixmap data: 117 | must be statically allocated for copy_cell() */ 118 | uint8_t pixmap[BYTES_PER_PIXEL * CELL_WIDTH * CELL_HEIGHT]; 119 | }; 120 | 121 | struct esc_t { 122 | char *buf; 123 | char *bp; 124 | int size; 125 | enum esc_state state; 126 | }; 127 | 128 | struct charset_t { 129 | uint32_t code; /* UCS4 code point: yaft only prints UCS2 and DRCSMMv1 */ 130 | int following_byte, count; 131 | bool is_valid; 132 | }; 133 | 134 | struct state_t { /* for save, restore state */ 135 | struct point_t cursor; 136 | enum term_mode mode; 137 | enum char_attr attribute; 138 | }; 139 | 140 | struct sixel_canvas_t { 141 | uint8_t *pixmap; 142 | struct point_t point; 143 | int width, height; 144 | int line_length; 145 | uint8_t color_index; 146 | uint32_t color_table[COLORS]; 147 | }; 148 | 149 | struct terminal_t { 150 | int fd; /* master of pseudo terminal */ 151 | int width, height; /* terminal size (pixel) */ 152 | int cols, lines; /* terminal size (cell) */ 153 | struct cell_t **cells; /* pointer to each cell: cells[y * lines + x] */ 154 | struct margin_t scroll; /* scroll margin */ 155 | struct point_t cursor; /* cursor pos (x, y) */ 156 | bool *line_dirty; /* dirty flag */ 157 | bool *tabstop; /* tabstop flag */ 158 | enum term_mode mode; /* for set/reset mode */ 159 | bool wrap_occurred; /* whether auto wrap occurred or not */ 160 | struct state_t state; /* for restore */ 161 | struct color_pair_t color_pair; /* color (fg, bg) */ 162 | enum char_attr attribute; /* bold, underscore, etc... */ 163 | struct charset_t charset; /* store UTF-8 byte stream */ 164 | struct esc_t esc; /* store escape sequence */ 165 | uint32_t virtual_palette[COLORS]; /* virtual color palette: always 32bpp */ 166 | bool palette_modified; /* true if palette changed by OSC 4/104 */ 167 | const struct glyph_t *glyph[UCS2_CHARS]; /* array of pointer to glyphs[] */ 168 | struct glyph_t drcs[DRCS_CHARS]; /* DRCS chars */ 169 | struct sixel_canvas_t sixel; 170 | }; 171 | 172 | struct parm_t { /* for parse_arg() */ 173 | int argc; 174 | char *argv[MAX_ARGS]; 175 | }; 176 | 177 | volatile sig_atomic_t vt_active = true; /* SIGUSR1: vt is active or not */ 178 | volatile sig_atomic_t need_redraw = false; /* SIGUSR1: vt activated */ 179 | volatile sig_atomic_t child_alive = false; /* SIGCHLD: child process (shell) is alive or not */ 180 | struct termios termios_orig; 181 | -------------------------------------------------------------------------------- /yaft_wall: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # usage: yaft_wall /path/to/image 3 | # you can use fbv or idump 4 | 5 | # fbv (http://www.eclis.ch/fbv/) 6 | echo -ne "\e[?25l" # hide cursor 7 | fbv -ciuker "$1" << EOF 8 | q 9 | EOF 10 | 11 | # idump (https://github.com/uobikiemukot/idump) 12 | #idump "$1" 13 | 14 | export YAFT="wall" 15 | exec yaft 16 | --------------------------------------------------------------------------------