_XALLOC: AN EXPANDED MEMORY MANAGER FOR TURBO PASCAL_ by Herbert Gintis [LISTING ONE] unit xlineobj; { Typical use: program xtest; uses xalloc,xlineobj; var s : xline; begin if not xalloc_init then halt; s.init; s.put_text('This goes into expanded memory'); writeln(s.get_text); s.done; xalloc_done; end. } interface uses xalloc; type xline = object len : byte; mem : xaddress; constructor init; destructor done; virtual; procedure newsize(ncols : integer); function get_text : string; procedure put_text(s : string); end; implementation var xs : ^string; constructor xline.init; const mincols = 8; begin xgetmem(mem,mincols); len := mincols-1; xs := xpage_in(mem); xs^ := ''; end; destructor xline.done; begin xfreemem(mem,len+1); end; procedure xline.newsize(ncols : integer); begin xfreemem(mem,len+1); xgetmem(mem,ncols+1); xs := xpage_in(mem); len := ncols; end; function xline.get_text : string; begin xs := xpage_in(mem); get_text := xs^; end; procedure xline.put_text(s : string); begin if length(s) <> len then newsize(length(s)); xs := xpage_in(mem); xs^ := s; end; end. [LISTING TWO] unit xalloc; {-See the unit xlineobj.pas for typical use of this unit} interface const nilpage = $ff; type xaddress = record page : byte; pos : word; end; function xalloc_init : boolean; procedure xgetmem(var x : xaddress;size : word); procedure xfreemem(var x : xaddress;size : word); function xpage_in(var x : xaddress) : pointer; function xmaxavail : longint; function xmemavail : longint; procedure xalloc_done; implementation uses crt,dos; const emm_int = $67; dos_int = $21; maxfreeblock = 4000; xblocksize = $4000; _get_frame = $41; _unalloc_count = $42; _alloc_pages = $43; _map_page = $44; _dealloc_pages = $45; _change_alloc = $51; type xheap = array[0..1000] of word; fblock = record page : byte; start,stop : word; end; fblockarray = array[1..maxfreeblock] of fblock; var regs : registers; handle,tot_pages : word; xheapptr : ^xheap; xfreeptr : ^fblockarray; last_page,lastptr : integer; map : array[0..3] of integer; frame : word; function ems_installed : boolean; const device_name : string[8] = 'EMMXXXX0'; var i : integer; begin ems_installed := false; with regs do begin {check for ems present} ah := $35; {get code segment pointed to by interrupt 67h} al := emm_int; intr(dos_int,regs); for i := 1 to 8 do if device_name[i] <> chr(mem[es : i + 9]) then exit; end; ems_installed := true; end; function unalloc_count(var available : word): boolean; begin with regs do begin ah := _unalloc_count; intr(emm_int,regs); available := bx; unalloc_count := ah = 0 {return the error code} end; end; function alloc_pages(needed: integer): boolean; begin with regs do begin ah := _alloc_pages; bx := needed; intr(emm_int,regs); handle := dx; alloc_pages := (ah = 0); {return the error code} end; end; function xdealloc_pages: boolean; begin with regs do begin ah := _dealloc_pages; dx := handle; intr(emm_int,regs); xdealloc_pages := (ah = 0); {return the error code} end; end; function change_alloc(needed : integer) : boolean; begin with regs do begin ah := _change_alloc; bx := needed; dx := handle; intr(emm_int,regs); change_alloc := (ah = 0); {return the error code} end; end; function xmap_page(l_page,p_page: integer): boolean; begin xmap_page := true; if map[p_page] <> l_page then with regs do begin ah := _map_page; al := p_page; bx := l_page; dx := handle; intr(emm_int,regs); xmap_page := (ah = 0); if ah = 0 then map[p_page] := l_page; end; end; function xpage_in(var x : xaddress) : pointer; begin if xmap_page(x.page,0) then xpage_in := ptr(frame,x.pos) else xpage_in := nil; end; function xget_frame(var frame: word): boolean; begin with regs do begin ah := _get_frame; intr(emm_int,regs); frame := bx; xget_frame := (ah = 0); {return the error code} end; end; procedure xgetmem(var x : xaddress;size : word); var i : integer; begin for i := 1 to lastptr do begin with xfreeptr^[i] do begin if size <= stop - start then begin x.page := page; x.pos := start; inc(start,size); if start = stop then begin xfreeptr^[i] := xfreeptr^[lastptr]; dec(lastptr); end; exit; end; end; end; x.page := nilpage; i := 0; repeat inc(i); if i > tot_pages then exit; if i > last_page then begin inc(last_page); if not change_alloc(last_page) then exit; end; until xblocksize - xheapptr^[pred(i)] > size; with x do begin page := pred(i); pos := xheapptr^[page]; inc(xheapptr^[page],size); end; end; procedure xfreemem(var x : xaddress;size : word); var i,xstop : integer; begin xstop := x.pos + size; i := 0; while i < lastptr do begin inc(i); with xfreeptr^[i] do begin if x.page = page then begin if x.pos >= start then begin if x.pos <= stop then begin x.pos := start; if xstop < stop then xstop := stop; xfreeptr^[i] := xfreeptr^[lastptr]; dec(lastptr); dec(i) end; end else if xstop >= start then begin if xstop < stop then xstop := stop; xfreeptr^[i] := xfreeptr^[lastptr]; dec(lastptr); dec(i) end; end; end; end; if lastptr > 0 then with xfreeptr^[lastptr] do if start = stop then dec(lastptr); if x.pos < xstop then begin if xstop = xheapptr^[x.page] then xheapptr^[x.page] := x.pos else begin if lastptr < maxfreeblock then begin inc(lastptr); with xfreeptr^[lastptr] do begin page := x.page; start := x.pos; stop := xstop; end; end; end; end; end; function xmemavail : longint; var s : longint; i : integer; begin s := 0; for i := 0 to pred(tot_pages) do inc(s,$4000 - xheapptr^[i]); for i := 1 to lastptr do with xfreeptr^[i] do inc(s,stop - start); xmemavail := s; end; function xmaxavail : longint; var s : longint; i : integer; begin s := 0; for i := 0 to pred(tot_pages) do if $4000 - xheapptr^[i] > s then s := $4000 - xheapptr^[i]; for i := 1 to lastptr do with xfreeptr^[i] do if stop - start > s then s := stop - start; xmaxavail := s; end; procedure xalloc_done; begin if not xdealloc_pages then; end; function xalloc_init : boolean; var i : word; begin xalloc_init := false; if not ems_installed then exit; if not unalloc_count(tot_pages) then exit; if tot_pages = 0 then exit; if not xget_frame(frame) then exit; getmem(xheapptr,tot_pages*sizeof(word)); if xheapptr = nil then exit; new(xfreeptr); if xfreeptr = nil then exit; for i := 0 to pred(tot_pages) do xheapptr^[i] := 0; if not alloc_pages(1) then exit; xalloc_init := true; lastptr := 0; last_page := 1; for i := 0 to 3 do map[i] := -1; end; end.