На мой предыдущий вопрос ответа нет (или никто ничего не знает). Зайду к моей проблемке с другой стороны. Нигде не нашел информации об использовании ncurses в паскале. Есть малость для Си. Но это для меня сложно. Есть ли где-то какая-нибудь информация именно для паскаля?
Я престарелый гуманитарий. Изучением Паскаля я занялся, потому что так захотелось. Пытался Си, но не идет. Какой-то он бардачный, сумбурный и корявый. А Паскаль в отличие от Си более стройный, логичный и понятный.
Изучаю самостоятельно, продираясь через откровенную макулатуру и выискивая ценную информацию. Спасают, в основном, форумы. Этот сайт, в частности, очень помогает. Правда информация не редко подается слишком сжато. Хотелось бы некой разжеванности. В интернете полезной информации практически не найти. Поиск выдает совершенно не нужную/неверную информацию (коммерция, что поделаешь). И эта тенденция растет год от года. Жаль.
По теме. О ncurses есть, например, очень не плохой сайт. Но сугубо для Си. Что-то пытался, но ступорится уже на подключении модуля. Сам ncurses установлен.
Надо понимать, что там за кулисами, и 1:1 переписывать. Машинный фундамент у Паскаля и Си общий.
Цитата
Что-то пытался, но ступорится уже на подключении модуля.
А что значит, подключение модуля? В моей практике, если модуля привязок хорошего, как нужно мне, нет, то его нужно писать. А писать все привязки обычно лень, хотя, конечно, автоматические генераторы серьёзно упрощают жизнь. Но написать привязки для пары-тройки функций вообще не проблема.
По ссылке я увидел:
main(int argc,char *argv[])
{
// инициализация (должна быть выполнена
// перед использованием ncurses)
initscr();
// перемещение курсора в стандартном экране y=10 x=30
move(10,30);
printw("Hello world !!!"); // вывод строки
refresh(); // обновить
getch(); // ждём нажатия символа
endwin(); // завершение работы с ncurses
}
Здесь используются функции initscr, move, printw, refresh, getch, endwin.
NCURSES_EXPORT — судя по названию, это макрос, который навешивает компилятороспецифичные атрибуты, а также они зависят от того, компилируется ли ncurses DLL или какой-то другой код, который от DLL зависит. Внутри этого макроса некий «WINDOW *», то есть, указатель на что-то. В примере на Си, как видно, результат отбрасывается, так что и WINDOW * полноценно можно не переносить. Впрочем, может, и не нужно переносить. Вот в Win32API все структуры достаточно стабильны, и если переписать их с Си на Делфи или Аду, то они сохраняют актуальность, а вот другие програиисты на Си такой дисциплиной не отличаются, и у них и размер, и прочее может без предупреждения меняться.
Короче, пишем:
const
Ncurses = 'ncurses.so';
type
PCursesWindow = Pointer;
function initscr: PCursesWindow; cdecl; external Ncurses name'initscr';
Идём дальше.
#define move(y,x) wmove(stdscr,(y),(x))
Макрос. Ясно. Значит, на самом деле нужен wmove. Ищем wmove.
Блин, тяжёлый случай. Я вот вижу этот код первый раз и без понятия, объявлен ли NCURSES_REENTRANT. Лучше бы ему быть объявленным, потому что Паскаль умеет импортировать только процедуры и функции. Переменные и константы умеет экспортировать, но не импортировать. В Win32 API такой фигни нет. Лишний повод понять, до чего же хорошо в Microsoft пишут на Си, кое-кому бы поучиться.
Понадеемся, что объявлен.
Тогда:
function stdscr: PCursesWindow; cdecl; external Ncurses name'stdscr';
Теперь возвращаемся к макросу:
function move(y, x: Integer): Integer; inline;
begin
Result := wmove(stdscr, y, x);
end;
Какие же козлы. Ну как им объяснить, что нельзя использовать varargs. В хороших языках программирования именно ради безопасности его нет, но вдруг приходится обращаться к библиотеке на Си, и тут же там какой-то козёл написал varargs. Вот в Win32 API такого почти не бывает. Я только одну функцию навскидку знаю. До чего же хорош Microsoft.
В языке Ада их нормально ни вызвать, ни реализовать. В Delphi можно вызвать, но нельзя реализовать. В FPC, наверное, тоже.
Так как в Паскале вызвать можно (синтаксис будет cdecl; varargs;), я подумал, может, так и сделать. Но потом решил сделать как надо. А будет лучше заменить printw на addstr, а форматирование, если хочется, через SysUtils.Format всегда доступно.
function addstr(const str: PAnsiChar): Integer; inline;
begin
Result := waddnstr(stdscr, str, -1);
end;
Попутно я понял, зачем тут n и -1. Это же длина в байтах. Но это небезопасно, и мы же не хотим, чтоб процессор лишний раз бегал по строке, ведь у нас полноценный язык программирования, способный на такой подвиг, как запомнить длину строки. Значит, лучше будет
#define addnstr(str,n) waddnstr(stdscr,(str),(n))
function addnstr(const str: PAnsiChar; n: Integer): Integer; inline;
begin
Result := waddnstr(stdscr, str, n);
end;
function wrefresh(win: PCursesWindow): Integer; cdecl; external Ncurses name 'wrefresh';
function refresh: Integer; inline;
begin
Result := wrefresh(stdscr);
end;
function endwin: Integer; external Ncurses name'endwin';
Всё вместе:
const
Ncurses = 'ncurses.so';
type
PCursesWindow = Pointer;
function initscr: PCursesWindow; cdecl; external Ncurses name'initscr';
function stdscr: PCursesWindow; cdecl; external Ncurses name'stdscr';
function wmove(win: PCursesWindow; y, x: Integer): Integer; cdecl; external Ncurses name'wmove';
function move(y, x: Integer): Integer; inline;
begin
Result := wmove(stdscr, y, x);
end;
function waddnstr(win: PCursesWindow; const astr: PAnsiChar; n: Integer): Integer; cdecl; external Ncurses name'waddnstr';
function addnstr(const str: PAnsiChar; n: Integer): Integer; inline;
begin
Result := waddnstr(stdscr, str, n);
end;
function wrefresh(win: PCursesWindow): Integer; cdecl; external Ncurses name'wrefresh';
function refresh: Integer; inline;
begin
Result := wrefresh(stdscr);
end;
function wgetch: Integer; cdecl; external Ncurses name'wgetch';
function getch: Integer; inline;
begin
Result := wgetch(stdscr);
end;
function endwin: Integer; external Ncurses name'endwin';
// выше была копия
// ниже вспомогательный код и переписанный пример
function addustr(const Str: UTF8String): Integer;
begin
Result := addnstr(PAnsiChar(Str), Length(Str));
end;
begin// инициализация (должна быть выполнена
// перед использованием ncurses)
initscr;
// перемещение курсора в стандартном экране y=10 x=30
move(10, 30);
addustr('Hello world !!!'); // вывод строки
refresh; // обновить
getch; // ждём нажатия символа
endwin; // завершение работы с ncurses
end.
Скорее всего, это не заработает с первого раза. Я никогда не писал на Паскале под Linux. Но по ошибкам компиляции, думаю, смогу починить.
Добавлено через 17 мин. Я сейчас прочитал, что ncursesw нужно подключать, а не ncurses.
const
Ncurses = 'ncursesw.so';
--------------------
If you want to get to the top, you have to start at the bottom