История изменений
Исправление shdown, (текущая версия) :
Попробуй сам с помощью wchar_t и сишной магии посчитать, сколько знакомест в терминале займёт «в̶̨̩̖̥̠̻̣̟͙̋̒̄̍̋̊̄̂̌͐́͛̊̒̈́̉̈́̆̽̾̿͗̈́̆̅̅͐̓̐͊̄͋̿͐̾̈̔̅̾̍̆͋͒̀̿̑̓͆̀̎̔̔̀̔̕͘̕͝͝͠о̷̞̲̲͓̖̭͕̫͓͈̼̜̟̖̖̪͇̠̪͍̻̹͚̗̻̦͕͇͊́̐̉̀̉͗̔͛̊̔͊́͂͑̄͐̈́̓̐̈́̂̏̾͘͝͝т̴̨̧̨̨̦͓̦̟̻͇̘̙͇̖͎͇̥̱̘̫͚̳̙̫̣͓͖̠̼̥̲̗͕̦̊͗͂͐̉̎̃̆̃̒̄̽̋̂͒̍́͒͋̔̋̉̌́̒̏̽̾̈́̽̐͑́̅͗̓̍͂̐̇̾̈́̍̅͂̕͘̚͝͝ ̴̡̡̨̧̘͚͎̭̗̜̭̮̘̫̮͎̰̤̝̝̩͇̤̪̯̱̪̹͉̥̹̘̱͚̖̝͈̟̫͓̻̫̍͌́͊̀͑͒̃̒̋̈́͒͆̓͑̀̋̏͐̽̐̑͊̽͊̐̎̒̈́͗̌̋̉͆͒́̒̍̓̔̿͂͌͐̽̀̀̉̅͊̋̋̀̃̆̚̚͘̕͠т̵̡̢̡̡̧̡̱̖̙̹̝̦̮̲͖̹̩͎̥̼̰̰̟̜̠͔̲̗͖̖͚̼̫͔͓͈̲̩̖̻̙͚̙̰̝̳̥͇̮̳̰͈̮̣̏̓̏̈́͋̋̚͘͜͜͝ͅа̵̡̨͓̯͙͇͚̘̬̲̣̮̬͔͚̠̹̼͚̮̩̥̘̼̝̖͒͗̆̒̅̈̀̂̃̽̿̎̓̐͘͜͝ͅк̷͔̏̀̀̓͗͑̈́͂̆̊̃͛̅͌̿̈̎̄̀̌̈̀́̃̔̍́̾̈́͊̚͠͠͝о̵̧̡̧̧̧̧̡̱̳͕̝̫̝̱͈͕͙̦̫̞̱͓̺̻̘̘͉̦͍͎̥̝͇͖͙̖͖̰̺͍̤̘͙̰́̂͊̕͜͜͝ͅй̸̧͇͔̳̘̬̗̼͔͉͉̮̪̰̳̹̦̟͚̞̔̓́̽̽̔͋̆̓̍̃̎̈́̀̂̈̆͗̿̍̈́̉̃͛̽̾̑̀ ̴̡̧̡̡̛͙̲̜͇̌̒̿̀́̉͋͂͑̓̋̇̚͜ͅт̶̛̭̎͊̑̿͛̏͆̀̿̓̌̌͋͋̍̂́̌̓̅̈̓̔̌͘̕͝е̷̡̛̛̜̰͚̜̱̮̂̄̓̈̒̔̔͊̂̐̀̈́̓̃̒̋͑̀̈̀̃̿̒͌̀͋̂̾̈́̔̒͒͂̓̑͑̀̾́́̍̆̐̿̔̓̌̆͂̽̀̕͘͘̕͘̚̚͠͝͝к̷̧̡̡̨̧̛̛̛̗̭̲̭̜͍̙̖̩̮̟̻͇̞̮͉͓̱͔̩̣̪̮͎̩̠̜͓̗̎̐̏̐̈́̀̈́̉͛͌̾̌̋̅͌̍͛̒͒͊̈́̈́͗̏̅͛̀̌́̏͆̎̄̾̊͋́͂̓͛͜͝͠͝ͅс̷̡̢̡̧̨̙͕̱̼͎̞̪͖͍̯̰͖̖̬̟͔̫̳̋̄͗̓̒̊̈́̓̍́̽͊̄̈́̓̈́̀т̸̡̨̡̧̨̮͙̫͎̳̲͎͓͚̣͙̞̠̻͉̟͉̟̯͔̣̭̭̩̝̼͎͍̠̥̣̺̠͖͍̪͎̇͜͜͜ͅͅ».
Да легко.
$ cat otakoi.txt; md5sum otakoi.txt # с переводом строки; MD5 для воспроизводимости
о̷̞̲͓̖̭͕̫͈̼̜̟̪͇̠͍̻̹͚̗̦͊́̐̉̀͗̔͛̊͂͑̄͐̈́̓̂̏̾͘͝т̴̨̧̦͓̟̻͇̘̙̖͎̥̱̫͚̳̣͖̠̼̲̗͕̊͗͂͐̉̎̃̆̒̄̽̋̂͒̍́͋̔̌̏̾̈́̐͑́̅̓̇̕͘̚͝ ̴̡̨̧̘͚͎̭̗̜̮̫̰̤̝̩͇̪̯̱̹͉̥̖͈̟͓̻̍͌́͊̀͑͒̃̒̋̈́͆̓̀̏͐̽̐̑̎͗̌̉̔̿͂̅̆̚͘̕͠т̵̡̢̧̱̖̙̹̝̦̮̲͖̩͎̥̼̰̟̜̠͔̗͚̫͓͈̻̳͇̣̏̓̈́͋̋̚͘͜͝ͅа̵̡̨͓̯͙͇͚̘̬̲̣̮͔̠̹̼̩̥̝̖͒͗̆̒̅̈̀̂̃̽̿̎̓̐͘͜͝ͅк̷͔̏̀̓͗͑̈́͂̆̊̃͛̅͌̿̈̎̄̌̀́̔̍́̾͊̚͠͝о̵̧̡̱̳͕̝̫͈͙̦̞͓̺̻̘͉͍͎̥͇͖̖̰̤́̂͊̕͜͝ͅй̸̧͇͔̳̘̬̗̼͉̮̪̰̹̦̟͚̞̔̓́̽͋̆̓̍̃̎̈́̀̂̈͗̿̉͛̾̑̀ ̴̡̧̛͙̲̜͇̌̒̿̀́̉͋͂͑̓̋̇̚͜ͅт̶̛̭̎͊̑̿͛̏͆̀̓̌͋̍̂́̓̅̈̔͘̕͝е̷̡̛̜̰͚̱̮̂̄̓̈̒̔͊̐̀̈́̓̃̋͑̿͌͋̾͒͂̑̀́̍̆̌̽̕͘̚͠͝к̷̧̡̨̛̗̭̲̜͍̙̖̩̮̟̻͇̞͉͓̱͔̣̪͎̠̎̐̏̈́̀̉͛͌̾̌̋̅̍̒͒͊͗̀́͆̄̊͋͂̓͜͝͠ͅс̷̡̢̧̨̙͕̱̼͎̞̪͖͍̯̰̖̬̟͔̫̳̋̄͗̓̒̊̈́̓̍́̽͊̀т̸̡̨̧̮͙̫͎̳̲͓͚̣̞̠̻͉̟̯͔̭̩̝̼͍̥̺͖̪̇͜ͅ
f3cd194b468ac9c372c55c5d9b8560b9 otakoi.txt
$ cat foo.c
#define _XOPEN_SOURCE
#include <wchar.h>
#include <stdio.h>
#include <locale.h>
int main()
{
if (!setlocale(LC_ALL, "")) {
fprintf(stderr, "setlocale() failed.\n");
return 1;
}
wchar_t buf[1024];
if (!fgetws(buf, 1024, stdin)) {
fprintf(stderr, "fgetws() failed.\n");
return 1;
}
size_t len = wcslen(buf);
while (len && (buf[len - 1] == L'\n' || buf[len - 1] == L'\r')) {
--len;
}
int w = wcswidth(buf, len);
printf("%d\n", w);
return 0;
}
$ tcc -run foo.c < otakoi.txt
14
$ cat test_otakoi.bash
get_cursor_column() {
echo -e '\033[6n' >&2
local res
IFS= read -rd R res || return $?
res=${res#*'['}
res=${res#*;}
echo "$res"
}
# Каждый раз переводим строку с помощью echo без аргументов, потому что
# get_cursor_column в процессе работы передвигает курсор вправо.
# Замеряем позицию курсора в самом левом столбце (должно быть 1).
echo
pos1=$(get_cursor_column)
# Замеряем позицию курсора после вывода текста (но без '\n').
echo
echo -n "$(cat otakoi.txt)"
pos2=$(get_cursor_column)
echo
echo "pos1=$pos1, pos2=$pos2, delta=$(( pos2 - pos1 ))"
$ bash test_otakoi.bash
^[[27;1R
о̷̞̲͓̖̭͕̫͈̼̜̟̪͇̠͍̻̹͚̗̦͊́̐̉̀͗̔͛̊͂͑̄͐̈́̓̂̏̾͘͝т̴̨̧̦͓̟̻͇̘̙̖͎̥̱̫͚̳̣͖̠̼̲̗͕̊͗͂͐̉̎̃̆̒̄̽̋̂͒̍́͋̔̌̏̾̈́̐͑́̅̓̇̕͘̚͝ ̴̡̨̧̘͚͎̭̗̜̮̫̰̤̝̩͇̪̯̱̹͉̥̖͈̟͓̻̍͌́͊̀͑͒̃̒̋̈́͆̓̀̏͐̽̐̑̎͗̌̉̔̿͂̅̆̚͘̕͠т̵̡̢̧̱̖̙̹̝̦̮̲͖̩͎̥̼̰̟̜̠͔̗͚̫͓͈̻̳͇̣̏̓̈́͋̋̚͘͜͝ͅа̵̡̨͓̯͙͇͚̘̬̲̣̮͔̠̹̼̩̥̝̖͒͗̆̒̅̈̀̂̃̽̿̎̓̐͘͜͝ͅк̷͔̏̀̓͗͑̈́͂̆̊̃͛̅͌̿̈̎̄̌̀́̔̍́̾͊̚͠͝о̵̧̡̱̳͕̝̫͈͙̦̞͓̺̻̘͉͍͎̥͇͖̖̰̤́̂͊̕͜͝ͅй̸̧͇͔̳̘̬̗̼͉̮̪̰̹̦̟͚̞̔̓́̽͋̆̓̍̃̎̈́̀̂̈͗̿̉͛̾̑̀ ̴̡̧̛͙̲̜͇̌̒̿̀́̉͋͂͑̓̋̇̚͜ͅт̶̛̭̎͊̑̿͛̏͆̀̓̌͋̍̂́̓̅̈̔͘̕͝е̷̡̛̜̰͚̱̮̂̄̓̈̒̔͊̐̀̈́̓̃̋͑̿͌͋̾͒͂̑̀́̍̆̌̽̕͘̚͠͝к̷̧̡̨̛̗̭̲̜͍̙̖̩̮̟̻͇̞͉͓̱͔̣̪͎̠̎̐̏̈́̀̉͛͌̾̌̋̅̍̒͒͊͗̀́͆̄̊͋͂̓͜͝͠ͅс̷̡̢̧̨̙͕̱̼͎̞̪͖͍̯̰̖̬̟͔̫̳̋̄͗̓̒̊̈́̓̍́̽͊̀т̸̡̨̧̮͙̫͎̳̲͓͚̣̞̠̻͉̟̯͔̭̩̝̼͍̥̺͖̪̇͜ͅ
^[[29;15R
pos1=1, pos2=15, delta=14
Исходная версия shdown, :
Попробуй сам с помощью wchar_t и сишной магии посчитать, сколько знакомест в терминале займёт «в̶̨̩̖̥̠̻̣̟͙̋̒̄̍̋̊̄̂̌͐́͛̊̒̈́̉̈́̆̽̾̿͗̈́̆̅̅͐̓̐͊̄͋̿͐̾̈̔̅̾̍̆͋͒̀̿̑̓͆̀̎̔̔̀̔̕͘̕͝͝͠о̷̞̲̲͓̖̭͕̫͓͈̼̜̟̖̖̪͇̠̪͍̻̹͚̗̻̦͕͇͊́̐̉̀̉͗̔͛̊̔͊́͂͑̄͐̈́̓̐̈́̂̏̾͘͝͝т̴̨̧̨̨̦͓̦̟̻͇̘̙͇̖͎͇̥̱̘̫͚̳̙̫̣͓͖̠̼̥̲̗͕̦̊͗͂͐̉̎̃̆̃̒̄̽̋̂͒̍́͒͋̔̋̉̌́̒̏̽̾̈́̽̐͑́̅͗̓̍͂̐̇̾̈́̍̅͂̕͘̚͝͝ ̴̡̡̨̧̘͚͎̭̗̜̭̮̘̫̮͎̰̤̝̝̩͇̤̪̯̱̪̹͉̥̹̘̱͚̖̝͈̟̫͓̻̫̍͌́͊̀͑͒̃̒̋̈́͒͆̓͑̀̋̏͐̽̐̑͊̽͊̐̎̒̈́͗̌̋̉͆͒́̒̍̓̔̿͂͌͐̽̀̀̉̅͊̋̋̀̃̆̚̚͘̕͠т̵̡̢̡̡̧̡̱̖̙̹̝̦̮̲͖̹̩͎̥̼̰̰̟̜̠͔̲̗͖̖͚̼̫͔͓͈̲̩̖̻̙͚̙̰̝̳̥͇̮̳̰͈̮̣̏̓̏̈́͋̋̚͘͜͜͝ͅа̵̡̨͓̯͙͇͚̘̬̲̣̮̬͔͚̠̹̼͚̮̩̥̘̼̝̖͒͗̆̒̅̈̀̂̃̽̿̎̓̐͘͜͝ͅк̷͔̏̀̀̓͗͑̈́͂̆̊̃͛̅͌̿̈̎̄̀̌̈̀́̃̔̍́̾̈́͊̚͠͠͝о̵̧̡̧̧̧̧̡̱̳͕̝̫̝̱͈͕͙̦̫̞̱͓̺̻̘̘͉̦͍͎̥̝͇͖͙̖͖̰̺͍̤̘͙̰́̂͊̕͜͜͝ͅй̸̧͇͔̳̘̬̗̼͔͉͉̮̪̰̳̹̦̟͚̞̔̓́̽̽̔͋̆̓̍̃̎̈́̀̂̈̆͗̿̍̈́̉̃͛̽̾̑̀ ̴̡̧̡̡̛͙̲̜͇̌̒̿̀́̉͋͂͑̓̋̇̚͜ͅт̶̛̭̎͊̑̿͛̏͆̀̿̓̌̌͋͋̍̂́̌̓̅̈̓̔̌͘̕͝е̷̡̛̛̜̰͚̜̱̮̂̄̓̈̒̔̔͊̂̐̀̈́̓̃̒̋͑̀̈̀̃̿̒͌̀͋̂̾̈́̔̒͒͂̓̑͑̀̾́́̍̆̐̿̔̓̌̆͂̽̀̕͘͘̕͘̚̚͠͝͝к̷̧̡̡̨̧̛̛̛̗̭̲̭̜͍̙̖̩̮̟̻͇̞̮͉͓̱͔̩̣̪̮͎̩̠̜͓̗̎̐̏̐̈́̀̈́̉͛͌̾̌̋̅͌̍͛̒͒͊̈́̈́͗̏̅͛̀̌́̏͆̎̄̾̊͋́͂̓͛͜͝͠͝ͅс̷̡̢̡̧̨̙͕̱̼͎̞̪͖͍̯̰͖̖̬̟͔̫̳̋̄͗̓̒̊̈́̓̍́̽͊̄̈́̓̈́̀т̸̡̨̡̧̨̮͙̫͎̳̲͎͓͚̣͙̞̠̻͉̟͉̟̯͔̣̭̭̩̝̼͎͍̠̥̣̺̠͖͍̪͎̇͜͜͜ͅͅ».
Да легко.
$ cat otakoi.txt; md5sum otakoi.txt
о̷̞̲͓̖̭͕̫͈̼̜̟̪͇̠͍̻̹͚̗̦͊́̐̉̀͗̔͛̊͂͑̄͐̈́̓̂̏̾͘͝т̴̨̧̦͓̟̻͇̘̙̖͎̥̱̫͚̳̣͖̠̼̲̗͕̊͗͂͐̉̎̃̆̒̄̽̋̂͒̍́͋̔̌̏̾̈́̐͑́̅̓̇̕͘̚͝ ̴̡̨̧̘͚͎̭̗̜̮̫̰̤̝̩͇̪̯̱̹͉̥̖͈̟͓̻̍͌́͊̀͑͒̃̒̋̈́͆̓̀̏͐̽̐̑̎͗̌̉̔̿͂̅̆̚͘̕͠т̵̡̢̧̱̖̙̹̝̦̮̲͖̩͎̥̼̰̟̜̠͔̗͚̫͓͈̻̳͇̣̏̓̈́͋̋̚͘͜͝ͅа̵̡̨͓̯͙͇͚̘̬̲̣̮͔̠̹̼̩̥̝̖͒͗̆̒̅̈̀̂̃̽̿̎̓̐͘͜͝ͅк̷͔̏̀̓͗͑̈́͂̆̊̃͛̅͌̿̈̎̄̌̀́̔̍́̾͊̚͠͝о̵̧̡̱̳͕̝̫͈͙̦̞͓̺̻̘͉͍͎̥͇͖̖̰̤́̂͊̕͜͝ͅй̸̧͇͔̳̘̬̗̼͉̮̪̰̹̦̟͚̞̔̓́̽͋̆̓̍̃̎̈́̀̂̈͗̿̉͛̾̑̀ ̴̡̧̛͙̲̜͇̌̒̿̀́̉͋͂͑̓̋̇̚͜ͅт̶̛̭̎͊̑̿͛̏͆̀̓̌͋̍̂́̓̅̈̔͘̕͝е̷̡̛̜̰͚̱̮̂̄̓̈̒̔͊̐̀̈́̓̃̋͑̿͌͋̾͒͂̑̀́̍̆̌̽̕͘̚͠͝к̷̧̡̨̛̗̭̲̜͍̙̖̩̮̟̻͇̞͉͓̱͔̣̪͎̠̎̐̏̈́̀̉͛͌̾̌̋̅̍̒͒͊͗̀́͆̄̊͋͂̓͜͝͠ͅс̷̡̢̧̨̙͕̱̼͎̞̪͖͍̯̰̖̬̟͔̫̳̋̄͗̓̒̊̈́̓̍́̽͊̀т̸̡̨̧̮͙̫͎̳̲͓͚̣̞̠̻͉̟̯͔̭̩̝̼͍̥̺͖̪̇͜ͅ
f3cd194b468ac9c372c55c5d9b8560b9 otakoi.txt
$ cat foo.c
#define _XOPEN_SOURCE
#include <wchar.h>
#include <stdio.h>
#include <locale.h>
int main()
{
if (!setlocale(LC_ALL, "")) {
fprintf(stderr, "setlocale() failed.\n");
return 1;
}
wchar_t buf[1024];
if (!fgetws(buf, 1024, stdin)) {
fprintf(stderr, "fgetws() failed.\n");
return 1;
}
size_t len = wcslen(buf);
while (len && (buf[len - 1] == L'\n' || buf[len - 1] == L'\r')) {
--len;
}
int w = wcswidth(buf, len);
printf("%d\n", w);
return 0;
}
$ tcc -run foo.c < otakoi.txt
14
$ cat test_otakoi.bash
get_cursor_column() {
echo -e '\033[6n' >&2
local res
IFS= read -rd R res || return $?
res=${res#*'['}
res=${res#*;}
echo "$res"
}
# Каждый раз переводим строку с помощью echo без аргументов, потому что
# get_cursor_column в процессе работы передвигает курсор вправо.
# Замеряем позицию курсора в самом левом столбце (должно быть 1).
echo
pos1=$(get_cursor_column)
# Замеряем позицию курсора после вывода текста (но без '\n').
echo
echo -n "$(cat otakoi.txt)"
pos2=$(get_cursor_column)
echo
echo "pos1=$pos1, pos2=$pos2, delta=$(( pos2 - pos1 ))"
$ bash test_otakoi.bash
^[[27;1R
о̷̞̲͓̖̭͕̫͈̼̜̟̪͇̠͍̻̹͚̗̦͊́̐̉̀͗̔͛̊͂͑̄͐̈́̓̂̏̾͘͝т̴̨̧̦͓̟̻͇̘̙̖͎̥̱̫͚̳̣͖̠̼̲̗͕̊͗͂͐̉̎̃̆̒̄̽̋̂͒̍́͋̔̌̏̾̈́̐͑́̅̓̇̕͘̚͝ ̴̡̨̧̘͚͎̭̗̜̮̫̰̤̝̩͇̪̯̱̹͉̥̖͈̟͓̻̍͌́͊̀͑͒̃̒̋̈́͆̓̀̏͐̽̐̑̎͗̌̉̔̿͂̅̆̚͘̕͠т̵̡̢̧̱̖̙̹̝̦̮̲͖̩͎̥̼̰̟̜̠͔̗͚̫͓͈̻̳͇̣̏̓̈́͋̋̚͘͜͝ͅа̵̡̨͓̯͙͇͚̘̬̲̣̮͔̠̹̼̩̥̝̖͒͗̆̒̅̈̀̂̃̽̿̎̓̐͘͜͝ͅк̷͔̏̀̓͗͑̈́͂̆̊̃͛̅͌̿̈̎̄̌̀́̔̍́̾͊̚͠͝о̵̧̡̱̳͕̝̫͈͙̦̞͓̺̻̘͉͍͎̥͇͖̖̰̤́̂͊̕͜͝ͅй̸̧͇͔̳̘̬̗̼͉̮̪̰̹̦̟͚̞̔̓́̽͋̆̓̍̃̎̈́̀̂̈͗̿̉͛̾̑̀ ̴̡̧̛͙̲̜͇̌̒̿̀́̉͋͂͑̓̋̇̚͜ͅт̶̛̭̎͊̑̿͛̏͆̀̓̌͋̍̂́̓̅̈̔͘̕͝е̷̡̛̜̰͚̱̮̂̄̓̈̒̔͊̐̀̈́̓̃̋͑̿͌͋̾͒͂̑̀́̍̆̌̽̕͘̚͠͝к̷̧̡̨̛̗̭̲̜͍̙̖̩̮̟̻͇̞͉͓̱͔̣̪͎̠̎̐̏̈́̀̉͛͌̾̌̋̅̍̒͒͊͗̀́͆̄̊͋͂̓͜͝͠ͅс̷̡̢̧̨̙͕̱̼͎̞̪͖͍̯̰̖̬̟͔̫̳̋̄͗̓̒̊̈́̓̍́̽͊̀т̸̡̨̧̮͙̫͎̳̲͓͚̣̞̠̻͉̟̯͔̭̩̝̼͍̥̺͖̪̇͜ͅ
^[[29;15R
pos1=1, pos2=15, delta=14