*************************************************************************** *** *** *** FFFFF IIIII X X EEEEE SSS #01 *** *** F I X X E S S *** *** F I X X E S *** *** FFFF I X EEEE SSS *** *** F I X X E S *** *** F I X X E S S *** *** F IIIII X X EEEEE SSS *** *** *** *************************************************************************** This text file contains several changes that can be made to the TopSpeed library source code. These changes represent temporary fixes to the libraries and are not guaranteed to work 100% in all cases but should work for most situatione. If you discover any problems with these fixes then please let the Tech Department aware as soon as possible so that we can revise this file and update our patches. It would also be helpfull if you can tell us if these changes improve you system, and generally any comments about this file will be helpfull. I should also point out that this file represents unofficial changes to the library to solve some problems. This file has been created jointly by the Tech Departments in London and the U.S.A. Contacts : Name Location Phone Fax ~~~~~~~~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~ Richard Stollar London (+44)71 253 4333 (+44)71 251 1442 Sean Wilson U.S.A (+1)305 785 4555 (+1)305 946 1650 CompuServe users can simply 'GO CLARION' Happy programming from the TopSpeed Technical Support Team. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *************************************************************************** * All TopSpeed Languages v3.10 * *************************************************************************** Problem: Under certain circumstances, if farcoreleft() is called, DOS memory allocation functions (INT21, ah=0x48) will report that no memory is available. Diagnosis: This is not a bug but may cause problems interfacing with some third party code. farcoreleft() calls INT21 es = __psp, ah=0x4A, bx=0xFFFF to determine the amount of memory available to the program. #include #include #include unsigned GetMaxParas() { union REGS R; R.h.ah = 0x48; R.x.bx = 0xFFFF; intdos(&R, &R); return R.x.bx; } int main(void) { unsigned long m; unsigned p; p = GetMaxParas(); printf("p = %u\n", p); m = farcoreleft(); printf("m = %lu\n", m); p = GetMaxParas(); /* p has changed though it shouldn't */ printf("p = %u\n", p); return 0; } Fix/Workaround: If farcoreleft() calls 0x48 instead, this problem does not occur. Modify COREMEM.A line 2563 to read: mov ah, 48H (* what has DOS got *) instead of mov ah, 4AH (* what has DOS got *) =========================================================================== Problem: Floating point errors in stack model or Windows programs will cause the stack to become imbalanced. Diagnosis: The __report_math_error function will does not push ds when it should but does pop ds (if it hasn't been pushed). Fix/Workaround: Change the lines near the start of __report_math_error, around line 1523 in COREMATH.A from: (*%T SameDS *) push ds (*%E *) To: (*%F SameDS *) push ds (*%E *) To match the exit code. =========================================================================== Problem: When you use SetClipRgn() in conjunction with FloodFill(), you get a leak from the object being filled. Fix/Workaround: To resolve this problem remove line 4797 in COREGRAPH.A after the label EGAnNewByte: EGAnNewByte: mov ax, bp mov cx, di sub cx, bp inc cx mov bp, cx and bp, 7 shr cx, 1 shr cx, 1 shr cx, 1 jcxz noneLeft sub al, al xchg si, di repe ; scasb xchg si, di (* je byteF REMOVED *) inc cx shl cx, 1 shl cx, 1 shl cx, 1 byteF: mov ax, di sub ax, cx sub ax, bp mov bp, ax inc bp cmp bp, di ja EGARsDone =========================================================================== Code Modification: When the procedure read() is used for text mode read, it returns the number of characters read, ignoring the documented fact that CR/LF only counts as 1 character and ^Z is not counted. Change line 1847 IN COREIO.A from : dec si to : dec di and 1872 from : mov ax,si to : mov ax,di =========================================================================== Code Modification: The variable beg_dummy_data (on line 114 of INITWIN.A) needs to occupy two more bytes to prevent corruption of other data. Simply append two 0's onto the definition: beg_data_dummy : dw 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 *************************************************************************** * TopSpeed C/C++ v3.10 * *************************************************************************** Problem: If you follow the instructions in COREFILE.CX to increase the number of handles available to your program, your program will behave unpredictably if compiled in a large data model. Diagnosis: The following program attempts to open all available files. If the user follows the instructions in COREFILE.CX to increase the number of files available to the program, then runs this program in a large data model, the program will not behave as expected. The reason is that the code in in COREIO.A which performs the initialisation assumes near data. When COREFILE.C is recompiled in a large data model, everything gets placed in far segments. #include #ifndef _OS2 #include #endif int main(void) { FILE *pfArray[FOPEN_MAX]; size_t i; #ifndef _OS2 // Extender allows 255 files union REGS r; r.h.ah = 0x67; r.x.bx = SYS_OPEN; intdos(&r, &r); if (r.x.cflag) { printf("Error: %s (%d)\n", strerror(r.x.ax), r.x.ax); } else #endif { for (i = 0; i < FOPEN_MAX; i++) { char Name[20]; sprintf(Name, "TST%02X.$$$", i); if ((pfArray[i] = fopen(Name, "w+")) != NULL) fprintf(pfArray[i], "%s\n", Name); } for (i = 0; i < FOPEN_MAX; i++) { if (pfArray[i]) fclose(pfArray[i]); } } } Fix/Workaround: The solution is to modify COREFILE.CX by placing the line: #pragma data(seg_name=>null) at the top of the file. This must appear before the #include otherwise _iob[] will be placed in FAR_BSS. =========================================================================== Problem: If the system() function is called in Overlay or DynaLink models, the program will run out of memory. Diagnosis: The problem occurs because the system() function calls _shr_mem() to release all unused memory before calling _exec(), it fails to call _res_mem() to reclaim memory so the heap shrinks irretrievably. #include #include #include #include "overlay.h" void main(void) { UserFlush(); printf("Coreleft = %lu\n", coreleft()); system("rip"); UserFlush(); printf("Coreleft = %lu\n", coreleft()); } Fix/Workaround: The fix is to modify the second definition of system() in CSYS.C: Before the definition, or in CLIB.H add the prototype: extern void (* _res_mem)(void); Immediately after the call to _exec() add the code: if (_res_mem) _res_mem(); =========================================================================== Problem: If you call realloc() with a NULL pointer, a windows UAE is generated. Fix/Workaround: Fix is to trap the NULL pointer by inserting the following code at the start of the procedure (Line 34) in CWINMEM.C if (buffer == NULL) ret=LocalAlloc(LMEM_FIXED,size); else ret=LocalReAlloc(LMEM_FIXED,size); ... =========================================================================== Problem: The Procedure strtoul() in the C library returns an incorrect pointer when you pass for example '0STOP'. You would expect the pointer to point to the beginning of the 'S' but it does infact point to the '0'. If you pass '0x0STOP' then this function works as expected and does indeed return a pointer to the 'S'. Fix/Workaround: Change the strtoul() procedure code in CLIB2.C around line 747 as follows: .... } else if((base == 8) || (base == 0)) flag|=_OCT; else // New Line scanned = 1; // NewLine } =========================================================================== Problem: There is a problem with number imputting in the following functions: IO.RdIn() IO.RdLngInt() IO.RdCard() IO.RdLngCard() Diagnosis: These procedures use a common procedure to determine if the characters are valid or not. This procedure StrToCI() checks for the following valid characters: '0123456789ABCDEF'. If you entre an 'A' when expcting a DECIMAL number to be input then the result will be 10; If you entre 'AA' then the result will be 110 (A^2 + A) 10^2+10. Fix/Workaround: Modify the StrToCI() procedure in STR.MOD as follows: PROCEDURE StrToCI(S: ARRAY OF CHAR; Base: CARDINAL; VAR OK: BOOLEAN) : LONGCARD; VAR i,l : CARDINAL; b,t,y : LONGCARD; c : CHAR; x : SHORTCARD; BEGIN CheckBase( Base ); b := VAL( LONGCARD,Base); i := 0; l := HIGH( S ); IF (S[0] = '-') OR (S[0] = '+') THEN i := 1; END; t := 0; IF S[i] = CHR(0) THEN OK := FALSE; END; WHILE (i <= l) AND (S[i] # CHR(0)) DO c := S[i]; (* Change made Here *) IF ( (Base=10) AND ((c<'0') OR (c>'9')) ) OR ( (Base=16) AND ((c<'0') OR (c>'F')) ) OR ( (Base<10) AND ((c<'0') OR (c>CHR(48+Base))) ) THEN OK := FALSE; RETURN t; END; x := ConvInt[c]; IF (x > SHORTCARD(b)-1 ) OR (t > (MAX(LONGCARD)-LONGCARD(x)) DIV b) THEN OK := FALSE; END; t := t*b+VAL( LONGCARD,x ); INC( i ); END; RETURN t; END StrToCI; =========================================================================== Problem: There is a problem with the real number scanning routines in IOSTREAM If an invalid floating point number is extracted from an input stream that has the form: [+ | -]{any old garbage}, the getreal() function in IOSTREAM.CPP will indicate that a value has been successfully read even though it has only read a '+' or a '-'. Diagnosis: #include #include int main(void) { double d; cin >> d; // Input an invalid number, e.g. +$$$ // or E100 if (cin.fail()) cout << "Failed\n"; else cout << "Good number: " << d; // Current code always succeeds } Fix/Workaround: The fix is to modify the code at line 720 in IOSTREAM.CPP from: if((c == '+') || (c == '-')) { /* leading sign */ good_scan=1; _fmt_buf[n++]= (char) c; c= is.get(); if(!is.good()) break; } To: if((c == '+') || (c == '-')) { * leading sign * _fmt_buf[n++]= (char) c; // Remove good_scan=1; c= is.get(); if(!is.good()) break; } And add the following statement: if (!good_scan) break; Just before the line: if((c == 'E') || (c == 'D') || (c == 'e') || (c == 'd')) { =========================================================================== Problem: The strstr() procedure fails if the first string is empty and the next character in memory is the search string. Fix/Workaround: Make a function that checks the length of the first string before calling strstr(): char *MyStrStr(const char *s1, const *s2) { if (*s1 ==0) { return NULL; } return strstr(s1,s2); } =========================================================================== Problem: The following program demonstrates a problem with using findfirst() function under the extender. #include #include static struct ffblk FlBlk; int main(void) { int i=0; while (!kbhit()) { printf("%06D: %02d\r", ++i, findfirst("*.*", &FlBlk,0)); } } Diagnosis: The problem is that findfirst() function always allocates handle space under the extender. If this isn't deallocated by a call to DosFindClose() when findnext() fails, the extender will crash. Fix/Workaround: One possible fix is to modify the findfirst() function to use the system hanele. This is consistent with the DOS limitations on th use of findfirst() and findnext() Modify the findfist() procedure around line 3118 in CIO2.C as follows: int findfirst(const char *path, struct ffblk *buffer, int attrib) { FILEFINDBUF b; unsigned status, handle, count; #ifdef _XTD // handle := HDIR_SYSTEM; // #else // Changes Here... handle = 0xffff; // #endif // count = 1; #ifndef _XTD attrib &= 0xfff7; #endif status = DosFindFirst((PSZ) path, (PHDIR) &handle, attrib, (PFILEFINDBUF) &b, sizeof(b), (PUSHORT) &count, 0); if (status) { errno = status; return status; } if (_wildinname(path)) * (unsigned *) buffer = handle; else { * (unsigned *) buffer = GuardHandle; DosFindClose(handle); } _findresult(buffer, &b); return 0; } *************************************************************************** * TopSpeed Modula-2 v3.10 * *************************************************************************** Problem: Programs that utilise and repeatedly re-initialise SIGNALs may eventually fail with a memory allocation error. Diagnosis: The following program illustrates the problem, it fails with a memory allocation failure after a few seconds. Calling the Init() procedure to initialise a SIGNAL allocates memory which is never deallocated during the lifetime of the program. This isn't a bug so much as a limitation. MODULE SW130; IMPORT Process, IO, BiosIO; VAR Restart : Process.SIGNAL; Quit : BOOLEAN; PROCEDURE Proc(); VAR Widget : ARRAY[0..4] OF CHAR; I : CARDINAL; BEGIN Widget := "-\|/*"; I := 0; LOOP IO.WrChar(Widget[I]); IO.WrChar(CHR(8)); INC(I); IF I = SIZE(Widget)-1 THEN I := 0; END; IF BiosIO.KeyPressed() AND (BiosIO.RdKey() = CHR(27)) THEN Quit := TRUE; END; Process.SEND(Restart); END END Proc; BEGIN Quit := FALSE; Process.StartScheduler(); Process.StartProcess(Proc, 1024, 0); REPEAT Process.Init(Restart); Process.WAIT(Restart); UNTIL Quit; Process.StopScheduler(); END SW130. Fix/Workaround: It seems that the only safe way of implementing a change is to maintain a linked list of currently active SigRecs. This linked list can then be deallocated by the StopScheduler() procedure. If it is necessary to re-initialise the SIGNAL, this can also be done by scanning the list to ensure that it exists, allocating a new SigRec if necessary or simply modifying the values otherwise. This can be achieved by modifying the Init() and StopScheduler() in PROCESS.MOD procedures as follows. VAR SigList : SIGNAL; PROCEDURE Init(VAR s: SIGNAL); VAR tmp : SIGNAL; BEGIN IF s # NIL THEN tmp := SigList; LOOP IF tmp = s THEN EXIT; ELSIF tmp = NIL THEN s := NIL; EXIT; ELSE tmp := tmp^.next; END END END; IF s = NIL THEN NEW(s); s^.next := SigList; SigList := s; END; s^.waiting := NIL; s^.count := 0; END Init; PROCEDURE StopScheduler; VAR ie : CARDINAL; s : SIGNAL; BEGIN ie := SYSTEM.GetFlags(); IF CoreProc._Started THEN SYSTEM.EI ; CoreProc._Started := FALSE; CoreProc.Stop := TRUE; WHILE CoreProc.Stop DO END; END; SYSTEM.SetFlags(ie); WHILE SigList # NIL DO (* Delete SigRecs *) s := SigList^.next; DISPOSE(SigList); SigList := s; END; END StopScheduler; =========================================================================== Problem: Programs which allocate memory directly from DOS using the INT21H, AH=48H function may cause the Storage procedures to fail with unpredictable results. Diagnosis: This is not a bug, but may be problem interacting with some third party code. The problem occurs if memory is allocated from DOS before the far heap is initialised. Any call to INT21H, AH=48H fragments memory causing InitFarHeap() to make a heap of size 0. Unfortunately this condition is not detected by FarMakeHeap() so that it appears that the heap is correctly constructed. This is because the far heap is created by expanding the memory allocated to the program from DOS. By allocating another block from DOS this expansion is prevented. Fix/Workaround: By calling INT21H, AX=5801H, BL=2 (Set allocation strategy to allocate last block) prior to allocating memory using a INT21H, AH=48H call, it is possible to reserve memory at the end of the DOS memory pool, without interfering with the initialsation of the far heap. =========================================================================== Problem: The StrToReal() procedure has a bug in it which causes IO.ReadReal() to report strings such as 'aaaaa' as valid real numbers. Diagnosis: MODULE SW164; IMPORT Str, IO; VAR r : LONGREAL; b : BOOLEAN; s : ARRAY [0..30] OF CHAR; BEGIN s := 'a0'; r := Str.StrToReal(s, b); IF b THEN IO.WrStr('Wrong! '); IO.WrStr(s); IO.WrStr(' Is not a valid REAL number'); IO.WrLn; END; END SW164. Fix/Workaround: The fix is to modify the code in Str.MOD around line 483 from: IF StrictRealConv & (c = 0C) THEN OK := FALSE; RETURN Zero; ELSE c := '.'; DEC(i) ; END; To: IF StrictRealConv & (c = 0C) THEN OK := FALSE; RETURN Zero; ELSE IF ((c # 0C) & (c # 'E')) THEN OK := FALSE; RETURN Zero; END; c := '.'; DEC(i) ; END; =========================================================================== Problem: Setting the Tme using Lib.SetTime() reports that the time was not set. Diagnosos: This procedure sets the time by using the DOS function 2Dh. This DOS function returns in AL if the setting was successfull. Lib.SetTime() returns TRUE if AX=0 otherwise returns FALSE. AH does not get reset by the DOS functyion so AX is never 0. Fix/Workaround: Change the procedure SetTime as follows: PROCEDURE SetTime(Hrs,Mins,Secs,Hsecs:CARDINAL):BOOLEAN; VAR R : SYSTEM.Registers; BEGIN WITH R DO AH := 2DH; CH := SHORTCARD(Hrs); CL := SHORTCARD(Mins); DH := SHORTCARD(Secs); DL := SHORTCARD(Hsecs); Lib.Dos(R); RETURN AL=0; END; (*WITH*) END SetTime; =========================================================================== Problem: Setting the Tme using Lib.SetDate() reports that the date was not set. Diagnosos: This procedure sets the date by using the DOS function 2Bh. This DOS function returns in AL if the date was set successfull. Lib.SetDate() returns TRUE if AX=0 otherwise returns FALSE. AH does not get reset by the DOS functyion so AX is never 0. Fix/Workaround: Change the procedure SetDate as follows: PROCEDURE SetDate(Year,Month,Day:CARDINAL):BOOLEAN; VAR R : SYSTEM.Registers; BEGIN WITH R DO AX := 2B00H; CX := Year; DH := SHORTCARD(Month); DL := SHORTCARD(Day); (*%T _WINDOWS *) DS := Seg(R); ES := Seg(R); (*%E *) Lib.Dos(R); RETURN AX=0; END; (*WITH*) END SetDate; =========================================================================== Problem: Lib.Exec() doesn't get the return code when calling another program. Fix/Workaround: Remove a section of code from SPAWN.A around line 2467. envSet: push ax push bx push ss lea ax, [bp][resbuf] push ax push [bp][pathbuf][2] push [bp][pathbuf] call far DOSEXECPGM or ax, ax jnz begetError (* REMOVE THIS CODE mov ax, [bp][flag] cmp ax, P_OVERLAY je terminate cmp ax, P_WAIT je getRetcode mov si, [bp][resbuf][codeTerminate] (* child's PID *) jmp begetDone *) =========================================================================== Problem: When using the EXTENDMT model, the _getTID() in COREPROC.A used to get information on the current thread does not work correctly. Fix/Workaround: You should implement a new procedure in IO.MOD, FIO.MOD and FIOR.MOD as follows: (*%T _mthread *) PROCEDURE _getTID(): CARDINAL; BEGIN (*%T _XTD*) RETURN LI^.tidCurrent; (*%E*) (*%F _XTD*) RETURN CoreProc._getTID(); (*%E*) END _getTID; (*%E*) You should then replace all calls to coreproc._getTID() with calls to your new local procedure _getTID(). *************************************************************************** * TopSpeed Pascal v3.10 * *************************************************************************** Problem: Under some circumstances the _VAL_INT() procedure fails to produce a valid result (SW108). Diagnosis: The following code illustrates a bug in the _VAL_INT() procedure in the Turbo Pascal compatibility library. If a digit in the string passed to _VAL_INT() is the value of the length of the string (high) then the procedure fails. PROGRAM ValI(OUTPUT); IMPORT TurboSYS*; VAR EndCh : WORD; MyVal : INTEGER; BEGIN _VAL_INT('12345', MyVal, EndCh); WriteLn('Converted value = ', MyVal); END. Fix/Workaround: TURBOSYS.PAS, around line 148 in _val_int() remove the following code: if t = high then begin code := n; goto 999; end; =========================================================================== Problem: Under some circumstances the _VAL_REAL() procedure fails to produce a valid result (SW109). Diagnosis: The following code illustrates a bug in the _VAL_REAL() procedure in the Turbo Pascal compatibility library. The problem is unpredictable but tends to manifest itself as a runtime error 'No matching Case Label' and is due to the fact that the variable 'state' is not initialised. PROGRAM ValR(OUTPUT); IMPORT TurboSYS*; VAR EndCh : WORD; MyVal : LONGREAL; BEGIN _VAL_REAL('123.45', MyVal, EndCh); WriteLn('Converted value = ', MyVal); END. Fix/Workaround: TURBOSYS.PAS, around line 180 in _val_real() add the line: state := Start; =========================================================================== Problem: Calling PasDos.BcdToLong() results in an unresolved external being reported by the linker. Diagnosis: BcdToLong() is not implemented. Fix/Workaround: The following code implements the PasDos.BcdToLong() function which has been omitted from the Pascal run-time libraries. This code should be inserted into the PASLOW.A file just after the code for LONGTOBCD. section (*%F _DLL *) (*%F SameDS *) segment PASDOS_TEXT(CODE,28H) (*%E *) (*%T SameDS *) segment _TEXT(CODE,28H) (*%E *) (*%E *) (*%T _DLL *) segment PASDOSDLL_TEXT(CODE,28H) (*%E *) public PASDOS$BCDTOLONG : Bcd = frame retSize = 10 push bp mov bp, sp fbld st(0), [bp][Bcd] fstp st(1), st(0) pop bp (*%F NearCall *) ret far retSize (*%E *) (*%T NearCall *) ret retSize (*%E *) =========================================================================== Problem: GetFAttr() and SetFAttr() do not appear to correctly get or set the specified file's attributes. Diagnosis: The following code illustrates a bug in the SetFAttr() procedure, and a similar bug in the GetFAttr() procedure. The program fails to set the correct file attributes for the specifed file. The problem is caused by the fact that both SetFAttr() and GetFAttr() fail to handle the file name correctly, they both use the code: R.DS := Seg((f:>filetype).name); R.DX := Ofs((f:>filetype).name); This will pass the address of the length byte before the name to DOS, furthermore the name is not always null-terminated. PROGRAM Attr(Output); VAR tf : TEXT; attr : WORD; BEGIN Assign(tf, 'fred.ro'); ReWrite(tf); WriteLn(tf, 'A line in read-only file FRED.ROA'); Close(tf); SetFAttr(tf, ReadOnly + Archive); GetFAttr(tf, attr); WriteLn('Attributes = ', attr, ' should be 33 (r/o + archive)'); END. Fix/Workaround: Both procedures should be rewritten as follows: procedure GetFAttr{(var f; var Attr: word)}; var R : PasDos.Registers; d : int16; name: DosPathStr; New file name variable begin StrToZ((f:>filetype).name, name); Obtain ASCIIZ file name d := CoreSig._seterrno(0); R.AH := 43H; R.AL := 0; R.DS := Seg(name); Segment of ASCIIZ name R.DX := Ofs(name); Offset of ASCIIZ name PasDos.MsDos(R); Attr := R.CX; end; procedure SetFAttr{(var f; Attr: word)}; var R : PasDos.Registers; d : int16; name: DosPathStr; New file name variable begin StrToZ((f:>filetype).name, name); Obtain ASCIIZ file name d := CoreSig._seterrno(0); R.AH := 43H; R.AL := 1; R.DS := Seg(name); Segment of ASCIIZ name R.DX := Ofs(name); Offset of ASCIIZ name R.CX := Attr; PasDos.MsDos(R); end; =========================================================================== Problem: Intermittent problems arise from the use of ReWrite() with a read-only file. Diagnosis: There is a bug in the _rewrite() procedure in PASLIB.PAS. The following code attempts to demonstrate it but will not do so consistently. The problem occurs when trying to ReWrite() a readonly file. _rewrite() attempts to open the file and then sets the file state to Initialized. It then checks for an IO error and if one has occured it returns. Of course, since the file is read only an error is returned. During a subsequent call to ReWrite() the file is checked to see if it is Initialized and if so it is closed() freeing associated buffers. Since The file was not successfully initialised freeing the buffer causes unpredictable (and not readily duplicated) problems. PROGRAM SW147(Output); IMPORT PasDOS; VAR tf : TEXT; attr : WORD; BEGIN Assign(tf, 'fred.ro'); ReWrite(tf); Close(tf); IOcheck := FALSE; PasDOS.SetFAttr(tf, ReadOnly + Archive); ReWrite(tf); Rewrite(tf); END. Fix/Workaround: The solution is to make the following modification to the _rewrite() procedure: if IOResult = 0 then ... Unchanged code end else } Added code f.state := f.state - [Initialized, TempFile]; } =========================================================================== Problem: If you run the example program PWDEMO in large memory model it will terminate with a GPF. Diagnosis: Then GPF occurs when the flushstdout() procedure is called on program termination. Under Windows the code in the body of this function should not be executed since the standard files are not opened. Fix/Workaround: Since flushstdout() is initially assigned to a variable cdp which is always called on exit the easiest fix is to conditionally exclude the body of this function in PASLIB.PAS, line 1222: procedure flushstdout; (* closedown procedure when no files used *) var ret: int16; BI: PasCore.FileInf; begin (*%F _WINDOWS *) BI := (PasLib._output.stream:>PasCore.FileInf); if (CoreFile._F_OUT in BI^.Flag) then (* flush output buffer *) ret := PasCore.FlsBuf(BI, (Acrt in PasLib._output.state)); BI^.Flag := BI^.Flag - [CoreFile._F_OUT]; BI^.Pback := 0; (* reset buffer *) BI^.Cnt := 0; BI^.Flag := (BI^.Flag + [CoreFile._F_RST]) - [CoreFile._F_OUT, CoreFile._F_IN]; (*%E*) end; =========================================================================== Problem: The end of file is not correctly determined under all circumstances. Diagnosis: This program fails under V3.10 when processing the file GETEOF.TXT, run with "SW153 < GETEOF.TXT". The reason being that the EOF condition is not detected if the EOF is at the end of the buffer. PROGRAM SW153(input, output); VAR str: STRING [128]; BEGIN WHILE NOT eof (input) DO BEGIN readln (str); writeln (str) END END. Fix/Workaround: The fix is to modify line 1577 in PASLIB from: if (TextFile in f.state) then to: if (not(CoreFile._F_EOF in St^.flag) and (TextFile in f.state)) then =========================================================================== Problem: If only the enter key is hit whilst readln() is waiting for input, a string of length 1 containing a space is returned. Diagnosis: The following program can be used to the way the ReadLn() function behaves. If only the enter key is hit when this program is executed, then a string of length 1 containing a single space is returned. The code in InStr() that tests the contents of the returned buffer is incorrect. PROGRAM Tst(Input, Output); VAR Str : STRING[20]; BEGIN ReadLn(Str); Write('Str = "', Str, '", len = ', Length(Str)); END. Fix/Workaround: A fix is to modify line 677 in InStr() in PASCORE.PAS from: IF (count = 1) AND (((EOLinBuffer IN f.state) AND ((f.bufferptr:>CharPtr)^ = CHR(0DH))) OR IsEOF(f)) THEN To: IF (count = 1) AND (((EOLinBuffer IN f.state) AND ((f.bufferptr:>CharPtr)^ = ' '})) OR IsEOF(f)) THEN This is necessary since get() ensures that the final 0DH is converted to a ' '. =========================================================================== Code Modification: A problem with using the FLUSH() function can be resolved by changing code around line 203 in PASLIB.PAS from : else if (BI^.Flag * [CoreFile._F_DEV] = []) then begin Pos := CoreIO.tell(f.handle); (* input stream *) if BI^.Pback <> 0 then Pos := Pos-1; Pos := Pos-BI^.Cnt; Pos := CoreIO.lseek(f.handle, Pos, CoreIO.SEEK_SET); BI^.Ptr := BI^.Base; end; to : else if (BI^.Flag * [CoreFile._F_DEV] = []) then begin Pos := CoreIO.tell(f.handle); (* input stream *) if BI^.Pback <> 0 then Pos := Pos-1; Pos := Pos-BI^.Cnt; Pos := CoreIO.lseek(f.handle, Pos, CoreIO.SEEK_SET); (* This Line *) BI^.Base := BI^.Ptr; end; *************************************************************************** * TopSpeed Extender v3.10 * *************************************************************************** Problem: Under some circumstances an Extended or ExtendedMT model program will generate an XTRACE on termination. Diagnosis: There is a problem with the _exit() function that is called in OS/2 or Extended Model programs. Currently it tests for the value in __SSisDS without ensuring that ds is set to the _DATA segment. Fix/Workaround: Modify the definition of _exit() around line 3171 of COREMAIN.A to read: public __exit : (* void __exit(int code) terminates process. *) (*%F RegParam *) code = frame push bp mov bp, sp mov ax, [bp][code] (*%E *) (*%F SameDS *) (*********************************) mov ax, _DATA (*** Ensure that DS is set to ***) mov ds, ax (*** _DATA. ***) (*%E *) (*********************************) cmp byte [__SSisDS], 1 jne farStack mov ss, [__ss_temp] mov sp, [__sp_temp] farStack: mov byte [__exit_list_done], 1 mov bx, EXIT_PROCESS push bx push ax call far DOSEXIT (* call exit function *) *************************************************************************** * TopSpeed Overlay Loader v3.10 * *************************************************************************** Problem: Calling the _heapchk(), _heapset() or _heapwalk() functions in Overlay or Dynalink model, always returns HEAPEND, without properly traversing the heap. Diagnosis: This is a trivial bug in the Overlay Loader. Fix/Workaround: Edit the procedure HeapWalk() in LOADER.MOD, move the lines: IF Seg(pentry^) = g.start THEN RETURN HEAPEND; END; (*IF*) From after the line: WITH T(pentry)^ DO Up, to after the line: pentry := [Seg(pentry^) + T(pentry)^.Size:0];