Betreff: Re: Sorting a linked list
     Datum: Wed, 25 Nov 1998 18:13:15 GMT
       Von: Robert AH Prins 
     Foren: comp.lang.pascal.borland


In article <365BFC7C.2932@csolve.net>,
  Mike Monett  wrote:
> Robert AH Prins wrote:
> >  As for the sort
> > procedure, its in assembler, drop me a line if you want me to post it.
>
> If its tooo big to post, could you email me a copy? Thanks!

It's hard to cut it out of the program, because, although it's a HEAPSORT,
it's fairly specific for the purpose of sorting a list in three different
ways on two fields, but given that I've not had any comments about previous
big postings, here it is: 

NB: I hate PaScAl case & love global variables...

{*
* Format of the input file is (first column is blank, real file
* contains high-ASCII box chars.

 +------+-----+--------+-------+-------+------------+
 | Trip | Day |     KM |  Time |    V= | Date       |
 +------+-----+--------+-------+-------+------------+
 |    1 |   1 |  638.2 |  6.36 |  96.7 | 16.06.1980 |
 |    1 |   2 |  116.0 |  1.33 |  74.8 | 17.06.1980 |
 |    1 |   3 |  190.0 |  2.24 |  79.2 | 20.06.1980 |
 |    1 |   4 |  128.0 |  1.58 |  65.1 | 21.06.1980 |
      .
      .
      .
 +------+-----+--------+-------+-------+------------+

* DAYFORM is a program to sort the list of totals per day into four
* different orders,
*
*  - days in trip order
*  - days in distance order
*  - days in time order
*  - days in velocity order
*
* It prints the result of each sort operation in a multi-columnar
format.
*}
program dayform;
type
  l25  = string[25];
  l54  = string[54];
  l55  = string[55];
  l255 = string[255];

  sdptr   = ^sd_list;
  sd_list = record
              sd_nxt: sdptr;
              km    : longint;
              time  : longint;
              v     : longint;
              line  : l55;
            end;

  _sd_ptr = ^_sd_tab;
  _sd_tab = array [0..65520 div sizeof(sdptr) - 1] of sdptr;

const
  segfs        = $64;
  r386         = $66;
  movsd        = $a566;
  stosd        = $ab66;
  imul_eax_ebx = $c3af0f66;
  fs_si_bp_4   = $0476b40f; {lfs   si, [bp + 4]}

  fastshift    = 32;
  _ibuf        = 8192;
  _obuf        = 8192;

const
  sd_ptr : sdptr = nil;
  sd_top : sdptr = nil;
  sd_end : sdptr = nil;
  sd_tab : _sd_ptr = nil;
  ibuf   : pointer = nil;
  obuf   : pointer = nil;
  km     : longint = 0;
  time   : longint = 0;
  v      : longint = 0;
  _line  : l255    = '';
  sd_std : l25     = ^M^J' Days in Trip order    ';
  sd_km  : array[1..14] of char = 'Distance order';
  sd_time: array[1..14] of char = 'Time order    ';
  sd_v   : array[1..14] of char = 'Velocity order';

const
  _days: integer             =  0;
  _c_  : array[1..4] of char = 'Cols';
  _cols: integer             =  4;
  _r_  : array[1..4] of char = 'Rows';
  _rows: integer             = 70;

const __crlf: boolean = false;

const {These are box chars in my program!}
  sd_topl: l54 = '
+------+-----+--------+-------+-------+------------+ ';
  sd_head: l54 = ' | Trip | Day |     KM |  Time |    V= | Date
| ';
  sd_sep : l54 = '
+------+-----+--------+-------+-------+------------+ ';
  sd_endl: l54 = '
+------+-----+--------+-------+-------+------------+ ';

var
  dayin, dayout: text;
  _b, _bl, _c, _col, _i, _icv, _ip, _p, _pages, _r: integer;
  tempstring: string[10];
  temp      : string[15];
  print     : string[15];
  _print    : integer absolute print;
  ires      : longint;

{*
* UPDATE_LIST_POINTERS:
*
* const
*   xyz_ptr: xyzptr = nil;
*   xyz_top: xyzptr = nil;
*   xyz_end: xyzptr = nil;
*
* Called as:
*
* asm
*   mov   di, offset xyz_ptr
*   call  update_list_pointers
* end;
*
* Replaces:
*
* if xyz_top = nil then
*   xyz_top:= xyz_ptr
* else
*   xyz_end^.xyz_nxt:= xyz_ptr;
*
* xyz_end:= xyz_ptr;
*}
procedure update_list_pointers; assembler;
asm
  mov   dx, di
  db    r386; mov   ax, [di + 4]
  db    r386; or    ax, ax
  db    r386; mov   ax, [di]
  jnz   @1
  db    r386; mov   [di + 4], ax
  jmp   @2
@1:
  les   di, [di + 8]
  db    r386; mov   es:[di], ax
@2:
  mov   di, dx
  db    r386; mov   [di + 8], ax
end; {update_list_pointers}

procedure core_4_cvi_cvr; assembler;
asm
  cld
  mov   dx, ds
  mov   es, dx
  mov   di, offset print
  xor   bx, bx
  lodsb
  or    al, al
  jz    @3

  mov   cl, al
@1:
  lodsb
  cmp   al, " "
  je    @2

  inc   bx
  mov   es:[di + bx], al
@2:
  dec   cl
  jnz   @1
@3:
  mov   ds, dx
  mov   byte ptr print, bl
end; {core_4_cvi_cvr}

function cvi(var anystring): longint;
begin;
  asm
    push  ds
    lds   si, anystring
    call  core_4_cvi_cvr
    pop   ds
  end;

  val(print, ires, _icv);
  if _icv <> 0 then
    ires:= -1;

  cvi:= ires;
end; {cvi}

procedure dayprint;
begin
  for _p:= 1 to _pages do
    begin
      if _pages > 1 then
        begin
          str(_p:2, temp);
          _line[0]:= char(_cols * 54 + 2);
          move(print[1], _line[_bl], integer(print[0]));

          asm
            mov   di, _ip
            mov   ax, word ptr temp[1]
            mov   [di + offset _line], ax
          end;
        end;

      asm
        mov   ax, _cols
        mov   _col, ax
        mov   bx, _rows
        imul  bx
        mov   cx, _p
        dec   cx
        imul  cx
        mov   _b, ax
      end; {_b:= pred(_p) * _rows * _cols;}

      asm
        inc   cx
        cmp   cx, _pages
        jne   @1

        neg   ax
        add   ax, _days
        add   ax, bx
        dec   ax
        cwd
        idiv  bx
        mov   _col, ax
      @1:
      end;
{
      if _p = _pages then
        _col:= (_days - _b + pred(_rows)) div _rows;
}
      write(dayout, _line, ^M^J^M^J);

      for _i:= 1 to _col do
        write(dayout, sd_topl);

      write(dayout, ^M^J);

      for _i:= 1 to _col do
        write(dayout, sd_head);

      write(dayout, ^M^J);

      for _i:= 1 to _col do
        write(dayout, sd_sep);

      write(dayout, ^M^J);

      for _r:= 1 to _rows do
        begin
          __crlf:= false;

          for _c:= 1 to _col do
            begin
              _i:= _r + _b + pred(_c) * _rows;

              if _i <= _days then
                begin
                  write(dayout, sd_tab^[_i]^.line);
                  __crlf:= true;
                end;

              if _i = succ(_days) then
                write(dayout, sd_endl);
            end;

          if __crlf then
            write(dayout, ^M^J);
        end;

      if (_p <> _pages) then
        for _c:= 1 to _cols do
          write(dayout, sd_endl);

      if (_p = _pages) then
        if (_days mod _rows = 0) then
          for _c:= 1 to _cols do
            write(dayout, sd_endl)
        else
          for _c:= 1 to pred(_col) do
            write(dayout, sd_endl);

      write(dayout, ^M^J' '^L);
    end;
end; {dayprint}

{*
* Sort the array of totals per day in distance, time or velocity
order
*}
procedure daysort(dtv: char; n: integer; var sd: _sd_ptr);
var
  _i, _j, _l, ir: integer;
  rra           : sdptr;
  ready, swap   : boolean;

begin
  asm
    dd    fs_si_bp_4  {lfs   si, [bp + 4]}
    mov   ready, false
    mov   ax, n
    mov   ir, ax
    shr   ax, 1 + fastshift
    inc   ax
    mov   ax, _l
  end;

  repeat
    if _l > 1 then
      asm
        mov   ax, _l
        dec   ax
        mov   _l, ax
        shl   ax, 2
        db    segfs; les   di, [si]
        add   di, ax
        db    r386; mov   ax, es:[di]
        db    r386; mov   word ptr rra, ax
      end
    else
      asm
        db    segfs; les   di, [si]
        db    r386; mov   bx, es:[di+4]

        mov   ax, ir
        shl   ax, 2
        add   di, ax
        db    r386; mov   ax, es:[di]
        db    r386; mov   word ptr rra, ax

        db    r386; mov   es:[di], bx

        mov   ax, ir
        dec   ax
        mov   ir, ax
        cmp   ax, 1
        jne   @1

        db    r386; mov   ax, word ptr rra
        db    segfs; les   di, [si]
        db    r386; mov   es:[di + 4], ax

        mov   ready, true
      @1:
      end;

    asm
      mov   ax, _l
      mov   _i, ax
      shl   ax, 1 + fastshift
      mov   _j, ax
    end;

    while (not ready) and
          (_j <= ir) do
      begin
        if _j < ir then
          asm
            mov   ax, _j
            shl   ax, 2
            db    segfs; les   di, [si]
            add   di, ax
            les   di, es:[di]
            db    r386; mov   bx, es:[di + offset sd_list.km]
            db    r386; mov   cx, es:[di + offset sd_list.time]
            db    r386; mov   dx, es:[di + offset sd_list.v]

            mov   ax, _j
            inc   ax
            shl   ax, 2
            db    segfs; les   di, [si]
            add   di, ax
            les   di, es:[di]
            mov   al, dtv
            cmp   al, "D"
            jne   @t

            db    r386; cmp   bx, es:[di + offset sd_list.km]
            jl    @i
            jne   @e
            db    r386; cmp   dx, es:[di + offset sd_list.v]
            jge   @e
            jmp   @i

          @t:
            cmp   al, "T"
            jne   @v

            db    r386; cmp   cx, es:[di + offset sd_list.time]
            jl    @i
            jne   @e
            db    r386; cmp   dx, es:[di + offset sd_list.v]
            jge   @e
            jmp   @i

          @v:
            cmp   al, "V"
            jne   @e

            db    r386; cmp   dx, es:[di + offset sd_list.v]
            jl    @i
            jne   @e
            db    r386; cmp   bx, es:[di + offset sd_list.km]
            jge   @e
          @i:
            inc   _j
          @e:
          end;

        asm
          mov   swap, false

          les   di, rra
          db    r386; mov   bx, es:[di + offset sd_list.km]
          db    r386; mov   cx, es:[di + offset sd_list.time]
          db    r386; mov   dx, es:[di + offset sd_list.v]

          mov   ax, _j
          shl   ax, 2
          db    segfs; les   di, [si]
          add   di, ax
          les   di, es:[di]
          mov   al, dtv
          cmp   al, "D"
          jne   @t

          db    r386; cmp   bx, es:[di + offset sd_list.km]
          jl    @i
          jne   @e
          db    r386; cmp   dx, es:[di + offset sd_list.v]
          jge   @e
          jmp   @i

        @t:
          cmp   al, "T"
          jne   @v

          db    r386; cmp   cx, es:[di + offset sd_list.time]
          jl    @i
          jne   @e
          db    r386; cmp   dx, es:[di + offset sd_list.v]
          jge   @e
          jmp   @i

        @v:
          cmp   al, "V"
          jne   @e

          db    r386; cmp   dx, es:[di + offset sd_list.v]
          jl    @i
          jne   @e
          db    r386; cmp   bx, es:[di + offset sd_list.km]
          jge   @e
        @i:
          mov   swap, true
        @e:
          cmp   swap, false
          je    @f

          mov   bx, _j
          shl   bx, 2
          db    segfs; les   di, [si]
          db    r386; mov   ax, es:[di + bx]
          mov   bx, _i
          shl   bx, 2
          db    r386; mov   es:[di + bx], ax

          mov   ax, _j
          mov   _i, ax
          shl   ax, 1 + fastshift
          mov   _j, ax
          jmp   @q

        @f:
          mov   ax, ir
          inc   ax
          mov   _j, ax
        @q:
        end;
      end;

    asm
      mov   ax, _i
      shl   ax, 2
      db    segfs; les   di, [si]
      add   di, ax
      db    r386; mov   ax, word ptr rra
      db    r386; mov   es:[di], ax
    end;
  until ready;
end; {daysort}

(* Original non-assembler version
--------------------------------------
{*
* Sort an array of integers in ascending order (Heapsort)
*}
procedure daysort(dtv: char; n: integer; var sd: _sd_ptr);
var
  _i, _j, _k, _l, ir: integer;
  rra: sdptr;
  ready, swap : boolean;

begin
  ready:= false;
  _l   := succ(n shr 1);
  ir   := n;

  repeat
    if _l > 1 then
      begin
        dec(_l);
        rra:= sd^[_l];
      end
    else
      begin
        rra    := sd^[ir];
        sd^[ir]:= sd^[1];
        dec(ir);

        if ir = 1 then
          begin
            sd^[1]:= rra;
            ready := true
          end;
      end;

    _i:= _l;
    _j:= _l * 2;

    while (not ready) and
          (_j <= ir) do
      begin
        if _j < ir then
          begin
            _k:= succ(_j);

            {*
            * Look at the code generated by TP in TD for the statements
            * below, and you'll understand why I'm using BASM...
            *}
            case dtv of
              'D': if (sd^[_j]^.km   < sd^[_k]^.km) or
                      (sd^[_j]^.km   = sd^[_k]^.km) and
                      (sd^[_j]^.v    < sd^[_k]^.v) then
                     inc(_j);

              'T': if (sd^[_j]^.time < sd^[_k]^.time) or
                      (sd^[_j]^.time = sd^[_k]^.time) and
                      (sd^[_j]^.v    < sd^[_k]^.v) then
                     inc(_j);

              'V': if (sd^[_j]^.v    < sd^[_k]^.v) or
                      (sd^[_j]^.v    = sd^[_k]^.v) and
                      (sd^[_j]^.km   < sd^[_k]^.km) then
                     inc(_j);
            end;
          end;

        swap:= false;

        case dtv of
          'D': if (rra^.km   < sd^[_j]^.km) or
                  (rra^.km   = sd^[_j]^.km) and
                  (rra^.v    < sd^[_j]^.v) then
                 swap:= true;

          'T': if (rra^.time < sd^[_j]^.time) or
                  (rra^.time = sd^[_j]^.time) and
                  (rra^.v    < sd^[_j]^.v) then
                 swap:= true;

          'V': if (rra^.v    < sd^[_j]^.v) or
                  (rra^.v    = sd^[_j]^.v) and
                  (rra^.km   < sd^[_j]^.km) then
                 swap:= true;
        end;

        if swap then
          begin
            sd^[_i]:= sd^[_j];
            _i     := _j;
            _j     := _j * 2;
          end
        else
          _j:= succ(ir);
      end;

    sd^[_i]:= rra;
  until ready;
end; {daysort}

----------------------------------------------------------------------*)
begin
  asm
    mov   al, byte ptr _c_ + 3
    cmp   al, byte ptr _r_ + 3
    jne   @q

    mov   ax, _rows
    cmp   ax, 1
    jge   @r
    mov   _rows, 70

  @r:
    cmp   ax, 100
    jle   @c
    mov   _rows, 100

  @c:
    cmp   _cols, 1
    jl    @a
    cmp   _cols, 4
    jle   @q

  @a:
    mov   _cols, 4
  @q:
  end;

  getmem(ibuf, _ibuf);
  getmem(obuf, _obuf);

  assign(dayin, 'DAYS.H-H');
  settextbuf(dayin, ibuf^, _ibuf);
  reset(dayin);

  assign(dayout, 'DAYS.H-C');
  settextbuf(dayout, obuf^, _obuf);
  rewrite(dayout);

  repeat
    readln(dayin, _line);

    if (_line[4] <> 'T') and
       (_line[4] <> '-') then
      begin
        inc(_days);

       {Do you really think I'm using "Copy"...}
        asm
          db    r386; mov   ax, word ptr _line[17]
          db    r386; mov   word ptr temp[1], ax
          mov   al, byte ptr _line[22]
          mov   byte ptr temp[5], al
          mov   byte ptr temp[0], 5
        end;
        km:= cvi(temp);

        asm
          mov   ax, word ptr _line[26]
          mov   word ptr temp[1], ax
          mov   byte ptr temp[0], 2
          mov   ax, word ptr _line[29]
          mov   word ptr tempstring[1], ax
          mov   byte ptr tempstring[0], 2
        end;
        time:= cvi(temp) * 60 + cvi(tempstring);
        v   := trunc(((km * 60000) / time) * 1000.0);

        new(sd_ptr);

        asm
          les   di, sd_ptr
          mov   cx, type sd_list / 4
          db    r386; xor   ax, ax
          cld
          rep;  dw    stosd

          mov   di, offset sd_ptr
          call  update_list_pointers
        end;

        sd_ptr^.km  := km;
        sd_ptr^.time:= time;
        sd_ptr^.v   := v;

        _line[0] := #54;
        _line[54]:= ' ';

        sd_ptr^.line:= _line;
      end;
  until eof(dayin);

  _i:= _days * sizeof(sdptr);

  getmem(sd_tab, _i);

  asm
    les   di, sd_tab
    mov   cx, _i
    shl   cx, 2
    db    r386; xor   ax, ax
    cld
    rep;  dw    stosd
  end; {filldword(sd_tab^, _i, #0#0#0#0);}

  asm
    db    $0f,$b4,$36; dw    offset sd_tab {lfs   si, sd_tab}
    db    r386; mov   ax, word ptr sd_top
  @1:
    db    r386; mov   word ptr sd_ptr, ax
    db    r386; or    ax, ax
    jz    @2

    add   si, 4

    db    r386; db    segfs; mov   [si], ax

    les   di, sd_ptr
    db    r386; mov   ax, es:[di]
    jmp   @1
  @2:
  end;
{ Original non-assembler, generated code is hopeless!
  sd_ptr:= sd_top;
  _i    := 1;

  repeat
    sd_tab^[_i]:= sd_ptr;
    inc(_i);
    sd_ptr:= sd_ptr^.sd_nxt;
  until sd_ptr = nil;
}
  _pages:= (((_days + _rows - 1) div _rows) + _cols - 1) div _cols;

  if _pages > 1 then
    begin
      _bl:= _cols * 54 - 11;
      _ip:= _bl + 6;

      str(_pages, print);

      case print[0] of
       #1: begin
             insert('  Page . of ', print, 0);
           end;

       #2: begin
             dec(_ip);
             insert('Page  . of ', print, 0);
           end;
      end;

      fillchar(_line, sizeof(_line), ' ');
    end;

  move(sd_std, _line, sizeof(sd_std));
  dayprint;

  daysort('D', _days, sd_tab);
  move(sd_km, _line[12], sizeof(sd_km));
  dayprint;

  daysort('T', _days, sd_tab);
  move(sd_time, _line[12], sizeof(sd_time));
  dayprint;

  daysort('V', _days, sd_tab);
  move(sd_v, _line[12], sizeof(sd_v));
  dayprint;

  close(dayin);
  close(dayout);
end.

For the other programs that make up my hitch-hiking processing suite, have a
look at http://www.suite101.com/article.cfm/hitch_hiking/11729 (and download
the executables) and if you don't know suite101, have a look at it, IMHO it
is an extremely well designed site!

Robert
--
Robert AH Prins
prinsra@williscorroon.com

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own

    Source: geocities.com/~franzglaser/tpsrc

               ( geocities.com/~franzglaser)