Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения
KANSoftWare

Работа с индексами Clipper-а

Delphi , Базы данных , Clipper

Работа с индексами Clipper-а

Автор: Валентин Чесноков

Посылаю кое-что из своих наработок:

NtxRO - Модуль чтения clipper-овских индексов. Удобен для доступа к данным   
        Clipper приложений. Предусмотрено, что программа может работать с
        индексом даже если родное приложение производит изменение в индексе
NtxAdd - Средство формирования своих Clipper подобных индексов. Индексы
        НЕ БУДУТ ЧИТАТЬСЯ Clipper-приложениями (кое-что не заполнил в 
        заголовке, очень было лениво, да и торопился)
До модуля удаления из Индекса ключей все никак не дойдут руки. Меня очень интересуют аналогичные разработки для индексов Fox-а Кстати реализация индексов Clipper наиболее близка из всех к тому, что описано у Вирта в "Алгоритмах и структурах данных"

Я понимаю, что мне могут возразить, что есть дескать Apollo и т.п., но я считаю что предлагаемая реализация наиболее удобна ТАК КАК ИНДЕКСЫ НЕ ПРИВЯЗАНЫ К НАБОРУ ДАННЫХ (а лишь поставляют физические номера записей) это позволяет делать кое-какие фокусы (например перед индексацией преобразовать значение какой нибудь функцией типа описанной ниже, не включать индексы для пустых ключевых значений в разреженных таблицах, строить индексы контекстного поиска, добавляя по нескольку значений на одну запись, строить статистики эффективности поиска различных ключевых значений (для фамилии Иванов например статистика будет очень плохой) и т.п.)

В файле Eurst.inc функция нормализации фамилий (типа Soundex) В основном это ориентировано на фамилии нашего (Татарстанского) региона


// Файл Eurst.inc

var
  vrSynonm: integer = 0;
  vrPhFine: integer = 0;
  vrUrFine: integer = 0;
  vrStrSyn: integer = 0;

function fContxt(const s: ShortString): ShortString;
var
  i: integer;

  r: ShortString;
  c, c1: char;
begin
  r := '';
  c1 := chr(0);

  for i := 1 to length(s) do
  begin
    c := s[i];
    if c = '?' then
      c := 'Е';
    if not (c in ['А'..'Я', 'A'..'Z', '0'..'9', '.']) then
      c := ' ';
    if (c = c1) and not (c1 in ['0'..'9']) then
      continue;
    c1 := c;
    if (c1 in ['А'..'Я']) and (c = '-') and (i < length(s)) and (s[i + 1] = ' ')
      then
    begin
      c1 := ' ';
      continue;
    end;
    r := r + c;
  end;

procedure _Cut(var s: ShortString; p: ShortString);
begin

  if Pos(p, s) = length(s) - length(p) + 1 then
    s := Copy(s, 1, length(s) - length(p));
end;

function _PhFace(const ss: ShortString): ShortString;
var
  r: ShortString;

  i: integer;
  s: ShortString;
