[Back to SORTING SWAG index]  [Back to Main SWAG index]  [Original]

{$A+,B-,D+,E-,F-,G+,I-,L+,N-,O-,R+,S+,V-,X+,M 4096,0,655360
NSORT version 3. Uses Shell sort instead of Insertion sort. Damn fast, still
handles all that can fit into conventional memory.
}

uses dos;

type
 pstring=^string;
 prec=^rec;
 rec=record
  s:pstring;
  n:prec;
 end;

const
 rsize=sizeof(rec);

var
 linet,linec:longint; {line total, current}
 list,start,lstptr,next:prec;
 {list,
  start of sorting zone,
  list stroller,
  next item to be swapped}
 infile,outfile,tmpline:string; {file names, input line}
 textf:text; {input/output file variable}
 tbuf:array [1..8192] of char; {text file buffer}

procedure progress;
var
 ctr,indicator:byte; {show graphically, how many blocks}
begin
 inc(linec); {increase current line}
 indicator:=100*linec div linet; {get %}
 write(indicator:5,'%  ');
 indicator:=indicator div 5; {get 1/20th portion}
 for ctr:=1 to 20 do
  if ctr<=indicator then write('o') {o=5% done, .=5% remaining}
  else write('.');
 write(^m); {only carriage return: not new line too}
end;

procedure TheEnd; far;
begin
 exitproc:=nil;
 case exitcode of
  1:writeln('Input file not found');
  2:writeln('Can''t open input file');
  3:writeln('Out of memory');
  4:writeln('Can''t create output file');
  5:writeln('Can''t finish output file');
  6:writeln('Insufficient disk space');
 end;
 writeln('NSort version 3.');
 writeln('NetRunner of Assassin Technologies. Lum''s Place 613 531 1911');
end;

procedure checkfit;
var
 f:file;
 size:longint;
 drive:string[1];
begin
 if infile<>outfile then begin
  assign(f,infile);
  reset(f,1);
  size:=filesize(f);
  drive:=fexpand(outfile);
  dec(drive[1],byte('A')-1);
  if size>diskfree(byte(drive[1])) then halt(6);
 end;
end;

procedure showhelp;
begin
 writeln('Heavy duty sorter. Syntax: NSORT infile outfile | /s');
 writeln('/s= use input name as output.');
 writeln('Batch file exit codes:');
 writeln('1 Input file not found');
 writeln('2 Can''t open input file');
 writeln('3 Out of memory');
 writeln('4 Can''t create output file');
 writeln('5 Can''t finish output file');
 writeln('6 Insufficient disk space');
 halt;
end;

procedure swap(var p1,p2:pstring);
var tmpptr:pstring;
begin
 tmpptr:=p1;
 p1:=p2;
 p2:=tmpptr;
end;

Function upstr(s:string):string;
var c:byte;
begin
 if length(s)>0 then for c:=1 to length(s) do s[c]:=upcase(s[c]);
 upstr:=s;
end;

Function fexist(fn:pathstr):boolean;
var f:file; it:word;
begin
 assign(f,fn);
 getfattr(f,it);
 fexist:=doserror=0;
 doserror:=0;
end;

function malloc(var p; ram:word):boolean;
begin
 if (maxavail>=ram) then begin
  if ram=0 then pointer(p):=nil {0 is OK but not an allocation}
  else getmem(pointer(p),ram); {allocate if RAM > 0}
  malloc:=true
 end
 else begin {not enough RAM}
  malloc:=false;
  pointer(p):=nil
 end
end;

begin
 exitproc:=@TheEnd; {set exit procedure}
 linec:=0; {init}
 linet:=0;

 if paramcount=0 then showhelp; {show online help, no cmd line}

 {set input/output files}

 infile:=upstr(paramstr(1));
 outfile:=upstr(paramstr(2));
 if outfile='/S' then outfile:=infile; {/s as output file = same name}

 if not fexist(infile) then halt(1); {stop if input doesn't exist}

 checkfit; {if output file too large/not enough space, this finds it}

 assign(textf,infile); {set input file}
 settextbuf(textf,tbuf); {set text buffer for speed}

 reset(textf);
 if ioresult<>0 then halt(2); {stop if error opening file}

 list:=nil;

 {input file processing}

 while not eof(textf) do begin
  readln(textf,tmpline); {get input}
  inc(linet); {total line count, setup in loop}
  if list=nil then begin {if list doesn't exist yet}
   if not malloc(pointer(list),rsize) then halt(3); {allocate linked list rec}
   next:=list; {next used to advance linked list}
  end
  else begin {current piece of list is not 1st}
   if not malloc(pointer(next^.n),rsize) then halt(3); {alloc linked list node}
   next:=next^.n; {advance placeholder}
  end;
  if not malloc(pointer(next^.s),length(tmpline)+1) then halt(3); {allocate
line}  move(tmpline,next^.s^,length(tmpline)+1);
  next^.n:=nil; {set list end = nil}
 end;
 close(textf); {close input file}

 {sorting begins here}

 start:=list;
 while start<>nil do begin
  next:=start;
  lstptr:=start;
  while lstptr<>nil do begin
   if lstptr^.s^ < next^.s^ then next:=lstptr;
   lstptr:=lstptr^.n; {advance list pointer}
  end;
  swap(start^.s,next^.s);
  progress;
  start:=start^.n; {advance start zone boundary, gradual reduction}
 end;
 writeln;

 {file output after complete sorting}

 lstptr:=list;
 assign(textf,outfile);
 rewrite(textf);
 if ioresult<>0 then halt(4);
 while lstptr<>nil do begin
  writeln(textf,lstptr^.s^);
  if ioresult<>0 then begin
   close(textf);
   halt(5);
  end;
  lstptr:=lstptr^.n;
 end;
 close(textf);
end.

[Back to SORTING SWAG index]  [Back to Main SWAG index]  [Original]