View Issue Details

IDProjectCategoryView StatusLast Update
0032558FPCRTLpublic2017-12-14 15:20
ReporterJames RichtersAssigned ToTomas Hajny 
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
PlatformWindowsOSWindowsOS Version10
Product Version3.0.2Product Build3.0.4rc1 - option not above 
Target Version3.2.0Fixed in Version3.1.1 
Summary0032558: CRT unit is not displaying characters correctly
DescriptionThe CRT unit changes how characters are displayed on the console in windows. It is not consistent with MAC or Linux versions of CRT that display Unicode correctly nor is it consistent with the way Turbo Pascal 7.0 displays characters, and it is also not consistent with the way a console program displays without the CRT Unit.
It is actually impossible to display ANY of the box drawing characters, either with extended ASCII codes (0000179 to 0000218) or Unicode (0009472 - 0009599), while using the CRT unit. These box characters are way more important than all the various ways of putting accents over and around characters, especially if the character set is not represented in its entirety, because the box characters allow you to output very nicely professional tables and such, but the accented characters are of no use unless the character set is complete and you can use ALL the exact accents you would need.

It should display either the entire extended ASCII or the entire Unicode character sets on a standard windows console screen without any modifications to the console window, and it should do so by default without any additional setting required.

Since displaying only the first 256 characters of Unicode is worthless, if there is a limitation of 256 characters, then the Extended ASCII character set should be used and mapped to properly display the Extended Ascii characters, with the default Consolas font. since this is a complete character set and is compatible with Borland Pascal 7 which the CRT unit is supposed to be compatible with.
Steps To ReproduceRun the sample programs provided with CRT and without CRT and with FPC for Windows, Mac and Linux, and Turbo Pascal V7 to observe the differences in the way characters are displayed.

5 Sample programs are included.
1. Ascii box.pas Original ASCII box drawing program from Borland Pascal V7
2. Asciibox2.pas Simpler test program that just does a bunch of Writeln's run with UNIT CRT; and with Unit CRT; commented out and compare the results;
3. ASCII box3.pas Same Asciibox2 but it uses the Unicode versions of the box characters, again run with and without UNIT CRT; to see the differences
4. ASCII Box4 same as Asciibox3, but the Unicode character numbers are used instead of the actual characters
5. ASCII Box5 is the same as Ascii box 4 but with the original Extended ASCII codes instead.

The results are all posted in screenshot compilations showing results in Lazarus, Free Pascal Text IDE, and Turbo Pascal V7.0 here:
http://www.productionautomation.net/FPC/ASCII/




Additional InformationSee the page I created about this here:
http://www.productionautomation.net/FPC/ASCII/

The above page includes sample programs, and screenshots of the results running these programs with Lazarus, FreePascal Text IDE, and Turbo Pascal 7 for comparison.

I have done extensive tests and provided screenshots to show that the CRT unit is not consistent with anything at all. In my opinion, since the CRT unit itself states:
"Borland Pascal 7 Compatible CRT Unit - win32 implentation" <-- (note typo in Implementation)

It should produce truly compatible results on a windows system, that means accepting the Extended ASCII character set from 0 to 255 and translating the characters as needed so they show up as the correct symbols on a standard windows console, with the default Consolas Font.

If it's decided that it should directly display Unicode instead, Then it should accept and properly display the entire Unicode character set, which it currently does not do. displaying the first 256 characters of a character set that contains thousands of characters is of no use to anyone. If Unicode was used there should be a TP7 compatibility mode it could be used in that would make it compatible as intended, and this should be the default setting because the purpose of the unit is TP7 compatibility