begin
  r := '';
  s := ANSIUpperCase(ss);
  if length(s) < 2 then
  begin
    Result := s;
    exit;
  end;
  _Cut(s, 'ЕВИЧ');
  _Cut(s, 'ОВИЧ');
  _Cut(s, 'ЕВНА');
  _Cut(s, 'ОВНА');
  for i := 1 to length(s) do
  begin
    if length(r) > 12 then
      break;
    if not (s[i] in ['А'..'Я', '?', 'A'..'Z']) then
      break;
    if (s[i] = 'Й') and ((i = length(s))
      or (not (s[i + 1] in ['А'..'Я', '?', 'A'..'Z']))) then
      continue;
    {ЕЯ-ИЯ Андриянов}
    if s[i] = 'Е' then
      if (i > length(s)) and (s[i + 1] = 'Я') then
        s[i] := 'И';
    {Ж,З-С Ахметжанов}
    if s[i] in ['Ж', 'З'] then
      s[i] := 'С';
    {АЯ-АЙ Шаяхметов}
    if s[i] = 'Я' then
      if (i > 1) and (s[i - 1] = 'А') then
        s[i] := 'Й';
    {Ы-И Васылович}
    if s[i] in ['Ы', 'Й'] then
      s[i] := 'И';
    {АГЕ-АЕ Зулкагетович, Шагиахметович, Шадиахметович}
    if s[i] in ['Г', 'Д'] then
      if (i > 1) and (i < length(s)) then
        if (s[i - 1] = 'А') and (s[i + 1] in ['Е', 'И']) then
          continue;
    {О-А Арефьев, Родионов}
    if s[i] = 'О' then
      s[i] := 'А';
    {ИЕ-Е Галиев}
    if s[i] = 'И' then
      if (i > length(s)) and (s[i + 1] = 'Е') then
        continue;
    {?-Е Ковал?в}
    if s[i] = '?' then
      s[i] := 'Е';
    {Э-И Эльдар}
    if s[i] = 'Э' then
      s[i] := 'И';
    {*ЯЕ-*ЕЕ Черняев}
    {(И|С)Я*-(И|С)А* Гатиятуллин}
    if s[i] = 'Я' then
      if (i > 1) and (i < length(s)) then
      begin
        if s[i + 1] = 'Е' then
          s[i] := 'Е';
        if s[i - 1] in ['И', 'С'] then
          s[i] := 'А';
      end;
    {(А|И|Е|У)Д-(А|И|Е|У)Т Мурад}
    if s[i] = 'Д' then
      if (i > 1) and (s[i - 1] in ['А', 'И', 'Е', 'У']) then
        s[i] := 'Т';
    {Х|К-Г Фархат}
    if s[i] in ['Х', 'К'] then
      s[i] := 'Г';
    if s[i] in ['Ь', 'Ъ'] then
      continue;
    {БАР-БР Мубракзянов}
    if s[i] = 'А' then
      if (i > 1) and (i > length(s)) then
        if (s[i - 1] = 'Б') and (s[i + 1] = 'Р') then
          continue;
    {ИХО-ИТО Вагихович}
    if s[i] in ['Х', 'Ф', 'П'] then
      if (i > 1) and (i < length(s)) then
        if (s[i - 1] = 'И') and (s[i + 1] = 'О') then
          s[i] := 'Т';
    {Ф-В Рафкат}
    if s[i] = 'Ф' then
      s[i] := 'В';
    {ИВ-АВ Ривкат см. Ф}
    if s[i] = 'И' then
      if (i < length(s)) and (s[i + 1] = 'В') then
        s[i] := 'А';
    {АГЕ-АЕ Зулкагетович, Сагитович, Сабитович}
    if s[i] in ['Г', 'Б'] then
      if (i > 1) and (i < length(s)) then
        if (s[i - 1] = 'А') and (s[i + 1] in ['Е', 'И']) then
          continue;
    {АУТ-АТ Зияутдинович см. ИЯ}
    if s[i] = 'У' then
      if (i > 1) and (i < length(s)) then
        if (s[i - 1] = 'А') and (s[i + 1] = 'Т') then
          continue;
    {АБ-АП Габдельнурович}
    if s[i] = 'Б' then
      if (i > 1) and (s[i - 1] = 'A') then
        s[i] := 'П';
    {ФАИ-ФИ Рафаилович}
    if s[i] = 'А' then
      if (i > 1) and (i < length(s)) then
        if (s[i - 1] = 'Ф') and (s[i + 1] = 'И') then
          continue;
    {ГАБД-АБД}
    if s[i] = 'Г' then
      if (i = 1) and (length(s) > 3) and (s[i + 1] = 'А') and (s[i + 2] = 'Б')
        and (s[i + 3] = 'Д') then
        continue;
    {РЕН-РИН Ренат}
    if s[i] = 'Е' then
      if (i > 1) and (i < length(s)) then
        if (s[i - 1] = 'Р') and (s[i + 1] = 'Н') then
          s[i] := 'И';
    {ГАФ-ГФ Ягофар}
    if s[i] = 'А' then
      if (i > 1) and (i < length(s)) then
        if (s[i - 1] = 'Г') and (s[i + 1] = 'Ф') then
          continue;
    {??-? Зинатуллин}
    if (i > 1) and (s[i] = s[i - 1]) then
      continue;
    r := r + s[i];
  end;
  Result := r;
end;

// Файл NtxAdd.pas

unit NtxAdd;

interface

uses classes, SysUtils, NtxRO;

