Готова KolBB v0.02. Ссылка на скачку в начале ветки.

Придумал интересный механизм для строковых полей объектов KolBB. В Delphi-версии KOL активно используются динамические строки (одна из причин почему KOL нельзя собрать в DLL и сделать обёртку), Оберон-2 и КП предлагают для хранения строковых полей неизвестной длины стандартный для них механизм динамической памяти и сборку мусора, поэтому хранить строки неизвестной длины в объектах можно только в виде указателей. Очень жаль, что при экспорте таких строк только для чтения остаётся возможность менять сами строки, нельзя менять лишь значение указателей. Естественно, можно не экспортировать такие поля напрямую, а обернуть возврат их значения в функцию, но это уже утяжеляет, хотя для критичных случаев придётся применять. Это делает KolBB ещё более отличным от Delphi-версии. Итак, для упрощения присвоения строковых полей-указателей на строки неизвестной длины я разработал процедуру KolStrings.Assign, которая следит, чтобы указатель не был NIL, при необходимости резервируя память. Если память уже выделена и места под размещение значения строки достаточно, она присваивается; если недостаточно, то происходит перевыделение памяти для размещения строки полностью. Это удобно, поскольку большая часть моих ошибок при работе на Оберонах связана с невыделением памяти и работой с памятью по NIL-указателям. Мне не нравится в механизме Assign только характерный для Си способ определения длины NULL-terminated строки путём постоянного подсчёта символов до '\0'. Традиционная и более эффективная Паскаль-модель работает с хранимой в отдельном поле реализации строковой пременной длины строки, что достижимо и в Оберонах, но требуется усложнить код введением нового типа-записи, реализующего работу с динамическими строками, что видится мне пока что неоправданным ввиду необходимости использования более усложнённых синтаксически конструкций [Вместо IF KolFn()^ = str2^ ... что-то вроде IF KolFn().GetStrVal()^ = str2.GetStrVal()^ ...]. Но это к вопросу об эффективной реализации на Оберон-языках динамических строк. Пока оставим это на будущее, недостаточно эффективную реализацию всегда можно усовершенствовать. Сейчас же пусть Assign выполняет свою главную роль: безопасного присвоения строковых значений полям объектов без боязни NIL-указателя и без боязни, что строка не поместится и будет обрезана.

Как отличается работа с KOL-Delphi от KolBB и как вообще выглядит программа на KolBB:
## Код:
```
MODULE KolIniFilesTest;

(*
Приведу небольшой пример того, как возможно одним и тем же кодом обеспечить и запись, и сохранение настроек. Пусть, например, мы хотим сохранять по завершении работы координаты окна приложения в файле настроек, а в начале работы восстанавливать их оттуда. Создадим метод, который будет выполнять обе эти операции:

procedure MyObj.ReadWriteIni( write: boolean );
var ini: PIniFile;
begin
  ini := OpenIniFile( GetStartDir + 'my.ini' );
  if write then ini.Mode := ifmWrite;
  ini.Section = 'position';
  form.Left := ini.ValueInteger( 'Left', form.Left );
  form.Top := ini.ValueInteger( 'Top', form.Top );
  ini.Free;
end;

Теперь, при запуске приложения организуем вызов этого метода с параметром false, а при закрытии - с параметром true. Предоставляю вам самим разобраться, почему этот код будет делать все, что от него требуется, хотя работают одни и те же операторы в обоих случаях.
*)

IMPORT
   IO := KolIO, Typ := KolTypes, Str := KolStrings,
   Files := KolFiles, Ini := KolIniFiles;

VAR
   formLeft, formTop: INTEGER;
   pi: REAL; path: POINTER TO Typ.KOLString;
   ch: CHAR;

PROCEDURE ReadWriteIni (mode: Ini.TIniFileMode);
VAR
   ini: Ini.PIniFile;
BEGIN
   ini := Ini.OpenIniFile(Files.GetStartDir() + 'my.ini');
   ini.mode := mode;
   Str.Assign(ini.section, 'Position');
   formLeft := ini.ValueInteger( 'Left', formLeft );
   formTop := ini.ValueInteger( 'Top', formTop );
   Str.Assign(ini.section, 'Misc');
   pi := ini.ValueDouble( 'Pi', pi );
   path := ini.ValueString( 'Path', path );
   (*ini.Free;*) ini.Destroy
END ReadWriteIni;

BEGIN
   IO.WriteLn("Hello World from KolBB!");
   IO.WriteLn("Sozdaem " + Files.GetStartDir() + "my.ini ...");
   formLeft := 123; formTop := 765;
   pi := 3.141592653589793;
   Str.Assign(path, Files.GetStartDir());
   ReadWriteIni(Ini.IfmWrite);
   IO.WriteLn("Gotovo. Chitaem iz my.ini ..."); IO.Ln;
   formLeft := 0; formTop := 0;
   pi := 0.0; Str.Assign(path, "");
   ReadWriteIni(Ini.IfmRead);
   IO.Write("formLeft = "); IO.WriteInt(formLeft);
   IO.Write(", formTop = "); IO.WriteInt(formTop); IO.Ln;
   IO.Write("pi = "); IO.Write(Typ.Double2Str(pi)); IO.Ln;
   IO.Write("path = "); IO.WriteLn(path); IO.Ln;
   ch := IO.ReadChar()
END KolIniFilesTest.

Generate independent Win32 console application w/o icon:
DevLinker.LinkExe dos KolIniFilesTest.exe := Kernel+
KolTypes KolStrings KolObjects KolIO KolFiles KolIniFiles KolIniFilesTest$ ~
```
