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

{
SEAN PALMER

> Can anyone (please, it's important) , post here an example of a source
> code that will show a Text File , and let me scroll it (Up , Down ) ?
> Also I need an example of a simple editor.

Try this For an example. Turbo Pascal 6.0+ source.
Compiles to a 7K Text editor. Neat?
}

{$A-,B-,D-,E-,F-,G-,I-,L-,N-,O-,R-,S-,V-,X+}
{$M $C00,0,0}

Program ghostEd; {Ghost Editor v0.4 (C) 1993 Sean L. Palmer}

Const
  version  = '0.4';
  maxF     = $3FFF;     {only handles small Files!}
  txtColor = $B;
  vSeg     : Word = $B800;

Var
  nLines   : Byte;
  halfPage : Byte;
  txt      : Array [0..maxF] of Char;
  crs,
  endF,
  pgBase,
  lnBase   : Integer;
  x, y     : Word;
  update   : Boolean;
  theFile  : File;
  ticks    : Word Absolute $40 : $6C;   {ticks happen 18.2 times/second}

Procedure syncTick;
Var
  i : Word;
begin
  i := ticks;
  Repeat Until i <> ticks;
end;

Function readKey : Char; Assembler;
Asm
  mov ah, $07
  int $21
end;

Function keyPressed : Boolean; Assembler;
Asm
  mov ah, $B
  int $21
  and al, $FE
end;

Procedure moveScrUp(s, d, n : Word); Assembler;
Asm
  mov  cx, n
  push ds
  mov  ax, vSeg
  mov  es, ax
  mov  ds, ax
        mov  si, s
  shl  si, 1
  mov  di, d
  shl  di, 1
  cld
  repz movsw {attr too!}
  pop  ds
 @X:
end;

Procedure moveScrDn(s, d, n : Word); Assembler;
Asm
  mov  cx, n
  push ds
  mov  ax, vSeg
  mov  es, ax
  mov  ds, ax
  mov  si, s
  add  si, cx
  shl  si, 1
  mov  di, d
  add  di, cx
  shl  di, 1
  std
  repz movsw {attr too!}
  pop  ds
 @X:
end;

Procedure moveScr(Var s; d, n : Word); Assembler;
Asm
  mov  cx, n
  jcxz @X
  push ds
  mov  ax, vSeg
  mov  es, ax
  mov  di, d
  shl  di, 1
  lds  si, s
  cld
 @L:
  movsb
  inc  di
  loop @L
  pop  ds
 @X:
end;

Procedure fillScr(d, n : Word; c : Char); Assembler;
Asm
  mov  cx, n
  jcxz @X
  mov  ax, vSeg
  mov  es, ax
  mov  di, d
  shl  di, 1
  mov  al, c
  cld
 @L:
  stosb
  inc  di
  loop @L
 @X:
end;

Procedure fillAttr(d, n : Word; c : Byte); Assembler;
Asm
  mov  cx, n
  jcxz @X
  mov  ax, vSeg
  mov  es, ax
  mov  di, d
  shl  di, 1
  mov  al, c
  cld
 @L:
  inc  di
  stosb
  loop @L
 @X:
end;

Procedure cls;
begin
  fillAttr(80, pred(nLines) * 80, txtColor);
  fillScr(80, pred(nLines) * 80, ' ');
end;

Procedure scrollUp;
begin
  moveScrUp(320, 160, pred(nLines) * 160);
  fillScr(pred(nLines) * 160, 80, ' ');
end;

Procedure scrollDn;
begin
  moveScrDn(160, 320, pred(nLines) * 320);
  fillScr(160, 80, ' ');
end;

{put cursor after preceding CR or at 0}
Function scanCrUp(i : Integer) : Integer; Assembler;
Asm
  mov   di, i
  mov   cx, di
  add   di, offset txt
  mov   ax, ds
  mov   es, ax
  std;
  mov   al, $D
  dec   di
  repnz scasb
  jnz   @S
  inc   di
 @S:
  inc   di
  sub   di, offset txt
  mov   ax, di
end;

{put cursor on next CR or endF}
Function scanCrDn(i:Integer):Integer;Assembler;Asm
  mov   di, i
  mov   cx, endF
  sub   cx, di
  inc   cx
  add   di, offset txt
  mov   ax, ds
  mov   es, ax
  cld
  mov   al, $D
  repnz scasb
  dec   di
  sub   di, offset txt
  mov   ax, di
end;

Procedure findxy;
begin
  lnBase := scanCrUp(crs);
  x      := crs - lnBase;
  y      := 1;
  pgBase := lnBase;
  While (pgBase > 0) and (y < halfPage) do
  begin
    pgBase := scanCrUp(pred(pgBase));
    inc(y);
  end;
end;

Procedure display;
Var
  i, j, k, oldY : Integer;
begin
  findXY;
  if update then
  begin
    update := False;
    j := pgBase;
    i := 1;
    While (j <= endf) and (i < pred(nLines)) do
    begin
      k := scanCrDn(j);
      moveScr(txt[j], i * 80, k - j);
      fillScr(i * 80 + k - j, 80 - k + j, ' ');
      fillAttr(i * 80, 80, txtColor);
      j := succ(k);
      inc(i);
    end;
    if i < pred(nLines) then
    begin
      fillScr(i * 80, 80 * pred(nLines - i), 'X');
      fillAttr(i * 80, 80 * pred(nLines - i), 1);
    end;
  end
  else
  begin
    i := scanCrDn(lnBase) - lnBase;
    moveScr(txt[lnBase], y * 80, i);
    fillScr(y * 80 + i, 80 - i, ' ');
  end;
end;

Procedure title;
Const
  menuStr : String = 'Ghost Editor v' + version + '-(C) Sean Palmer 1993';
begin
  fillAttr(0, 80, $70);
  fillScr(0, 80, ' ');
  MoveScr(MenuStr[1], 1, length(MenuStr));
end;

Procedure error(s : String);
begin
  fillattr(0, 80, $CE);
  fillScr(0, 80, ' ');
  moveScr(s[1], 1, length(s));
  Write(^G);
  ReadKey;
  title;
end;

Procedure tooBigErr;
begin
  error('File too big');
end;

Procedure insChar(c : Char); forward;
Procedure delChar; forward;
Procedure backChar; forward;

Procedure trimLine;
Var
  i, t, b : Integer;
begin
  i   := crs;
  b   := scanCrDn(crs);
  t   := scanCrUp(crs);
  crs := b;
  While txt[crs] = ' ' do
  begin
    delChar;
    if i > crs then
      dec(i);
    if crs > 0 then
      dec(crs);
  end;
  crs := i;
end;

Procedure checkWrap(c : Integer);
Var
  i, t, b : Integer;
begin
  b := scanCrDn(c);
  t := scanCrUp(c);
  i := b;
  if i - t >= 79 then
  begin
    i := t + 79;
    Repeat
      dec(i);
    Until (txt[i] = ' ') or (i = t);
    if i = t then
      backChar   {just disallow lines that long With no spaces}
    else
    begin
      txt[i] := ^M;  {change sp into cr, to wrap}
      update := True;
      if (b < endF) and (txt[b] = ^M) and (txt[succ(b)] <> ^M) then
      begin
        txt[b] := ' '; {change cr into sp, to append wrapped part to next
line}         checkWrap(b);  {recursively check next line since it got stuff
added}       end;
    end;
  end;
end;

Procedure changeLines;
begin
  trimLine;
  update := True;  {signal to display to redraw}
end;

Procedure insChar(c : Char);
begin
  if endf = maxF then
  begin
    tooBigErr;
    exit;
  end;
  move(txt[crs], txt[succ(crs)], endf - crs);
  txt[crs] := c;
  inc(crs);
  inc(endf);
  if c = ^M then
    changeLines;
  checkWrap(crs);
end;

Procedure delChar;
begin
  if crs = endf then
    Exit;
  if txt[crs] = ^M then
    changeLines;
  move(txt[succ(crs)], txt[crs], endf - crs);
  dec(endf);
  checkWrap(crs);
end;

Procedure addLF;
Var
  i : Integer;
begin
  For crs := endF downto 1 do
  if txt[pred(crs)] = ^M then
  begin
    insChar(^J);
    dec(crs);
  end;
end;

Procedure stripLF;
Var
  i : Integer;
begin
  For crs := endF downto 0 do
  if txt[crs] = ^J then
    delChar;
end;

Procedure WriteErr;
begin
  error('Write Error');
end;

Procedure saveFile;
begin
  addLF;
  reWrite(theFile, 1);
  if ioresult <> 0 then
    WriteErr
  else
  begin
    blockWrite(theFile, txt, endf);
    if ioresult <> 0 then
      WriteErr;
    close(theFile);
  end;
end;

Procedure newFile;
begin
  crs    := 0;
  endF   := 0;
  update := True;
end;

Procedure readErr;
begin
  error('Read Error');
end;

Procedure loadFile;
Var
  i, n : Integer;
begin
  reset(theFile, 1);
  if ioresult <> 0 then
    newFile
  else
  begin
    n := Filesize(theFile);
    if n > maxF then
    begin
      tooBigErr;
      n := maxF;
    end;
    blockread(theFile, txt, n, i);
    if i < n then
      readErr;
    close(theFile);
    crs    := 0;
    endf   := i;
    update := True;
    stripLF;
  end;
end;

Procedure signOff;
Var
  f    : File;
  i, n : Integer;
begin
  assign(f, 'signoff.txt');
  reset(f, 1);
  if ioresult <> 0 then
    error('No SIGNOFF.TXT defined')  {no macro defined}
  else
  begin
    n := Filesize(f);
    blockread(f, txt[endF], n, i);
    if i < n then
      readErr;
    close(f);
    inc(endf, i);
    update := True;
    i := crs;
    stripLF;
    crs := i; {stripLF messes With crs}
  end;
end;

Procedure goLf;
begin
  if crs > 0 then
    dec(crs);
  if txt[crs] = ^M then
    changeLines;
end;

Procedure goRt;
begin
  if txt[crs] = ^M then
    changeLines;
  if crs < endf then
    inc(crs);
end;

Procedure goCtrlLf;
Var
  c : Char;
begin
  Repeat
    goLf;
    c := txt[crs];
  Until (c <= ' ') or (crs = 0);
end;

Procedure goCtrlRt;
Var
  c : Char;
begin
  Repeat
    goRt;
    c := txt[crs];
  Until (c <= ' ') or (crs >= endF);
end;

Procedure goUp;
Var
  i : Integer;
begin
  if lnBase > 0 then
  begin
    changeLines;
    lnBase := scanCrUp(pred(lnBase));
    crs := lnBase;
    i := scanCrDn(crs) - crs;
    if i >= x then
      inc(crs, x)
    else
      inc(crs,i);
  end;
end;

Procedure goDn;
Var
  i : Integer;
begin
  changeLines;
  crs := scanCrDn(crs);
  if crs >= endF then
    Exit;
  inc(crs);
  lnBase := crs;
  i := scanCrDn(crs) - crs;
  if i >= x then
    inc(crs, x)
  else
    inc(crs, i);
end;

Procedure goPgUp;
Var
  i : Byte;
begin
  For i := halfPage downto 0 do
    goUp;
end;

Procedure goPgDn;
Var
  i : Byte;
begin
  For i := halfPage downto 0 do
    goDn;
end;

Procedure goHome;
begin
  crs := scanCrUp(crs);
end;

Procedure goend;
begin
  crs := scanCrDn(crs);
end;

Procedure backChar;
begin
  if (crs > 0) then
  begin
    goLf;
    delChar;
  end;
end;

Procedure deleteLine;
Var
  i : Integer;
begin
  i := scanCrDn(crs);
  crs := scanCrUp(crs);
  if i < endF then
  begin
    move(txt[succ(i)], txt[crs], endf - i);
    dec(endF);
  end;
  dec(endf, i - crs);
  changeLines;
end;

Procedure flipCursor;
Var
  j, k, l : Word;
begin
  j := succ((y * 80 + x) shl 1);
  l := mem[vSeg : j];   {save attr under cursor}
  mem[vSeg : j] := $7B;
  if not KeyPressed then
    syncTick;
  mem[vSeg : j] := l;
  if not KeyPressed then
    syncTick;
end;

Procedure edit;
Var
  c : Char;
begin
  Repeat
    display;
    Repeat
      flipcursor;
    Until KeyPressed;

    c := ReadKey;
    if c = #0 then
      Case ReadKey of
        #59  : signOff;
        #75  : goLf;
        #77  : goRt;
        #115 : goCtrlLf;
        #116 : goCtrlRt;
        #72  : goUp;
        #80  : goDn;
        #83  : delChar;
        #73  : goPgUp;
        #81  : goPgDn;
        #71  : goHome;
        #79  : goend;
      end
    else
      Case c of
        ^[ : saveFile;
        ^H : backChar;
        ^C : {abortFile};
        ^Y : deleteLine;
     else
       insChar(c);
     end;
  Until (c = ^[) or (c = ^C);
end;

Function getRows : Byte; Assembler;
Asm
  mov  ax, $1130
  xor  dx, dx
  int  $10
  or   dx, dx
  jnz  @S
  mov  dx, 24
 @S: {cga/mda don't have this fn}
  inc  dx
  mov  al, dl
end;

Var
  oldMode : Byte;
begin
  Asm
    mov ah, $F
    int $10
    mov oldMode, al
  end;  {save old Gr mode}

  if oldMode = 7 then
    vSeg := $B000;  {check For Mono}

  nLines := getRows;
  halfPage := pred(nLines shr 1);
  cls;
  title;

  if paramCount = 0 then
    error('Need Filename as parameter')
  else
  begin
    Asm
      mov bh, 0
      mov dl, 0
      mov dh, nLines
      mov ah, 2
      int $10
    end; {put cursor of}

    assign(theFile, paramStr(1));
    loadFile;
    edit;
  end;
end.

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