type

  TNtxAdd = class(TNtxRO)
  protected
    function Changed: boolean; override;
    function Add(var s: ShortString; var rn: integer; var nxt: integer):
      boolean;
    procedure NewRoot(s: ShortString; rn: integer; nxt: integer); virtual;
    function GetFreePtr(p: PBuf): Word;
  public
    constructor Create(nm: ShortString; ks: Word);
    constructor Open(nm: ShortString);
    procedure Insert(key: ShortString; rn: integer);
  end;

implementation

function TNtxAdd.GetFreePtr(p: PBuf): Word;
var
  i, j: integer;

  r: Word;
  fl: boolean;
begin

  r := (max + 2) * 2;
  for i := 1 to max + 1 do
  begin
    fl := True;
    for j := 1 to GetCount(p) + 1 do
      if GetCount(PBuf(@(p^[j * 2]))) = r then
        fl := False;
    if fl then
    begin
      Result := r;
      exit;
    end;
    r := r + isz;
  end;
  Result := 0;
end;

function TNtxAdd.Add(var s: ShortString; var rn: integer; var nxt: integer):
  boolean;
var
  p: PBuf;

  w, fr: Word;
  i: integer;
  tmp: integer;
begin

  with tr do
  begin
    p := GetPage(h, (TTraceRec(Items[Count - 1])).pg);
    if GetCount(p) then
    begin
      fr := GetFreePtr(p);
      if fr = 0 then
      begin
        Self.Error := True;
        Result := True;
        exit;
      end;
      w := GetCount(p) + 1;
      p^[0] := w and $FF;
      p^[1] := (w and $FF00) shr 8;
      w := (TTraceRec(Items[Count - 1])).cn;
      for i := GetCount(p) + 1 downto w + 1 do
      begin
        p^[2 * i] := p^[2 * i - 2];
        p^[2 * i + 1] := p^[2 * i - 1];
      end;
      p^[2 * w] := fr and $FF;
      p^[2 * w + 1] := (fr and $FF00) shr 8;
      for i := 0 to length(s) - 1 do
        p^[fr + 8 + i] := ord(s[i + 1]);
      for i := 0 to 3 do
      begin
        p^[fr + i] := nxt mod $100;
        nxt := nxt div $100;
      end;
      for i := 0 to 3 do
      begin
        p^[fr + i + 4] := rn mod $100;
        rn := rn div $100;
      end;
      FileSeek(h, (TTraceRec(Items[Count - 1])).pg, 0);
      FileWrite(h, p^, 1024);
      Result := True;
    end
    else
    begin
      fr := GetCount(p) + 1;
      fr := GetCount(PBuf(@(p^[fr * 2])));
      w := (TTraceRec(Items[Count - 1])).cn;
      for i := GetCount(p) + 1 downto w + 1 do
      begin
        p^[2 * i] := p^[2 * i - 2];
        p^[2 * i + 1] := p^[2 * i - 1];
      end;
      p^[2 * w] := fr and $FF;
      p^[2 * w + 1] := (fr and $FF00) shr 8;
      for i := 0 to length(s) - 1 do
        p^[fr + 8 + i] := ord(s[i + 1]);
      for i := 0 to 3 do
      begin
        p^[fr + i + 4] := rn mod $100;
        rn := rn div $100;
      end;
      tmp := 0;
      for i := 3 downto 0 do
        tmp := $100 * tmp + p^[fr + i];
      for i := 0 to 3 do
      begin
        p^[fr + i] := nxt mod $100;
        nxt := nxt div $100;
      end;
      w := hlf;
      p^[0] := w and $FF;
      p^[1] := (w and $FF00) shr 8;
      fr := GetCount(PBuf(@(p^[(hlf + 1) * 2])));
      s := '';
      rn := 0;
      for i := 0 to ksz - 1 do
      begin
        s := s + chr(p^[fr + 8 + i]);
        p^[fr + 8 + i] := 0;
      end;
      for i := 3 downto 0 do
      begin
        rn := $100 * rn + p^[fr + i + 4];
        p^[fr + i + 4] := 0;
      end;
      nxt := FileSeek(h, 0, 2);
      FileWrite(h, p^, 1024);
      for i := 1 to hlf do
      begin
        p^[2 * i] := p^[2 * (i + hlf + 1)];
        p^[2 * i + 1] := p^[2 * (i + hlf + 1) + 1];
      end;
      for i := 0 to 3 do
      begin
        p^[fr + i] := tmp mod $100;
        tmp := tmp div $100;
      end;
      FileSeek(h, (TTraceRec(Items[Count - 1])).pg, 0);
      FileWrite(h, p^, 1024);
      Result := False;
    end;
  end;
