Для одного проекта мне понадобился просмотрщик памяти в DOS. В идеале хотелось бы иметь редактор памяти, чтобы в нём был поиск по ключевым словам, перемещение к заданному адресу. Но для старта мне было бы достаточно хотя бы возможность просмотра всего мегабайта доступной «нижней» памяти.
Старожилы знают, что в комплекте с различными версиями ДОС шли дополнительные утилиты, и среди них была «замечательная» утилита
debug
, которая убога чуть более, чем полностью. Ещё во времена моей молодости эта утилита вызывала у меня самые противоречивые чувства, то сейчас и подавно. Пользоваться ей без успокоительных очень сложно, с другой стороны, хорошо, что она есть. Но мне возможностей и удобства этой утилиты не хватало, поэтому пришлось искать другой подходящий инструмент. После длительного гугления наткнулся на исходники утилиты RAM View.К сожалению, исполняемого файла найти не удалось, только исходные коды под
Borland C++ 3.1
, и как впоследствии оказалось, сама программа содержала ошибки.Всё это вылилось в интересный квест по поиску старого компилятора, исправления ошибок в программе 25-летней давности и создания запроса на слияние.
❯ Компиляция
Поскольку утилита поставляется только в исходных кодах, то её необходимо собрать. Как я не пытался, найти исполняемого файла мне не удалось. Поэтому придётся пройти этот тернистый путь, благо хотя бы компиляторы все в доступе.
Для того чтобы собрать и проверить эту утилиту, мне понадобится программа DOSBOX. До того как запускать коробку с ДОС, создаю папку
DOS
в корне диска C, либо ~/DOS
в любимом Linux. Перехожу в эту папку и клонирую туда этот проект:
git clone https://github.com/aurelitec/ramview.git
Сборка старых программ – это определённый квест, доступный не каждому: старые компиляторы, у которых есть свои особенности работы с ними, описанные в книгах, сданных в макулатуру. Поскольку ранее с компилятором
Borland C++
дел не имел, пришлось идти в ретрочатик t.me/retrocomps и просить помощи.Согласно описанию в гите, мне нужен
Borland C++ 3.1
, который я скачал отсюда. Выбрал портабельную последнюю версию, чтобы не заниматься установкой, и распаковываю её в папку C:\DOS\BC\
.После чего запускаю DOSBOX и монтирую локальную папку
C:\DOS
, как диск C:\
:Если просто открыть проект в компиляторе BC и попробовать собрать, то вылезет ошибка, что библиотеки не найдены, и тут начинается главная магия. Идея в том, что надо понять в какую папку был установлен компилятор у автора, чтобы пути к библиотекам в его проекте совпали с реальным их расположением, но как это сделать? Всё достаточно просто, возможно вариант не самый элегантный, но рабочий.
Первое – это нужно получить Makefile из самого проекта, делается это командой
PRJ2MAK
(не забываем указать пути к исполняемому файлу):PRJ2MAK RAMVIEW.PRJ
После этого у нас появится Makefile
RAMVIEW.MAK
, в котором уже можно посмотреть пути, где должен обитать компилятор.Теперь осталось перенести компилятор в папку
BORLANDC
и должно произойти чудо.Переименование папки
Запускаю компилятор, собираю и да, полный успех!
Казалось бы, вот оно счастье! Программа собралась, и можно пользоваться.
После всех неочевидных манипуляций запускаю программу и вижу такую картину:
Куча мусорных символов, которые разделяют шестнадцатеричные данные, и количество символов справа меньше 16 (вылезают за пределы экрана). Связанно это с тем, что отображаемый символ не один, а три, вот он и «выдавливает» текст за пределы строки.
Ну что ж, пришла пора исправлять чужие ошибки в старой программе.
❯ Исправление ошибок в чужом коде
Проблема достаточно банальная, автор программы писал во времена DOS, в кодировке IBM CP866, а потом исходники видимо кочевали по разным дискам, вот и потерялись различные спецсимволы, которые затем были некорректно декодированы при заливке на github.
В этом можно убедиться, если открыть Notepad++ и посмотреть исходники, то достаточно быстро можно найти подобные места:
Некорректное отображение символов
Если в настройках сменить кодировку на CP866 (в моём случае это кириллица), то места станут намного более очевидными. А главное, они сразу будут узнаваемы с теми символами, что на скриншоте.
Проблемные места в кодировке CP866
Всё достаточно банально, нужно просто подобрать в ASCII-кодах подходящие символы и вставить их в нужные места. Первые две «сломанные» строки – это явно вертикальный символ, а нижний – это красивая деталь разделитель рамки.
Таблица ASCII – кириллица
Результатом стал выбор символа 0xB3 для вертикальной черты, и 0xBA для детали рамки.
cputs(" Version 0.1 \xb3 Copyright (c) 1997 Aurelitec");
…
cputs("\xb3 F10 = Exit");
…
strcat(buffer, " \xba");
Очень удобно редактировать код в Notepad++, а затем собирать в DOSBOX, новейшие технологии стучатся в наши двери (сарказм). После перекомпиляции получаем программу, которая выглядит и работает, так как надо:
Область памяти с ROM BIOS
Вот, теперь всё на своих местах. Есть разделители, четыре блока по четыре байта, итого 16 символов. Справа ровно 16 символов для текста, и ничего не теряется. Программа работает именно так, как нужно.
В целом можно добавить и другой функционал, например, поиск в памяти, который есть у того же debug, но мне пока лень.
Поскольку автор предоставляет нам как лицензионную, так и просто человеческую возможность вносить изменения в свою программу:
ContributingЭтой возможностью мы и воспользуемся.
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
❯ Оформление изменений в чужой проект
Это самая главная задача, из-за которой и была написана эта статья. Мне бы хотелось, чтобы читатели не боялись создавать запросы на слияния в чужие репозитории и исправляли чужие ошибки или писали дополнения. Плюс это весьма полезный опыт для новичков.
Если попробовать закоммитить полученные изменения в репозиторий, из которого мы склонировали, то ничего не выйдет. Для этого в github есть другой механизм, по-русски называемый запросом на слияние. В gitlab он называется merge request, в github именуется pull request. Так как мне довелось достаточно долго поработать с github и gitlab, то я больше люблю за удобство gitlab, он сделан людьми для людей. Но человек ко всему привыкает и даже к таким ужасным вещам, как неочевидный интерфейс github.
Первое, что потребуется сделать – это создать ответвление от родительского проекта (fork). Для этого нужно клацнуть по соответствующей кнопке в родительском репозитории.
Кнопка — создание форка репозитория
Клонирование репозитория к себе, в моём случае форк уже создан
После чего, у вас в профиле, появится такой же репозиторий с тем же именем и содержанием.
После этого необходимо в вашем локальном репозитории, который на вашем компьютере, переключить origin с адреса родительского репозитория, на ваш удалённый. Для этого нужно скопировать путь до вашего репозитория.
В локальном репозитории выполняем:
git remote set-url origin https://github.com/dlinyj/ramview.git
Далее можно добавить все изменённые файлы, сделать коммит и затолкать изменения в наш форкнутый репозиторий.
git add <files>
git commit -m "Fixed minor bugs with the display of symbols"
git push
И тут начинается самое интересное. Вообще, как я понимаю, можно сделать и локально запрос на слияние, но мне удобнее через web-интерфейс.
В веб-интерфейсе вашего удалённого репозитория нужно зайти «Pull requests» и там нажать кнопку «New pull request».
Там будет предложено выбрать удалённый репозиторий, в который нам нужно произвести слияние, по умолчанию там будет уже стоять родительский, и описание вашего запроса на слияние. В результате всех манипуляций в родительском репозитории появится запрос на слияние следующего вида:
Как выглядит запрос на слияние
К сожалению для меня, и к счастью для вас, владелец репозитория проигнорировал мой запрос, и вы можете его посмотреть по следующей ссылке.
На этом ваши приключения не заканчиваются, а только начинаются. Это самая интересная, может кому-то неприятная, часть заливки кода в чужеродный репозиторий.
После того как вы создали запрос на слияние, может быть несколько вариантов развития событий: игнорирование (как в этом случае), автор может отклонить ваш запрос, добавить его в основную ветку, или самый распространённый случай, написать вам замечания, которые вы должны будете исправлять.
Самое неприятное и распространённое – это исправление замечаний от владельца репозитория. Вы вносите эти изменения точно так же локально, но когда вы делаете коммит, то не создаёте новый, а добавляете изменения в старый коммит, так чтобы его hash не менялся.
Делается это следующей командой:
git commit --amend
Но git push у вас сделать не получится, потому что это вы будете вносить исправления в уже существующие коммиты на удалённом сервере. Поэтому надо его запихать туда принудительно, без предварительных ласк и грубой силой, используя опцию
--force
. Крайне не рекомендуется её использовать, но других вариантов я не знаю.git push --force
Это обновит содержимое вашего репозитория, а также исправит содержание запроса на слияние у владельца.
У такого подхода есть недостаток, что стираются замечания, которые владелец вам оставил (это особенность github, у нормального gitlab таких проблем нет), так что рекомендую сохранять все замечания до финального коммита.
❯ Выводы
Реальное применение исправленной программы
Достаточно часто встречаю от начинающих программистов вопрос: как мне набраться опыта в программировании? И всем им даю один и тот же ответ: идите на гитхаб и принимайте участие в каком-либо проекте. Правка чужого кода – это лучший способ научиться программировать. Поэтому настоятельно рекомендую не стесняться и делать такие правки, в худшем случае отклонят ваш запрос на слияние. В любом случае вы получите полезный опыт.
В моём случае это представляло скорее спортивный интерес, плюс мне нужна была рабочая версия программы, а сделать запрос на слияние для меня дело пяти минут.
Для тех, кому нужен исполняемый файл, вы можете его скачать у меня с диска.
❯ Полезные ссылки:
- Оригинальный репозиторий.
- Моя исправления копия.
- Оформленный запрос на слияние.
- Готовая собранная программа.
P.S. Попробуем правила 6 рукопожатий, быть может, кто-то из вас знает владельца репозитория и попросит его посмотреть мой запрос на слияние?
Комментарии (40)
AlexanderS
07.11.2022 13:51+7Отличная работа. Отдельное спасибо за раздел «Оформление изменений в чужой проект» — теперь эту статью можно как мануал другим показывать!
dlinyj Автор
07.11.2022 13:58+4Спасибо. В общем-то так и старался написать, чтобы была готовая мурзилка-мануал.
0xd34df00d
07.11.2022 18:40+6Только у вас там что-то странное написано:
но когда вы делаете коммит, то не создаёте новый, а добавляете изменения в старый коммит, так чтобы его hash не менялся.
У вас это не получится сделать (с точностью до коллизий хэш-функции), потому что хэш зависит от содержания.
И, если честно, мне как принимающему изменения не хотелось бы видеть amend'нутые коммиты после ревью — сложнее увидеть, что еще изменилось. Если мейнтейнер репозитория так уж не хочет иметь несколько коммитов после одного PR, то он может вместо мерджа squash'нуть.
Короче, в этом случае аменд лучше не делать.
dlinyj Автор
07.11.2022 19:26+1Можете рассказать подробную инструкцию, как лучше делать. Не считаю себя знатоком гита, и поэтому мог что-то упустить.
zloddey
07.11.2022 22:27+7Сделать ещё один коммит с исправлениями поверх первого. А потом обычный пуш (без `--force`). Pull request привязывается к ветке, а не к коммиту. После этого в нём появится оба коммита, и будет возможно увидеть как суммарные изменения по обоим коммитам, так и сам отдельный фикс.
screwer
07.11.2022 14:06+2Ещё один вариант - автор не принимает ваш пуллоеквест, не просит сделать изменения, а по "образу и подобию" делает коммит от своего имени. Вот от такого поведения желание делать пуллреквесты быстро угасает.
dlinyj Автор
07.11.2022 14:22+9Да ладно, главное конечный результат — код правильный. А ЧСВ почесать это мы в другом месте успеем.
motoroller95
07.11.2022 15:39+2у меня был подобный случай. уже не помню в какой проект контрибьютил, но самое забавное что автор сам закомитил мои изменение, так еще и в коменты мне написал мол чел, у тебя там конфликты, пофиксай.
BubaVV
07.11.2022 14:24+5Лучше
git push --force-with-lease .
Это тоже форс, но он не позволит случайно переписать чужой коммит
fk0
07.11.2022 14:47+6Есть же qview (https://www.enlight.ru/qview/about.htm)... Зачем что-то собирать самому, кроме как за ради интереса?
dlinyj Автор
07.11.2022 14:51+2Видимо потому, что я гуглил, гуглил и не нашёл эту чудесную утилиту. Ну и чтобы был хороший пример :).
Спасибо, гляну при случае.
Pochemuk
07.11.2022 14:49+2Хех! А ведь я когда-то тоже писал просмотрщик дампа памяти для DOS. На Ассемблере. Похожий, но красивше. И висел он в резидентах и его окно вызывалось по горячим клавишам. Даже из графического режима (при закрытии окна графический режим восстанавливался (разрешение, палитра, смещение окна отображения экрана). Было удобно для анализа игрушек - где какой счетчик хранится.
Я даже нашел сорс и скомпилированный исполнимый коммандник. Но, к сожалению, запустить даже из под DOSBox не получилось - не реагирует на горячие клавиши. Видимо, в DOSBox нельзя перехватить клавиатурное прерывание 16H. Да и вообще нельзя подменять/перехватывать вызов обработчиков.
dlinyj Автор
07.11.2022 14:52Ну у меня задача именно на реальном железе. Тем более, что ДОС можно накатить на виртуальную машину.
Pochemuk
07.11.2022 16:21+1Могу выслать командник и сорс. Правда, не уверен, что именно это та версия, которая с графикой работает корректно. Вернее, работает только с EGA - VGA, когда это писалось, еще не были широко распространены.
Mishootk
07.11.2022 15:28+2В детстве баловались набором читеров: резидентом скидывали память в файлы, утилиткой и ручками искали счетчики, прописывали в конфиг, еще одним резидентом эти счетчики принудительно восстанавливались в нужное нам значение. Бесконечные патроны для игрушек - замечательно.
gwer
07.11.2022 15:56+5Вы вносите эти изменения точно так же локально, но когда вы делаете коммит, то не создаёте новый, а добавляете изменения в старый коммит, так чтобы его hash не менялся.
Это утверждение не совсем корректно.
git commit --amend
создаст новый коммит, и хэш у него будет новый.
Упрощённо это можно называть изменением коммита, но если мы дошли до таких подробностей, как хэш, то уже нет — коммиты атомарны, менять их содержимое нельзя.
В общем-то можно и без--amend
, засквошить коммиты можно и непосредственно перед слиянием.
Ну и пушить лучше черезgit push --force-with-lease
— это безопаснее. Всё ещё не слишком хорошо, но в свою личную ветку можно.dlinyj Автор
07.11.2022 15:59Да, вы совершенно правы. И я читателям статьи рекомендую обратить внимание на ваше замечание.
misha98857
07.11.2022 15:57+1Под рукой pull request-а на GitHub не оказалось, чтобы проверить. Разве у GitHub нет возможности squash-нуть все коммиты в MR в один merge коммит и не использовать хак с force push?
dlinyj Автор
07.11.2022 15:58Немного в другом проблема. Вы сделали мердж, уже всё готово. Все коммиты сквасились, но вдруг вам замечания прилетают. И вот чтобы исправленные замечания попали снова в этот же мердж, нужно сделать --force.
SuperFly
07.11.2022 17:38+9Пока ПР не смержен, просто продолжаете коммитить в свою ветку, без всяких амендов и форс-пуш. Когда владелец посчитает, что все замечания учтены и код готов к слиянию, он сможет выбрать как имено это сделать - сквошить ли все в один коммит или оставить все ваши коммиты как есть.
по моему такdlinyj Автор
07.11.2022 17:43Если ветка в едином репозитории, то да. Тут залив происходит из одной репы в другую.
SuperFly
07.11.2022 18:11+2Не возьмусь утверждать что это сейчас именно так, но насколько я помню, там что с форка, что с другой ветки - работает одинаково.
последние несколько лет, работал с единым репозиторием. до этого год через форк.
(А несколько месяцев назад сменил работу и тут гитлаб. Так вот у меня перманентная фрустрация: какого хера и для кого это сделано вообще? это как комент к вашему "gitlab, он сделан людьми для людей", так что дело привычки, надеюсь и я в какой-то момент привыкну к гитлабу)
Mingun
07.11.2022 18:02+4А зачем вы сами делаете мердж? Это обязанность того, кто принимать будет, а не ваша
Mingun
07.11.2022 18:00-1Есть конечно
- простой мердж, со своим сообщением
- squash всего, объединение всех сообщений коммитов в список
- ребейз поверх цели и встраивание коммитов без мерджа (fast-forward)
- обязательный мердж (даже когда можно сделать fast-forward)
Mingun
07.11.2022 17:53+2Если в настройках сменить кодировку на CP866 (в моём случае это кириллица),
Эм… а что, есть другие варианты?
У такого подхода есть недостаток, что стираются замечания, которые владелец вам оставил (это особенность github, у нормального gitlab таких проблем нет), так что рекомендую сохранять все замечания до финального коммита.
Вы из какого века пишете? Ничего не стирается, на GitHub-е уже лет 5 как все ваши force-push-и ничего не забывают и даже кнопочка рядом с каждым есть, чтобы посмотреть различия force-push-нутого от того, что было раньше (любуйтесь: https://github.com/pegjs/pegjs/pull/399). Может только если вы зайдете в репозиторий и принудительно запустите в нем
git gc
, ну так кто ж в этом виноват...И что сложного в создании PR? После пуша там висит уведомление о том, что вы только что ветку протолкнули, хотите сделать PR? Не заметить просто нереально. Не говоря уж о том, что при пуше новой ветки git возвращает сообщение с url-ом для создания PR, только кликай и все (может в консольном и нет такого, никогда не пробовал, но что-то я сомневаюсь, что это самодеятельность TortoiseGit)
Так что нечего дурить молодежи головуПравка чужого кода – это лучший способ научиться программировать.
А вот это действительно очень и очень ценная мысль.
m_shamhalov
08.11.2022 11:39+1Скачал и запустил ваш исправленный бинарник и запустил во FreeDOS.
dlinyj Автор
08.11.2022 11:52+1Спасибо за замечание, лучше было в личном сообщении. Пожалуйста проверьте ещё раз, должно всё работать. Заменил на рабочий.
BubaVV
08.11.2022 19:27+1А вот вопрос из практики, пока нерешенный. Есть проект А, и его форк Б. Владелец Б делает пулл-реквест в А, который фиксит багу, которая лично мне очень мешает. Автор А этот пулл-реквест не принимает, а автор Б уходит в закат и не ребейзит его на свежий мастер А. Ребейз там несложный, но автоматом не поребейзит - А развивается довольно динамично. Я сдуру форкнул Б и поправил ПР, но теперь могу его отправить только в Б, а там никакой активности. Форкнуть А теперь не дает гитхаб, говорит уже есть форк.
Внимание, вопрос: как мне нормально закоммитить рабочий ПР, желательно не снося свой форк репы? Ну и чтобы не обидеть автора Б, который собственно основной автор патча?
dlinyj Автор
09.11.2022 12:10Весь вечер думал над вашим вопросом, элегантного решения нет. Я бы сделал так, сделал форк от действющего A, сделал бы ребейз вашего форка от Б и смерджил его туда, а потом бы уже этот форк добавил бы в А. Но если у вас будет скваш коммитов, то работа того товарища потеряется.
Mingun
09.11.2022 17:42Я бы сделал так, сделал форк от действющего A
Сказано же, что GitHub не даёт сделать форк, потому что уже есть форк от форка:
Форкнуть А теперь не дает гитхаб, говорит уже есть форк.
dlinyj Автор
09.11.2022 19:17Ну в локальной репе-то можно делать всё что душе угодно, а там отребейзить всё локально и сделать всё по уму.
Mingun
09.11.2022 12:52+1Я вижу 2 варианта:
- Можете написать в поддержку GitHub-а, чтобы ваш форк сделали самостоятельным репозиторием. Затем форкните заново
- Можете слить себе все нужные ветки локально, удалить свой форк на гитхабе, сделать новый форк от правильного репозитория
В конце обоих вариантов проталкиваете изменения из вашей локальной копии в новый форк. Авторство коммитов сохранится.
sfrolov
Да, рекомендую тот ретрочатик
dlinyj Автор
Продублирую ссылку, чтобы в тексте не искать. Тоже рекомендую, тепло и лампово.