TagsNo tags attached.
Fixed in Revision37674
FPCOldBugId
FPCTarget
Attached Files
  • Free Pascal CRT Information.zip (2,177 bytes)
  • fixed.JPG (259,423 bytes)
    fixed.JPG (259,423 bytes)
  • CRT.diff (5,500 bytes)
    ��diff --git a/packages/rtl-console/src/win/crt.pp b/packages/rtl-console/src/win/crt.pp
    
    index 3a0668138d..d1df084ec8 100644
    
    --- a/packages/rtl-console/src/win/crt.pp
    
    +++ b/packages/rtl-console/src/win/crt.pp
    
    @@ -18,6 +18,7 @@ interface
    
     
    
     {$i crth.inc}
    
     
    
    +Procedure CrtCodePage (CCP:integer);
    
     procedure Window32(X1,Y1,X2,Y2: DWord);
    
     procedure GotoXY32(X,Y: DWord);
    
     function WhereX32: DWord;
    
    @@ -34,6 +35,7 @@ uses
    
     var
    
         SaveCursorSize: Longint;
    
         Win32Platform : Longint; // pulling in sysutils changes exception behaviour
    
    +    OldConsoleOutputCP : Word;
    
     
    
     {****************************************************************************
    
                                Low level Routines
    
    @@ -95,6 +97,17 @@ end;
    
     ****************************************************************************}
    
     
    
     
    
    +Procedure CrtCodePage (CCP:integer);
    
    +Begin
    
    +  If CCP = 0 then
    
    +      SetConsoleOutputCP(GetACP)
    
    +  ELSE
    
    +    If CCP = -1 Then
    
    +      SetConsoleOutputCP(OldConsoleOutputCP)
    
    +    ELSE
    
    +      SetConsoleOutputCP(CCP);
    
    +End;
    
    +
    
     procedure TextMode (Mode: word);
    
     begin
    
     end;
    
    @@ -751,10 +764,10 @@ Procedure CrtWrite(var f : textrec);
    
     var
    
       i : longint;
    
       s : string;
    
    -  OldConsoleOutputCP : Word;
    
    +  //OldConsoleOutputCP : Word;
    
     begin
    
    -  OldConsoleOutputCP:=GetConsoleOutputCP;
    
    -  SetConsoleOutputCP(GetACP);
    
    +  //OldConsoleOutputCP:=GetConsoleOutputCP;
    
    +  //SetConsoleOutputCP(GetACP);
    
     
    
       GetScreenCursor(CurrX, CurrY);
    
       s:='';
    
    @@ -781,7 +794,7 @@ begin
    
         WriteStr(s);
    
       SetScreenCursor(CurrX, CurrY);
    
     
    
    -  SetConsoleOutputCP(OldConsoleOutputCP);
    
    +  //SetConsoleOutputCP(OldConsoleOutputCP);
    
     
    
       f.bufpos:=0;
    
     end;
    
    @@ -801,10 +814,10 @@ Procedure CrtRead(Var F: TextRec);
    
     
    
     var
    
       ch : Char;
    
    -  OldConsoleOutputCP : Word;
    
    +  //OldConsoleOutputCP : Word;
    
     Begin
    
    -  OldConsoleOutputCP:=GetConsoleOutputCP;
    
    -  SetConsoleOutputCP(GetACP);
    
    +  //OldConsoleOutputCP:=GetConsoleOutputCP;
    
    +  //SetConsoleOutputCP(GetACP);
    
     
    
       GetScreenCursor(CurrX,CurrY);
    
       f.bufpos:=0;
    
    @@ -883,7 +896,7 @@ Begin
    
           end;
    
       until false;
    
     
    
    -  SetConsoleOutputCP(OldConsoleOutputCP);
    
    +  //SetConsoleOutputCP(OldConsoleOutputCP);
    
     	
    
       f.bufpos:=0;
    
       SetScreenCursor(CurrX, CurrY);
    
    @@ -1023,6 +1036,9 @@ Initialization
    
       if PrevCtrlBreakHandler = TCtrlBreakHandler (pointer (-1)) then
    
        PrevCtrlBreakHandler := nil;
    
       CheckBreak := true;
    
    +  OldConsoleOutputCP:=GetConsoleOutputCP;
    
    +  CrtCodePage(0);
    
    +
    
     
    
     finalization
    
       if beeperDevice <> INVALID_HANDLE_VALUE then begin
    
    @@ -1030,4 +1046,5 @@ finalization
    
         CloseHandle(beeperDevice);
    
         DefineDosDevice(DDD_REMOVE_DEFINITION,'DosBeep','\Device\Beep');
    
       end;
    
    +  CrtCodePage(-1);
    
     end. { unit Crt }
    
    
    CRT.diff (5,500 bytes)
  • TestCrtCodePage.pas (2,309 bytes)
    Program CRTTEST;
    Uses CRT, windows;
    Var i: Byte;
    Begin
    Writeln('Code Page after Initialization: ',GetConsoleOutputCP);
    textcolor(2);
    For I:=33 to 255 do
    Write(Chr(i),' ');
    Writeln;
    Readkey;
    CrtCodePage(437); //set to Code Page 437
    textcolor(3);
    Writeln('Code Page 437: ',GetConsoleOutputCP);
    For I:=33 to 255 do
    Write(Chr(i),' ');
    Writeln;
    Readkey;
    CrtCodePage(0);   //set to system Code Page reported by GetACP
    textcolor(4);
    Writeln('Code Page from GetACP ',GetACP,':  ',GetConsoleOutputCP);
    For I:=33 to 255 do
    Write(Chr(i),' ');
    Writeln;
    Readkey;
    CrtCodePage(-1);   //restore Code Page original
    textcolor(4);
    Writeln('Code Page set back to Original: ',GetConsoleOutputCP);
    For I:=33 to 255 do
    Write(Chr(i),' ');
    Writeln;
    Readkey;
    
    textcolor(13);
    Writeln('         �����������������������������ͻ');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Write('         �     ');
    CrtCodePage(0);
    Write('���ͻ');
    CrtCodePage(-1);
    Writeln('    �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Textcolor(15);
    Writeln('         �����������������������������͹');
    Textcolor(11);
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �����������������������������ͼ');
    Textcolor(10);
    Readkey;
    End.
    
    TestCrtCodePage.pas (2,309 bytes)
  • CrtCodePageTest.JPG (106,998 bytes)
    CrtCodePageTest.JPG (106,998 bytes)
  • TestCodePages.pas (4,102 bytes)
    Program TestCodePages;
    Uses CRT;
    Begin
       CrtCodePage(437);
       Textcolor(15);
       Writeln('Code Page Change Directly from 869 and 1119');
       Textcolor(12);
       Writeln('Approximately symbol is not displayed correctly');
       Textcolor(14);
       Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
       Write('     ',#186);
       Textcolor(10);
       CrtCodePage(869);
       Write('  ',#234); {Pi}
       Textcolor(11);
       CrtCodePage(1119);
       Write(' ',#247,' '); {Approximatly}
       CrtCodePage(437);
       Textcolor(13);
       Write('3.14159');
       Textcolor(14);
       Writeln(' ',#186);
       Write('     '#186);
       Textcolor(10);
       Write(' ',#251,'2 ');{Sqrt 2}
       Textcolor(11);
       CrtCodePage(1119);
       Write(#247,' '); {Approximatly}
       CrtCodePage(437);
       Textcolor(13);
       Write('1.414');
       Textcolor(14);
       Writeln('   ',#186);
       Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
       Writeln;
       Writeln;
    
    
       CrtCodePage(437);
       Textcolor(15);
       Writeln('Code Page Change to 437 between 869 and 1119');
       Textcolor(9);
       Writeln('Approximately symbol is displayed correctly');
       Textcolor(14);
       Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
       Write('     ',#186);
       Textcolor(10);
       CrtCodePage(869);
       Write('  ',#234); {Pi}
       CrtCodePage(437);
       Textcolor(11);
       CrtCodePage(1119);
       Write(' ',#247,' '); {Approximatly}
       CrtCodePage(437);
       Textcolor(13);
       Write('3.14159');
       Textcolor(14);
       Writeln(' ',#186);
       Write('     '#186);
       Textcolor(10);
       Write(' ',#251,'2 ');{Sqrt 2}
       Textcolor(11);
       CrtCodePage(1119);
       Write(#247,' '); {Approximatly}
       CrtCodePage(437);
       Textcolor(13);
       Write('1.414');
       Textcolor(14);
       Writeln('   ',#186);
       Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
       Writeln;
       Writeln;
    
    
       CrtCodePage(437);
       Textcolor(15);
       Writeln('Code Page Change to 0 (GetACP) between 869 and 1119');
       Textcolor(12);
       Writeln('Approximately symbol is not displayed correctly');
       Textcolor(14);
       Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
       Write('     ',#186);
       Textcolor(10);
       CrtCodePage(869);
       Write('  ',#234); {Pi}
       //CrtCodePage(437);  //with or without this makes no differnce
       CrtCodePage(0);
       Textcolor(11);
       CrtCodePage(1119);
       Write(' ',#247,' '); {Approximatly}
       CrtCodePage(437);
       Textcolor(13);
       Write('3.14159');
       Textcolor(14);
       Writeln(' ',#186);
       Write('     '#186);
       Textcolor(10);
       Write(' ',#251,'2 ');{Sqrt 2}
       Textcolor(11);
       CrtCodePage(1119);
       Write(#247,' '); {Approximatly}
       CrtCodePage(437);
       Textcolor(13);
       Write('1.414');
       Textcolor(14);
       Writeln('   ',#186);
       Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
       Writeln;
       Writeln;
    
       CrtCodePage(437);
       Textcolor(15);
       Writeln('Code Page -1 (Reset to origianl) between 869 and 1119');
       Textcolor(9);
       Writeln('Approximately symbol is displayed correctly');
       Textcolor(14);
       Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
       Write('     ',#186);
       Textcolor(10);
       CrtCodePage(869);
       Write('  ',#234); {Pi}
       CrtCodePage(-1);
       Textcolor(11);
       CrtCodePage(1119);
       Write(' ',#247,' '); {Approximatly}
       CrtCodePage(437);
       Textcolor(13);
       Write('3.14159');
       Textcolor(14);
       Writeln(' ',#186);
       Write('     '#186);
       Textcolor(10);
       Write(' ',#251,'2 ');{Sqrt 2}
       Textcolor(11);
       CrtCodePage(1119);
       Write(#247,' '); {Approximatly}
       CrtCodePage(437);
       Textcolor(13);
       Write('1.414');
       Textcolor(14);
       Writeln('   ',#186);
       Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
       Writeln;
       Writeln;
       Readkey;
    End.
    
    TestCodePages.pas (4,102 bytes)
  • TestCodePage Output.JPG (108,069 bytes)
    TestCodePage Output.JPG (108,069 bytes)
  • CRT Flags Only.diff (11,496 bytes)
    ��diff --git a/packages/rtl-console/src/win/crt.pp b/packages/rtl-console/src/win/crt.pp
    
    index de68c4e95d..3a0668138d 100644
    
    --- a/packages/rtl-console/src/win/crt.pp
    
    +++ b/packages/rtl-console/src/win/crt.pp
    
    @@ -18,8 +18,6 @@ interface
    
     
    
     {$i crth.inc}
    
     
    
    -Procedure CRT_Switch_CodePage(CSCP:Boolean);
    
    -Procedure CRT_TP_Compatible(CTC:Boolean);
    
     procedure Window32(X1,Y1,X2,Y2: DWord);
    
     procedure GotoXY32(X,Y: DWord);
    
     function WhereX32: DWord;
    
    @@ -36,13 +34,7 @@ uses
    
     var
    
         SaveCursorSize: Longint;
    
         Win32Platform : Longint; // pulling in sysutils changes exception behaviour
    
    -    
    
    -   TP_Compatible      : Boolean; // If True will not change the codepage to GetACP for compatibility
    
    -                                      // with Turbo Pascal CRT Unit
    
    -    
    
    -   Switch_CodePage : Boolean; // If True  Codepage will be switched every read and write. 
    
    -                                      // If False Codepage will only be set on Initialization and Finalization
    
    -   OriginalConsoleOutputCP : Word;
    
    +
    
     {****************************************************************************
    
                                Low level Routines
    
     ****************************************************************************}
    
    @@ -101,28 +93,7 @@ end;
    
     {****************************************************************************
    
                                  Public Crt Functions
    
     ****************************************************************************}
    
    -Procedure CRT_Switch_CodePage(CSCP:Boolean);
    
    -Begin
    
    -    Switch_CodePage:=CSCP;
    
    -    If Switch_CodePage then
    
    -      SetConsoleOutputCP(OriginalConsoleOutputCP)   // Set Console back to Original since it will now be switched
    
    -                                                    // every read and write
    
    -    Else
    
    -      If Not(TP_Compatible) then
    
    -        SetConsoleOutputCP(GetACP);   // Set Console only once here if CRT_Switch_CodePage is False and
    
    -                                      // if CRT_TP_Compatible is also False
    
    -End;
    
    -
    
    -Procedure CRT_TP_Compatible(CTC:Boolean);
    
    -Begin
    
    -    TP_Compatible:=CTC;
    
    -    If TP_Compatible Then
    
    -      SetConsoleOutputCP(OriginalConsoleOutputCP)    // Set Console back to Original if CRT_TP_Compatible is True
    
    -    Else
    
    -      if Not(Switch_CodePage) Then
    
    -        SetConsoleOutputCP(GetACP);   // Set Console only once here if CRT_Switch_CodePage is False and
    
    -                                      // if CRT_TP_Compatible is False
    
    -End;
    
    +
    
     
    
     procedure TextMode (Mode: word);
    
     begin
    
    @@ -780,14 +751,11 @@ Procedure CrtWrite(var f : textrec);
    
     var
    
       i : longint;
    
       s : string;
    
    -  OldConsoleOutputCP : Word;
    
    +  OldConsoleOutputCP : Word;
    
     begin
    
    -  If Switch_CodePage and Not(TP_Compatible) then    //Switch Codepage every Read.
    
    -    Begin
    
    -      OldConsoleOutputCP:=GetConsoleOutputCP;
    
    -      SetConsoleOutputCP(GetACP);
    
    -    End;
    
    -
    
    +  OldConsoleOutputCP:=GetConsoleOutputCP;
    
    +  SetConsoleOutputCP(GetACP);
    
    +
    
       GetScreenCursor(CurrX, CurrY);
    
       s:='';
    
       for i:=0 to f.bufpos-1 do
    
    @@ -796,7 +764,7 @@ begin
    
             if s<>'' then
    
               begin
    
                 WriteStr(s);
    
    -            s:='';
    
    + 	    s:='';
    
               end;
    
             WriteChar(f.buffer[i]);
    
           end
    
    @@ -813,11 +781,7 @@ begin
    
         WriteStr(s);
    
       SetScreenCursor(CurrX, CurrY);
    
     
    
    -  If Switch_CodePage then        //Restore CodePage Every Write
    
    -    If TP_Compatible Then
    
    -      SetConsoleOutputCP(OriginalConsoleOutputCP) 
    
    -    Else
    
    -      SetConsoleOutputCP(OldConsoleOutputCP);
    
    +  SetConsoleOutputCP(OldConsoleOutputCP);
    
     
    
       f.bufpos:=0;
    
     end;
    
    @@ -836,15 +800,12 @@ Procedure CrtRead(Var F: TextRec);
    
       end;
    
     
    
     var
    
    -  ch : Char;
    
    -  OldConsoleOutputCP : Word;
    
    +  ch : Char;
    
    +  OldConsoleOutputCP : Word;
    
     Begin
    
    -  If Switch_CodePage and Not(TP_Compatible) then    //Switch Codepage every Read.
    
    -    Begin
    
    -      OldConsoleOutputCP:=GetConsoleOutputCP;
    
    -      SetConsoleOutputCP(GetACP);
    
    -    End;
    
    -
    
    +  OldConsoleOutputCP:=GetConsoleOutputCP;
    
    +  SetConsoleOutputCP(GetACP);
    
    +
    
       GetScreenCursor(CurrX,CurrY);
    
       f.bufpos:=0;
    
       f.bufend:=0;
    
    @@ -922,12 +883,8 @@ Begin
    
           end;
    
       until false;
    
     
    
    -  If Switch_CodePage then        //Restore CodePage Every Read
    
    -    If TP_Compatible Then
    
    -      SetConsoleOutputCP(OriginalConsoleOutputCP) 
    
    -    Else
    
    -      SetConsoleOutputCP(OldConsoleOutputCP);
    
    -
    
    +  SetConsoleOutputCP(OldConsoleOutputCP);
    
    +	
    
       f.bufpos:=0;
    
       SetScreenCursor(CurrX, CurrY);
    
     End;
    
    @@ -1027,13 +984,6 @@ Initialization
    
       LastMode := 3;
    
     
    
       SetActiveWindow(0);
    
    -
    
    -  OriginalConsoleOutputCP:=GetConsoleOutputCP;  //Aways save the original console codepage so it can be resored on exit.
    
    -  Switch_CodePage:=True;  // Default to use GetACP CodePage to remain compatible with previous CRT version.
    
    -  TP_Compatible:=False;   // Default to switch codepage every read and write to remain compatible with previous CRT version.
    
    -                          
    
    -  //CRT_Switch_CodePage(False); // With These defaults the code page does not need to be changed here.  If Switch_CodePage and
    
    -                                // TP_Compatible both defaulted to False then CRT_Switch_CodePage(False) needs to be run here.
    
     
    
       {--------------------- Get the cursor size and such -----------------------}
    
       FillChar(CursorInfo, SizeOf(CursorInfo), 00);
    
    @@ -1080,6 +1030,4 @@ finalization
    
         CloseHandle(beeperDevice);
    
         DefineDosDevice(DDD_REMOVE_DEFINITION,'DosBeep','\Device\Beep');
    
       end;
    
    -  SetConsoleOutputCP(OriginalConsoleOutputCP);  //Always put the colsole back the way it was on exit.
    
    -                                                //useful if the program is executed from command line.
    
     end. { unit Crt }
    
    
    CRT Flags Only.diff (11,496 bytes)
  • CRT_Flags_Only_TestCodePages.pas (5,538 bytes)
    Program TestCodePages;
    Uses CRT,Windows;
    Begin
       CRT_Switch_CodePage(True);
       CRT_TP_Compatible(False);
       SetConsoleOutputCP(437);
       Textcolor(15);
       Writeln('CRT_Switch_CodePage(True) CRT_TP_Compatible(False)');
       Textcolor(12);
       Writeln('Not TP Compatible and Impossible to change Code Page');
       Textcolor(14);
       Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
       SetConsoleOutputCP(437);
       Write('     ',#186);
       Textcolor(10);
       SetConsoleOutputCP(869);
       Write('  ',#234); {Pi}
       Textcolor(11);
       SetConsoleOutputCP(1119);
       Write(' ',#247,' '); {Approximatly}
       SetConsoleOutputCP(437);
       Textcolor(13);
       Write('3.14159');
       Textcolor(14);
       Writeln(' ',#186);
       Write('     '#186);
       Textcolor(10);
       Write(' ',#251,'2 ');{Sqrt 2}
       Textcolor(11);
       SetConsoleOutputCP(1119);
       Write(#247,' '); {Approximatly}
       SetConsoleOutputCP(437);
       Textcolor(13);
       Write('1.414');
       Textcolor(14);
       Writeln('   ',#186);
       Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
       Writeln;
       Writeln;
    
    
       CRT_Switch_CodePage(False);
       CRT_TP_Compatible(False);
       Textcolor(15);
       Writeln('CRT_Switch_CodePage(False) CRT_TP_Compatible(False)');
       Textcolor(13);
       Writeln('Not Initially TP Compatible, but now Possible to change Code Page');
       Textcolor(14);
       Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
       Write('     ',#186);
       Textcolor(10);
       SetConsoleOutputCP(869);
       Write('  ',#234); {Pi}
       Textcolor(11);
       SetConsoleOutputCP(437);
       SetConsoleOutputCP(1119);
       Write(' ',#247,' '); {Approximatly}
       Textcolor(13);
       Write('3.14159');
       Textcolor(14);
       Writeln(' ',#186);
       Write('     '#186);
       Textcolor(10);
       SetConsoleOutputCP(1119);
       Write(' ',#251,'2 ');{Sqrt 2}
       Textcolor(11);
       SetConsoleOutputCP(1119);
       Write(#247,' '); {Approximatly}
       SetConsoleOutputCP(437);
       Textcolor(13);
       Write('1.414');
       Textcolor(14);
       Writeln('   ',#186);
       Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
       Writeln;
       Writeln;
    
    
       CRT_Switch_CodePage(False);
       CRT_TP_Compatible(True);
       Textcolor(15);
       Writeln('CRT_Switch_CodePage(False) CRT_TP_Compatible(True)  No CP(437)s');
       Textcolor(12);
       Writeln('TP Compatible, & Possible to change Code Page, Code Page will remain until changed');
       Textcolor(14);
       Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
       Write('     ',#186);
       Textcolor(10);
       SetConsoleOutputCP(869);
       Write('  ',#234); {Pi}
       Textcolor(11);
       SetConsoleOutputCP(1119);
       Write(' ',#247,' '); {Approximatly}
       Textcolor(13);
       Write('3.14159');
       Textcolor(14);
       Writeln(' ',#186);
       Write('     '#186);
       Textcolor(10);
       Write(' ',#251,'2 ');{Sqrt 2}
       Textcolor(11);
       SetConsoleOutputCP(1119);
       Write(#247,' '); {Approximatly}
       Textcolor(13);
       Write('1.414');
       Textcolor(14);
       Writeln('   ',#186);
       Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
       Writeln;
       Writeln;
    
       CRT_Switch_CodePage(False);
       CRT_TP_Compatible(True);
       Textcolor(15);
       Writeln('CRT_Switch_CodePage(False) CRT_TP_Compatible(True)  With CP(437)s');
       Textcolor(9);
       Writeln('TP Compatible, & Possible to change Code Page, Code Page will remain until changed');
       Textcolor(14);
       Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
       Write('     ',#186);
       Textcolor(10);
       SetConsoleOutputCP(869);
       Write('  ',#234); {Pi}
       SetConsoleOutputCP(437);
       Textcolor(11);
       SetConsoleOutputCP(1119);
       Write(' ',#247,' '); {Approximatly}
       SetConsoleOutputCP(437);
       Textcolor(13);
       Write('3.14159');
       Textcolor(14);
       Writeln(' ',#186);
       Write('     '#186);
       Textcolor(10);
       Write(' ',#251,'2 ');{Sqrt 2}
       Textcolor(11);
       SetConsoleOutputCP(1119);
       Write(#247,' '); {Approximatly}
       SetConsoleOutputCP(437);
       Textcolor(13);
       Write('1.414');
       Textcolor(14);
       Writeln('   ',#186);
       Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
       Writeln;
       Writeln;
    
       CRT_Switch_CodePage(True);
       CRT_TP_Compatible(True);
       Textcolor(15);
       Writeln('CRT_Switch_CodePage(True) CRT_TP_Compatible(True)  No CP(437)s');
       Textcolor(9);
       Writeln('TP Compatible, & Possible to change Code Page, But Code Page will reset to original after every write');
       Textcolor(14);
       Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
       Write('     ',#186);
       Textcolor(10);
       SetConsoleOutputCP(869);
       Write('  ',#234); {Pi}
       Textcolor(11);
       SetConsoleOutputCP(1119);
       Write(' ',#247,' '); {Approximatly}
       Textcolor(13);
       Write('3.14159');
       Textcolor(14);
       Writeln(' ',#186);
       Write('     '#186);
       Textcolor(10);
       Write(' ',#251,'2 ');{Sqrt 2}
       Textcolor(11);
       SetConsoleOutputCP(1119);
       Write(#247,' '); {Approximatly}
       Textcolor(13);
       Write('1.414');
       Textcolor(14);
       Writeln('   ',#186);
       Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
       Writeln;
       Writeln;
       Readkey;
    End.
    
  • CRT_Flags_and_RemapScanCode.diff (12,336 bytes)
    ��diff --git a/packages/rtl-console/src/win/crt.pp b/packages/rtl-console/src/win/crt.pp
    
    index 3a0668138d..8bac8f06ea 100644
    
    --- a/packages/rtl-console/src/win/crt.pp
    
    +++ b/packages/rtl-console/src/win/crt.pp
    
    @@ -18,6 +18,8 @@ interface
    
     
    
     {$i crth.inc}
    
     
    
    +Procedure CRT_Switch_CodePage(CSCP:Boolean);
    
    +Procedure CRT_TP_Compatible(CTC:Boolean);
    
     procedure Window32(X1,Y1,X2,Y2: DWord);
    
     procedure GotoXY32(X,Y: DWord);
    
     function WhereX32: DWord;
    
    @@ -34,7 +36,13 @@ uses
    
     var
    
         SaveCursorSize: Longint;
    
         Win32Platform : Longint; // pulling in sysutils changes exception behaviour
    
    -
    
    +    
    
    +   TP_Compatible      : Boolean; // If True will not change the codepage to GetACP for compatibility
    
    +                                      // with Turbo Pascal CRT Unit
    
    +    
    
    +   Switch_CodePage : Boolean; // If True  Codepage will be switched every read and write. 
    
    +                                      // If False Codepage will only be set on Initialization and Finalization
    
    +   OriginalConsoleOutputCP : Word;
    
     {****************************************************************************
    
                                Low level Routines
    
     ****************************************************************************}
    
    @@ -93,7 +101,28 @@ end;
    
     {****************************************************************************
    
                                  Public Crt Functions
    
     ****************************************************************************}
    
    -
    
    +Procedure CRT_Switch_CodePage(CSCP:Boolean);
    
    +Begin
    
    +    Switch_CodePage:=CSCP;
    
    +    If Switch_CodePage then
    
    +      SetConsoleOutputCP(OriginalConsoleOutputCP)   // Set Console back to Original since it will now be switched
    
    +                                                    // every read and write
    
    +    Else
    
    +      If Not(TP_Compatible) then
    
    +        SetConsoleOutputCP(GetACP);   // Set Console only once here if CRT_Switch_CodePage is False and
    
    +                                      // if CRT_TP_Compatible is also False
    
    +End;
    
    +
    
    +Procedure CRT_TP_Compatible(CTC:Boolean);
    
    +Begin
    
    +    TP_Compatible:=CTC;
    
    +    If TP_Compatible Then
    
    +      SetConsoleOutputCP(OriginalConsoleOutputCP)    // Set Console back to Original if CRT_TP_Compatible is True
    
    +    Else
    
    +      if Not(Switch_CodePage) Then
    
    +        SetConsoleOutputCP(GetACP);   // Set Console only once here if CRT_Switch_CodePage is False and
    
    +                                      // if CRT_TP_Compatible is False
    
    +End;
    
     
    
     procedure TextMode (Mode: word);
    
     begin
    
    @@ -260,7 +289,7 @@ var
    
        DoingNumChars: Boolean;
    
        DoingNumCode: Byte;
    
     
    
    -Function RemapScanCode (ScanCode: byte; CtrlKeyState: byte; keycode:longint): byte;
    
    +Function RemapScanCode (ScanCode: byte; CtrlKeyState: word; keycode:longint): byte;
    
       { Several remappings of scancodes are necessary to comply with what
    
         we get with MSDOS. Special Windows keys, as Alt-Tab, Ctrl-Esc etc.
    
         are excluded }
    
    @@ -751,11 +780,14 @@ Procedure CrtWrite(var f : textrec);
    
     var
    
       i : longint;
    
       s : string;
    
    -  OldConsoleOutputCP : Word;
    
    +  OldConsoleOutputCP : Word;
    
     begin
    
    -  OldConsoleOutputCP:=GetConsoleOutputCP;
    
    -  SetConsoleOutputCP(GetACP);
    
    -
    
    +  If Switch_CodePage and Not(TP_Compatible) then    //Switch Codepage every Read.
    
    +    Begin
    
    +      OldConsoleOutputCP:=GetConsoleOutputCP;
    
    +      SetConsoleOutputCP(GetACP);
    
    +    End;
    
    +
    
       GetScreenCursor(CurrX, CurrY);
    
       s:='';
    
       for i:=0 to f.bufpos-1 do
    
    @@ -764,7 +796,7 @@ begin
    
             if s<>'' then
    
               begin
    
                 WriteStr(s);
    
    - 	    s:='';
    
    +            s:='';
    
               end;
    
             WriteChar(f.buffer[i]);
    
           end
    
    @@ -781,7 +813,11 @@ begin
    
         WriteStr(s);
    
       SetScreenCursor(CurrX, CurrY);
    
     
    
    -  SetConsoleOutputCP(OldConsoleOutputCP);
    
    +  If Switch_CodePage then        //Restore CodePage Every Write
    
    +    If TP_Compatible Then
    
    +      SetConsoleOutputCP(OriginalConsoleOutputCP) 
    
    +    Else
    
    +      SetConsoleOutputCP(OldConsoleOutputCP);
    
     
    
       f.bufpos:=0;
    
     end;
    
    @@ -800,12 +836,15 @@ Procedure CrtRead(Var F: TextRec);
    
       end;
    
     
    
     var
    
    -  ch : Char;
    
    -  OldConsoleOutputCP : Word;
    
    +  ch : Char;
    
    +  OldConsoleOutputCP : Word;
    
     Begin
    
    -  OldConsoleOutputCP:=GetConsoleOutputCP;
    
    -  SetConsoleOutputCP(GetACP);
    
    -
    
    +  If Switch_CodePage and Not(TP_Compatible) then    //Switch Codepage every Read.
    
    +    Begin
    
    +      OldConsoleOutputCP:=GetConsoleOutputCP;
    
    +      SetConsoleOutputCP(GetACP);
    
    +    End;
    
    +
    
       GetScreenCursor(CurrX,CurrY);
    
       f.bufpos:=0;
    
       f.bufend:=0;
    
    @@ -883,8 +922,12 @@ Begin
    
           end;
    
       until false;
    
     
    
    -  SetConsoleOutputCP(OldConsoleOutputCP);
    
    -	
    
    +  If Switch_CodePage then        //Restore CodePage Every Read
    
    +    If TP_Compatible Then
    
    +      SetConsoleOutputCP(OriginalConsoleOutputCP) 
    
    +    Else
    
    +      SetConsoleOutputCP(OldConsoleOutputCP);
    
    +
    
       f.bufpos:=0;
    
       SetScreenCursor(CurrX, CurrY);
    
     End;
    
    @@ -984,6 +1027,13 @@ Initialization
    
       LastMode := 3;
    
     
    
       SetActiveWindow(0);
    
    +
    
    +  OriginalConsoleOutputCP:=GetConsoleOutputCP;  //Aways save the original console codepage so it can be resored on exit.
    
    +  Switch_CodePage:=True;  // Default to use GetACP CodePage to remain compatible with previous CRT version.
    
    +  TP_Compatible:=False;   // Default to switch codepage every read and write to remain compatible with previous CRT version.
    
    +                          
    
    +  //CRT_Switch_CodePage(False); // With These defaults the code page does not need to be changed here.  If Switch_CodePage and
    
    +                                // TP_Compatible both defaulted to False then CRT_Switch_CodePage(False) needs to be run here.
    
     
    
       {--------------------- Get the cursor size and such -----------------------}
    
       FillChar(CursorInfo, SizeOf(CursorInfo), 00);
    
    @@ -1030,4 +1080,6 @@ finalization
    
         CloseHandle(beeperDevice);
    
         DefineDosDevice(DDD_REMOVE_DEFINITION,'DosBeep','\Device\Beep');
    
       end;
    
    +  SetConsoleOutputCP(OriginalConsoleOutputCP);  //Always put the colsole back the way it was on exit.
    
    +                                                //useful if the program is executed from command line.
    
     end. { unit Crt }
    
    
  • CRT_Flags_And_RemapScanCode_2.diff (12,332 bytes)
    ��diff --git a/packages/rtl-console/src/win/crt.pp b/packages/rtl-console/src/win/crt.pp
    
    index 3a0668138d..ab29f94374 100644
    
    --- a/packages/rtl-console/src/win/crt.pp
    
    +++ b/packages/rtl-console/src/win/crt.pp
    
    @@ -18,6 +18,8 @@ interface
    
     
    
     {$i crth.inc}
    
     
    
    +Procedure CRT_Switch_CodePage(CSCP:Boolean);
    
    +Procedure CRT_TP_Compatible(CTC:Boolean);
    
     procedure Window32(X1,Y1,X2,Y2: DWord);
    
     procedure GotoXY32(X,Y: DWord);
    
     function WhereX32: DWord;
    
    @@ -34,7 +36,13 @@ uses
    
     var
    
         SaveCursorSize: Longint;
    
         Win32Platform : Longint; // pulling in sysutils changes exception behaviour
    
    -
    
    +    
    
    +   TP_Compatible      : Boolean; // If True will not change the codepage to GetACP for compatibility
    
    +                                      // with Turbo Pascal CRT Unit
    
    +    
    
    +   Switch_CodePage : Boolean; // If True  Codepage will be switched every read and write. 
    
    +                                      // If False Codepage will only be set on Initialization and Finalization
    
    +   OriginalConsoleOutputCP : Word;
    
     {****************************************************************************
    
                                Low level Routines
    
     ****************************************************************************}
    
    @@ -93,7 +101,28 @@ end;
    
     {****************************************************************************
    
                                  Public Crt Functions
    
     ****************************************************************************}
    
    -
    
    +Procedure CRT_Switch_CodePage(CSCP:Boolean);
    
    +Begin
    
    +    Switch_CodePage:=CSCP;
    
    +    If Switch_CodePage then
    
    +      SetConsoleOutputCP(OriginalConsoleOutputCP)   // Set Console back to Original since it will now be switched
    
    +                                                    // every read and write
    
    +    Else
    
    +      If Not(TP_Compatible) then
    
    +        SetConsoleOutputCP(GetACP);   // Set Console only once here if CRT_Switch_CodePage is False and
    
    +                                      // if CRT_TP_Compatible is also False
    
    +End;
    
    +
    
    +Procedure CRT_TP_Compatible(CTC:Boolean);
    
    +Begin
    
    +    TP_Compatible:=CTC;
    
    +    If TP_Compatible Then
    
    +      SetConsoleOutputCP(OriginalConsoleOutputCP)    // Set Console back to Original if CRT_TP_Compatible is True
    
    +    Else
    
    +      if Not(Switch_CodePage) Then
    
    +        SetConsoleOutputCP(GetACP);   // Set Console only once here if CRT_Switch_CodePage is False and
    
    +                                      // if CRT_TP_Compatible is False
    
    +End;
    
     
    
     procedure TextMode (Mode: word);
    
     begin
    
    @@ -260,7 +289,7 @@ var
    
        DoingNumChars: Boolean;
    
        DoingNumCode: Byte;
    
     
    
    -Function RemapScanCode (ScanCode: byte; CtrlKeyState: byte; keycode:longint): byte;
    
    +Function RemapScanCode (ScanCode: word; CtrlKeyState: dword; keycode:word): byte;
    
       { Several remappings of scancodes are necessary to comply with what
    
         we get with MSDOS. Special Windows keys, as Alt-Tab, Ctrl-Esc etc.
    
         are excluded }
    
    @@ -751,11 +780,14 @@ Procedure CrtWrite(var f : textrec);
    
     var
    
       i : longint;
    
       s : string;
    
    -  OldConsoleOutputCP : Word;
    
    +  OldConsoleOutputCP : Word;
    
     begin
    
    -  OldConsoleOutputCP:=GetConsoleOutputCP;
    
    -  SetConsoleOutputCP(GetACP);
    
    -
    
    +  If Switch_CodePage and Not(TP_Compatible) then    //Switch Codepage every Read.
    
    +    Begin
    
    +      OldConsoleOutputCP:=GetConsoleOutputCP;
    
    +      SetConsoleOutputCP(GetACP);
    
    +    End;
    
    +
    
       GetScreenCursor(CurrX, CurrY);
    
       s:='';
    
       for i:=0 to f.bufpos-1 do
    
    @@ -764,7 +796,7 @@ begin
    
             if s<>'' then
    
               begin
    
                 WriteStr(s);
    
    - 	    s:='';
    
    +            s:='';
    
               end;
    
             WriteChar(f.buffer[i]);
    
           end
    
    @@ -781,7 +813,11 @@ begin
    
         WriteStr(s);
    
       SetScreenCursor(CurrX, CurrY);
    
     
    
    -  SetConsoleOutputCP(OldConsoleOutputCP);
    
    +  If Switch_CodePage then        //Restore CodePage Every Write
    
    +    If TP_Compatible Then
    
    +      SetConsoleOutputCP(OriginalConsoleOutputCP) 
    
    +    Else
    
    +      SetConsoleOutputCP(OldConsoleOutputCP);
    
     
    
       f.bufpos:=0;
    
     end;
    
    @@ -800,12 +836,15 @@ Procedure CrtRead(Var F: TextRec);
    
       end;
    
     
    
     var
    
    -  ch : Char;
    
    -  OldConsoleOutputCP : Word;
    
    +  ch : Char;
    
    +  OldConsoleOutputCP : Word;
    
     Begin
    
    -  OldConsoleOutputCP:=GetConsoleOutputCP;
    
    -  SetConsoleOutputCP(GetACP);
    
    -
    
    +  If Switch_CodePage and Not(TP_Compatible) then    //Switch Codepage every Read.
    
    +    Begin
    
    +      OldConsoleOutputCP:=GetConsoleOutputCP;
    
    +      SetConsoleOutputCP(GetACP);
    
    +    End;
    
    +
    
       GetScreenCursor(CurrX,CurrY);
    
       f.bufpos:=0;
    
       f.bufend:=0;
    
    @@ -883,8 +922,12 @@ Begin
    
           end;
    
       until false;
    
     
    
    -  SetConsoleOutputCP(OldConsoleOutputCP);
    
    -	
    
    +  If Switch_CodePage then        //Restore CodePage Every Read
    
    +    If TP_Compatible Then
    
    +      SetConsoleOutputCP(OriginalConsoleOutputCP) 
    
    +    Else
    
    +      SetConsoleOutputCP(OldConsoleOutputCP);
    
    +
    
       f.bufpos:=0;
    
       SetScreenCursor(CurrX, CurrY);
    
     End;
    
    @@ -984,6 +1027,13 @@ Initialization
    
       LastMode := 3;
    
     
    
       SetActiveWindow(0);
    
    +
    
    +  OriginalConsoleOutputCP:=GetConsoleOutputCP;  //Aways save the original console codepage so it can be resored on exit.
    
    +  Switch_CodePage:=True;  // Default to use GetACP CodePage to remain compatible with previous CRT version.
    
    +  TP_Compatible:=False;   // Default to switch codepage every read and write to remain compatible with previous CRT version.
    
    +                          
    
    +  //CRT_Switch_CodePage(False); // With These defaults the code page does not need to be changed here.  If Switch_CodePage and
    
    +                                // TP_Compatible both defaulted to False then CRT_Switch_CodePage(False) needs to be run here.
    
     
    
       {--------------------- Get the cursor size and such -----------------------}
    
       FillChar(CursorInfo, SizeOf(CursorInfo), 00);
    
    @@ -1030,4 +1080,6 @@ finalization
    
         CloseHandle(beeperDevice);
    
         DefineDosDevice(DDD_REMOVE_DEFINITION,'DosBeep','\Device\Beep');
    
       end;
    
    +  SetConsoleOutputCP(OriginalConsoleOutputCP);  //Always put the colsole back the way it was on exit.
    
    +                                                //useful if the program is executed from command line.
    
     end. { unit Crt }
    
    
  • CRT_fix.diff (3,870 bytes)
    ��diff --git a/packages/rtl-console/src/win/crt.pp b/packages/rtl-console/src/win/crt.pp
    
    index ab0a617166..92c7b81048 100644
    
    --- a/packages/rtl-console/src/win/crt.pp
    
    +++ b/packages/rtl-console/src/win/crt.pp
    
    @@ -123,12 +123,12 @@ procedure SetUseACP(ACP:Boolean);
    
     begin
    
         UseACP:=ACP;
    
         if UseACP then
    
    -      if not(SafeCPSwitching) then
    
    -        SetConsoleOutputCP(GetACP)   // Set console CP only once here if SafeCPSwitching is False and
    
    -                                     // if UseACP is True
    
    -      else
    
    -       SetConsoleOutputCP(OriginalConsoleOutputCP)    // Set console back to original if UseACP is False
    
    +      Begin
    
    +        if not(SafeCPSwitching) then
    
    +          SetConsoleOutputCP(GetACP);   // Set console CP only once here if SafeCPSwitching is False and
    
    +      End                               // if UseACP is True
    
         else
    
    +      SetConsoleOutputCP(OriginalConsoleOutputCP);    // Set console back to original if UseACP is False
    
     end;
    
     
    
     procedure TextMode (Mode: word);
    
    @@ -820,8 +820,11 @@ begin
    
         WriteStr(s);
    
       SetScreenCursor(CurrX, CurrY);
    
     
    
    -  if SafeCPSwitching and UseACP then     //restore codepage on every write if set previously
    
    -    SetConsoleOutputCP(OldConsoleOutputCP);
    
    +  if SafeCPSwitching then
    
    +    if UseACP then     //restore codepage on every write
    
    +      SetConsoleOutputCP(OldConsoleOutputCP)
    
    +    else
    
    +      SetConsoleOutputCP(OriginalConsoleOutputCP);
    
     
    
       f.bufpos:=0;
    
     end;
    
    @@ -926,9 +929,11 @@ begin
    
           end;
    
       until false;
    
     
    
    -  if SafeCPSwitching and UseACP then    //Restore codepage on every Read if set previously
    
    -    SetConsoleOutputCP(OldConsoleOutputCP);
    
    -	
    
    +  if SafeCPSwitching then
    
    +    if UseACP then     //restore codepage on every read
    
    +      SetConsoleOutputCP(OldConsoleOutputCP)
    
    +    else
    
    +      SetConsoleOutputCP(OriginalConsoleOutputCP);
    
       f.bufpos:=0;
    
       SetScreenCursor(CurrX, CurrY);
    
     End;
    
    
    CRT_fix.diff (3,870 bytes)
  • CRT_TestCodePages.pas (5,450 bytes)
    Program TestCodePages;
    Uses CRT,Windows;
    Begin
       SetSafeCPSwitching(True);
       SetUseACP(True);
       SetConsoleOutputCP(437);
       Textcolor(15);
       Writeln('SetSafeCPSwitching(True) SetUseACP(True)');
       Textcolor(12);
       Writeln('Not TP Compatible and Impossible to change Code Page');
       Textcolor(14);
       Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
       SetConsoleOutputCP(437);
       Write('     ',#186);
       Textcolor(10);
       SetConsoleOutputCP(869);
       Write('  ',#234); {Pi}
       Textcolor(11);
       SetConsoleOutputCP(1119);
       Write(' ',#247,' '); {Approximatly}
       SetConsoleOutputCP(437);
       Textcolor(13);
       Write('3.14159');
       Textcolor(14);
       Writeln(' ',#186);
       Write('     '#186);
       Textcolor(10);
       Write(' ',#251,'2 ');{Sqrt 2}
       Textcolor(11);
       SetConsoleOutputCP(1119);
       Write(#247,' '); {Approximatly}
       SetConsoleOutputCP(437);
       Textcolor(13);
       Write('1.414');
       Textcolor(14);
       Writeln('   ',#186);
       Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
       Writeln;
       Writeln;
    
    
       SetSafeCPSwitching(False);
       SetUseACP(True);
       Textcolor(15);
       Writeln('SetSafeCPSwitching(False) SetUseACP(True)');
       Textcolor(13);
       Writeln('Not Initially TP Compatible, but now Possible to change Code Page');
       Textcolor(14);
       Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
       Write('     ',#186);
       Textcolor(10);
       SetConsoleOutputCP(869);
       Write('  ',#234); {Pi}
       Textcolor(11);
       SetConsoleOutputCP(437);
       SetConsoleOutputCP(1119);
       Write(' ',#247,' '); {Approximatly}
       Textcolor(13);
       Write('3.14159');
       Textcolor(14);
       Writeln(' ',#186);
       Write('     '#186);
       Textcolor(10);
       SetConsoleOutputCP(1119);
       Write(' ',#251,'2 ');{Sqrt 2}
       Textcolor(11);
       SetConsoleOutputCP(1119);
       Write(#247,' '); {Approximatly}
       SetConsoleOutputCP(437);
       Textcolor(13);
       Write('1.414');
       Textcolor(14);
       Writeln('   ',#186);
       Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
       Writeln;
       Writeln;
    
    
       SetSafeCPSwitching(False);
       SetUseACP(False);
       Textcolor(15);
       Writeln('SetSafeCPSwitching(False) SetUseACP(False)  No CP(437)s');
       Textcolor(12);
       Writeln('TP Compatible, & Possible to change Code Page, Code Page will remain until changed');
       Textcolor(14);
       Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
       Write('     ',#186);
       Textcolor(10);
       SetConsoleOutputCP(869);
       Write('  ',#234); {Pi}
       Textcolor(11);
       SetConsoleOutputCP(1119);
       Write(' ',#247,' '); {Approximatly}
       Textcolor(13);
       Write('3.14159');
       Textcolor(14);
       Writeln(' ',#186);
       Write('     '#186);
       Textcolor(10);
       Write(' ',#251,'2 ');{Sqrt 2}
       Textcolor(11);
       SetConsoleOutputCP(1119);
       Write(#247,' '); {Approximatly}
       Textcolor(13);
       Write('1.414');
       Textcolor(14);
       Writeln('   ',#186);
       Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
       Writeln;
       Writeln;
    
       SetSafeCPSwitching(False);
       SetUseACP(False);
       Textcolor(15);
       Writeln('SetSafeCPSwitching(False) SetUseACP(False)  With CP(437)s');
       Textcolor(9);
       Writeln('TP Compatible, & Possible to change Code Page, Code Page will remain until changed');
       Textcolor(14);
       Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
       Write('     ',#186);
       Textcolor(10);
       SetConsoleOutputCP(869);
       Write('  ',#234); {Pi}
       SetConsoleOutputCP(437);
       Textcolor(11);
       SetConsoleOutputCP(1119);
       Write(' ',#247,' '); {Approximatly}
       SetConsoleOutputCP(437);
       Textcolor(13);
       Write('3.14159');
       Textcolor(14);
       Writeln(' ',#186);
       Write('     '#186);
       Textcolor(10);
       Write(' ',#251,'2 ');{Sqrt 2}
       Textcolor(11);
       SetConsoleOutputCP(1119);
       Write(#247,' '); {Approximatly}
       SetConsoleOutputCP(437);
       Textcolor(13);
       Write('1.414');
       Textcolor(14);
       Writeln('   ',#186);
       Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
       Writeln;
       Writeln;
    
       SetSafeCPSwitching(True);
       SetUseACP(False);
       Textcolor(15);
       Writeln('SetSafeCPSwitching(True) SetUseACP(False)  No CP(437)s');
       Textcolor(9);
       Writeln('TP Compatible, & Possible to change Code Page, But Code Page will reset to original after every write');
       Textcolor(14);
       Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
       Write('     ',#186);
       Textcolor(10);
       SetConsoleOutputCP(869);
       Write('  ',#234); {Pi}
       Textcolor(11);
       SetConsoleOutputCP(1119);
       Write(' ',#247,' '); {Approximatly}
       Textcolor(13);
       Write('3.14159');
       Textcolor(14);
       Writeln(' ',#186);
       Write('     '#186);
       Textcolor(10);
       Write(' ',#251,'2 ');{Sqrt 2}
       Textcolor(11);
       SetConsoleOutputCP(1119);
       Write(#247,' '); {Approximatly}
       Textcolor(13);
       Write('1.414');
       Textcolor(14);
       Writeln('   ',#186);
       Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
       Writeln;
       Writeln;
       Readkey;
    End.
    
    CRT_TestCodePages.pas (5,450 bytes)
  • Asciibox2_SafeSwitch_First.pas (1,504 bytes)
    Program ASCIIbox2;
    Uses CRT;
    Begin
    SetSafeCPSwitching(False);
    SetUseACP(False);
    Writeln('         �����������������������������ͻ');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �����������������������������͹');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �              �              �');
    Writeln('         �����������������������������ͼ');
    Readln;
    End.
    
  • codepagetest.pas (293 bytes)
    Program codepagetest;
    Uses CRT,Windows;
    Begin
       SetSafeCPSwitching(True);
       SetUseACP(False);
       SetConsoleOutputCP(869);
       Write('  ',#234); {Pi}
       SetConsoleOutputCP(1119);
       Write(' ',#247,' '); {Approximatly}
       SetConsoleOutputCP(437);
       Write('3.14');
       Readln;
    End.
    
    codepagetest.pas (293 bytes)
  • CRT_Fix2.diff (2,246 bytes)
    ��diff --git a/packages/rtl-console/src/win/crt.pp b/packages/rtl-console/src/win/crt.pp
    
    index c601011df6..813cda35fd 100644
    
    --- a/packages/rtl-console/src/win/crt.pp
    
    +++ b/packages/rtl-console/src/win/crt.pp
    
    @@ -821,8 +821,11 @@ begin
    
         WriteStr(s);
    
       SetScreenCursor(CurrX, CurrY);
    
     
    
    -  if SafeCPSwitching and UseACP then     //restore codepage on every write if set previously
    
    -    SetConsoleOutputCP(OldConsoleOutputCP);
    
    +  if SafeCPSwitching then
    
    +    if UseACP then     //restore codepage on every write
    
    +      SetConsoleOutputCP(OldConsoleOutputCP)
    
    +    else
    
    +      SetConsoleOutputCP(OriginalConsoleOutputCP);
    
     
    
       f.bufpos:=0;
    
     end;
    
    @@ -927,9 +930,11 @@ begin
    
           end;
    
       until false;
    
     
    
    -  if SafeCPSwitching and UseACP then    //Restore codepage on every Read if set previously
    
    -    SetConsoleOutputCP(OldConsoleOutputCP);
    
    -	
    
    +  if SafeCPSwitching then
    
    +    if UseACP then     //restore codepage on every read
    
    +      SetConsoleOutputCP(OldConsoleOutputCP)
    
    +    else
    
    +      SetConsoleOutputCP(OriginalConsoleOutputCP);
    
       f.bufpos:=0;
    
       SetScreenCursor(CurrX, CurrY);
    
     End;
    
    
    CRT_Fix2.diff (2,246 bytes)

Activities

James Richters

2017-10-16 21:04

reporter  

Free Pascal CRT Information.zip (2,177 bytes)

Anton Kavalenka

2017-10-16 21:33

reporter   ~0103493

Last edited: 2017-10-16 21:36

View 2 revisions

* What codepage are your sources?

* Does the option
-Fc<x> Set input codepage to <x>
help?

* What chcp says in Window$ console?

Btw you can edit your box-drawing sources in Lazarus - select proper codepage like win1252 in editor context menu.

James Richters

2017-10-16 23:52

reporter   ~0103498

Last edited: 2017-10-16 23:53

View 2 revisions

CHCP reports: Active code page: 437 I've tried several windows 10 PCs and get the same.

The Extended ASCII version of characters come from the Extended ASCII chart similar to:
http://www.cpptutor.com/ascii-chart.htm or
http://www.asciitable.com/


The Unicode Characters came from opening Character Map in Windows and changing the 'Consolas' font since that is the default font for windows console. The Windows 10 Version of Character Map shows the code as U+xxxx where xxxx is a hex representation. I converted the hex to decimal for the # versions of the codes, or just cut and pasted them from character map for the direct character version.

I tried compiling with -Fc437 and the results are the same.

Thaddy de Koning

2017-10-17 09:10

reporter   ~0103502

Last edited: 2017-10-17 09:13

View 3 revisions

Afaik the crt unit is not and will never be unicode. It relies on the ansi code page of the system. It is legacy support for legacy code. Any new code should use a different approach. There are many, many related reports... For new code it is almost always the wrong choice.

In my experience, old TP code simply works given the correct codepage. And even x-platform. But it requires ANSI and an ANSI Terminal/console.

Anton Kavalenka

2017-10-17 10:32

reporter   ~0103505

Just run the cycle printing $20 to $ff and see what printed. You have to see the exact cp437 symbols as in Wikipedia.

Specifying -Fc means you EXACTLY know what codepage your sources, it is not target console codepage but the codepage your files encoded.

By default Lazarus and FP write files in UTF-8 without BOM.

Bart Broersma

2017-10-17 10:55

reporter   ~0103507

On the forum there are several solutions/workarounds for this problem.
All of them involve adding a dependency on LazUtils package and/or specifying a unicode-eneabled font for the console (which Windows by default does not use).

James Richters

2017-10-17 13:15

reporter   ~0103516

Solutions that rely on modifying the system are not valid solutions at all. If I cannot send my program to a non-technical person, and they run it on their system and get the expected results, then it is worthless as it’s now a program only I can run on my modified system, and that is simply unacceptable.

The CRT should display the correct symbols on the default console with the default font without any system modification so the results of running the program on ANY random system are the same. If it does not do this, then it is not the way it should be.

Run the following Program with CRT and without it.

Program ASCIIChars;
Uses CRT;
Var i: Byte;
Begin
For I:=33 to 255 do
Write(Chr(i),' ');
End.

Without CRT the correct Extended ASCII symbols are displayed, WITH CRT the incorrect Unicode symbols are displayed. CRT is not supposed to be Unicode, so it should NEVER display these symbols. It should not be dependent on the system being configured in a particular way, it should display the correct symbols the same way that the correct symbols are displayed without CRT.

I know of no alternative to CRT even for new console applications. I also have applications that use the console in conjunction with a PTCGraph window. There is a place for CRT and a place for console applications. Without CRT, I can write to the console, but I can’t change the colors of the text and I can’t use even simple functions like readkey.

It can’t be that difficult to make CRT display the correct symbols on the default console with the default font without unacceptably modifying the system. CRT should just work as expected and the program generated should be able to be run on any random system with consistent results.

Marco van de Voort

2017-10-17 14:01

manager   ~0103518

I tried you asciibox2 with Crt and got linedrawing characters. My chcp returns 850

James Richters

2017-10-17 15:24

reporter   ~0103520

Last edited: 2017-10-17 15:25

View 2 revisions

How do you set it to 850? All my windows computers are 437 and I don't know how to change it, and any client I would send my program to also would not know how to change it.

If I got to my command prompt properties, it lists Current code page 437 (OEM - United States) but there is no option to change it.

It looks like Codepage 850 is similar to 437, but what is used in Europe.
https://en.wikipedia.org/wiki/Code_page_850
https://en.wikipedia.org/wiki/Code_page_437

Perhaps what is needed for CRT to function properly is a variable where you define the codepage of your system so that it acts correctly? but that still doesn't explain why it's correct without CRT and incorrect with it

Anton Kavalenka

2017-10-17 15:42

reporter   ~0103521

Last edited: 2017-10-17 18:30

View 3 revisions

Seems like win10 consoles refuse to work in OEM cp.
Win2003 with Fixedsys font draws properly.
Win10 can not do it any way, besides it refuse to change font to raster.

Florian

2017-10-17 19:53

administrator   ~0103528

> It can’t be that difficult to make CRT display the correct
> symbols on the default console with the default
> font without unacceptably modifying the system.


If it is not that difficult, why didn't you provide a patch then?

James Richters

2017-10-17 22:18

reporter   ~0103533

>If it is not that difficult, why didn't you provide a patch then?

I would be happy to work on it if someone could point me in the right direction.

My point was, since the default console can display the required characters, It should be a matter of replacing the incorrect characters with the correct ones so they display correctly.

I don't know where the CRT unit source code is and I am not familiar with how it ties into everything, or why Write() and Writeln() behave differently when CRT is used compared to when it's not being used. You can't do something like crt.writeln(), but you can do crt.readkey() So if CRT doesn't have it's own Writeln() how is it affecting the output on the console?

Bart Broersma

2017-10-17 23:31

reporter   ~0103535

On every write crt does, it sets the console codepage to the result of GetACP (procedure CrtWrite).
However the console codepage differs from GetACP, at least on my Win10 machine,
In a console chcp reports codepage 850, but GetACP reports 1252.

As for the original reporter, writing Char(1) to Char(255), gives different results when I use crt (wrong symbols) or not (correct symbols).

James Richters

2017-10-17 23:52

reporter   ~0103537

I'm happy to report that I've solved this issue, I'll provide a patch as soon as I get a chance to figure out how to do it. I'm not familiar with svn how to generate the required patch, I only know how to do things like pull requests on GIT.

James Richters

2017-10-17 23:53

reporter  

fixed.JPG (259,423 bytes)
fixed.JPG (259,423 bytes)

James Richters

2017-10-17 23:58

reporter   ~0103538

Last edited: 2017-10-18 00:08

View 4 revisions

My fix was just to comment out the codepage changes... Looks like Bart figured it out the same time I did. I've tested it on Windows 98, Windows 2000, Windows XP, Windows 7 and Windows 10. I have not tested any other win OS yet to see if they break without the codepage change.. are there any other relevent OS to test?

Windows 98 and Windows 2000 work fine with the original CRT and my TestCRT.

Windows XP, Windows 7, and Windows 10, all are incorrect with the original and now correct with my testcrt.

Apparently at some point windows console was already taking care of the codepage and trying to set it was only making it come out wrong.

All I did was comment out
//OldConsoleOutputCP:=GetConsoleOutputCP;
//SetConsoleOutputCP(GetACP);
//SetConsoleOutputCP(OldConsoleOutputCP);
from both CRTRead and CRTWrite.

Perhaps someone with more experience than me can comment these out and submit a patch?

Tomas Hajny

2017-10-18 00:39

manager   ~0103539

No, that is not the right solution. Changing the console codepage was performed some time ago based on another Mantis report and for a reason. The problem is as follows:

1) The semigraphic symbols only exist in the so-called OEM codepages (i.e. those originally used in BIOS and/or MS-DOS).

2) Microsoft decided to use different codepages as default in MS Windows ("ANSI"), because the semigraphic symbols aren't that important in a GUI.

3) Various accented characters necessary for other languages than English exist in both OEM codepages and ANSI codepages, but they have different positions there.

4) As pointed out above, current codepage is the same for Win32 applications compiled for console and GUI application - that is what is returned by the GetACP call. However, the default codepage used by MS Windows for output in console ("text-mode") applications is different. Let's say you want to write out an accented character. That character may be e.g. read from a file created in another (GUI) application on the same machine. The accented character is specified using its position in the current process codepage. If you write it out without changing the console output codepage, the character is not displayed correctly - that's the reason, why the change was performed. Output of localized text is much more common than output of semi-graphic characters these days.

Now the solution is actually simple and does not require you to ask the user for performing some changes on his side - you as the programmer know that your program uses the semigraphic characters and no localized characters. You may thus call GetConsoleOutputCP and SetACP at the beginning of your program (if running under MS-Windows - e.g. OS/2 doesn't have a difference between the process codepage and the console codepage). _If_ the default console codepage for the environment of your user contains the necessary characters (it doesn't have to - various OEM codepages contain different subsets of those semi-graphic characters!!!), your application will work correctly. You may also decide to enforce codepage 437 (rather than checking the original console output codepage) to have full control over what is displayed, but you need to be aware, that your users may not be able to write their own name there if they're e.g. Dutch.

James Richters

2017-10-18 02:42

reporter   ~0103541

Last edited: 2017-10-18 02:51

View 2 revisions

Thank you for this really helpful information, Tomas.

I can understand the logic you provided.

I am trying to get this to work as you recommend, but I'm having some difficulty implementing it.

I am unable to run SetACP(); I get 'Error Identifier not found SetACP'
I am able to run GetACP() and it returns 1252.
I am able to run GetConsoleOutputCP and it returns 437.
I am able to run SetConsoleOutputCP() and change the console to some other CP, and verify that it has changed with GetConsoleOutputCP(), but none of this helps me SetACP which is what needs to happen for CRT to set it the way I want.


It would be so helpful if there was some information here:
http://wiki.freepascal.org/crt_unit

Is there some better documentation of the CRT unit somewhere?
if not, I will be happy to donate some time documenting the CRT Unit in detail.

I think the issue here is that the current behavior of the CRT unit is not compatible with the original Borland Pascal CRT unit, because it was never necessary to mess with code pages, however, I can understand why this became necessary. I think some good documentation on this would help a lot of people who are confused by this, especially when the output is as expected on Linux or Mac without messing with any codepages.

I would like to make 2 suggestions.
1. It seems inefficient to save, change, and restore the code page on every write, could this not be changed so it's saved and changed at the beginning of the program and restored at the end, or is there a reason it needs to be set for every write?

2. To simplify this whole codepage thing, could we have a variable in CRT called CRT_Codepage, this variable could default to 0, and a 0 would continue the existing behavior, however, if the Variable was set to a specific codepage, then it would use that page instead. Also a value of -1 could just skip all the codepage stuff and use the console as-is. Since CRT can only deal with 256 characters, having this variable would allow a much easier way to get characters from different codepages, simply do a CRT_Codepage=437 then Write(chr(201)) then CRT_Codepage= 1252 , Write... etc.. Then the program only needs Uses CRT and nothing else, it's easy to understand, and it works for everyone. It also has a benefit of being much more efficient if you define the page variable, then CRT does not need to read the system codepage, just set it to the variable.

Obviously, I can just modify my own personal copy of CRT to get by if there isn't an easy way to get SetACP working, but I would really like to address this issue once and for all so everyone can benefit from the effort. I think a CRT_Codepage variable would be great, but what does everyone else think? I am happy to implement and thoroughly test an improvement to CRT to solves this issue, but it would be best to be on a path that will be acceptable to everyone.

Tomas Hajny

2017-10-18 09:06

manager   ~0103545

Oops, you're indeed right, the function for setting the process codepage is apparently not available in Win32, sorry for this confusion. :-(

Yes, your suggested solution to provide a global flag influencing whether unit Crt changes the console output CP, or not, might be an option in my opinion.

James Richters

2017-10-18 12:47

reporter   ~0103551

Last edited: 2017-10-18 13:14

View 2 revisions

Since there is no way to change the process codepage, then is it really of any use to save the codepage, set the codepage, then reset the codepage back on every single read and write? Why not save and set it to the default in the initialization section, then restore it in finalization? Then simply provide a procedure that can either force to a specific codepage, restore to original, or once again set the codepage = getacp?

Changing it, then setting it back on every read and write is very misleading because if you do a GetConsoleOutputCP in your program to try to figure out why you aren't getting the characters you expect, it reports Codepage 437 even though 1252 is the only codepage that can possibly be used

Now with this kind of procedure, everything can be easily addressed with the CRT unit alone. This also allows a very easy way to use as many codepages as you want, so if someone wants to, they could use the box characters and put them around their name with all the special characters they want, even if the character they want is the same code as the box character.

I am submitting a diff here, please forgive me if it's not the correct way to generate it. I also have the changes here if the diff does not work:

https://github.com/graemeg/freepascal/compare/master...Zaaphod:CRT_Code_Page?expand=1#diff-68d19cec64cacca1542e421676b8357c

Personally, I think think the default should be to just leave the codepage alone or to set it to 437, because the intent of CRT is compatibility with Borland Pascal 7, however, I think the FPC CRT unit has been like this for so long now that it would be of less impact to the greatest number of people if the default was to behave the way it currently does, however some documentation is definitely in order.

I have also uploaded a sample program which demonstrates the codepage changes, and also shows using characters from different codepages on the same line.

James Richters

2017-10-18 12:48

reporter  

CRT.diff (5,500 bytes)
��diff --git a/packages/rtl-console/src/win/crt.pp b/packages/rtl-console/src/win/crt.pp

index 3a0668138d..d1df084ec8 100644

--- a/packages/rtl-console/src/win/crt.pp

+++ b/packages/rtl-console/src/win/crt.pp

@@ -18,6 +18,7 @@ interface

 

 {$i crth.inc}

 

+Procedure CrtCodePage (CCP:integer);

 procedure Window32(X1,Y1,X2,Y2: DWord);

 procedure GotoXY32(X,Y: DWord);

 function WhereX32: DWord;

@@ -34,6 +35,7 @@ uses

 var

     SaveCursorSize: Longint;

     Win32Platform : Longint; // pulling in sysutils changes exception behaviour

+    OldConsoleOutputCP : Word;

 

 {****************************************************************************

                            Low level Routines

@@ -95,6 +97,17 @@ end;

 ****************************************************************************}

 

 

+Procedure CrtCodePage (CCP:integer);

+Begin

+  If CCP = 0 then

+      SetConsoleOutputCP(GetACP)

+  ELSE

+    If CCP = -1 Then

+      SetConsoleOutputCP(OldConsoleOutputCP)

+    ELSE

+      SetConsoleOutputCP(CCP);

+End;

+

 procedure TextMode (Mode: word);

 begin

 end;

@@ -751,10 +764,10 @@ Procedure CrtWrite(var f : textrec);

 var

   i : longint;

   s : string;

-  OldConsoleOutputCP : Word;

+  //OldConsoleOutputCP : Word;

 begin

-  OldConsoleOutputCP:=GetConsoleOutputCP;

-  SetConsoleOutputCP(GetACP);

+  //OldConsoleOutputCP:=GetConsoleOutputCP;

+  //SetConsoleOutputCP(GetACP);

 

   GetScreenCursor(CurrX, CurrY);

   s:='';

@@ -781,7 +794,7 @@ begin

     WriteStr(s);

   SetScreenCursor(CurrX, CurrY);

 

-  SetConsoleOutputCP(OldConsoleOutputCP);

+  //SetConsoleOutputCP(OldConsoleOutputCP);

 

   f.bufpos:=0;

 end;

@@ -801,10 +814,10 @@ Procedure CrtRead(Var F: TextRec);

 

 var

   ch : Char;

-  OldConsoleOutputCP : Word;

+  //OldConsoleOutputCP : Word;

 Begin

-  OldConsoleOutputCP:=GetConsoleOutputCP;

-  SetConsoleOutputCP(GetACP);

+  //OldConsoleOutputCP:=GetConsoleOutputCP;

+  //SetConsoleOutputCP(GetACP);

 

   GetScreenCursor(CurrX,CurrY);

   f.bufpos:=0;

@@ -883,7 +896,7 @@ Begin

       end;

   until false;

 

-  SetConsoleOutputCP(OldConsoleOutputCP);

+  //SetConsoleOutputCP(OldConsoleOutputCP);

 	

   f.bufpos:=0;

   SetScreenCursor(CurrX, CurrY);

@@ -1023,6 +1036,9 @@ Initialization

   if PrevCtrlBreakHandler = TCtrlBreakHandler (pointer (-1)) then

    PrevCtrlBreakHandler := nil;

   CheckBreak := true;

+  OldConsoleOutputCP:=GetConsoleOutputCP;

+  CrtCodePage(0);

+

 

 finalization

   if beeperDevice <> INVALID_HANDLE_VALUE then begin

@@ -1030,4 +1046,5 @@ finalization

     CloseHandle(beeperDevice);

     DefineDosDevice(DDD_REMOVE_DEFINITION,'DosBeep','\Device\Beep');

   end;

+  CrtCodePage(-1);

 end. { unit Crt }

CRT.diff (5,500 bytes)

James Richters

2017-10-18 13:07

reporter  

TestCrtCodePage.pas (2,309 bytes)
Program CRTTEST;
Uses CRT, windows;
Var i: Byte;
Begin
Writeln('Code Page after Initialization: ',GetConsoleOutputCP);
textcolor(2);
For I:=33 to 255 do
Write(Chr(i),' ');
Writeln;
Readkey;
CrtCodePage(437); //set to Code Page 437
textcolor(3);
Writeln('Code Page 437: ',GetConsoleOutputCP);
For I:=33 to 255 do
Write(Chr(i),' ');
Writeln;
Readkey;
CrtCodePage(0);   //set to system Code Page reported by GetACP
textcolor(4);
Writeln('Code Page from GetACP ',GetACP,':  ',GetConsoleOutputCP);
For I:=33 to 255 do
Write(Chr(i),' ');
Writeln;
Readkey;
CrtCodePage(-1);   //restore Code Page original
textcolor(4);
Writeln('Code Page set back to Original: ',GetConsoleOutputCP);
For I:=33 to 255 do
Write(Chr(i),' ');
Writeln;
Readkey;

textcolor(13);
Writeln('         �����������������������������ͻ');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Write('         �     ');
CrtCodePage(0);
Write('���ͻ');
CrtCodePage(-1);
Writeln('    �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Textcolor(15);
Writeln('         �����������������������������͹');
Textcolor(11);
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �����������������������������ͼ');
Textcolor(10);
Readkey;
End.
TestCrtCodePage.pas (2,309 bytes)

James Richters

2017-10-18 13:12

reporter  

CrtCodePageTest.JPG (106,998 bytes)
CrtCodePageTest.JPG (106,998 bytes)

Tomas Hajny

2017-10-18 15:00

manager   ~0103554

The programmer may change the console codepage in his code and perform console output directly independent of Crt routines (his primary reason for using this unit may not be related to the output). That's the reason for switching the codepage back and forth. I'll have a look at the provided diff and let you know.

James Richters

2017-10-18 23:09

reporter   ~0103576

Thank you for your time and consideration of this issue.

I'm hoping it will not be necessary to switch the codepage on every read and every write... writing to console is slow enough as it is. However, if it's determined to still be necessary to switch the codepage every read and write, I can think of 2 possible ways it could be improved:

1. Store the parameter passed to CrtCodePage(), if it's a 0 then the user wants the console to automatically follow GetACP, so in this case, do the codepage switching... but if it's anything else then the programmer has specifically set the codepage to a specific state, and it should just be set and not switched. If the user wants it to automatically switch every read and write, he can always set CrtCodePage() back to 0.

2. Define a flag to enable/disable code page switching. This option allows more control because you could stop codepage switching with CrtCodePage(0) or use codepage switching with any other option. With this option, it would need to be determined what the default condition would be.

However, I think that if switching the code page every read and every write, is better handled outside the CRT unit by the programmer. The CrtCodePage procedure would make it very easy to create a simple function or procedure if and when this would ever be needed.
CrtCodePage(xxx); //change code page
Writeln(things);
CrtCodePage(-1); //put code page back
it's the same thing as what happens now, but not inside the CRT unit, so it would only be implemented if and when it was ever needed.

let me know your thoughts on the switching issue and the best way to deal with it.

James Richters

2017-10-20 17:33

reporter  

TestCodePages.pas (4,102 bytes)
Program TestCodePages;
Uses CRT;
Begin
   CrtCodePage(437);
   Textcolor(15);
   Writeln('Code Page Change Directly from 869 and 1119');
   Textcolor(12);
   Writeln('Approximately symbol is not displayed correctly');
   Textcolor(14);
   Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
   Write('     ',#186);
   Textcolor(10);
   CrtCodePage(869);
   Write('  ',#234); {Pi}
   Textcolor(11);
   CrtCodePage(1119);
   Write(' ',#247,' '); {Approximatly}
   CrtCodePage(437);
   Textcolor(13);
   Write('3.14159');
   Textcolor(14);
   Writeln(' ',#186);
   Write('     '#186);
   Textcolor(10);
   Write(' ',#251,'2 ');{Sqrt 2}
   Textcolor(11);
   CrtCodePage(1119);
   Write(#247,' '); {Approximatly}
   CrtCodePage(437);
   Textcolor(13);
   Write('1.414');
   Textcolor(14);
   Writeln('   ',#186);
   Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
   Writeln;
   Writeln;


   CrtCodePage(437);
   Textcolor(15);
   Writeln('Code Page Change to 437 between 869 and 1119');
   Textcolor(9);
   Writeln('Approximately symbol is displayed correctly');
   Textcolor(14);
   Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
   Write('     ',#186);
   Textcolor(10);
   CrtCodePage(869);
   Write('  ',#234); {Pi}
   CrtCodePage(437);
   Textcolor(11);
   CrtCodePage(1119);
   Write(' ',#247,' '); {Approximatly}
   CrtCodePage(437);
   Textcolor(13);
   Write('3.14159');
   Textcolor(14);
   Writeln(' ',#186);
   Write('     '#186);
   Textcolor(10);
   Write(' ',#251,'2 ');{Sqrt 2}
   Textcolor(11);
   CrtCodePage(1119);
   Write(#247,' '); {Approximatly}
   CrtCodePage(437);
   Textcolor(13);
   Write('1.414');
   Textcolor(14);
   Writeln('   ',#186);
   Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
   Writeln;
   Writeln;


   CrtCodePage(437);
   Textcolor(15);
   Writeln('Code Page Change to 0 (GetACP) between 869 and 1119');
   Textcolor(12);
   Writeln('Approximately symbol is not displayed correctly');
   Textcolor(14);
   Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
   Write('     ',#186);
   Textcolor(10);
   CrtCodePage(869);
   Write('  ',#234); {Pi}
   //CrtCodePage(437);  //with or without this makes no differnce
   CrtCodePage(0);
   Textcolor(11);
   CrtCodePage(1119);
   Write(' ',#247,' '); {Approximatly}
   CrtCodePage(437);
   Textcolor(13);
   Write('3.14159');
   Textcolor(14);
   Writeln(' ',#186);
   Write('     '#186);
   Textcolor(10);
   Write(' ',#251,'2 ');{Sqrt 2}
   Textcolor(11);
   CrtCodePage(1119);
   Write(#247,' '); {Approximatly}
   CrtCodePage(437);
   Textcolor(13);
   Write('1.414');
   Textcolor(14);
   Writeln('   ',#186);
   Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
   Writeln;
   Writeln;

   CrtCodePage(437);
   Textcolor(15);
   Writeln('Code Page -1 (Reset to origianl) between 869 and 1119');
   Textcolor(9);
   Writeln('Approximately symbol is displayed correctly');
   Textcolor(14);
   Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
   Write('     ',#186);
   Textcolor(10);
   CrtCodePage(869);
   Write('  ',#234); {Pi}
   CrtCodePage(-1);
   Textcolor(11);
   CrtCodePage(1119);
   Write(' ',#247,' '); {Approximatly}
   CrtCodePage(437);
   Textcolor(13);
   Write('3.14159');
   Textcolor(14);
   Writeln(' ',#186);
   Write('     '#186);
   Textcolor(10);
   Write(' ',#251,'2 ');{Sqrt 2}
   Textcolor(11);
   CrtCodePage(1119);
   Write(#247,' '); {Approximatly}
   CrtCodePage(437);
   Textcolor(13);
   Write('1.414');
   Textcolor(14);
   Writeln('   ',#186);
   Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
   Writeln;
   Writeln;
   Readkey;
End.
TestCodePages.pas (4,102 bytes)

James Richters

2017-10-20 17:35

reporter  

TestCodePage Output.JPG (108,069 bytes)
TestCodePage Output.JPG (108,069 bytes)

James Richters

2017-10-20 17:44

reporter   ~0103611

Last edited: 2017-10-20 17:45

View 2 revisions

I ran across something odd while doing more testing. For some reason, if I change to codepage 869 to get character 234 π(pi symbol) then just change to codepage 1119 to get character 247 ≈(approximately symbol) I am getting the wrong character. If I switch back to the original codepage first, then to 1119 I get the correct symbol, or if I switch to codepage 437, then to 1119 I get the correct symbol, but if I switch to the system codepage reported by GetACP, I get the incorrect symbol. The issue is easy enough to fix, I just change back to original before changing to codepage 1119... but I think it would be best if it did this in the CRT unit. I don't really understand why this is needed. I've uploaded my test program and a screenshot of the output.

Tomas Hajny

2017-10-20 19:19

manager   ~0103614

Responding to the comment (0103576) first:

1) Switching in the programmer code makes no sense, because the calls may need to be replicated on a zillion places (depending on the amount of WriteLn calls). I don't really understand the difference between the "flag" option and "storing the parameter" (to a flag???) option, but I believe that there should be simply an option.

2) Although your solution allowing to change any given codepage is nice, I wouldn't want to promote the possibility of directly specifying any particular codepage using a routine provided by the Crt unit, which is supposed to be a cross-platform unit, unless such a change may be implemented to other platforms as well (I suppose that this won't be the case). Obviously, the programmer may still do the same using the respective Win32 API function together with the new flag preventing any codepage changes before and after writing the string out, but then he should know that this solution is specific to a particular platform and it won't work elsewhere.

Regarding your new comment (0103611) - no, I don't know for sure, but it might be some MS Windows bug <- <- <- feature ( ;-) ) as well.

James Richters

2017-10-20 21:26

reporter   ~0103621

Last edited: 2017-10-20 21:27

View 2 revisions

1. I agree and a flag is much easier to implement and would be immediately compatible with the existing CRT unit if the flag defaulted to the existing behavior.


2. If I understand you correctly, the issue would be if a programmer tried to compile a program that was working on another platform, he would then have issues with the codepage functions of the windows CRT unit because they would not be implemented there, and the codes given would be different... so the incorrect character would be displayed. That makes sense to me, but that is also the problem we are trying to solve here. The problem is, that no matter what is done, using CRT on windows is not compatible with platforms that use full Unicode with the CRT unit, like Linux. the reason this issue even came up was that a programmer posted on the FPC mailing list that he had a program that worked fine in Linux with Unicode box characters and it wouldn't run correctly on windows, and not only that, it was impossible to make it work. So whether using characters from other codepages, or Unicode, there is no way to make the CRT unit 100% compatible across platforms no matter what you do. At least by giving the windows CRT unit the ability to change code pages, a programmer could make a cross-platform program that worked on both multiple platforms... all he would have to do is:
{$ifdef windows}
CrtCodepage(437)
Write(# 234)
{$endif}
{$ifdef linux}
Write('Ω');
{$endif}
If the CRTCodePage procedure was documented with cross-platform examples, and it was made clear that the procedure is only included to help with compatibility with Unicode capable platforms, then I would think that having a readily available solution to make windows programs compatible with other platforms would be beneficial. For other platforms, a null procedure could be included so a program written for windows would compile and run, perhaps the null procedures could generate a warning that it's a windows compatibility procedure. The characters displayed may not be the same as on windows, but they aren't going to be the same no matter what anyway. At least the warning could point a programmer in the right direction to figure out how to solve the issue.

The only other way to solve the issue is to figure out how to make CRT display Unicode... but that's a whole other issue altogether... I'm not sure it's even possible, and even if it is, you still need to be able to switch between Unicode and ASCII or you aren't compatible with Borland Pascal 7 anymore, although that's the easy part, just have another flag.

For now, I will make a .diif with only the flag to determine if the codepage is switched every read/write or not. It sounds to me like that would be the best place to start.

James Richters

2017-10-21 00:39

reporter  

CRT Flags Only.diff (11,496 bytes)
��diff --git a/packages/rtl-console/src/win/crt.pp b/packages/rtl-console/src/win/crt.pp

index de68c4e95d..3a0668138d 100644

--- a/packages/rtl-console/src/win/crt.pp

+++ b/packages/rtl-console/src/win/crt.pp

@@ -18,8 +18,6 @@ interface

 

 {$i crth.inc}

 

-Procedure CRT_Switch_CodePage(CSCP:Boolean);

-Procedure CRT_TP_Compatible(CTC:Boolean);

 procedure Window32(X1,Y1,X2,Y2: DWord);

 procedure GotoXY32(X,Y: DWord);

 function WhereX32: DWord;

@@ -36,13 +34,7 @@ uses

 var

     SaveCursorSize: Longint;

     Win32Platform : Longint; // pulling in sysutils changes exception behaviour

-    

-   TP_Compatible      : Boolean; // If True will not change the codepage to GetACP for compatibility

-                                      // with Turbo Pascal CRT Unit

-    

-   Switch_CodePage : Boolean; // If True  Codepage will be switched every read and write. 

-                                      // If False Codepage will only be set on Initialization and Finalization

-   OriginalConsoleOutputCP : Word;

+

 {****************************************************************************

                            Low level Routines

 ****************************************************************************}

@@ -101,28 +93,7 @@ end;

 {****************************************************************************

                              Public Crt Functions

 ****************************************************************************}

-Procedure CRT_Switch_CodePage(CSCP:Boolean);

-Begin

-    Switch_CodePage:=CSCP;

-    If Switch_CodePage then

-      SetConsoleOutputCP(OriginalConsoleOutputCP)   // Set Console back to Original since it will now be switched

-                                                    // every read and write

-    Else

-      If Not(TP_Compatible) then

-        SetConsoleOutputCP(GetACP);   // Set Console only once here if CRT_Switch_CodePage is False and

-                                      // if CRT_TP_Compatible is also False

-End;

-

-Procedure CRT_TP_Compatible(CTC:Boolean);

-Begin

-    TP_Compatible:=CTC;

-    If TP_Compatible Then

-      SetConsoleOutputCP(OriginalConsoleOutputCP)    // Set Console back to Original if CRT_TP_Compatible is True

-    Else

-      if Not(Switch_CodePage) Then

-        SetConsoleOutputCP(GetACP);   // Set Console only once here if CRT_Switch_CodePage is False and

-                                      // if CRT_TP_Compatible is False

-End;

+

 

 procedure TextMode (Mode: word);

 begin

@@ -780,14 +751,11 @@ Procedure CrtWrite(var f : textrec);

 var

   i : longint;

   s : string;

-  OldConsoleOutputCP : Word;

+  OldConsoleOutputCP : Word;

 begin

-  If Switch_CodePage and Not(TP_Compatible) then    //Switch Codepage every Read.

-    Begin

-      OldConsoleOutputCP:=GetConsoleOutputCP;

-      SetConsoleOutputCP(GetACP);

-    End;

-

+  OldConsoleOutputCP:=GetConsoleOutputCP;

+  SetConsoleOutputCP(GetACP);

+

   GetScreenCursor(CurrX, CurrY);

   s:='';

   for i:=0 to f.bufpos-1 do

@@ -796,7 +764,7 @@ begin

         if s<>'' then

           begin

             WriteStr(s);

-            s:='';

+ 	    s:='';

           end;

         WriteChar(f.buffer[i]);

       end

@@ -813,11 +781,7 @@ begin

     WriteStr(s);

   SetScreenCursor(CurrX, CurrY);

 

-  If Switch_CodePage then        //Restore CodePage Every Write

-    If TP_Compatible Then

-      SetConsoleOutputCP(OriginalConsoleOutputCP) 

-    Else

-      SetConsoleOutputCP(OldConsoleOutputCP);

+  SetConsoleOutputCP(OldConsoleOutputCP);

 

   f.bufpos:=0;

 end;

@@ -836,15 +800,12 @@ Procedure CrtRead(Var F: TextRec);

   end;

 

 var

-  ch : Char;

-  OldConsoleOutputCP : Word;

+  ch : Char;

+  OldConsoleOutputCP : Word;

 Begin

-  If Switch_CodePage and Not(TP_Compatible) then    //Switch Codepage every Read.

-    Begin

-      OldConsoleOutputCP:=GetConsoleOutputCP;

-      SetConsoleOutputCP(GetACP);

-    End;

-

+  OldConsoleOutputCP:=GetConsoleOutputCP;

+  SetConsoleOutputCP(GetACP);

+

   GetScreenCursor(CurrX,CurrY);

   f.bufpos:=0;

   f.bufend:=0;

@@ -922,12 +883,8 @@ Begin

       end;

   until false;

 

-  If Switch_CodePage then        //Restore CodePage Every Read

-    If TP_Compatible Then

-      SetConsoleOutputCP(OriginalConsoleOutputCP) 

-    Else

-      SetConsoleOutputCP(OldConsoleOutputCP);

-

+  SetConsoleOutputCP(OldConsoleOutputCP);

+	

   f.bufpos:=0;

   SetScreenCursor(CurrX, CurrY);

 End;

@@ -1027,13 +984,6 @@ Initialization

   LastMode := 3;

 

   SetActiveWindow(0);

-

-  OriginalConsoleOutputCP:=GetConsoleOutputCP;  //Aways save the original console codepage so it can be resored on exit.

-  Switch_CodePage:=True;  // Default to use GetACP CodePage to remain compatible with previous CRT version.

-  TP_Compatible:=False;   // Default to switch codepage every read and write to remain compatible with previous CRT version.

-                          

-  //CRT_Switch_CodePage(False); // With These defaults the code page does not need to be changed here.  If Switch_CodePage and

-                                // TP_Compatible both defaulted to False then CRT_Switch_CodePage(False) needs to be run here.

 

   {--------------------- Get the cursor size and such -----------------------}

   FillChar(CursorInfo, SizeOf(CursorInfo), 00);

@@ -1080,6 +1030,4 @@ finalization

     CloseHandle(beeperDevice);

     DefineDosDevice(DDD_REMOVE_DEFINITION,'DosBeep','\Device\Beep');

   end;

-  SetConsoleOutputCP(OriginalConsoleOutputCP);  //Always put the colsole back the way it was on exit.

-                                                //useful if the program is executed from command line.

 end. { unit Crt }

CRT Flags Only.diff (11,496 bytes)

James Richters

2017-10-21 00:46

reporter  

CRT_Flags_Only_TestCodePages.pas (5,538 bytes)
Program TestCodePages;
Uses CRT,Windows;
Begin
   CRT_Switch_CodePage(True);
   CRT_TP_Compatible(False);
   SetConsoleOutputCP(437);
   Textcolor(15);
   Writeln('CRT_Switch_CodePage(True) CRT_TP_Compatible(False)');
   Textcolor(12);
   Writeln('Not TP Compatible and Impossible to change Code Page');
   Textcolor(14);
   Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
   SetConsoleOutputCP(437);
   Write('     ',#186);
   Textcolor(10);
   SetConsoleOutputCP(869);
   Write('  ',#234); {Pi}
   Textcolor(11);
   SetConsoleOutputCP(1119);
   Write(' ',#247,' '); {Approximatly}
   SetConsoleOutputCP(437);
   Textcolor(13);
   Write('3.14159');
   Textcolor(14);
   Writeln(' ',#186);
   Write('     '#186);
   Textcolor(10);
   Write(' ',#251,'2 ');{Sqrt 2}
   Textcolor(11);
   SetConsoleOutputCP(1119);
   Write(#247,' '); {Approximatly}
   SetConsoleOutputCP(437);
   Textcolor(13);
   Write('1.414');
   Textcolor(14);
   Writeln('   ',#186);
   Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
   Writeln;
   Writeln;


   CRT_Switch_CodePage(False);
   CRT_TP_Compatible(False);
   Textcolor(15);
   Writeln('CRT_Switch_CodePage(False) CRT_TP_Compatible(False)');
   Textcolor(13);
   Writeln('Not Initially TP Compatible, but now Possible to change Code Page');
   Textcolor(14);
   Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
   Write('     ',#186);
   Textcolor(10);
   SetConsoleOutputCP(869);
   Write('  ',#234); {Pi}
   Textcolor(11);
   SetConsoleOutputCP(437);
   SetConsoleOutputCP(1119);
   Write(' ',#247,' '); {Approximatly}
   Textcolor(13);
   Write('3.14159');
   Textcolor(14);
   Writeln(' ',#186);
   Write('     '#186);
   Textcolor(10);
   SetConsoleOutputCP(1119);
   Write(' ',#251,'2 ');{Sqrt 2}
   Textcolor(11);
   SetConsoleOutputCP(1119);
   Write(#247,' '); {Approximatly}
   SetConsoleOutputCP(437);
   Textcolor(13);
   Write('1.414');
   Textcolor(14);
   Writeln('   ',#186);
   Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
   Writeln;
   Writeln;


   CRT_Switch_CodePage(False);
   CRT_TP_Compatible(True);
   Textcolor(15);
   Writeln('CRT_Switch_CodePage(False) CRT_TP_Compatible(True)  No CP(437)s');
   Textcolor(12);
   Writeln('TP Compatible, & Possible to change Code Page, Code Page will remain until changed');
   Textcolor(14);
   Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
   Write('     ',#186);
   Textcolor(10);
   SetConsoleOutputCP(869);
   Write('  ',#234); {Pi}
   Textcolor(11);
   SetConsoleOutputCP(1119);
   Write(' ',#247,' '); {Approximatly}
   Textcolor(13);
   Write('3.14159');
   Textcolor(14);
   Writeln(' ',#186);
   Write('     '#186);
   Textcolor(10);
   Write(' ',#251,'2 ');{Sqrt 2}
   Textcolor(11);
   SetConsoleOutputCP(1119);
   Write(#247,' '); {Approximatly}
   Textcolor(13);
   Write('1.414');
   Textcolor(14);
   Writeln('   ',#186);
   Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
   Writeln;
   Writeln;

   CRT_Switch_CodePage(False);
   CRT_TP_Compatible(True);
   Textcolor(15);
   Writeln('CRT_Switch_CodePage(False) CRT_TP_Compatible(True)  With CP(437)s');
   Textcolor(9);
   Writeln('TP Compatible, & Possible to change Code Page, Code Page will remain until changed');
   Textcolor(14);
   Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
   Write('     ',#186);
   Textcolor(10);
   SetConsoleOutputCP(869);
   Write('  ',#234); {Pi}
   SetConsoleOutputCP(437);
   Textcolor(11);
   SetConsoleOutputCP(1119);
   Write(' ',#247,' '); {Approximatly}
   SetConsoleOutputCP(437);
   Textcolor(13);
   Write('3.14159');
   Textcolor(14);
   Writeln(' ',#186);
   Write('     '#186);
   Textcolor(10);
   Write(' ',#251,'2 ');{Sqrt 2}
   Textcolor(11);
   SetConsoleOutputCP(1119);
   Write(#247,' '); {Approximatly}
   SetConsoleOutputCP(437);
   Textcolor(13);
   Write('1.414');
   Textcolor(14);
   Writeln('   ',#186);
   Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
   Writeln;
   Writeln;

   CRT_Switch_CodePage(True);
   CRT_TP_Compatible(True);
   Textcolor(15);
   Writeln('CRT_Switch_CodePage(True) CRT_TP_Compatible(True)  No CP(437)s');
   Textcolor(9);
   Writeln('TP Compatible, & Possible to change Code Page, But Code Page will reset to original after every write');
   Textcolor(14);
   Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
   Write('     ',#186);
   Textcolor(10);
   SetConsoleOutputCP(869);
   Write('  ',#234); {Pi}
   Textcolor(11);
   SetConsoleOutputCP(1119);
   Write(' ',#247,' '); {Approximatly}
   Textcolor(13);
   Write('3.14159');
   Textcolor(14);
   Writeln(' ',#186);
   Write('     '#186);
   Textcolor(10);
   Write(' ',#251,'2 ');{Sqrt 2}
   Textcolor(11);
   SetConsoleOutputCP(1119);
   Write(#247,' '); {Approximatly}
   Textcolor(13);
   Write('1.414');
   Textcolor(14);
   Writeln('   ',#186);
   Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
   Writeln;
   Writeln;
   Readkey;
End.

James Richters

2017-10-21 00:47

reporter  

James Richters

2017-10-21 01:02

reporter   ~0103632

Last edited: 2017-10-21 01:16

View 3 revisions

I have uploaded "CRT Flags Only.diff" This has 2 flags and 2 procedures to set them and configure the code pages as needed so correct handling of the code pages will happen after the procedures are run.

Procedures are:
Crt_TP_Compatibile() - When True it will not change the code page to GetACP. The default is False so it will function the same as it does now by default.

Crt_Switch_CodePage() - When True and CRT_TP_Comaptible is False, the code pages will switch with every read and every write as they do now. When false The code page will be set as needed only once when the procedure is called and remain set. This is set to True by default so initially, CRT will behave as it does now.

There is the possibility to set Crt_TP_Compatible and CRT_Switch_CodePage both to true when in this mode, it will not change the codepage before read or write, but it will reset it back to the original after the read or write. This allows a change for a single operation without the need to reset it after.

The code page is always restored to the original in Finialization so if your program is run from a command prompt (or run from the FPC Text IDE) the codepage will be the same as it was before the program was run. This needed if CRT_Switch_CodePage is false, or if Crt_TP_Comaptible is true since you could have changed the codepage during your program, or it could still be set to GetACP.

I have provided a test program and output that illustrates the different modes of these flags. (note: comment out the first 2 lines to demonstrate the default condition is as expected) After working on the test program, I realized that there isn't really a need for the CRT unit to change the codepage to a specific one, as all you need is SetConsoleOutputCP(869); And you could always use CRT_TP_Compatible(true) to reset to the original if you don't want to bother storing it yourself.

more details are in the commit on GitHub at:
https://github.com/Zaaphod/freepascal/commit/887cb454cdeece630db1190b850f37a81f9342cb

James Richters

2017-10-21 01:34

reporter   ~0103633

I am curious what the thoughts are on moving:

function GetScreenHeight : DWord;
function GetScreenWidth : DWord;

From Private to Public?
These very useful functions are already there and since windows consoles are completely variable and draggable, they would be very handy functions to be available to the Programmer. I suspect that the original DOS version of CRT had them private because the screen was not so easy to change on the fly, and if you did change it with a mode command, you know what you just set it to, so no need to make them available to the programmer. Consoles are not so rigid anymore.

I believe moving these to public is something that could be done cross-platform as well. It's not super necessary because the programmer could get this information himself, but, many don't know they could get it (like me until I saw them there) It does seem a shame to duplicate code when there are perfectly good functions already in place.

James Richters

2017-10-22 19:35

reporter   ~0103687

Last edited: 2017-10-22 20:08

View 5 revisions

I discovered a bug in CRT.

There is an incorrect type for CtrlKeyState in Function RemapScanCode:
Function RemapScanCode (ScanCode: byte; CtrlKeyState: byte; keycode:longint): byte;

CtrlKeyState is passed from KeyEvent.dwControlKeyState and is defined as a Byte, however according to the documentation of dwControlkeyState here:
https://docs.microsoft.com/en-us/windows/console/key-event-record-str

dwControlKeyState is a dword variable.
I encountered a range check error when pushing the right arrow key and received a range check error. I found that the dwControlKeyState being received was $0120 thus putting it out of range of a byte.

with CtrlKeyState properly defined as a dWord, the function now operates correctly and does not produce a range check error, and also returns the correct remapping of the key.

I also noticed the type of wVirtualScanCode is a word but was defined as a byte in the function and wVirtualKeyCode is also a word by defined as a longint. I properly defined these as well. The longint instead of word would never matter, but the byte instead of a word for the scancode could cause a range check issue for keyboards that could produce codes out of range of a byte.

The only way CRT could have worked at all is if it was compiled with range checking turned off, but for some reason that I don't understand, I turned off range checking in the FPC textmode IDE and compiled the original CRT, and still got the range check error.

I have added the correction and re-submitted my .diff

I also noticed that I have been creating my .diff files incorrectly, I had them reversed. The new one appears to be correct. Please use CRT_Flags_And_RemapScanCode_2.diff. I don't know how to delete the old incorrect files. Please let me know if there is any difficulty with my .diff file.

Changes are also here:
https://github.com/Zaaphod/freepascal/commit/4c5f10a17ef163976ae48f4f465390455920fbee

James Richters

2017-10-22 19:37

reporter  

CRT_Flags_and_RemapScanCode.diff (12,336 bytes)
��diff --git a/packages/rtl-console/src/win/crt.pp b/packages/rtl-console/src/win/crt.pp

index 3a0668138d..8bac8f06ea 100644

--- a/packages/rtl-console/src/win/crt.pp

+++ b/packages/rtl-console/src/win/crt.pp

@@ -18,6 +18,8 @@ interface

 

 {$i crth.inc}

 

+Procedure CRT_Switch_CodePage(CSCP:Boolean);

+Procedure CRT_TP_Compatible(CTC:Boolean);

 procedure Window32(X1,Y1,X2,Y2: DWord);

 procedure GotoXY32(X,Y: DWord);

 function WhereX32: DWord;

@@ -34,7 +36,13 @@ uses

 var

     SaveCursorSize: Longint;

     Win32Platform : Longint; // pulling in sysutils changes exception behaviour

-

+    

+   TP_Compatible      : Boolean; // If True will not change the codepage to GetACP for compatibility

+                                      // with Turbo Pascal CRT Unit

+    

+   Switch_CodePage : Boolean; // If True  Codepage will be switched every read and write. 

+                                      // If False Codepage will only be set on Initialization and Finalization

+   OriginalConsoleOutputCP : Word;

 {****************************************************************************

                            Low level Routines

 ****************************************************************************}

@@ -93,7 +101,28 @@ end;

 {****************************************************************************

                              Public Crt Functions

 ****************************************************************************}

-

+Procedure CRT_Switch_CodePage(CSCP:Boolean);

+Begin

+    Switch_CodePage:=CSCP;

+    If Switch_CodePage then

+      SetConsoleOutputCP(OriginalConsoleOutputCP)   // Set Console back to Original since it will now be switched

+                                                    // every read and write

+    Else

+      If Not(TP_Compatible) then

+        SetConsoleOutputCP(GetACP);   // Set Console only once here if CRT_Switch_CodePage is False and

+                                      // if CRT_TP_Compatible is also False

+End;

+

+Procedure CRT_TP_Compatible(CTC:Boolean);

+Begin

+    TP_Compatible:=CTC;

+    If TP_Compatible Then

+      SetConsoleOutputCP(OriginalConsoleOutputCP)    // Set Console back to Original if CRT_TP_Compatible is True

+    Else

+      if Not(Switch_CodePage) Then

+        SetConsoleOutputCP(GetACP);   // Set Console only once here if CRT_Switch_CodePage is False and

+                                      // if CRT_TP_Compatible is False

+End;

 

 procedure TextMode (Mode: word);

 begin

@@ -260,7 +289,7 @@ var

    DoingNumChars: Boolean;

    DoingNumCode: Byte;

 

-Function RemapScanCode (ScanCode: byte; CtrlKeyState: byte; keycode:longint): byte;

+Function RemapScanCode (ScanCode: byte; CtrlKeyState: word; keycode:longint): byte;

   { Several remappings of scancodes are necessary to comply with what

     we get with MSDOS. Special Windows keys, as Alt-Tab, Ctrl-Esc etc.

     are excluded }

@@ -751,11 +780,14 @@ Procedure CrtWrite(var f : textrec);

 var

   i : longint;

   s : string;

-  OldConsoleOutputCP : Word;

+  OldConsoleOutputCP : Word;

 begin

-  OldConsoleOutputCP:=GetConsoleOutputCP;

-  SetConsoleOutputCP(GetACP);

-

+  If Switch_CodePage and Not(TP_Compatible) then    //Switch Codepage every Read.

+    Begin

+      OldConsoleOutputCP:=GetConsoleOutputCP;

+      SetConsoleOutputCP(GetACP);

+    End;

+

   GetScreenCursor(CurrX, CurrY);

   s:='';

   for i:=0 to f.bufpos-1 do

@@ -764,7 +796,7 @@ begin

         if s<>'' then

           begin

             WriteStr(s);

- 	    s:='';

+            s:='';

           end;

         WriteChar(f.buffer[i]);

       end

@@ -781,7 +813,11 @@ begin

     WriteStr(s);

   SetScreenCursor(CurrX, CurrY);

 

-  SetConsoleOutputCP(OldConsoleOutputCP);

+  If Switch_CodePage then        //Restore CodePage Every Write

+    If TP_Compatible Then

+      SetConsoleOutputCP(OriginalConsoleOutputCP) 

+    Else

+      SetConsoleOutputCP(OldConsoleOutputCP);

 

   f.bufpos:=0;

 end;

@@ -800,12 +836,15 @@ Procedure CrtRead(Var F: TextRec);

   end;

 

 var

-  ch : Char;

-  OldConsoleOutputCP : Word;

+  ch : Char;

+  OldConsoleOutputCP : Word;

 Begin

-  OldConsoleOutputCP:=GetConsoleOutputCP;

-  SetConsoleOutputCP(GetACP);

-

+  If Switch_CodePage and Not(TP_Compatible) then    //Switch Codepage every Read.

+    Begin

+      OldConsoleOutputCP:=GetConsoleOutputCP;

+      SetConsoleOutputCP(GetACP);

+    End;

+

   GetScreenCursor(CurrX,CurrY);

   f.bufpos:=0;

   f.bufend:=0;

@@ -883,8 +922,12 @@ Begin

       end;

   until false;

 

-  SetConsoleOutputCP(OldConsoleOutputCP);

-	

+  If Switch_CodePage then        //Restore CodePage Every Read

+    If TP_Compatible Then

+      SetConsoleOutputCP(OriginalConsoleOutputCP) 

+    Else

+      SetConsoleOutputCP(OldConsoleOutputCP);

+

   f.bufpos:=0;

   SetScreenCursor(CurrX, CurrY);

 End;

@@ -984,6 +1027,13 @@ Initialization

   LastMode := 3;

 

   SetActiveWindow(0);

+

+  OriginalConsoleOutputCP:=GetConsoleOutputCP;  //Aways save the original console codepage so it can be resored on exit.

+  Switch_CodePage:=True;  // Default to use GetACP CodePage to remain compatible with previous CRT version.

+  TP_Compatible:=False;   // Default to switch codepage every read and write to remain compatible with previous CRT version.

+                          

+  //CRT_Switch_CodePage(False); // With These defaults the code page does not need to be changed here.  If Switch_CodePage and

+                                // TP_Compatible both defaulted to False then CRT_Switch_CodePage(False) needs to be run here.

 

   {--------------------- Get the cursor size and such -----------------------}

   FillChar(CursorInfo, SizeOf(CursorInfo), 00);

@@ -1030,4 +1080,6 @@ finalization

     CloseHandle(beeperDevice);

     DefineDosDevice(DDD_REMOVE_DEFINITION,'DosBeep','\Device\Beep');

   end;

+  SetConsoleOutputCP(OriginalConsoleOutputCP);  //Always put the colsole back the way it was on exit.

+                                                //useful if the program is executed from command line.

 end. { unit Crt }

James Richters

2017-10-22 20:00

reporter  

CRT_Flags_And_RemapScanCode_2.diff (12,332 bytes)
��diff --git a/packages/rtl-console/src/win/crt.pp b/packages/rtl-console/src/win/crt.pp

index 3a0668138d..ab29f94374 100644

--- a/packages/rtl-console/src/win/crt.pp

+++ b/packages/rtl-console/src/win/crt.pp

@@ -18,6 +18,8 @@ interface

 

 {$i crth.inc}

 

+Procedure CRT_Switch_CodePage(CSCP:Boolean);

+Procedure CRT_TP_Compatible(CTC:Boolean);

 procedure Window32(X1,Y1,X2,Y2: DWord);

 procedure GotoXY32(X,Y: DWord);

 function WhereX32: DWord;

@@ -34,7 +36,13 @@ uses

 var

     SaveCursorSize: Longint;

     Win32Platform : Longint; // pulling in sysutils changes exception behaviour

-

+    

+   TP_Compatible      : Boolean; // If True will not change the codepage to GetACP for compatibility

+                                      // with Turbo Pascal CRT Unit

+    

+   Switch_CodePage : Boolean; // If True  Codepage will be switched every read and write. 

+                                      // If False Codepage will only be set on Initialization and Finalization

+   OriginalConsoleOutputCP : Word;

 {****************************************************************************

                            Low level Routines

 ****************************************************************************}

@@ -93,7 +101,28 @@ end;

 {****************************************************************************

                              Public Crt Functions

 ****************************************************************************}

-

+Procedure CRT_Switch_CodePage(CSCP:Boolean);

+Begin

+    Switch_CodePage:=CSCP;

+    If Switch_CodePage then

+      SetConsoleOutputCP(OriginalConsoleOutputCP)   // Set Console back to Original since it will now be switched

+                                                    // every read and write

+    Else

+      If Not(TP_Compatible) then

+        SetConsoleOutputCP(GetACP);   // Set Console only once here if CRT_Switch_CodePage is False and

+                                      // if CRT_TP_Compatible is also False

+End;

+

+Procedure CRT_TP_Compatible(CTC:Boolean);

+Begin

+    TP_Compatible:=CTC;

+    If TP_Compatible Then

+      SetConsoleOutputCP(OriginalConsoleOutputCP)    // Set Console back to Original if CRT_TP_Compatible is True

+    Else

+      if Not(Switch_CodePage) Then

+        SetConsoleOutputCP(GetACP);   // Set Console only once here if CRT_Switch_CodePage is False and

+                                      // if CRT_TP_Compatible is False

+End;

 

 procedure TextMode (Mode: word);

 begin

@@ -260,7 +289,7 @@ var

    DoingNumChars: Boolean;

    DoingNumCode: Byte;

 

-Function RemapScanCode (ScanCode: byte; CtrlKeyState: byte; keycode:longint): byte;

+Function RemapScanCode (ScanCode: word; CtrlKeyState: dword; keycode:word): byte;

   { Several remappings of scancodes are necessary to comply with what

     we get with MSDOS. Special Windows keys, as Alt-Tab, Ctrl-Esc etc.

     are excluded }

@@ -751,11 +780,14 @@ Procedure CrtWrite(var f : textrec);

 var

   i : longint;

   s : string;

-  OldConsoleOutputCP : Word;

+  OldConsoleOutputCP : Word;

 begin

-  OldConsoleOutputCP:=GetConsoleOutputCP;

-  SetConsoleOutputCP(GetACP);

-

+  If Switch_CodePage and Not(TP_Compatible) then    //Switch Codepage every Read.

+    Begin

+      OldConsoleOutputCP:=GetConsoleOutputCP;

+      SetConsoleOutputCP(GetACP);

+    End;

+

   GetScreenCursor(CurrX, CurrY);

   s:='';

   for i:=0 to f.bufpos-1 do

@@ -764,7 +796,7 @@ begin

         if s<>'' then

           begin

             WriteStr(s);

- 	    s:='';

+            s:='';

           end;

         WriteChar(f.buffer[i]);

       end

@@ -781,7 +813,11 @@ begin

     WriteStr(s);

   SetScreenCursor(CurrX, CurrY);

 

-  SetConsoleOutputCP(OldConsoleOutputCP);

+  If Switch_CodePage then        //Restore CodePage Every Write

+    If TP_Compatible Then

+      SetConsoleOutputCP(OriginalConsoleOutputCP) 

+    Else

+      SetConsoleOutputCP(OldConsoleOutputCP);

 

   f.bufpos:=0;

 end;

@@ -800,12 +836,15 @@ Procedure CrtRead(Var F: TextRec);

   end;

 

 var

-  ch : Char;

-  OldConsoleOutputCP : Word;

+  ch : Char;

+  OldConsoleOutputCP : Word;

 Begin

-  OldConsoleOutputCP:=GetConsoleOutputCP;

-  SetConsoleOutputCP(GetACP);

-

+  If Switch_CodePage and Not(TP_Compatible) then    //Switch Codepage every Read.

+    Begin

+      OldConsoleOutputCP:=GetConsoleOutputCP;

+      SetConsoleOutputCP(GetACP);

+    End;

+

   GetScreenCursor(CurrX,CurrY);

   f.bufpos:=0;

   f.bufend:=0;

@@ -883,8 +922,12 @@ Begin

       end;

   until false;

 

-  SetConsoleOutputCP(OldConsoleOutputCP);

-	

+  If Switch_CodePage then        //Restore CodePage Every Read

+    If TP_Compatible Then

+      SetConsoleOutputCP(OriginalConsoleOutputCP) 

+    Else

+      SetConsoleOutputCP(OldConsoleOutputCP);

+

   f.bufpos:=0;

   SetScreenCursor(CurrX, CurrY);

 End;

@@ -984,6 +1027,13 @@ Initialization

   LastMode := 3;

 

   SetActiveWindow(0);

+

+  OriginalConsoleOutputCP:=GetConsoleOutputCP;  //Aways save the original console codepage so it can be resored on exit.

+  Switch_CodePage:=True;  // Default to use GetACP CodePage to remain compatible with previous CRT version.

+  TP_Compatible:=False;   // Default to switch codepage every read and write to remain compatible with previous CRT version.

+                          

+  //CRT_Switch_CodePage(False); // With These defaults the code page does not need to be changed here.  If Switch_CodePage and

+                                // TP_Compatible both defaulted to False then CRT_Switch_CodePage(False) needs to be run here.

 

   {--------------------- Get the cursor size and such -----------------------}

   FillChar(CursorInfo, SizeOf(CursorInfo), 00);

@@ -1030,4 +1080,6 @@ finalization

     CloseHandle(beeperDevice);

     DefineDosDevice(DDD_REMOVE_DEFINITION,'DosBeep','\Device\Beep');

   end;

+  SetConsoleOutputCP(OriginalConsoleOutputCP);  //Always put the colsole back the way it was on exit.

+                                                //useful if the program is executed from command line.

 end. { unit Crt }

Tomas Hajny

2017-12-05 02:12

manager   ~0104441

Thanks, patch applied with slight changes - primarily different names of the flags and procedures (avoided underscores, removed Crt unit name prefix for procedures, avoided the potentially misleading TP reference). I also removed the part restoring the codepage to the original setting on program start at the end of CrtRead/CrtWrite if it was not changed to ACP at the beginning, because I don't see a reason why this should be done.

I applied the changes in two revisions, because the RemapScanCodes changes are not related to the other part.

Sorry for the long delay.

James Richters

2017-12-06 18:56

reporter   ~0104539

Last edited: 2017-12-11 16:13

View 4 revisions

Thank you for adjusting my patch and applying it. I was testing it and found a few anomalies.

1. If you set SetUseACP(False); first then SetSafeCPSwitching(False); it works as expected, however, if you reverse them and SetSafeCPSwitching(False); and then do SetUseACP(False); results are not as expected and the codepage is still left set to ACP.

2. There is a bug, possibly with windows itself that will not always set the correct code page if it is not reverted back to the original one first... it is strange but repeatble with a sample program, and that was the reason for resetting back to original if SafeCPSwtiching was True and UseACP was false... it gives the programmer an easy way to work around the bug, and since the feature can be easily controlled with the SafeCPSwitching flag and the logic is already in there for UseACP, it might as well be allowed to be used to also fix the windows bug.

I have uploaded a patch that fixes both these issues. and also provided some sample programs that demonstrate them:

Asciibox2_SafeSwitch_First.pas
shows how the order of the flags makes a difference and how my new patch resolves the issue. I think it makes is less confusing for the programmer if the order the flags are is unimportant.

CRT_TestCodePages.pas
shows how the code page will not set correctly if going from one to another without going back to the original first. lines 158 to 164 show this effect:
   SetConsoleOutputCP(869);
   Write(' ',# 234); {Pi}
   Textcolor(11);
   SetConsoleOutputCP(1119);
   Write(' ',# 247,' '); {Approximatly}
   Textcolor(13);
   Write('3.14159');
as it is, the above code does not properly change to code page 1119 however with the proposed changes setting UseACP to False and SafeCPSwitching to True would allow the above code to run as expected, as SafeCPSwithcing would reset the codepage back to the original after each write. I am wondering if this is the reason for the code page switching in the first place? in any event, allowing SafeCPSwitching allows a quick workaround.


I also think it would be beneficial to document these changes on the page at:
https://www.freepascal.org/docs-html/rtl/crt/index.html
I am willing to put some time into composing such documentation, how would I submit proposed changes?

James Richters

2017-12-06 18:57

reporter  

CRT_fix.diff (3,870 bytes)
��diff --git a/packages/rtl-console/src/win/crt.pp b/packages/rtl-console/src/win/crt.pp

index ab0a617166..92c7b81048 100644

--- a/packages/rtl-console/src/win/crt.pp

+++ b/packages/rtl-console/src/win/crt.pp

@@ -123,12 +123,12 @@ procedure SetUseACP(ACP:Boolean);

 begin

     UseACP:=ACP;

     if UseACP then

-      if not(SafeCPSwitching) then

-        SetConsoleOutputCP(GetACP)   // Set console CP only once here if SafeCPSwitching is False and

-                                     // if UseACP is True

-      else

-       SetConsoleOutputCP(OriginalConsoleOutputCP)    // Set console back to original if UseACP is False

+      Begin

+        if not(SafeCPSwitching) then

+          SetConsoleOutputCP(GetACP);   // Set console CP only once here if SafeCPSwitching is False and

+      End                               // if UseACP is True

     else

+      SetConsoleOutputCP(OriginalConsoleOutputCP);    // Set console back to original if UseACP is False

 end;

 

 procedure TextMode (Mode: word);

@@ -820,8 +820,11 @@ begin

     WriteStr(s);

   SetScreenCursor(CurrX, CurrY);

 

-  if SafeCPSwitching and UseACP then     //restore codepage on every write if set previously

-    SetConsoleOutputCP(OldConsoleOutputCP);

+  if SafeCPSwitching then

+    if UseACP then     //restore codepage on every write

+      SetConsoleOutputCP(OldConsoleOutputCP)

+    else

+      SetConsoleOutputCP(OriginalConsoleOutputCP);

 

   f.bufpos:=0;

 end;

@@ -926,9 +929,11 @@ begin

       end;

   until false;

 

-  if SafeCPSwitching and UseACP then    //Restore codepage on every Read if set previously

-    SetConsoleOutputCP(OldConsoleOutputCP);

-	

+  if SafeCPSwitching then

+    if UseACP then     //restore codepage on every read

+      SetConsoleOutputCP(OldConsoleOutputCP)

+    else

+      SetConsoleOutputCP(OriginalConsoleOutputCP);

   f.bufpos:=0;

   SetScreenCursor(CurrX, CurrY);

 End;

CRT_fix.diff (3,870 bytes)

James Richters

2017-12-06 19:02

reporter  

CRT_TestCodePages.pas (5,450 bytes)
Program TestCodePages;
Uses CRT,Windows;
Begin
   SetSafeCPSwitching(True);
   SetUseACP(True);
   SetConsoleOutputCP(437);
   Textcolor(15);
   Writeln('SetSafeCPSwitching(True) SetUseACP(True)');
   Textcolor(12);
   Writeln('Not TP Compatible and Impossible to change Code Page');
   Textcolor(14);
   Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
   SetConsoleOutputCP(437);
   Write('     ',#186);
   Textcolor(10);
   SetConsoleOutputCP(869);
   Write('  ',#234); {Pi}
   Textcolor(11);
   SetConsoleOutputCP(1119);
   Write(' ',#247,' '); {Approximatly}
   SetConsoleOutputCP(437);
   Textcolor(13);
   Write('3.14159');
   Textcolor(14);
   Writeln(' ',#186);
   Write('     '#186);
   Textcolor(10);
   Write(' ',#251,'2 ');{Sqrt 2}
   Textcolor(11);
   SetConsoleOutputCP(1119);
   Write(#247,' '); {Approximatly}
   SetConsoleOutputCP(437);
   Textcolor(13);
   Write('1.414');
   Textcolor(14);
   Writeln('   ',#186);
   Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
   Writeln;
   Writeln;


   SetSafeCPSwitching(False);
   SetUseACP(True);
   Textcolor(15);
   Writeln('SetSafeCPSwitching(False) SetUseACP(True)');
   Textcolor(13);
   Writeln('Not Initially TP Compatible, but now Possible to change Code Page');
   Textcolor(14);
   Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
   Write('     ',#186);
   Textcolor(10);
   SetConsoleOutputCP(869);
   Write('  ',#234); {Pi}
   Textcolor(11);
   SetConsoleOutputCP(437);
   SetConsoleOutputCP(1119);
   Write(' ',#247,' '); {Approximatly}
   Textcolor(13);
   Write('3.14159');
   Textcolor(14);
   Writeln(' ',#186);
   Write('     '#186);
   Textcolor(10);
   SetConsoleOutputCP(1119);
   Write(' ',#251,'2 ');{Sqrt 2}
   Textcolor(11);
   SetConsoleOutputCP(1119);
   Write(#247,' '); {Approximatly}
   SetConsoleOutputCP(437);
   Textcolor(13);
   Write('1.414');
   Textcolor(14);
   Writeln('   ',#186);
   Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
   Writeln;
   Writeln;


   SetSafeCPSwitching(False);
   SetUseACP(False);
   Textcolor(15);
   Writeln('SetSafeCPSwitching(False) SetUseACP(False)  No CP(437)s');
   Textcolor(12);
   Writeln('TP Compatible, & Possible to change Code Page, Code Page will remain until changed');
   Textcolor(14);
   Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
   Write('     ',#186);
   Textcolor(10);
   SetConsoleOutputCP(869);
   Write('  ',#234); {Pi}
   Textcolor(11);
   SetConsoleOutputCP(1119);
   Write(' ',#247,' '); {Approximatly}
   Textcolor(13);
   Write('3.14159');
   Textcolor(14);
   Writeln(' ',#186);
   Write('     '#186);
   Textcolor(10);
   Write(' ',#251,'2 ');{Sqrt 2}
   Textcolor(11);
   SetConsoleOutputCP(1119);
   Write(#247,' '); {Approximatly}
   Textcolor(13);
   Write('1.414');
   Textcolor(14);
   Writeln('   ',#186);
   Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
   Writeln;
   Writeln;

   SetSafeCPSwitching(False);
   SetUseACP(False);
   Textcolor(15);
   Writeln('SetSafeCPSwitching(False) SetUseACP(False)  With CP(437)s');
   Textcolor(9);
   Writeln('TP Compatible, & Possible to change Code Page, Code Page will remain until changed');
   Textcolor(14);
   Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
   Write('     ',#186);
   Textcolor(10);
   SetConsoleOutputCP(869);
   Write('  ',#234); {Pi}
   SetConsoleOutputCP(437);
   Textcolor(11);
   SetConsoleOutputCP(1119);
   Write(' ',#247,' '); {Approximatly}
   SetConsoleOutputCP(437);
   Textcolor(13);
   Write('3.14159');
   Textcolor(14);
   Writeln(' ',#186);
   Write('     '#186);
   Textcolor(10);
   Write(' ',#251,'2 ');{Sqrt 2}
   Textcolor(11);
   SetConsoleOutputCP(1119);
   Write(#247,' '); {Approximatly}
   SetConsoleOutputCP(437);
   Textcolor(13);
   Write('1.414');
   Textcolor(14);
   Writeln('   ',#186);
   Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
   Writeln;
   Writeln;

   SetSafeCPSwitching(True);
   SetUseACP(False);
   Textcolor(15);
   Writeln('SetSafeCPSwitching(True) SetUseACP(False)  No CP(437)s');
   Textcolor(9);
   Writeln('TP Compatible, & Possible to change Code Page, But Code Page will reset to original after every write');
   Textcolor(14);
   Writeln('     ',#201,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#187);
   Write('     ',#186);
   Textcolor(10);
   SetConsoleOutputCP(869);
   Write('  ',#234); {Pi}
   Textcolor(11);
   SetConsoleOutputCP(1119);
   Write(' ',#247,' '); {Approximatly}
   Textcolor(13);
   Write('3.14159');
   Textcolor(14);
   Writeln(' ',#186);
   Write('     '#186);
   Textcolor(10);
   Write(' ',#251,'2 ');{Sqrt 2}
   Textcolor(11);
   SetConsoleOutputCP(1119);
   Write(#247,' '); {Approximatly}
   Textcolor(13);
   Write('1.414');
   Textcolor(14);
   Writeln('   ',#186);
   Writeln('     ',#200,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#205,#188);
   Writeln;
   Writeln;
   Readkey;
End.
CRT_TestCodePages.pas (5,450 bytes)

James Richters

2017-12-06 19:09

reporter  

Asciibox2_SafeSwitch_First.pas (1,504 bytes)
Program ASCIIbox2;
Uses CRT;
Begin
SetSafeCPSwitching(False);
SetUseACP(False);
Writeln('         �����������������������������ͻ');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �����������������������������͹');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �              �              �');
Writeln('         �����������������������������ͼ');
Readln;
End.

Tomas Hajny

2017-12-06 19:16

manager   ~0104540

Thanks for the update, I'll have a look at it.

Regarding the documentation - that will not work, because this is generated and the platform specific extensions don't fit into this well. I'd recommend adding information about it to the Wiki page related to porting fro TP/BP to FPC (once it's finished and thus the final behaviour is known) - I'd say that it's quite a logical place and you can add it there yourself.

Tomas Hajny

2017-12-10 23:09

manager   ~0104629

Alright, I looked at it. The first point (issue with order of calling the two new procedures) was a silly oversight, fixed in revision 37709. However - what exactly is supposed to be wrong with number 2 (apart from things that may have been impacted by the first point as well - that should be fixed now)?

James Richters

2017-12-11 16:10

reporter   ~0104636

Last edited: 2017-12-11 16:15

View 5 revisions

Thank you for fixing issue # 1, I have tested revision 37709 and can confirm this issue is fixed.

issue # 2: I suppose this is really a feature request that I am asking for, because the real issue being addressed is really a windows issue. I am proposing using SafeCPSwitching to True when UseACP is false to provide a convenient fix to the windows bug.

to illustrate: If you run the following test with revision 37709
   SetSafeCPSwitching(True);
   SetUseACP(False);
   SetConsoleOutputCP(869);
   Write(' ',# 234); {Pi} //no space between # and 234, it just won't display right without the space
   SetConsoleOutputCP(1119);
   Write(' ',# 247,' '); {Approximatly}
   SetConsoleOutputCP(437);
   Write('3.14');

you do not get the codepage change to 1119, it's as if you never did SetConsoleOutputCP(1119);

If you do the following:
   SetSafeCPSwitching(True);
   SetUseACP(False);
   SetConsoleOutputCP(869);
   Write(' ',# 234); {Pi}
   SetConsoleOutputCP(437);
   SetConsoleOutputCP(1119);
   Write(' ',# 247,' '); {Approximatly}
   SetConsoleOutputCP(437);
   Write('3.14');

now the output is as expected... I have no idea why you can't go from CP869 directly to CP1119, but going back to CP437 fixes it. This seems to be a windows issue, because using the windows function call SetConsoleOutputCP() function to set the codepage to 1119 should always result in the codepage now being 1119 regardless of the previous codepage used.

With my proposed patch CRT_fix.diff the programmer can use SafeCPSwitching to True when UseACP is False to automatically revert back to the original CP after every write in the same way it would if UseACP were true. Since SafeCPSwitching is already in CRT, why not allow it's use as an option to use it to fix this windows bug? This also has an additional benefit one does not even need to know what the original code page is, the programmer can just change to a specific codepage to write a special character, then it will automatically go back to whatever the original codepage was, and the results will be the same on any system it is run on... regardless of how the system has the console codepage set. If the programmer does not want this to happen, they only need to set SafeCPSwitching to False.

James Richters

2017-12-11 16:12

reporter  

codepagetest.pas (293 bytes)
Program codepagetest;
Uses CRT,Windows;
Begin
   SetSafeCPSwitching(True);
   SetUseACP(False);
   SetConsoleOutputCP(869);
   Write('  ',#234); {Pi}
   SetConsoleOutputCP(1119);
   Write(' ',#247,' '); {Approximatly}
   SetConsoleOutputCP(437);
   Write('3.14');
   Readln;
End.
codepagetest.pas (293 bytes)

James Richters

2017-12-11 16:44

reporter  

CRT_Fix2.diff (2,246 bytes)
��diff --git a/packages/rtl-console/src/win/crt.pp b/packages/rtl-console/src/win/crt.pp

index c601011df6..813cda35fd 100644

--- a/packages/rtl-console/src/win/crt.pp

+++ b/packages/rtl-console/src/win/crt.pp

@@ -821,8 +821,11 @@ begin

     WriteStr(s);

   SetScreenCursor(CurrX, CurrY);

 

-  if SafeCPSwitching and UseACP then     //restore codepage on every write if set previously

-    SetConsoleOutputCP(OldConsoleOutputCP);

+  if SafeCPSwitching then

+    if UseACP then     //restore codepage on every write

+      SetConsoleOutputCP(OldConsoleOutputCP)

+    else

+      SetConsoleOutputCP(OriginalConsoleOutputCP);

 

   f.bufpos:=0;

 end;

@@ -927,9 +930,11 @@ begin

       end;

   until false;

 

-  if SafeCPSwitching and UseACP then    //Restore codepage on every Read if set previously

-    SetConsoleOutputCP(OldConsoleOutputCP);

-	

+  if SafeCPSwitching then

+    if UseACP then     //restore codepage on every read

+      SetConsoleOutputCP(OldConsoleOutputCP)

+    else

+      SetConsoleOutputCP(OriginalConsoleOutputCP);

   f.bufpos:=0;

   SetScreenCursor(CurrX, CurrY);

 End;

CRT_Fix2.diff (2,246 bytes)

James Richters

2017-12-11 16:46

reporter   ~0104637

Uploaded CRT_Fix2.diff - contains only the changes proposed above applied to revision 37709

Tomas Hajny

2017-12-11 17:35

manager   ~0104638

I'm sorry, but this makes no sense to me. As far as I can see, CP 1119 is not a valid codepage under MS Windows - what about checking the return value of SetConsoleOutputCP in your test program??? What's wrong with keeping CP 437 in place all the time if you try to output characters based on their location in that character set?

James Richters

2017-12-12 00:19

reporter   ~0104649

Doh, my mistake, you are right, CP 1119 is not even valid for windows. If I test with valid codepages, then everything is fine and no need to do anything else.

It's also no big deal to get the original codepage yourself, but you don't even need to bother, you can just call SetUseACP(False); again and it sets it back to the original.

Thanks again for your help and correcting me.

James Richters

2017-12-12 00:27

reporter   ~0104651

Just to make sure I am accurate with Wiki documentation, This version of CRT will be released with 3.1.1?

Tomas Hajny

2017-12-14 15:19

manager   ~0104709

It is included in snapshots and SVN builds of 3.1.1 (i.e. the SVN trunk). It will be included in release 3.2.0. It might be included in release 3.0.6 if such a release is published (rather then going to 3.2.0 directly) and if this change is merged into the fixes branch in the meantime (there are no technical reasons for not doing it from my point of view, but that's just my opinion at the moment). See the FAQ point related to release numbering.

Issue History

Date Modified Username Field Change
2017-10-16 21:04 James Richters New Issue
2017-10-16 21:04 James Richters File Added: Free Pascal CRT Information.zip
2017-10-16 21:33 Anton Kavalenka Note Added: 0103493
2017-10-16 21:36 Anton Kavalenka Note Edited: 0103493 View Revisions
2017-10-16 23:52 James Richters Note Added: 0103498
2017-10-16 23:53 James Richters Note Edited: 0103498 View Revisions
2017-10-17 09:10 Thaddy de Koning Note Added: 0103502
2017-10-17 09:12 Thaddy de Koning Note Edited: 0103502 View Revisions
2017-10-17 09:13 Thaddy de Koning Note Edited: 0103502 View Revisions
2017-10-17 10:32 Anton Kavalenka Note Added: 0103505
2017-10-17 10:55 Bart Broersma Note Added: 0103507
2017-10-17 13:15 James Richters Note Added: 0103516
2017-10-17 14:01 Marco van de Voort Note Added: 0103518
2017-10-17 15:24 James Richters Note Added: 0103520
2017-10-17 15:25 James Richters Note Edited: 0103520 View Revisions
2017-10-17 15:42 Anton Kavalenka Note Added: 0103521
2017-10-17 15:44 Anton Kavalenka Note Edited: 0103521 View Revisions
2017-10-17 18:30 Anton Kavalenka Note Edited: 0103521 View Revisions
2017-10-17 19:53 Florian Note Added: 0103528
2017-10-17 22:18 James Richters Note Added: 0103533
2017-10-17 23:31 Bart Broersma Note Added: 0103535
2017-10-17 23:52 James Richters Note Added: 0103537
2017-10-17 23:53 James Richters File Added: fixed.JPG
2017-10-17 23:58 James Richters Note Added: 0103538
2017-10-18 00:01 James Richters Note Edited: 0103538 View Revisions
2017-10-18 00:03 James Richters Note Edited: 0103538 View Revisions
2017-10-18 00:08 James Richters Note Edited: 0103538 View Revisions
2017-10-18 00:39 Tomas Hajny Note Added: 0103539
2017-10-18 02:42 James Richters Note Added: 0103541
2017-10-18 02:51 James Richters Note Edited: 0103541 View Revisions
2017-10-18 09:06 Tomas Hajny Note Added: 0103545
2017-10-18 12:47 James Richters Note Added: 0103551
2017-10-18 12:48 James Richters File Added: CRT.diff
2017-10-18 13:07 James Richters File Added: TestCrtCodePage.pas
2017-10-18 13:12 James Richters File Added: CrtCodePageTest.JPG
2017-10-18 13:14 James Richters Note Edited: 0103551 View Revisions
2017-10-18 14:56 Tomas Hajny Assigned To => Tomas Hajny
2017-10-18 14:56 Tomas Hajny Status new => assigned
2017-10-18 15:00 Tomas Hajny Note Added: 0103554
2017-10-18 23:09 James Richters Note Added: 0103576
2017-10-20 17:33 James Richters File Added: TestCodePages.pas
2017-10-20 17:35 James Richters File Added: TestCodePage Output.JPG
2017-10-20 17:44 James Richters Note Added: 0103611
2017-10-20 17:45 James Richters Note Edited: 0103611 View Revisions
2017-10-20 19:19 Tomas Hajny Note Added: 0103614
2017-10-20 21:26 James Richters Note Added: 0103621
2017-10-20 21:27 James Richters Note Edited: 0103621 View Revisions
2017-10-21 00:39 James Richters File Added: CRT Flags Only.diff
2017-10-21 00:46 James Richters File Added: CRT_Flags_Only_TestCodePages.pas
2017-10-21 00:47 James Richters File Added: CRT Flags Only TestCodePage Output.JPG
2017-10-21 01:02 James Richters Note Added: 0103632
2017-10-21 01:06 James Richters Note Edited: 0103632 View Revisions
2017-10-21 01:16 James Richters Note Edited: 0103632 View Revisions
2017-10-21 01:34 James Richters Note Added: 0103633
2017-10-22 19:35 James Richters Note Added: 0103687
2017-10-22 19:37 James Richters File Added: CRT_Flags_and_RemapScanCode.diff
2017-10-22 19:43 James Richters Note Edited: 0103687 View Revisions
2017-10-22 19:49 James Richters Note Edited: 0103687 View Revisions
2017-10-22 20:00 James Richters File Added: CRT_Flags_And_RemapScanCode_2.diff
2017-10-22 20:03 James Richters Note Edited: 0103687 View Revisions
2017-10-22 20:08 James Richters Note Edited: 0103687 View Revisions
2017-12-05 02:12 Tomas Hajny Fixed in Revision => 37674
2017-12-05 02:12 Tomas Hajny Note Added: 0104441
2017-12-05 02:12 Tomas Hajny Status assigned => resolved
2017-12-05 02:12 Tomas Hajny Fixed in Version => 3.1.1
2017-12-05 02:12 Tomas Hajny Resolution open => fixed
2017-12-05 02:12 Tomas Hajny Target Version => 3.2.0
2017-12-06 18:56 James Richters Note Added: 0104539
2017-12-06 18:56 James Richters Status resolved => feedback
2017-12-06 18:56 James Richters Resolution fixed => reopened
2017-12-06 18:57 James Richters File Added: CRT_fix.diff
2017-12-06 18:59 James Richters Note Edited: 0104539 View Revisions
2017-12-06 19:02 James Richters File Added: CRT_TestCodePages.pas
2017-12-06 19:09 James Richters File Added: Asciibox2_SafeSwitch_First.pas
2017-12-06 19:16 Tomas Hajny Note Added: 0104540
2017-12-06 19:18 James Richters Note Edited: 0104539 View Revisions
2017-12-10 23:09 Tomas Hajny Note Added: 0104629
2017-12-11 16:10 James Richters Note Added: 0104636
2017-12-11 16:10 James Richters Status feedback => assigned
2017-12-11 16:11 James Richters Note Edited: 0104636 View Revisions
2017-12-11 16:12 James Richters File Added: codepagetest.pas
2017-12-11 16:13 James Richters Note Edited: 0104636 View Revisions
2017-12-11 16:13 James Richters Note Edited: 0104539 View Revisions
2017-12-11 16:14 James Richters Note Edited: 0104636 View Revisions
2017-12-11 16:15 James Richters Note Edited: 0104636 View Revisions
2017-12-11 16:44 James Richters File Added: CRT_Fix2.diff
2017-12-11 16:46 James Richters Note Added: 0104637
2017-12-11 17:35 Tomas Hajny Note Added: 0104638
2017-12-12 00:19 James Richters Note Added: 0104649
2017-12-12 00:27 James Richters Note Added: 0104651
2017-12-14 15:19 Tomas Hajny Note Added: 0104709
2017-12-14 15:20 Tomas Hajny Status assigned => resolved
2017-12-14 15:20 Tomas Hajny Resolution reopened => fixed