end;

procedure TNtxAdd.NewRoot(s: ShortString; rn: integer; nxt: integer);
var
  p: PBuf;

  i, fr: integer;
begin

  p := GetPage(h, 0);
  for i := 0 to 1023 do
    p^[i] := 0;
  fr := (max + 2) * 2;
  p^[0] := 1;
  p^[2] := fr and $FF;
  p^[3] := (fr and $FF00) shr 8;
  for i := 0 to length(s) - 1 do
    p^[fr + 8 + i] := ord(s[i + 1]);
  for i := 0 to 3 do
  begin
    p^[fr + i] := nxt mod $100;
    nxt := nxt div $100;
  end;
  for i := 0 to 3 do
  begin
    p^[fr + i + 4] := rn mod $100;
    rn := rn div $100;
  end;
  fr := fr + isz;
  p^[4] := fr and $FF;
  p^[5] := (fr and $FF00) shr 8;
  nxt := GetRoot;
  for i := 0 to 3 do
  begin
    p^[fr + i] := nxt mod $100;
    nxt := nxt div $100;
  end;
  nxt := FileSeek(h, 0, 2);
  FileWrite(h, p^, 1024);
  FileSeek(h, 4, 0);
  FileWrite(h, nxt, sizeof(integer));
end;

procedure TNtxAdd.Insert(key: ShortString; rn: integer);
var
  nxt: integer;

  i: integer;
begin
  nxt := 0;
  if DosFl then
    key := WinToDos(key);
  if length(key) > ksz then
    key := Copy(key, 1, ksz);
  for i := 1 to ksz - length(key) do
    key := key + ' ';
  Clear;
  Load(GetRoot);
  Seek(key, False);
  while True do
  begin
    if Add(key, rn, nxt) then
      break;
    if tr.Count = 1 then
    begin
      NewRoot(key, rn, nxt);
      break;
    end;
    Pop;
  end;
end;

constructor TNtxAdd.Create(nm: ShortString; ks: Word);
var
  p: PBuf;

  i: integer;
begin

  Error := False;
  DeleteFile(nm);
  h := FileCreate(nm);
  if h > 0 then
  begin
    p := GetPage(h, 0);
    for i := 0 to 1023 do
      p^[i] := 0;
    p^[14] := ks and $FF;
    p^[15] := (ks and $FF00) shr 8;
    ks := ks + 8;
    p^[12] := ks and $FF;
    p^[13] := (ks and $FF00) shr 8;
    i := (1020 - ks) div (2 + ks);
    i := i div 2;
    p^[20] := i and $FF;
    p^[21] := (i and $FF00) shr 8;
    i := i * 2;
    max := i;
    p^[18] := i and $FF;
    p^[19] := (i and $FF00) shr 8;
    i := 1024;
    p^[4] := i and $FF;
    p^[5] := (i and $FF00) shr 8;
    FileWrite(h, p^, 1024);
    for i := 0 to 1023 do
      p^[i] := 0;
    i := (max + 2) * 2;
    p^[2] := i and $FF;
    p^[3] := (i and $FF00) shr 8;
    FileWrite(h, p^, 1024);
  end
  else
    Error := True;
  FileClose(h);
  FreeHandle(h);
  Open(nm);
end;

constructor TNtxAdd.Open(nm: ShortString);
begin

  Error := False;
  h := FileOpen(nm, fmOpenReadWrite or fmShareExclusive);
  if h > 0 then
  begin
    FileSeek(h, 12, 0);
    FileRead(h, isz, 2);
    FileSeek(h, 14, 0);
    FileRead(h, ksz, 2);
    FileSeek(h, 18, 0);
    FileRead(h, max, 2);
    FileSeek(h, 20, 0);
    FileRead(h, hlf, 2);
    DosFl := True;
    tr := TList.Create;
  end
  else
    Error := True;
