home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / TP6BUGS5.ZIP / TVBUGS / text0000.txt < prev   
Encoding:
Text File  |  1991-12-02  |  31.6 KB  |  916 lines

  1. >Thanks, modifications to tvdemos programs would be fine.  If you can, please
  2. >package up the whole program; a "diff" file would be hard to apply since I
  3. >have a different version of the files than you do.  It'll also make it clearer
  4. >which bugs have been addressed in the June 91 release.
  5. Now I'm ready. Since there is one program being very similar to TVEDIT.PAS
  6. I just gave the additions to that file. Including the whole file would be
  7. a waste of space.
  8.  
  9. >> >bugs@borland.com).  Have you already done that?
  10. >> No.
  11. >I'll wait for you demonstration code then, and send it myself.
  12. Meanwhile I got the address of Sydney Markowitz (sydney@borland.com)
  13. and sent him the list. You can send it to bugs@borland.com anyway.
  14. And now the list:
  15.  
  16. Bugs in TurboVision and TurboPascal 6.0
  17.  This file contains a collection of bugs found in Borland's
  18. TurboPascal 6.0 compiler and the TurboVision units. Each
  19. bug is described in the following form:
  20.  
  21.    Bug: procedure/function name (Unit name)
  22.      short description explaining the context and effect
  23.    Example:
  24.      sample Pascal text or name of file, with instructions
  25.      how to see the bug in effect. CAUTION: some bugs will
  26.      cause the system to hang, so be sure to save all your
  27.      important data.
  28.      Some of the sample programs are appended to this text,
  29.      separated by lines like:
  30.          ---------  FILENAME.PAS  -------------------
  31.      One of them, EDIT.PAS, is derived from TVEDIT.PAS
  32.      and TVDEMO.PAS (both by Borland). So I added a
  33.      description how to generate it, instead of the
  34.      whole file.
  35.    Fix:
  36.      Replacement/addition for the buggy routine
  37.  
  38.    Some improvements are added, in a similar form.
  39.  
  40.  
  41. Bug: procedure TFileEditor.InitBuffer (Unit Editors)
  42.   TFileEditor.NewBuffer allocates 0 bytes, but does not set BufSize
  43.   to 0. Now, if TFileEditor.Load loads a TFileEditor from a stream,
  44.   BufSize is read from the stream, too, and has its old value.
  45.   InitBuffer (called by TEditor.Load) ignores it, so the content
  46.   of the editor is loaded into memory, which was never allocated
  47.   -> the program will crash. So you can't use TFileEditors, if you
  48.   store and load the desktop.
  49. Example:
  50.   Compile the file EDIT.PAS to disk and start it. Open two edit
  51.   windows via File!New, type in some text and save them. Do not
  52.   close the windows! Save the desktop with Windows!Save desktop,
  53.   then reload it with Windows!Retrieve and type a single key:
  54.   The actual edit window will show some weird chars in the
  55.   beginning of the first line. Edit the text in one window and
  56.   then select the other one; watch the effects. If you exit the
  57.   program, sometimes your system hangs because of corrupted
  58.   memory control blocks.
  59. Fix:
  60.   procedure TFileEditor.InitBuffer;
  61.   begin
  62.     NewBuffer(Pointer(Buffer));
  63.   (* Bugfix 13.05.91 JS: consider BufSize! TEditor.InitBuffer
  64.      allocates BufSize bytes, this routine allocates 0 Bytes,
  65.      but does not set BufSize to the correct value. If BufSize
  66.      is <>0 (e.g. after TEditor.Load from a stream), the pro-
  67.      gram will crash. *)
  68.     BufSize:=0;
  69.   end;
  70.  
  71.  
  72. Bug: function IScan (Unit Editors)
  73.   In this assembly-routine the programmer forgot, that MOV does
  74.   not set the flags. If the search string nearly matches the last
  75.   chars in the text, the routine runs over the end of the text --
  76.   eventually replacing text! Here is an example:
  77.     Let '123456' be the text, and search for '45z'.
  78.     The routine scans the text '1234' for the '4' and finds it:
  79.          123456
  80.             45z
  81.     Then it compares the rest, finds the difference and skips
  82.     this occurence. CX (number the chars left in the text) is
  83.     now 0, but the routine just MOVs it back from DX, jumping
  84.     then with JNE. Now it is behind the end of text!
  85. Example:
  86.   TVDEMO\TVEDIT.PAS. Open a new edit window and type "123456"
  87.   without the quote marks. Do not terminate the line with
  88.   Enter! Press the Home key, then Ctrl-Q F to invoke the Find
  89.   dialog. Enter "45z" as search text (without the quote marks)
  90.   and press Enter (Case sensitivity is unselected by default):
  91.   Your system hangs (sometimes wrong occurences are shown, or
  92.   the search wraps around).
  93. Fix:
  94.   (* Comment: The only change needed is the line marked with ***.
  95.      But for better use of TEditor objects outside the USA and
  96.      GB, it's better to use the DOS codepage (MSDOS3.X or higher
  97.      required) for case conversion. *)
  98.  
  99.   { Improvement JS: UpperCase uses DOS codepage }
  100.   procedure DOSUpCase; assembler;
  101.   { a dummy to get a pointer in the codesegment }
  102.   asm
  103.           DD 0
  104.   end;
  105.  
  106.   function UpperCase:Char ; assembler ;
  107.   { changes lower case to upper case letters, using DOS codepage.
  108.     does not need DS to point to Turbo's global data segment.
  109.     input : AL char
  110.     output: AL upper case of it }
  111.   asm
  112.           CMP  AL,'a'           { normal lower case chars.. }
  113.           JB   @@1
  114.           CMP  AL,'z'
  115.           JBE  @@4              { .. get normal treatment. }
  116.           DB   $2E,$FF,$1E      { this is a CALLF [cs:] }
  117.           DW   DOSUpCase        { all others are converted using }
  118.           JMP  @@1              { the DOS codepage }
  119.   @@4:
  120.           SUB AL,20H
  121.   @@1:
  122.   end ;
  123.  
  124.   function UpCase(c:Char): Char; assembler;
  125.   { should be exported, i.e. included in interface }
  126.   asm
  127.           MOV   AL,c
  128.           CALL UpperCase
  129.   end;
  130.  
  131.   function IScan(var Block; Size: Word; Str: String): Word; assembler;
  132.   var
  133.     S: String;
  134.   asm
  135.           PUSH  DS
  136.           MOV   AX,SS           { copy the Str to S, converting it.. }
  137.           MOV   ES,AX           { to upper case }
  138.           LEA   DI,S
  139.           LDS   SI,Str
  140.           XOR   AH,AH
  141.           LODSB                 { copy string length }
  142.           STOSB
  143.           MOV   CX,AX
  144.           MOV   BX,AX
  145.           JCXZ  @@9
  146.   @@1:    LODSB                 { load each char from Str.. }
  147.           CALL  UpperCase       { get upper case of it.. }
  148.           STOSB                 { and store it to S }
  149.           LOOP  @@1
  150.           SUB   DI,BX           { goto beginning of S (without length byte) }
  151.           LDS   SI,Block
  152.           MOV   CX,Size
  153.           JCXZ  @@8
  154.           CLD
  155.           SUB   CX,BX           { no need to examine the last chars in..}
  156.           JB    @@8             { Block, the search string won't fit }
  157.           INC   CX
  158.   @@4:    MOV   AH,ES:[DI]      { search for the first char of search string }
  159.   @@5:    LODSB
  160.           CALL  UpperCase
  161.           CMP AL,AH             { compare chars from Block with first char.. }
  162.           LOOPNE @@5            { of search string until found }
  163.           JNE   @@8             { no occurence -> goto end }
  164.           DEC   SI              { compare the whole search string }
  165.           MOV   DX,CX           { save number of remaining bytes in Block }
  166.           MOV   CX,BX           { get search string length }
  167.   @@6:    REPE  CMPSB           { exact match.. }
  168.           JE    @@10            { up to end of search string -> success }
  169.           MOV   AL,DS:[SI-1]    { else: }
  170.           CALL  UpperCase       { compare upper case }
  171.           CMP   AL,ES:[DI-1]
  172.           JE    @@6             { matches -> continue }
  173.           SUB   CX,BX           { else compare failed; restore pointers.. }
  174.           ADD   SI,CX           { in Block.. }
  175.           ADD   DI,CX           { and search string }
  176.           INC   SI
  177.           MOV   CX,DX           { restore number of remaining bytes in Block }
  178.           OR    CX,CX           { *** MOV does not modify the flags! }
  179.           JNE   @@4             { zero remaining bytes -> end }
  180.   @@8:    XOR   AX,AX           { end without success: return 0 }
  181.           JMP   @@11
  182.   @@9:    MOV   AX, 1           { end with empty search string:.. }
  183.           JMP   @@11            { pointer to next char }
  184.   @@10:   SUB   SI,BX           { end with success: return pointer to.. }
  185.           MOV   AX,SI           { found occurence }
  186.           SUB   AX,WORD PTR Block
  187.           INC   AX
  188.   @@11:   DEC   AX              { set correct range of AX for BOOLEAN }
  189.           POP DS
  190.   end;
  191.  
  192.   { an init routine, replacing the END. at the end of EDITORS.PAS: }
  193.   const RetFar:Byte=$CB ;
  194.   var i: Integer;
  195.   begin
  196.     { Improvement JS: UpperCase uses DOS codePage }
  197.     asm
  198.               push  ds
  199.               mov   ds,PrefixSeg
  200.               mov   dx,$D0        { DS:DX = 32 bytes scratch area in the PSP }
  201.               mov   ax,$3800      { get extended country information }
  202.               int   21h
  203.               mov   bx,dx
  204.               mov   ax,[bx+$12]   { Pointer to case conversion routine.. }
  205.               mov   bx,[bx+$14]   { for chars >80h }
  206.               pop   ds
  207.               jnc   @@ok          { if DOS reports error, set it to RETF }
  208.               mov   ax,Offset RetFar
  209.               mov   bx,ds
  210.     @@ok:
  211.               mov   word ptr cs:DOSUpCase,ax
  212.               mov   word ptr cs:DOSUpCase+2,bx
  213.     end ;
  214.   end.
  215.  
  216.  
  217. Bug: procedure TEditor.HandleEvent (Unit Editors)
  218.   This routine consumes all cmScrollBarChanged-events, without
  219.   testing the sender. With TEditor, everything is ok, but with
  220.   TMemo, there is a problem: this object cannot coexist in a
  221.   TDialog with other objects having scrollbars. The test, whe-
  222.   ther a cmScrollBarChanged-event is from one of its own scroll
  223.   bars is done in the local procedure CheckScrollBar, but the
  224.   HandleEvent routine clears the event in any case.
  225. Example:
  226.   TESTMEMO. Start it and press F1 to get a MemoDialog, where a
  227.   TMemo field is together with a TListviewer, both having scroll-
  228.   bars. Try to position the focus in the TListbox with the scroll-
  229.   bar or with the cursor keys (they are translated by the scroll-
  230.   bar as well): it won't work. On the contrary, the TMemo works
  231.   fine.
  232. Fix:
  233.   TEditor.HandleEvent(var Event: TEvent);
  234.  
  235.   (* ... several lines skipped ... *)
  236.  
  237.   { Bugfix JS: function CheckScrollBar:Boolean returns False, if
  238.     the sending scrollbar was not the scrollbar in question. }
  239.   function CheckScrollBar(P: PScrollBar; var D: Integer): Boolean;
  240.   begin
  241.     if (Event.InfoPtr = P) and (P^.Value <> D) then
  242.     begin
  243.       D := P^.Value;
  244.       Update(ufView);
  245.       CheckScrollBar := True;
  246.     end
  247.     else CheckScrollBar := False;
  248.   end;
  249.  
  250.   begin
  251.     TView.HandleEvent(Event);
  252.     ConvertEvent(Event);
  253.  
  254.   (* ... several lines skipped ... *)
  255.  
  256.       evBroadcast:
  257.         case Event.Command of
  258.           cmScrollBarChanged:
  259.             { Bugfix JS: function CheckScrollBar():Boolean returns False,
  260.               if the sending scrollbar was not the scrollbar in question.
  261.               The EXIT prevents the Event from being cleared. }
  262.             if not(CheckScrollBar(HScrollBar, Delta.X) or
  263.                    CheckScrollBar(VScrollBar, Delta.Y)) then Exit;
  264.           else Exit;
  265.         end;
  266.     end;
  267.     ClearEvent(Event);
  268.   end;
  269.  
  270.  
  271. Bug: function TEditor.InsertBuffer (Unit Editors)
  272.   Overwriting chars in an TEditor object is done in TEditor.Handle-
  273.   Event by marking the next char as block and calling InsertBuffer
  274.   via InsertText. This routine checks, whether there is enough
  275.   memory and complains (edOutOfMemory), but does not reset the
  276.   block marker. If you now press backspace, the block is deleted
  277.   (i.e. the char under the cursor), not the char on the left side
  278.   of the cursor.
  279. Example:
  280.   Be sure to compile TVDEMOS\TVEDIT.PAS without the Range Check
  281.   option; there seems to be another minor bug concerning Integer
  282.   and Word types. Start TVEDIT.EXE, open a new edit window and
  283.   start typing until the messagebox 'Not enough memory for this
  284.   operation' comes up. Press Enter to close the messagebox, move
  285.   the cursor in the middle of a line and type until the messagebox
  286.   comes up again. Press Enter to close it again and then press
  287.   Backspace. Not the char on the left side of the cursor will be
  288.   deleted, but the char at cursor position.
  289. Fix:
  290.   function TEditor.InsertBuffer(var P: PEditBuffer; Offset, Length: Word;
  291.     AllowUndo, SelectText: Boolean): Boolean;
  292.   var
  293.     SelLen, DelLen, SelLines, Lines: Word;
  294.     NewSize: Longint;
  295.   begin
  296.     InsertBuffer := True;
  297.     Selecting := False;
  298.     SelLen := SelEnd - SelStart;
  299.     if (SelLen = 0) and (Length = 0) then Exit;
  300.     DelLen := 0;
  301.     if AllowUndo then
  302.       if CurPtr = SelStart then DelLen := SelLen else
  303.         if SelLen > InsCount then DelLen := SelLen - InsCount;
  304.     NewSize := Longint(BufLen + DelCount - SelLen + DelLen) + Length;
  305.     if NewSize > BufLen + DelCount then
  306.       if (NewSize > $FFF0) or not SetBufSize(NewSize) then
  307.       begin
  308.         EditorDialog(edOutOfMemory, nil);
  309.         { Bugfix JS: reset block markers to avoid abnormal behaviour
  310.           of a following BackSpace: }
  311.         SelEnd := SelStart;
  312.         InsertBuffer := False;
  313.         Exit;
  314.       end;
  315.  
  316.   (* ... several lines skipped ... *)
  317.  
  318.     SetBufSize(BufLen + DelCount);
  319.     if (SelLines = 0) and (Lines = 0) then Update(ufLine) else Update(ufView);
  320.   end;
  321.  
  322. Bug: function NoWildChars (Unit StdDlg)
  323.   This routine is used by TFileDialog-objects to delete wildcards
  324.   in filenames. If called with an empty argument, it overwrites
  325.   the stack. Try it: just give first '*' as mask, then a name with
  326.   no extension in a TFileDialog.
  327. Example:
  328.   TVDEMOS\TVDEMO.PAS. Create the file TEST (no extension!), then
  329.   start TVDEMO.EXE. Press F3 to invoke the FileOpen dialog. Type
  330.   "*" without the quote marks, press Enter, choose TEST from the
  331.   file list and press Enter again: The system hangs.
  332. Fix:
  333.   function NoWildChars(S: String): String; assembler;
  334.   asm
  335.           PUSH  DS
  336.           LDS   SI,S            { pointer to argument string }
  337.           LES   DI,@Result      { same to result string }
  338.           XOR   AX,AX
  339.           LODSB                 { get length of argument string }
  340.           { Bugfix JS: test for empty argument string }
  341.           OR    AL,AL           { length=0 ? }
  342.           JE    @@3             { -> result = '' }
  343.           XCHG  AX,CX           { else: }
  344.           INC   DI              { skip result length byte }
  345.   @@1:    LODSB                 { get char from argument string }
  346.           CMP   AL,'?'          { '?' or '*' ? }
  347.           JE    @@2             { then skip it.. }
  348.           CMP   AL,'*'
  349.           JE    @@2
  350.           STOSB                 { else copy it into result string }
  351.   @@2:    LOOP  @@1
  352.           XCHG  AX,DI           { calculate length of result string.. }
  353.           MOV DI,WORD PTR @Result
  354.           SUB AX,DI             { as Endoffset+1 - Startoffset }
  355.           DEC     AX            { don't count the length byte }
  356.   @@3:
  357.           STOSB                 { set length of result string }
  358.           POP DS
  359.   end;
  360.  
  361. Bug: procedure THelpTopic.AddCrossRef (Unit HelpFile)
  362.   In this routine the programmer allocates memory and then
  363.   forgets to use the pointer to it. He just forgot a line.
  364. Example:
  365.   No example. 'The code is obvious.'
  366. Fix:
  367.   procedure THelpTopic.AddCrossRef(Ref: TCrossRef);
  368.   var
  369.     P: PCrossRefs;
  370.   begin
  371.     GetMem(P, (NumRefs+1) * SizeOf(TCrossRef));
  372.     if NumRefs > 0 then
  373.     begin
  374.       Move(CrossRefs^, P^, NumRefs * SizeOf(TCrossRef));
  375.       FreeMem(CrossRefs, NumRefs * SizeOf(TCrossRef));
  376.     end;
  377.     { Bugfix JS: the following line is missing in the original }
  378.     CrossRefs := P;
  379.     CrossRefs^[NumRefs] := Ref;
  380.     Inc(NumRefs);
  381.   end;
  382.  
  383. Bug: function THelpIndex.Position (Unit HelpFile)
  384.   If called with a negative argument, it returns random values,
  385.   since it checks only for the upper bound, not for the lower
  386.   one. The help compiler TVHC uses -1 for unknown topics, so
  387.   this doesn't work.
  388. Example:
  389.   Compile TVDEMOS\TVDEMO.PAS to disk. Then add the
  390.   line
  391.     {abc}
  392.   to the first topic in TVDEMOS\DEMOHELP.TXT and
  393.   compile it with
  394.      TVHC DEMOHELP.TXT
  395.   This will produce DEMOHELP.HLP and DEMOHELP.PAS.
  396.   Start TVDEMO.EXE, press F1 to see the general help
  397.   and then Enter to follow the cross reference 'abc'.
  398.   You will not see the text 'No help available in this
  399.   context.', as intended by HELPFILE.PAS, but get a
  400.   runtime error (if you compiled TVDEMO with Range Check
  401.   option) or a randomly chosen help text if any (without
  402.   Range checking).
  403. Fix:
  404.   function THelpIndex.Position(I: Integer): Longint;
  405.   begin
  406.     if (-1 < I) and (I < Size) then Position := Index^[I]
  407.     else Position := -1;
  408.   end;
  409.  
  410. Bug: procedure AddToBuffer (Programm TVHC)
  411.   No range checking is done in this routine. If a paragraph is
  412.   longer than specified in the constant BufferSize (default:1024),
  413.   memory behind the buffer is overwritten, resulting in crash.
  414. Example:
  415.   Create a file TESTHELP.TXT with this content:
  416.     .topic TestContext
  417.     The following paragraph is too long to fit into the
  418.     standard-sized buffer of TVHC.PAS:
  419.       1234567890123456789012345678901234567890
  420.       1234567890123456789012345678901234567890
  421.  
  422.         .. another 100 lines likes these ..
  423.  
  424.       1234567890123456789012345678901234567890
  425.       1234567890123456789012345678901234567890
  426.   Now start TVHC on it:
  427.     TVHC TESTHELP.TXT
  428.   Your system will hang, if you haven't compiled TVHC with Range
  429.   Check option, otherwise you will get a runtime error 204.
  430. Fix:
  431.   procedure AddToBuffer(var Line: String; Wrapping: Boolean); assembler;
  432.   asm
  433.           PUSH    DS
  434.           CLD
  435.           PUSH    DS
  436.           POP     ES
  437.           MOV     DI,OFFSET Buffer
  438.           ADD     DI,Ofs
  439.           LDS     SI,Line
  440.           LODSB
  441.           XOR     AH,AH
  442.           { Bugfix JS: the following test is missing in the original
  443.             version. Causes crashes on buffer overflow }
  444.           MOV     BX,BufferSize { BufferSize-Ofs is the space left in Buffer }
  445.           SUB     BX,ES:Ofs
  446.           CMP     BX,AX         { AX holds the needed amount of space }
  447.           JAE     @@0           { enough -> ok }
  448.           MOV     AX,BX         { else just fill the Buffer up }
  449.   @@0:
  450.           ADD     ES:Ofs,AX
  451.           XCHG    AX,CX
  452.           JCXZ    @@3           { don't copy 64K if there is nothing to do }
  453.           REP     MOVSB
  454.           CMP     ES:Ofs,BufferSize
  455.           JE      @@3           { don't append ' '/#13 if there is no room }
  456.           XOR     AL,AL
  457.           INC     ES:Ofs
  458.           TEST    Wrapping,1    { Only add a #13, line terminator, if not }
  459.           JE      @@1           { currently wrapping the text. Otherwise  }
  460.           MOV     AL,' '-13     { add a ' '.                              }
  461.   @@1:    ADD     AL,13
  462.   @@2:    STOSB
  463.   @@3:
  464.           POP     DS
  465.   end;
  466.  
  467. Bug: procedure THistory.Draw (Unit Dialogs)
  468.   For the history button sides, the chars ASCII 221 and 222 are
  469.   used. These chars are _not_ included in codepages other than
  470.   437 (e.g. codepage 850, recommended by IBM for europe). So,
  471.   the button looks somewhat awful in europe.
  472. Example:
  473.   To use codepage 850 with your display, include the lines
  474.   (with correct paths, of course)
  475.       nlsfunc.exe country.sys
  476.       mode con cp prepare=((850)ega.cpi)
  477.   in your AUTOEXEC.BAT and type CHCP 850 at the DOS prompt after
  478.   startup. DOS will complain, because you haven't prepared this
  479.   codepage for all devices, but this doesn't matter. Start
  480.   TVDEMOS\TVDEMO and press F3 to invoke a TFileDialog with a
  481.   history button on the left side of the 'Name' input line.
  482.   Look at the System-menu symbol for another example of such
  483.   incompatibly written software.
  484. Fix:
  485.   No fix.
  486.  
  487. Bug: integrated assembler
  488.   The integrated assembler doesn't generate the correct code for
  489.   lines like this:
  490.  
  491.          MOV AX,[WORD PTR BX]
  492.  
  493.   The alternative form
  494.  
  495.          MOV AX,WORD PTR [BX]
  496.  
  497.   is handled properly. This is especially bad, since the first form
  498.   is TASM syntax in Ideal mode, while the latter is MASM syntax.
  499. Example:
  500.   Compile TESTASM.PAS to disk. Then start DEBUG with TESTASM.EXE
  501.   and type 'u' to unassemble the code. You will see
  502.     MOV  BX,0038
  503.     MOV  AX,[0000]
  504.     MOV  AX,[BX]
  505. Fix:
  506.   No fix.
  507.  
  508.  
  509. Some improvements:
  510. Behaviour: ^T in TVEdit sometimes deletes more than the next word.
  511. Explanation:
  512.   ^T deletes _up to the next_ word, to be exact: up to the next
  513.   char out of
  514.     WordChars: set of Char = ['0'..'9', 'A'..'Z', '_', 'a'..'z']
  515.   This will usually be just the next word, but can be more. The
  516.   IDE editor first skips the current word if the cursor is in one.
  517.   Then it skips blanks and tabs up to the next non-blank/non-tab.
  518. Example:
  519.   EDIT.PAS. Open a new edit window and type this line:
  520.     abc[[[[123]
  521.   Press Home to position the cursor on the 'a'. Press ^T; this
  522.   will delete 'abc[[[['. The TurboPascal Editor would delete 'abc'.
  523. Fix:
  524.   function TEditor.NextWord(P: Word): Word;
  525.   begin
  526.     if BufChar(P) in WordChars then
  527.       while (P < BufLen) and (BufChar(P) in WordChars) do
  528.         P := NextChar(P)
  529.     else
  530.       P := NextChar(P);
  531.     while (P < BufLen) and ((BufChar(P) = ' ') or (BufChar(P) = #9)) do
  532.       P := NextChar(P);
  533.     NextWord := P;
  534.   end ;
  535.  
  536. Behaviour: ^QF followed by ^L followed by Space deletes words in TVEdit.
  537. Explanation:
  538.   If you mark a block manually and type a key, the block will be
  539.   replaced by the key. Because occurences of the search string
  540.   are marked as block, the described effect is seen. If you
  541.   really want to avoid it, you have to change TEditor.HandleEvent
  542.   to clear the blockmarkers before inserting a normal char.
  543. Example:
  544.   EDIT.PAS. Open a new edit window and type this:
  545.     1234567890
  546.   Move the cursor to the '3', hold down a Shift key and move the
  547.   cursor to the '8' to mark the string '34567'. Press the space
  548.   bar; this will replace '34567' by ' '.
  549. Fix:
  550.   TEditor.HandleEvent(var Event: TEvent);
  551.  
  552.   (* ... several lines skipped ... *)
  553.  
  554.   begin
  555.  
  556.   (* ... several lines skipped ... *)
  557.  
  558.       evKeyDown:
  559.         case Event.CharCode of
  560.           #9,#32..#255:
  561.             begin
  562.               Lock;
  563.               { Improvement JS: reset blockmarkers if not overwriting }
  564.               if Overwrite then
  565.                 begin
  566.                   if CurPtr <> LineEnd(CurPtr) then SelEnd := NextChar(CurPtr)
  567.                 end
  568.               else
  569.                 SelEnd := SelStart;
  570.               InsertText(@Event.CharCode, 1, False);
  571.               TrackCursor(CenterCursor);
  572.               Unlock;
  573.             end;
  574.         else
  575.           Exit;
  576.         end;
  577.  
  578.   (* ... several lines skipped ... *)
  579.  
  580.   end;
  581.  
  582.  
  583. What I thought to be a bug, but was not:
  584. Bug: local assembly-procedures in assembly-procedures
  585.   Here the compiler seems to have problems with the parameter
  586.   sizes. Look at this:
  587.  
  588.     function FnTruncSet(Pattern:String):Boolean ; assembler ;
  589.         procedure Number ; assembler ;
  590.         asm
  591.           [....]
  592.         end ;
  593.     asm
  594.       [....]
  595.       call Number
  596.       [....]
  597.     end ;
  598.  
  599.   For the procedure Number, the compiler generates a RET 2 instead
  600.   of RET. I have no idea, why it wants to pop 2 bytes while having
  601.   no argument; in this form, it will crash.
  602. Explanation:
  603.   In the Programmer's reference, nested procedures are described.
  604.   TurboPascal always pushes BP onto the stack to allow local pro-
  605.   cedures to access the arguments of the enclosing routine. So, it
  606.   has to pop 2 Bytes at the end.
  607. Fix:
  608.   RTFM. Or, TurboPascal should not do this, because the same manual
  609.   states that ASSEMBLER routines do not get a stack frame, if they
  610.   have no arguments and local variables. So BP doesn't have to be
  611.   pushed, it already has its correct value inside the local routine.
  612.  
  613. ---------------------------  EDIT.PAS  ------------------------------
  614. { This text describes changes to be applied to the program TVEDIT.PAS
  615.   from Borland. The changes will extend it to allow storing and reloa-
  616.   ding the desktop with routines from TVDEMO.PAS. All changes are
  617.   described in the form
  618.     (* TVEDIT.PAS original <place/routine name> *)
  619.       ... program text from TVEDIT.PAS ...
  620.     (* EDIT.PAS replacement *)
  621.       ... some other program text ...
  622.   Just replace (or better: add) as described, and you will get EDIT.PAS
  623. }
  624.  
  625. (* TVEDIT.PAS original, at the top: *)
  626.   const
  627.     cmOpen       = 100;
  628.     cmNew        = 101;
  629.     cmChangeDir  = 102;
  630.     cmDosShell   = 103;
  631.     cmCalculator = 104;
  632.     cmShowClip   = 105;
  633.  
  634. (* EDIT.PAS replacement *)
  635.   const
  636.     cmOpen       = 100;
  637.     cmNew        = 101;
  638.     cmChangeDir  = 102;
  639.     cmDosShell   = 103;
  640.     cmCalculator = 104;
  641.     cmShowClip   = 105;
  642.     cmSaveDesktop     =1000;
  643.     cmRetrieveDesktop =1001;
  644.  
  645.  
  646. (* TVEDIT.PAS original, at the top *)
  647.   type
  648.     PEditorApp = ^TEditorApp;
  649.     TEditorApp = object(TApplication)
  650.       constructor Init;
  651.       destructor Done; virtual;
  652.       procedure HandleEvent(var Event: TEvent); virtual;
  653.       procedure InitMenuBar; virtual;
  654.       procedure InitStatusLine; virtual;
  655.       procedure OutOfMemory; virtual;
  656.     end;
  657.  
  658. (* EDIT.PAS replacement *)
  659.   type
  660.     PEditorApp = ^TEditorApp;
  661.     TEditorApp = object(TApplication)
  662.       constructor Init;
  663.       destructor Done; virtual;
  664.       procedure HandleEvent(var Event: TEvent); virtual;
  665.       procedure InitMenuBar; virtual;
  666.       procedure InitStatusLine; virtual;
  667.       procedure LoadDesktop(var S: TStream);
  668.       procedure StoreDesktop(var S: TStream);
  669.       procedure OutOfMemory; virtual;
  670.     end;
  671.  
  672. (* TVEDIT.PAS original, TEditorApp.Init *)
  673.     if H > HeapSize then BufHeapSize := H - HeapSize else BufHeapSize := 0;
  674.     InitBuffers;
  675.     TApplication.Init;
  676.     DisableCommands([cmSave, cmSaveAs, cmCut, cmCopy, cmPaste, cmClear,
  677.       cmUndo, cmFind, cmReplace, cmSearchAgain]);
  678.  
  679. (* EDIT.PAS replacement
  680.     if H > HeapSize then BufHeapSize := H - HeapSize else BufHeapSize := 0;
  681.     InitBuffers;
  682.     RegisterObjects;
  683.     RegisterViews;
  684.     RegisterMenus;
  685.     RegisterDialogs;
  686.     RegisterApp;
  687.     RegisterEditors;
  688.     RegisterCalc;
  689.     TApplication.Init;
  690.     DisableCommands([cmSave, cmSaveAs, cmCut, cmCopy, cmPaste, cmClear,
  691.       cmUndo, cmFind, cmReplace, cmSearchAgain]);
  692.  
  693.  
  694. (* TVEDIT.PAS, original does not include the following routines: *)
  695. (* EDIT.PAS addition *)
  696.   { copied from TVDEMO.PAS and modified TTVDemo to TEditorApp }
  697.   { Since the safety pool is only large enough to guarantee that allocating
  698.     a window will not run out of memory, loading the entire desktop without
  699.     checking LowMemory could cause a heap error.  This means that each
  700.     window should be read individually, instead of using Desktop's Load.
  701.   }
  702.  
  703.   procedure TEditorApp.LoadDesktop(var S: TStream);
  704.   var
  705.     P: PView;
  706.  
  707.   procedure CloseView(P: PView); far;
  708.   begin
  709.     Message(P, evCommand, cmClose, nil);
  710.   end;
  711.  
  712.   begin
  713.     if Desktop^.Valid(cmClose) then
  714.     begin
  715.       Desktop^.ForEach(@CloseView); { Clear the desktop }
  716.       repeat
  717.         P := PView(S.Get);
  718.         Desktop^.InsertBefore(ValidView(P), Desktop^.Last);
  719.       until P = nil;
  720.     end;
  721.   end;
  722.  
  723.   procedure TEditorApp.StoreDesktop(var S: TStream);
  724.  
  725.   procedure WriteView(P: PView); far;
  726.   begin
  727.     if P <> Desktop^.Last then S.Put(P);
  728.   end;
  729.  
  730.   begin
  731.     Desktop^.ForEach(@WriteView);
  732.     S.Put(nil);
  733.   end;
  734.  
  735.  
  736. (* TVEDIT.PAS original, TEditorApp.HandleEvent does not include the
  737.    following local routines: *)
  738. (* EDIT.PAS addition *)
  739.   { copied from TVDEMO.PAS and modified filenames }
  740.   procedure RetrieveDesktop;
  741.   var
  742.     S: PStream;
  743.   begin
  744.     S := New(PBufStream, Init('TVEDIT.DSK', stOpenRead, 1024));
  745.     if LowMemory then OutOfMemory
  746.     else if S^.Status <> stOk then
  747.       MessageBox('Could not open desktop file', nil, mfOkButton + mfError)
  748.     else
  749.     begin
  750.       LoadDesktop(S^);
  751.       if S^.Status <> stOk then
  752.         MessageBox('Error reading desktop file', nil, mfOkButton + mfError);
  753.     end;
  754.     Dispose(S, Done);
  755.   end;
  756.  
  757.   procedure SaveDesktop;
  758.   var
  759.     S: PStream;
  760.     F: File;
  761.   begin
  762.     S := New(PBufStream, Init('TVEDIT.DSK', stCreate, 1024));
  763.     if not LowMemory and (S^.Status = stOk) then
  764.     begin
  765.       StoreDesktop(S^);
  766.       if S^.Status <> stOk then
  767.       begin
  768.         MessageBox('Could not create TVEDIT.DSK.', nil, mfOkButton + mfError);
  769.         {$I-}
  770.         Dispose(S, Done);
  771.         Assign(F, 'TVEDIT.DSK');
  772.         Erase(F);
  773.         Exit;
  774.       end;
  775.     end;
  776.     Dispose(S, Done);
  777.   end;
  778.  
  779.  
  780. (* TVEDIT.PAS original, TEditorApp.HandleEvent *)
  781.           cmCalculator: Calculator;
  782.           cmShowClip: ShowClip;
  783.           cmTile: Tile;
  784.           cmCascade: Cascade;
  785.         else
  786.           Exit;
  787.  
  788. (* EDIT.PAS replacement *)
  789.           cmCalculator: Calculator;
  790.           cmShowClip: ShowClip;
  791.           cmTile: Tile;
  792.           cmCascade: Cascade;
  793.           cmSaveDesktop: SaveDesktop;
  794.           cmRetrieveDesktop: RetrieveDesktop;
  795.         else
  796.           Exit;
  797.  
  798.  
  799. (* TVEDIT.PAS original, TEditorApp.InitMenuBar *)
  800.       NewItem('~P~revious', 'Shift-F6', kbShiftF6, cmPrev, hcNoContext,
  801.       NewItem('~C~lose', 'Alt-F3', kbAltF3, cmClose, hcNoContext,
  802.       NewLine(
  803.       NewItem('Ca~l~culator', '', kbNoKey, cmCalculator, hcNoContext,
  804.       nil)))))))))),
  805.     nil)))))));
  806. end;
  807.  
  808. (* EDIT.PAS replacement *)
  809.         NewItem('~P~revious', 'Shift-F6', kbShiftF6, cmPrev, hcNoContext,
  810.         NewItem('~C~lose', 'Alt-F3', kbAltF3, cmClose, hcNoContext,
  811.         NewLine(
  812.         NewItem('Ca~l~culator', '', kbNoKey, cmCalculator, hcNoContext,
  813.         NewLine(
  814.         NewItem('~R~etrieve desktop', '', kbNoKey, cmRetrieveDesktop, hcNoContex
  815.         NewItem('Sa~v~e desktop', '', kbNoKey, cmSaveDesktop, hcNoContext,
  816.         nil)))))))))))))
  817.       nil)))))));
  818.   end;
  819.  
  820. ---------------------------  TESTASM.PAS  ---------------------------
  821. program TestAsm;
  822. begin
  823.   asm
  824.     MOV  BX,OFFSET PrefixSeg
  825.     MOV  AX,[WORD PTR BX]
  826.     MOV  AX,WORD PTR [BX]
  827.   end;
  828. end.
  829. ---------------------------  TESTMEMO.PAS  --------------------------
  830. program TestMemos ;
  831. uses Objects,Drivers,Views,Menus,Dialogs,Editors,App;
  832.  
  833. const
  834.   cmMemo = 1000;
  835.  
  836. type
  837.   PDemoListViewer = ^TDemoListViewer;
  838.   TDemoListViewer = object(TListViewer)
  839.     function GetText(Item: Integer; MaxLen: Integer): String; virtual;
  840.   end;
  841.  
  842. type
  843.   TMemoApp=object(TApplication)
  844.     procedure InitStatusLine; virtual;
  845.     procedure HandleEvent(var Event:TEvent); virtual;
  846.   end;
  847.  
  848. function TDemoListViewer.GetText(Item: Integer; MaxLen: Integer): String;
  849. var
  850.   S: String[5];
  851. begin
  852.   Str(Item, S);
  853.   GetText := copy('Item '+S,1,MaxLen);
  854. end;
  855.  
  856. procedure TMemoApp.InitStatusLine;
  857. var
  858.   R: TRect;
  859. begin
  860.   GetExtent(R);
  861.   R.A.Y := R.B.Y - 1;
  862.   New(StatusLine, Init(R,
  863.     NewStatusDef(0, $FFFF,
  864.       NewStatusKey('~Alt-X~ Exit', kbALtX, cmQuit,
  865.       NewStatusKey('~F1~ MemoDialog', kbF1, cmMemo,
  866.       nil)),
  867.     nil)));
  868. end;
  869.  
  870. procedure TMemoApp.HandleEvent(var Event:TEvent);
  871. var
  872.   R: TRect;
  873.   D: PDialog;
  874.   V,W: PView;
  875. begin
  876.   TApplication.HandleEvent(Event);
  877.   if (Event.What = evCommand) and (Event.Command = cmMemo) then
  878.     begin
  879.       R.Assign(22, 3, 58, 19);
  880.       D := New(PDialog,Init(R, 'MemoDialog'));
  881.       with D^ do
  882.         begin
  883.           R.Assign(12, 2, 13, 14);
  884.           V := New(PScrollBar, Init(R));
  885.           Insert(V);
  886.           R.Assign(2, 2, 12, 14);
  887.           V := New(PDemoListViewer, Init(R, 1, nil, PScrollBar(V)));
  888.           PDemoListViewer(V)^.SetRange(20);
  889.           Insert(V);
  890.  
  891.           R.Assign(33, 2, 34, 13);
  892.           V := New(PScrollBar, Init(R));
  893.           Insert(V);
  894.           R.Assign(14, 13, 33, 14);
  895.           W := New(PScrollBar, Init(R));
  896.           Insert(W);
  897.           R.Assign(14, 2, 33, 13);
  898.           V := New(PMemo, Init(R, PScrollBar(W), PScrollBar(V), nil, 1024));
  899.           Insert(V);
  900.         end;
  901.       DeskTop^.ExecView(D);
  902.       D^.Done;
  903.     end;
  904. end;
  905.  
  906. var MemoApp:TMemoApp;
  907. begin
  908.   MemoApp.Init;
  909.   MemoApp.Run;
  910.   MemoApp.Done;
  911. end.
  912. --------------------  End of bugs!  ---------------------------------
  913. I got an update to TP6.01, but they haven't change anything.
  914. -  J"urgen Schlegelmilch
  915.  
  916.