(* * * * * * * * * * * * * * * * * * *
 *
 * prog4-6.pas
 *
 *      Demonstrates
 *          - Map multiple pages by #/segment
 *          - Save/restore partial map
 *          - Mapping pages in lower 640K
 *
 * * * * * * * * * * * * * * * * * * *)

program prog4_6;

uses    _globals,
        _ems;


var
    ems:                EMS_Ems;

    i:                  Word;

    numMappablePages:   Word;
    numMappablePages2:  Word;
    numAvailableFrames: Word;

    pfa:                EMS_PageFrame;
    
    pageAddress:       ^EMS_MappablePagesInfoArr;
    availableFrame:    ^EMS_MappablePagesInfoArr;

    mapByNumber:        array[0..5] of EMS_MapByNumber;
    mapByAddress:       array[0..5] of EMS_MapByAddress;

    restOfMem:          Pointer;
    memLeft:            DWord;    

    mapPageList:        array[0..6] of Word;
    mapSize:            Word;
    mapSave1:           Pointer;
    mapSave2:           Pointer;

    handle:             EMS_EmBlk;

    frame:              array[0..5] of ^EMS_Page;

begin

    (*
     *  First check for presence of EMS
     *)
    if ems.init then begin
        writeln('EMS is not present');
        Halt;
        end;

    (*
     *  Now get the Page Frame Address:
     *)
    if ems.getPFA(pfa) then begin
        ems_demoError('EMS_Ems.getPFA');
        end;

    (*
     *  We'll want a dozen pages of EMS, so allocate them now.
     *)
    if handle.allocEM(12) then begin
        ems_demoError('EMS_EmBlk.allocEM');
        end;

    (*
     *  Find out how many mappable pages we have all together. In
     *  4.0, we do not have a fixed size page frame, we may have
     *  many more than 4 mappable pages.
     *)
    if ems.getNumMappable40(numMappablePages) then begin
        ems_demoError('EMS_Ems.getNumMappable40');
        end;

    (*
     *  Now allocate a buffer big enough to hold the addresses
     *  of these pages.
     *)
    GetMem(pageAddress, sizeof(EMS_MappablePagesInfo) * numMappablePages);
    GetMem(availableFrame, sizeof(EMS_MappablePagesInfo) * numMappablePages);

    (*
     *  Get the info
     *)
    if ems.getAddrsMappable40(pageAddress^, numMappablePages2) then begin
        ems_demoError('EMS_Ems.getAddrsMappable40');
        end;

    (*
     *  We now allocate half of memory in order to control
     *  some of the remappable pages.
     *)
    memLeft:= 327680;
    GetMem(restOfMem, memLeft);
    if restOfMem = Nil then begin
        writeln('Unable to allocate conventional memory');
        Halt;
        end;
    
    (*
     *  Record the mappable pages which fall inside the bounds of
     *  our memory block OR are part of the standard (3.0) page
     *  frame area. Keep count of how many mappable pages
     *  we have in total.
     *)
    numAvailableFrames:= 0;
    for i:= 0 to numMappablePages-1 do begin
        if (segToPhys(pageAddress^[i].pageSegment) >= segOffToPhys(restOfMem)) and
                 (SegToPhys(pageAddress^[i].pageSegment) + EMS_STD_PAGE_SIZE <=
                      segOffToPhys(restOfMem) + memLeft)
            or (SegToPhys(pageAddress^[i].pageSegment) >= segOffToPhys(pfa)) and
                 (SegToPhys(pageAddress^[i].pageSegment) + EMS_STD_PAGE_SIZE <=
                    segOffToPhys(pfa) + EMS_STD_PAGE_SIZE*4) then begin
            availableFrame^[numAvailableFrames].physNumber:=
                pageAddress^[i].physNumber;
            availableFrame^[numAvailableFrames].pageSegment:=
                pageAddress^[i].pageSegment;
            numAvailableFrames:= numAvailableFrames + 1;
            end;
        end;

    (*
     *  We will be using 6 page frames. Make sure we have enough.
     *)
    if numAvailableFrames < 6 then begin
        writeln('Insufficient number of available remappable pages');
        Halt;
        end;

    (*
     *  We'll be working with the first six available page frames.
     *  Let's create an array which will allow us to easily
     *  access them.
     *
     *  At the same time, set up the map list for saving the state.
     *)
    for i:= 0 to 5 do begin
        frame[i]:= Ptr(availableFrame^[i].pageSegment, 0);
        mapPageList[i+1]:= availableFrame^[i].pageSegment;
        end;
    mapPageList[0]:= 6;

    (*
     *  Let's put some text into the area.
     *)
    StrPtr(@frame[0]^[123])^:=
        'CM:     In perpetrating a revolution there are two';
    StrPtr(@frame[1]^[456])^:=
        'CM:     requirements: someone or something to revolt';
    StrPtr(@frame[2]^[789])^:=
        'CM:     against and someone to actually show up and';
    StrPtr(@frame[3]^[12])^:=
        'CM:     do the revolting. Dress is usually casual';
    StrPtr(@frame[4]^[345])^:=
        'CM:';
    StrPtr(@frame[5]^[678])^:=
        'CM:                         -- Woody Allen'#13#10;

    (*
     *  Let's the current state of these pages. Note that since
     *  they (with the exception of those in the standard PFA), are
     *  in the conventional memory area, they already have pages mapped
     *  to them.
     *)
    if ems.getPMapInfoSize40(6, mapSize) then begin
        ems_demoError('EMS_Ems.getPMapInfoSize');
        end;

    GetMem(mapSave1, mapSize);
    GetMem(mapSave2, mapSize);

    if ems.savePartialMap40(@mapPageList, mapSave1) then begin
        ems_demoError('EMS_Ems.savePartialMap40');
        end;

    (*
     *  Now that we've saved the current state, let's map some
     *  new pages in. We'll do it by number here.
     *)
    for i:= 0 to 5 do begin
        mapByNumber[i].logicalPage:= i;
        mapByNumber[i].physicalPage:= availableFrame^[i].physNumber;
        end;

    if handle.mapPagesByNum40(6, @mapByNumber) then begin
        ems_demoError('EMS_EmBlk.mapPagesByNum40');
        end;

    (*
     *  Now let's put some new text in:
     *)
    StrPtr(@frame[0]^[123])^:=
        'EMA:    Someone did a study of the three most-often-heard phrases';
    StrPtr(@frame[1]^[456])^:=
        'EMA:    in New York City. One is "Hey taxi." Two is "What train';
    StrPtr(@frame[2]^[789])^:=
        'EMA:    do I take to get to Bloomingdales?" And three is "Don''t';
    StrPtr(@frame[3]^[12])^:=
        'EMA:    worry, it''s only a flesh wound."';
    StrPtr(@frame[4]^[345])^:=
        'EMA:';
    StrPtr(@frame[5]^[678])^:=
        'EMA:                        -- David Letterman'#13#10;

    (*
     *  Let's save this map.
     *)
    if ems.savePartialMap40(@mapPageList, mapSave2) then begin
        ems_demoError('EMS_Ems.savePartialMap40');
        end;

    (*
     *  Now let's map a third set of pages, this time by segment
     *)
    for i:= 0 to 5 do begin
        mapByAddress[i].logicalPage:= 6 + i;
        mapByAddress[i].physicalSeg:= availableFrame^[i].pageSegment;
        end;

    if handle.mapPagesByAddr40(6, @mapByAddress) then begin
        ems_demoError('EMS_EmBlk.mapPagesByAddr40');
        end;

    (*
     *  Put some text in
     *)
    StrPtr(@frame[0]^[123])^:=
        'EMB:    I grew up to have my father''s looks, my father''s';
    StrPtr(@frame[1]^[456])^:=
        'EMB:    speech patterns, my father''s posture, my father''s';
    StrPtr(@frame[2]^[789])^:=
        'EMB:    walk, my father''s opinions and my mother''s contempt';
    StrPtr(@frame[3]^[12])^:=
        'EMB:    for my father.';
    StrPtr(@frame[4]^[345])^:=
        'EMB:';
    StrPtr(@frame[5]^[678])^:=
        'EMB:                        -- Jules Feiffer'#13#10;
    
    (*
     *  Now let's print out the stuff in the newest map.
     *)
    writeln(StrPtr(@frame[0]^[123])^);
    writeln(StrPtr(@frame[1]^[456])^);
    writeln(StrPtr(@frame[2]^[789])^);
    writeln(StrPtr(@frame[3]^[12])^);
    writeln(StrPtr(@frame[4]^[345])^);
    writeln(StrPtr(@frame[5]^[678])^);

    (* 
     *  Let's restore the second map and print the contents.
     *)
    if ems.restPartialMap40(mapSave2) then begin
        ems_demoError('EMS_Ems.restPartialMap40');
        end;

    writeln(StrPtr(@frame[0]^[123])^);
    writeln(StrPtr(@frame[1]^[456])^);
    writeln(StrPtr(@frame[2]^[789])^);
    writeln(StrPtr(@frame[3]^[12])^);
    writeln(StrPtr(@frame[4]^[345])^);
    writeln(StrPtr(@frame[5]^[678])^);

    (*
     *  And finally, let's restore the original map (the conventional
     *  memory pages), and print the contents.
     *)
    if ems.restPartialMap40(mapSave1) then begin
        ems_demoError('EMS_Ems.restPartialMap40');
        end;

    writeln(StrPtr(@frame[0]^[123])^);
    writeln(StrPtr(@frame[1]^[456])^);
    writeln(StrPtr(@frame[2]^[789])^);
    writeln(StrPtr(@frame[3]^[12])^);
    writeln(StrPtr(@frame[4]^[345])^);
    writeln(StrPtr(@frame[5]^[678])^);


    (*
     *  Now we free that which must be freed.
     *)
    FreeMem(restOfMem, memLeft);

    if handle.freeEM then begin
        ems_demoError('EMS_EmBlk.freeEM');
        end;


end.
