refactor(who): убрать глобальные буферы из команды "кто" (#3807) - #3809
Closed
bylins wants to merge 4 commits into
Closed
refactor(who): убрать глобальные буферы из команды "кто" (#3807)#3809bylins wants to merge 4 commits into
bylins wants to merge 4 commits into
Conversation
Первый файл слоя 1. Команда собирала весь вывод в глобальных buf, buf1 и arg -- общих на весь процесс. Любой вызов посреди сборки строки затирал накопленное, а переполнение ловилось только сторожевым байтом, уже постфактум. Разбор аргументов ведёт свои локальные буферы, строка игрока и итоговые счётчики собираются через fmt::format в std::string. sprintf и strcat в файле не осталось ни одного. Заодно ушла лишняя пересылка: строка игрока раньше писалась в глобальный buf через strcpy(buf, fmt::format(...).c_str()), теперь fmt::format пишет прямо в свою строку. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XUwDWDnYdXrJdvjDVd36QH
Первая версия правки заменила глобальные буферы локальными char[] -- это было и неверно, и не то, что задумано. Неверно: half_chop копирует остаток строки через strl_cpy с оглядкой на kMaxStringLength, то есть до 32768 байт, а буферы были по kMaxInputLength = 2048. Сегодня это не стреляет только потому, что строка команды и строка триггера ограничены теми же 2048 байтами; любое изменение лимита -- и запись уходит за границу стекового массива. Не то: слой 1 из #3807 -- про переход на std::string, а не про перенос тех же char[] из глобальной области в локальную. Теперь разбор ведёт локальный помощник ChopWord: первое слово в нижнем регистре и остаток, обе части -- std::string. Фиксированных буферов в файле не осталось. Заодно чинится "кто боги": условие было if (!str_cmp(arg, "боги") && strlen(arg) == 4) В KOI8-R "боги" занимало ровно 4 байта, в UTF-8 -- 8, поэтому вторая половина условия перестала выполняться, и слово уходило в поиск по имени. Проверка длины тут вообще лишняя: str_cmp сравнивает строки целиком, а не по префиксу. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XUwDWDnYdXrJdvjDVd36QH
В коротком списке ("кто -s") имя сначала оборачивали в цвет, а потом дополняли
до тридцати знаков:
tmp = цвет + имя + сброс
"{:<30}" по tmp
Цветовой код -- семь невидимых символов (\x1B[1;31m), сброс -- ещё семь. fmt
считает их наравне с буквами, поэтому в колонке оставалось 16 видимых знаков
вместо тридцати. Проверено: было 16, стало 30.
Теперь ширина добирается внутри цветов: fmt::format("{}{:<30}{}", цвет, имя,
сброс). Колонка стала той ширины, что задумана.
Заодно снят устаревший комментарий про то, что fmt считает ширину в байтах: это
было верно, пока русский текст лежал в KOI8-R и не был валидным UTF-8. Сейчас
fmt считает символы.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUwDWDnYdXrJdvjDVd36QH
Свой разбор строки был лишним: строковый аналог half_chop в проекте уже есть -- utils::ExtractFirstArgument (utils_string.h:150). Локальный ChopWord остался тонкой обёрткой над ним и добавляет только то, чего тот не делает, а half_chop делал: понижает регистр слова (сравнения в разборе на него рассчитывают) и срезает ведущие пробелы в остатке. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XUwDWDnYdXrJdvjDVd36QH
Owner
Author
|
Собрано вместе с остальными в #3813 — там все три темы одним PR, потому что |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Первый файл слоя 1 из #3807 — заодно проба приёма на небольшом объёме.
Что было
Команда «кто» собирала вывод в глобальных
buf,buf1иarg(utils.h:638) — 54 обращения на 360 строк файла. Буферы общие на весь процесс, поэтому любой вызов посреди сборки строки затирает накопленное, а переполнение ловится только сторожевым байтомplant_magic, уже после факта.Отдельно забавное место: строка игрока и так собиралась через
fmt::format, но результат потом переписывался в глобальный буфер:Что стало
ChopWord— первое слово в нижнем регистре и остаток, обе частиstd::string;fmt::formatвstd::string;strcpyушла —fmt::formatпишет сразу в свою строку.sprintfиstrcatв файле не осталось ни одного. Обращений к глобальным буферам — тоже.Вывод не менялся: те же форматы, та же ширина
{:<30}, те же цветовые коды.Проверено
Сборка чистая, 673 теста зелёные, малый мир поднимается. Проверять на живом — команда
ктово всех видах:кто,кто -s,кто -n имя,кто -c профессия,кто боги,кто 20-30.Дальше
По плану #3807 следующие кандидаты, от простого к сложному:
do_set.cpp/do_set_all.cpp(61/62 обращения),corpse.cpp(52),named_stuff.cpp(85),punishments.cpp(98),identify.cpp(149),do_score.cpp(137),do_show.cpp(97),do_stat.cpp(350),dg_scripts.cpp(479).🤖 Generated with Claude Code
https://claude.ai/code/session_01XUwDWDnYdXrJdvjDVd36QH
Правка после ревью (второй коммит)
Первая версия заменила глобальные буферы локальными
char[]— и это было неверно дважды.Неверно по существу.
half_chopкопирует остаток черезstrl_cpy(arg2, temp, kMaxStringLength), то есть рассчитывает на буфер в 32768 байт, а я передавал буферы поkMaxInputLength= 2048. Сегодня это не стреляет только потому, что и строка команды, и строка триггера ограничены теми же 2048 байтами (kMaxTrglineLength == kMaxInputLength). Любое изменение лимита — и запись уходит за границу стекового массива.Не то по замыслу. Слой 1 из #3807 — про переход на
std::string, а не про перенос тех жеchar[]из глобальной области в локальную. И это прямо расходилось с правилом, которое только что легло вCONTRIBUTING.md(#3808).Теперь фиксированных буферов в файле не осталось вовсе.
Заодно починилось «кто боги»
В KOI8-R «боги» занимало ровно 4 байта, в UTF-8 — 8. После перехода вторая половина условия перестала выполняться, и слово уходило в поиск по имени:
кто богиискал игрока с именем «боги» вместо списка бессмертных.Проверка длины тут и не нужна —
str_cmpсравнивает строки целиком, а не по префиксу, так что условие сократилось доtoken == "боги"(слово уже приведено к нижнему регистру).Отдельно проверить в игре стоит именно
кто боги.Третий коммит: ширина колонки в коротком списке
В
кто -sимя сначала оборачивали в цвет, а потом дополняли до тридцати знаков:Цветовой код — семь невидимых символов (
\x1B[1;31m), сброс — ещё семь, иfmtсчитает их наравне с буквами. В колонке оставалось 16 видимых знаков вместо тридцати:Теперь ширина добирается внутри цветов —
fmt::format("{}{:<30}{}", цвет, имя, сброс).Заодно снят устаревший комментарий, утверждавший, что
fmtмеряет ширину в байтах. Это было верно, пока русский текст лежал в KOI8-R: такая строка не является валидным UTF-8, иfmtсчитал байты. После флипа он считает символы — проверено замером.Четвёртый коммит: опереться на готовое
Свой разбор строки оказался лишним — строковый аналог
half_chopв проекте уже есть:utils::ExtractFirstArgument(utils_string.h:150, прямо подписан «аналог one_argument для string»).Локальный
ChopWordостался тонкой обёрткой над ним и добавляет ровно то, чего тот не делает, аhalf_chopделал: понижает регистр слова (сравнения в разборе на это рассчитывают) и срезает ведущие пробелы в остатке.