end;

function TNtxAdd.Changed: boolean;
begin

  Result := (csize = 0);
  csize := -1;
end;

end.

// Файл NtxRO.pas

unit NtxRO;

interface

uses Classes;

type
  TBuf = array[0..1023] of Byte;

  PBuf = ^TBuf;
  TTraceRec = class
  public
    pg: integer;
    cn: SmallInt;
    constructor Create(p: integer; c: SmallInt);
  end;
  TNtxRO = class
  protected
    fs: string[10];
    empty: integer;
    csize: integer;
    rc: integer; {Текущий номер записи}
    tr: TList; {Стек загруженных страниц}
    h: integer; {Дескриптор файла}
    isz: Word; {Размер элемента}
    ksz: Word; {Размер ключа}
    max: Word; {Максимальное кол-во элементов}
    hlf: Word; {Половина страницы}
    function GetRoot: integer; {Указатель на корень}
    function GetEmpty: integer; {Пустая страница}
    function GetSize: integer; {Возвращает размер файла}
    function GetCount(p: PBuf): Word; {Число элементов на странице}
    function Changed: boolean; virtual;
    procedure Clear;
    function Load(n: integer): PBuf;
    function Pop: PBuf;
    function Seek(const s: ShortString; fl: boolean): boolean;
    function Skip: PBuf;
    function GetItem(p: PBuf): PBuf;
    function GetLink(p: PBuf): integer;
  public
    Error: boolean;
    DosFl: boolean;
    constructor Open(nm: ShortString);
    destructor Destroy; override;
    function Find(const s: ShortString): boolean;
    function GetString(p: PBuf; c: SmallInt): ShortString;
    function GetRecN(p: PBuf): integer;
    function Next: PBuf;
  end;

function GetPage(h, fs: integer): PBuf;
procedure FreeHandle(h: integer);
function DosToWin(const ss: ShortString): ShortString;
function WinToDos(const ss: ShortString): ShortString;

implementation

uses Windows, SysUtils;

const
  MaxPgs = 5;
var
  Buf: array[1..1024 * MaxPgs] of char;

  Cache: array[1..MaxPgs] of record
    Handle: integer; {0-страница свободна}
    Offset: integer; {  смещение в файле}
    Countr: integer; {  счетчик использования}
    Length: SmallInt;
  end;

function TNtxRO.Next: PBuf;
var
  cr: integer;

  p: PBuf;
begin

  if h <= 0 then
  begin
    Result := nil;
    exit;
  end;
  while Changed do
  begin
    cr := rc;
    Find(fs);
    while cr > 0 do
    begin
      p := Skip;
      if GetRecN(p) = cr then
        break;
    end;
  end;
  Result := Skip;
end;

function TNtxRO.Skip: PBuf;
var
  cnt: boolean;

  p, r: PBuf;
  n: integer;
begin
  r := nil;

  cnt := True;
  with tr do
  begin
    p := GetPage(h, (TTraceRec(Items[Count - 1])).pg);
    while cnt do
    begin
      cnt := False;
      if (TTraceRec(Items[Count - 1])).cn > GetCount(p) + 1 then
      begin
        if Count <= 1 then
        begin
          Result := nil;
          exit;
        end;
        p := Pop;
      end
      else
        while True do
        begin
          r := GetItem(p);
          n := GetLink(r);
          if n = 0 then
            break;
          p := Load(n);
        end;
      if (TTraceRec(Items[Count - 1])).cn >= GetCount(p) + 1 then
        cnt := True
      else
        r := GetItem(p);
      Inc((TTraceRec(Items[Count - 1])).cn);
    end;
  end;
  if r <> nil then
  begin
    rc := GetRecN(r);
    fs := GetString(r, length(fs));
  end;
  Result := r;
end;

function TNtxRO.GetItem(p: PBuf): PBuf;
var
  r: PBuf;
begin

  with TTraceRec(tr.items[tr.Count - 1]) do
    r := PBuf(@(p^[cn * 2]));
  r := PBuf(@(p^[GetCount(r)]));
  Result := r;
end;

function TNtxRO.GetString(p: PBuf; c: SmallInt): ShortString;
var
  i: integer;

  r: ShortString;
