Turbo-Pascal 5.5 (и другие) в браузере — с загрузкой программ по ссылке
«Эх вот в школе я такую программулину написал, на Паскале» — бывают такие мысли, особенно у тех кто учился, скажем, в 90е. И даже находятся порой эти старые программы на старом диске. Но если запустить их ещё в DosBox у себя на машине можно — то как показать-похвастаться другим, в интернете?
Возьмём эмулятор js-dos (им старые игры в браузере запускают) — и поколдуем над ним, чтобы можно было своими паскальными-бейсиковыми программулинами делиться всем на радость.
Пользоваться этой поделкой вы сможете не вникая в подробности! Есть страничка для подготовки ссылок с программами — хоть сразу делитесь в комментариях :) А для тех кому захочется по аналогии и другие компиляторы-интерпретаторы подключить — будет немножко пояснений что и как там сделано — чтобы форкнув код на гитхабе вы могли быстро внести нужные изменения.
Как этим пользоваться?
Нам нужна страничка в которой выполняется, например, старый добрый Quick Basic 1.1 или Turbo Pascal 5.5 (до кучи я добавил Matlab 3.05) — притом такая, чтобы ей можно было каким-то образом передать программу для загрузки и выполнения.
А как именно «передать»? Мы же по ссылке делиться будем — ну значит в параметре ссылки передавать либо целиком программу (если она небольшая) — либо урл откуда её можно взять (главное чтобы cross-origin работал).
Если хотите сразу посмотреть на результат, то вот пожалуйста:
Игра «Escape» по мотивам Ж.Арсака
В открывшемся окне вы увидите довольно знакомый интерфейс редактора Турбо-Паскаля — нажмите Ctrl-F9
(как встарь) или Alt-R
и Enter
— и программа должна запуститься. Есть и возможность автозапуска — дальше увидим.
Зелёное — выход. Синее — игрок. Красно-жёлтое — падающие фрагменты.
В этой игре нужно (в пошаговом режиме) пробраться через прямоугольный зал к выходу (в левом верхнем углу) — стараясь не попасть под падающие сверху блоки. Поскольку падают они рандомно, особой стратегии тут нет. Главное долго не плутать.
Если хотите попробовать «приготовить» ссылку с собственным кодом — зайдите на центральную страничку https://rodiongork.github.io/dosprog/ — внизу есть поле для ввода программы — скопируйте туда например следующую чепуху (отредактируйте по вкусу):
program demo;
uses crt;
begin
clrscr;
gotoxy(33, 13);
writeln('I am a beautiful message!');
readln;
end.
После чего убедитесь что выбран нужный язык (паскаль в данном случае) и нажмите кнопку. Под ней появится ссылка — по этой ссылке будет открываться ваша программа, можете попробовать. Если щёлкнете чекбокс «Autorun» — программа не откроется в редакторе, а сразу запустится на выполнение.
Поскольку программа может быть длинной, можно также разместить код программы где-нибудь в интернете (например на github pages как с примером выше) — и вместо самого кода использовать ссылку на него. Кроме возможности таким образом сделать большую программу с довольно короткой ссылкой это ещё и позволит редактировать впоследствии код не меняя самой ссылки.
Теперь когда в общих чертах понятно — давайте посмотрим подробности — они понадобятся если вы захотите аналогичным образом какую-то другую среду разработки запустить.
Создадим страницу с компилятором / интерпретатором
Эта часть очень простая. На сайте js-dos.com мы находим раздел Getting Started — и в нём готовый пример. В двух словах идея такая:
js-dos в себе содержит эмулятор (DoxBox) скомпилированный в JavaScript
поэтому на странице вы только создаёте зону где отображать «экран» (например, во всю страницу) и вставляете ссылки на таблицу стилей и на js-файл. Их можно либо использовать либо прямо с сайта js-dos (как в примере), либо скачать себе.
создаёте «бандл» с приложением — в общем-то zip-архив, в котором лежит кроме того и конфиг для DosBox
Первые два пункта развернутых пояснений не требуют, на третий взглянем чуть подробнее.
Во-первых, как «приготовить» бандл? Если у вас уже есть zip-архив с нужной досовской программой — останется только добавить конфиг.
Если архива пока нет, удобнее всего (по-моему) DosBox запустить на локальной машине, в него скачать все что надо, установить-настроить нужную программулину -, а потом её уже сархивировать в бандл. И опять же добавить конфиг.
Что там за конфиг? Обычный конфиг для DosBox — для начала можно взять тот что в примере (с диггером). В целом всевозможные настройки понятно описаны — самая важная для нас часть — в конце. Там перечислены несколько команд (на манер autoexec
) для того чтобы загрузить нужную нам программу после старта.
Конфиг укладывается в подкаталог .jsdos
с именем dosbox.conf
— типичное его окончание может выглядеть так:
[autoexec]
mount c .
c:
c:\tp\turbo.exe
Сам код для запуска бандла в странице выглядит тоже достаточно понятно — имеет смысл только добавить параметр автозапуска (иначе отображается шестерёнка которую нужно кликнуть чтобы DosBox запустился):
Dos(document.getElementById("dos"), {
url: "./my_bundle.zip",
autoStart: true,
});
Подразумевая что бандл с именем my_bundle.zip
лежит в той же директории что и сама страница — и что элемент для отображения рабочего окна программы имеет id="dos"
.
Если вы это проделаете — и запустите хотя бы локально (нужно использовать хоть простейший локальный сервер, типа busybox — или python3 -m http.server
) — то скорее всего с радостью убедитесь что программа запускается (ну, если все сделано правильно). И выдаёт картинку, например как в заголовке статьи. Или вот с матлабом вариант:
в матлабе всё работает только графика в досбоксе почему-то плохо отображается
Но как подгрузить текст программы?
Вот здесь и начинаются пляски с бубном.
То что код программы мы в простейшем случае кодируем в base64
и добавляем к ссылке как значение параметра ?p=...
— это уже наверное понятно. Написать кусочек javascript чтобы взять урл текущей страницы и вытащить оттуда этот код — несложно:
let ppos = location.href.indexOf('?p=');
let data = atob(location.href.substring(ppos+3));
Это конечно упрощённый способ — мы не парсим параметры всерьёз, а просто находим нужный фрагмент с названием параметра (p), считая что параметр только один. Если вам понадобится больше — поправьте эту часть. После этого atob
расшифровывает base64
кодировку — и в общем текст нашей программы в переменной data
.
Здесь сразу добавим возможность вытащить программу из интернета, если вместо неё оказался урл:
if (data.substring(0, 5) == 'https') {
let req = new XMLHttpRequest();
req.open('GET', data, false);
req.send(null);
data = (req.status === 200) ? req.responseText : '{error loading file}';
}
Здесь мы используем синхронный XMLHttpRequest
— это не лучший вариант, но для минимизации примера пусть так останется. Как видите, в случае ошибки мы вместо результата запроса хотим показать что сообщение о неуспешной загрузке.
Важный момент — конечно сервер с которого вы грузите программу должен отдавать её с соответствующим заголовком, позволяющим загрузку в другие страницы, например: Access-Control-Allow-Origin: *
В частности github-pages
так делают, а gist.github.com
нет. Если вы захотите подгружать код с гист-гитхаб или с pastebin — скорее всего вам придётся что-то химичить.
Но это лишь пол-дела, даже наверное треть. Надо загрузить программу в наш DosBox.
Тут проблема. Конфигурация js-dos
(в джаваскрипте, не в конфиге dosbox-а) позволяет указать например параметр initFs
и dosboxConf
— первый из них позволяет добавить файлы в файловую систему, второй помогает скорректировать например строку запуска нашей программы. К сожалению оба они не работают если используется «бандл».
На эту тему даже заведён issue в гитхабе js-dos-а. Там есть мелкие технические сложности, но возможно когда-то это будет улучшено. Пока же приходится мудрить.
В параметре onEvent
можно указать функцию которая будет вызвана когда эмулятор уже загружен и в неё будет передан параметр — объект CommandInterface
— у него в частности есть методы для работы с файловой системой.
К сожалению когда эмулятор уже загружен, вроде бы уже поздно что-то грузить в файловую систему :) Во-первых наша «IDE» уже будет запущена — да и DosBox не видит новых файлов пока не выполнишь команду rescan
. Однако давайте есть слона по частям. Здесь оставим кусочек джаваскриптового кода который «забросит» нашу программу в файловую систему -, а в следующем разделе разберемся как её использовать.
Dos(document.getElementById("dos"), {
url: "./my_bundle.zip",
autoStart: true,
onEvent: (event, ci) => {
if (event === "ci-ready") {
// здесь подготовим переменную "data" как показано выше
// и теперь грузим:
ci.fsWriteFile(dosprog.fname, new TextEncoder().encode(data));
}
}
});
BAT-файл для подгрузки программы
Итак, забросить файл в файловую систему эмулятора мы смогли, однако:
он её не видит пока не сделаем
rescan
поскольку всё работает асинхронно, в эмуляторе редактор может запуститься раньше чем программа будет загружена
Чтобы не дожидаться пока какую-то фичу для этого запилят в js-dos
(а может и есть какой-то ход до которого я не додумался) — можно просто написать старый-добрый досовский BAT-файл (аналог юниксовых shell
-скриптов, только проще).
Мы будем запускать этот файл из autoexec-секции в конце dosbox.conf -, а что же будет в самом файле?
Будем делать rescan
, проверять, появилась ли программа на диске, и если появилась то запускаем IDE -, а иначе повторяем операцию в цикле.
Один нюанс — нам нужна и возможность загружаться «начисто» — если никакой программы не передано. Ну что ж, будем в этом случае сигнализировать «добрасывая» в файловую систему пустой файл с именем, например, nofile.pas
— в общем, BAT-файл получится такой:
:repeat
rescan
if exist prg.pas goto withfile
if exist nofile.pas goto nofile
goto repeat
:withfile
\tp\turbo.exe prg.pas
goto done
:nofile
\tp\turbo.exe
:done
Как видите, циклы, goto и переходы по меткам — логика простая. Если появился файл prg.pas
— выскакиваем из цикла и переходим к запуску с файлом. Если появился файл nofile.pas
— тоже выскакиваем и переходим к запуску без файла.
В javascript есть отдельная строчка чтобы этот nofile
передать -, но не будем на этом сейчас останавливаться, просто посмотрите в коде по необходимости.
Автозапуск
В качестве приятной фичи желательно добавить возможность автозапуска. В случае с бейсиком это осуществляется добавлением ключа /run
в командную строку. С турбо-паскалём я такого ключа не припомню, поэтому надо запустить компилятор tp.exe
, а потом запустить скомпилированную программу. В случае матлаба файл и так запускается интерпретатором (отдельный вопрос — может это неудобно).
В общем всё это легко добавить в BAT-файл. Осталось только придумать как передать что мы хотим «автозапустить» программу. Я не придумал ничего лучше кроме как использовать ещё одно отдельное имя файла программы (например auto.pas
) и по нему выбирать какой именно режим запуска требуется.
Ну, а чтобы на стороне джаваскрипта выбрать нужен ли автозапуск, условимся что это сигнализируется именем параметра в ссылке. Если это буква P
большая — значит нужен. Если p
маленькая — значит нет. Конечно это вы можете переделать на свой вкус.
На упомянутой «главной» страничке форма для создания ссылок имеет чекбокс чтобы отметить автозапуск.
Заключение
Код выложен на гитхаб — можно пользоваться как есть, можно склонировать себе и добавить любимые компиляторы и т.п.
Для удобства общий джаваскриптовый код отвечающий за запуск вынесен в файл dosprog.js
— так что если захотите добавить например Turbo C 2.0
, то вам нужны следующие шаги:
форкаем или клонируем репозиторий
копируем файл
tp55.html
например вtc20.html
— и в нём редактируем заголовок, названия файлов (вместоprg.pas
напримерprg.c
и так далее) -, а также имя бандласоздаём бандл с таким именем как задали выше, в него положим кроме Turbo C также поправленный конфиг dosbox.conf и модифицированный BAT-файл (в общем-то тоже меняются имена файлов и все).
Можно было бы сделать удобнее если использовать серверную часть для хранения пользовательских программ (собственный «pastebin»), сделать пользовательские аккаунты и так далее. Но неясно насколько эта смешная поделка актуальна — кроме того тогда уже не будет так легко добавить собственные компиляторы и т.п.
Хорошо бы иметь возможность экспортировать отредактированный файл. Ведь из досбокса с экрана ничего не скопируешь. Такая возможность добавлена — если открыть консоль разработчика (Developer Console) в браузере и выполнить во вкладке console функцию в духе:
getFile("PRG.PAS")
то в консоль же будет выдана наша программа, уже закодированная в base64. Можно было бы сделать какой-то всплывающий диалог -, но пока не придумал куда прилепить кнопку для его вызова. Главное — заметьте что здесь регистр имени файла различается -, а в досе нет. Чаще всего файлы будут созданы с большими буквами в имени.
Переводы строк. Это больная тема — по умолчанию нередко может оказаться что они не «досовские» — и приложения типа турбо-паскаля отобразят все в одну строку. Для этого в код загрузки добавлена небольшая «автоподстановка»:
data = data.replace(/(?
Не пугайтесь её -, но если будут какие-то проблемы с переводами строк — вы теперь знаете где можно поправить.
Вот и всё! Можете пробовать и делиться своими историческими чудо-программами в комментариях :)
P.S. данную статью не следует рассматривать как руководство по JavaScript — автор мало знаком с ним и с фронтенд-разработкой — так что тут наверняка есть что улучшать!