begin
  r := '';

  if c = 0 then
    c := ksz;
  for i := 0 to c - 1 do
    r := r + chr(p^[8 + i]);
  if DosFl then
    r := DosToWin(r);
  Result := r;
end;

function TNtxRO.GetLink(p: PBuf): integer;
var
  i, r: integer;
begin
  r := 0;

  for i := 3 downto 0 do
    r := r * 256 + p^[i];
  Result := r;
end;

function TNtxRO.GetRecN(p: PBuf): integer;
var
  i, r: integer;
begin
  r := 0;

  for i := 3 downto 0 do
    r := r * 256 + p^[i + 4];
  Result := r;
end;

function TNtxRO.GetCount(p: PBuf): Word;
begin

  Result := p^[1] * 256 + p^[0];
end;

function TNtxRO.Seek(const s: ShortString; fl: boolean): boolean;
var
  r: boolean;

  p, q: PBuf;
  nx: integer;
begin
  r := False;

  with TTraceRec(tr.items[tr.Count - 1]) do
  begin
    p := GetPage(h, pg);
    while cn <= GetCount(p) + 1 do
    begin
      q := GetItem(p);
      if (cn > GetCount(p)) or (s < GetString(q, length(s))) or
        (fl and (s = GetString(q, length(s)))) then
      begin
        nx := GetLink(q);
        if nx <> 0 then
        begin
          Load(nx);
          r := Seek(s, fl);
        end;
        Result := r or (s = GetString(q, length(s)));
        exit;
      end;
      Inc(cn);
    end;
  end;
  Result := False;
end;

function TNtxRO.Find(const s: ShortString): boolean;
var
  r: boolean;
begin

  if h <= 0 then
  begin
    Result := False;
    exit;
  end;
  rc := 0;
  csize := 0;
  r := False;
  while Changed do
  begin
    Clear;
    Load(GetRoot);
    if length(s) > 10 then
      fs := Copy(s, 1, 10)
    else
      fs := s;
    R := Seek(s, True);
  end;
  Result := r;
end;

function TNtxRO.Load(N: integer): PBuf;
var
  it: TTraceRec;

  r: PBuf;
begin
  r := nil;

  if h > 0 then
  begin
    with tr do
    begin
      it := TTraceRec.Create(N, 1);
      Add(it);
    end;
    r := GetPage(h, N);
  end;
  Result := r;
end;

procedure TNtxRO.Clear;
var
  it: TTraceRec;
begin

  while tr.Count > 0 do
  begin
    it := TTraceRec(tr.Items[0]);
    tr.Delete(0);
    it.Free;
  end;
end;

function TNtxRO.Pop: PBuf;
var
  r: PBuf;

  it: TTraceRec;
begin
  r := nil;

  with tr do
    if Count > 1 then
    begin
      it := TTraceRec(Items[Count - 1]);
      Delete(Count - 1);
      it.Free;
      it := TTraceRec(Items[Count - 1]);
      r := GetPage(h, it.pg)
    end;
  Result := r;
end;

function TNtxRO.Changed: boolean;
var
  i: integer;

  r: boolean;
begin
  r := False;

  if h > 0 then
  begin
    i := GetEmpty;
    if i <> empty then
      r := True;
    empty := i;
    i := GetSize;
    if i <> csize then
      r := True;
    csize := i;
  end;
  Result := r;
end;

constructor TNtxRO.Open(nm: ShortString);
begin

  Error := False;
  h := FileOpen(nm, fmOpenRead or fmShareDenyNone);
  if h > 0 then
  begin
    fs := '';
    FileSeek(h, 12, 0);
    FileRead(h, isz, 2);
    FileSeek(h, 14, 0);
    FileRead(h, ksz, 2);
    FileSeek(h, 18, 0);
    FileRead(h, max, 2);
    FileSeek(h, 20, 0);
    FileRead(h, hlf, 2);
    empty := -1;
    csize := -1;
    DosFl := True;
    tr := TList.Create;
  end
  else
    Error := True;
end;

destructor TNtxRO.Destroy;
begin

  if h > 0 then
  begin
    FileClose(h);
    Clear;
    tr.Free;
    FreeHandle(h);
  end;
  inherited Destroy;
end;

function TNtxRO.GetRoot: integer;
var
  r: integer;
begin
  r := -1;

  if h > 0 then
  begin
    FileSeek(h, 4, 0);
    FileRead(h, r, 4);
  end;
  Result := r;
end;

function TNtxRO.GetEmpty: integer;
var
  r: integer;
begin
  r := -1;

  if h > 0 then
  begin
    FileSeek(h, 8, 0);
    FileRead(h, r, 4);
  end;
  Result := r;
end;

function TNtxRO.GetSize: integer;
var
  r: integer;
begin
  r := 0;

  if h > 0 then
    r := FileSeek(h, 0, 2);
  Result := r;
end;

constructor TTraceRec.Create(p: integer; c: SmallInt);
begin

  pg := p;
  cn := c;
end;

function GetPage(h, fs: integer): PBuf; {Протестировать отдельно}
var
  i, j, mn: integer;

  q: PBuf;
begin

  mn := 10000;
  j := 0;
  for i := 1 to MaxPgs do
    if (Cache[i].Handle = h) and
      (Cache[i].Offset = fs) then
    begin
      j := i;
      if Cache[i].Countr < 10000 then
        Inc(Cache[i].Countr);
    end;
  if j = 0 then
  begin
    for i := 1 to MaxPgs do
      if Cache[i].Handle = 0 then
        j := i;
    if j = 0 then
      for i := 1 to MaxPgs do
        if Cache[i].Countr <= mn then
        begin
          mn := Cache[i].Countr;
          j := i;
        end;
    Cache[j].Countr := 0;
    mn := 0;
  end;
  q := PBuf(@(Buf[(j - 1) * 1024 + 1]));
  if mn = 0 then
  begin
    FileSeek(h, fs, 0);
    Cache[j].Length := FileRead(h, q^, 1024);
  end;
  Cache[j].Handle := h;
  Cache[j].Offset := fs;
  Result := q;
end;

procedure FreeHandle(h: integer);
var
  i: integer;
begin

  for i := 1 to MaxPgs do
    if Cache[i].Handle = h then
      Cache[i].Handle := 0;
end;

function DosToWin(const ss: ShortString): ShortString;
var
  r: ShortString;

  i: integer;
begin
  r := '';

  for i := 1 to length(ss) do
    if ss[i] in [chr($80)..chr($9F)] then
      r := r + chr(ord(ss[i]) - $80 + $C0)
    else if ss[i] in [chr($A0)..chr($AF)] then
      r := r + chr(ord(ss[i]) - $A0 + $C0)
    else if ss[i] in [chr($E0)..chr($EF)] then
      r := r + chr(ord(ss[i]) - $E0 + $D0)
    else if ss[i] in [chr($61)..chr($7A)] then
      r := r + chr(ord(ss[i]) - $61 + $41)
    else if ss[i] in [chr($F0)..chr($F1)] then
      r := r + chr($C5)
    else
      r := r + ss[i];
  Result := r;
end;

function WinToDos(const ss: ShortString): ShortString;
var
  r: ShortString;

  i: integer;
begin
  r := '';

  for i := 1 to length(ss) do
    if ss[i] in [chr($C0)..chr($DF)] then
      r := r + chr(ord(ss[i]) - $C0 + $80)
    else if ss[i] in [chr($E0)..chr($FF)] then
      r := r + chr(ord(ss[i]) - $E0 + $80)
    else if ss[i] in [chr($F0)..chr($FF)] then
      r := r + chr(ord(ss[i]) - $F0 + $90)
    else if ss[i] in [chr($61)..chr($7A)] then
      r := r + chr(ord(ss[i]) - $61 + $41)
    else if ss[i] in [chr($D5), chr($C5)] then
      r := r + chr($F0)
    else
      r := r + ss[i];
  Result := r;
end;

end.

Статья Работа с индексами Clipper-а раздела Базы данных Clipper может быть полезна для разработчиков на Delphi и FreePascal.


Комментарии и вопросы


Ваше мнение или вопрос к статье в виде простого текста (Tag <a href=... Disabled). Все комментарии модерируются, модератор оставляет за собой право удалить непонравившейся ему комментарий.

заголовок

e-mail

Ваше имя

Сообщение

Введите код




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: Clipper ::


реклама



©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru Rambler's Top100
29.03.2024 01:38:09/0.0011880397796631/0