home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / database / gsdb28 / gs_dbfld.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-02-27  |  49.1 KB  |  1,482 lines

  1. {                      dBase III Field Handler
  2.  
  3.        GS_DBFLD Copyright (c)  Richard F. Griffin
  4.  
  5.        15 November 1990
  6.  
  7.        102 Molded Stone Pl
  8.        Warner Robins, GA  31088
  9.  
  10.        -------------------------------------------------------------
  11.        This unit handles field processing for all dBase III file (.DBF)
  12.        operations.
  13.  
  14.                    SHAREWARE  -- COMMERCIAL USE RESTRICTED
  15.  
  16.        Changes:
  17.  
  18.        02 May 91 - Changed the type of value returned for a date field from
  19.                    string to longint.  The value assigned is the julian date.
  20.                    Note that the Julian day number is not the same as the
  21.                    serial day number (1-366) which is sometimes (erroneously)
  22.                    called a Julian date.  Refer to the GS_Date unit for more
  23.                    information.
  24.  
  25.        03 May 91 - Ensured Date field is a julian date for .NDX indexes in the
  26.                    IndexTo method.
  27.  
  28.        02 Jun 91 - Allowed a 'blank' date field to be acccepted if the field
  29.                    was originally blank in AcceptField.
  30.  
  31.        31 Jul 91 - Created a StatusUpdate virtual method to allow a user to
  32.                    track progress of actions such as Pack and IndexTo.  The
  33.                    status will be passed to StatusUpdate from within those
  34.                    methods.  The basic StatusUpdate is empty and does nothing
  35.                    with the passed status.  The user has the option to create
  36.                    his own virtual method to capture this information.
  37.  
  38.        20 Oct 91 - Added a Zap method to delete and remove all records.
  39.  
  40.        20 Oct 91 - Corrected the Pack Method to write the EOF Mark in the
  41.                    proper location.
  42.  
  43.        11 Nov 91 - Corrected IndexTo problem with garbage object data.
  44.                    Added close and init calls to ensure good object.
  45.  
  46.        20 Feb 92 - Added a Done destructor to allow dynamic allocation
  47.                    of objects.
  48.  
  49.                    Added GSP_dBFld_Objct as pointer type to the object.
  50.                    This facilitates dynamic creation of the object.
  51.  
  52. ------------------------------------------------------------------------------}
  53. {
  54.                            ┌──────────────────────┐
  55.                            │  INTERFACE SECTION:  │
  56.                            └──────────────────────┘
  57. }
  58. unit GS_dBFld;
  59. {$D-}
  60.  
  61. interface
  62.  
  63. uses
  64.    CRT,
  65.    GS_Date,
  66.    GS_Edit,
  67.    GS_FileH,
  68.    GS_Error,
  69.    GS_KeyI,
  70.    GS_Strng,
  71.    GS_Winfc,
  72.    GS_dBase;
  73.  
  74. const
  75.    StatusStart     = -1;
  76.    StatusStop      = 0;
  77.    StatusIndexTo   = 1;
  78.    StatusPack      = 2;
  79.  
  80. type
  81.    GSP_dBFld_Objt = ^GS_dBFld_Objt;
  82.    GS_dBFld_Objt   = object(GS_dBase_dB)
  83.       LastFldTyp   : char;            {Last FieldGet type field}
  84.       LastFldDec   : integer;         {Last FieldGet Decimals}
  85.       LastFldLth   : integer;         {Last FieldGet Length}
  86.       LastFldNam   : string[11];      {Last FieldGet Name}
  87.       LastFldNum   : integer;         {Last FieldGet Number}
  88.       EditOn       : boolean;         {Edit allowed}
  89.       RecChanged   : boolean;         {Flag for record changed}
  90.       Memo_Loc     : longint;         {Starting memo block for field}
  91.       Memo_Bloks   : integer;         {Number of blocks used for the field}
  92.       Memo_Store   : GS_Edit_Objt;    {Object to store/edit memos}
  93.       DeleteOnF9   : boolean;         {Flag to permit F9 to delete/undelete}
  94.  
  95.       Constructor Init(FName : string);
  96.       Destructor Done;
  97.       Procedure Check_Func_Keys; virtual;
  98.       Function  Create(FName : string) : boolean;
  99.       function  DateGet(st : string) : longint;
  100.       function  DateGetN(n : integer) : longint;
  101.       Procedure DatePut(st : string; jdte : longint);
  102.       Procedure DatePutN(n : integer; jdte : longint);
  103.       Function  FieldAccept(st,Titl : string; x,y : integer) : string;
  104.       Procedure FieldDisplay(st,Titl : string; x,y : integer);
  105.       Function  FieldDisplayScreen : boolean;
  106.       Function  FieldGet(st : string) : string;
  107.       Function  FieldGetN(n : integer) : string;
  108.       Procedure FieldPut(st1, st2 : string);
  109.       Procedure FieldPutN(n : integer; st1 : string);
  110.       Function  FieldUpdateScreen : boolean;
  111.       Function  FieldAppendScreen(empty : boolean) : boolean;
  112.       Function  Formula(st : string; var ftyp : char) : string; virtual;
  113.       Function  HuntFieldName(st : string; var fs : integer) : boolean;
  114.       Procedure IndexTo(filname, formla : string);
  115.       function  LogicGet(st : string) : boolean;
  116.       function  LogicGetN(n : integer) : boolean;
  117.       Procedure LogicPut(st : string; b : boolean);
  118.       Procedure LogicPutN(n : integer; b : boolean);
  119.       Procedure MemoEdit;
  120.       function  MemoGetLine(linenum : integer) : string;
  121.       procedure MemoGet(rpt : string);
  122.       Procedure MemoWidth(l : integer);
  123.       function  MemoLines : integer;
  124.       function  MemoPut : string;
  125.       function  NumberGet(st : string) : real;
  126.       function  NumberGetN(n : integer) : real;
  127.       Procedure NumberPut(st : string; r : real);
  128.       Procedure NumberPutN(n : integer; r : real);
  129.       Procedure Pack;
  130.       Procedure StatusUpdate(statword1,statword2,statword3 : longint); virtual;
  131.       function  StringGet(st : string) : string;
  132.       function  StringGetN(n : integer) : string;
  133.       Procedure StringPut(st1, st2 : string);
  134.       Procedure StringPutN(n : integer; st1 : string);
  135.       Procedure Zap;
  136.    end;
  137.  
  138. implementation
  139.  
  140. constructor GS_dBFld_Objt.Init(FName : string);
  141. begin
  142.    EditOn := true;
  143.    GS_dBase_DB.Init(FName);
  144.    Memo_Store.Init;                   {Initialize the edit object}
  145.    Memo_Store.Edit_Lgth := 50;        {Set default memo line size to 50}
  146.    Wait_Cr := false;                  {Set EditString not to wait for CR}
  147.    DeleteOnF9 := false;               {Turn off F9 for delete/undelete}
  148. end;
  149.  
  150. destructor GS_dBFld_Objt.Done;
  151. begin
  152.    Memo_Store.Done;
  153.    GS_dBase_DB.UnInit;
  154. end;
  155.  
  156. procedure GS_dBFld_Objt.Check_Func_Keys;
  157. begin
  158.    case ch of
  159.      Kbd_F9   : begin
  160.                    if DeleteOnF9 then
  161.                    begin
  162.                       if RecNumber < 0 then
  163.                       begin
  164.                          if DelFlag then CurRecord^[0] :=  32
  165.                             else CurRecord^[0] := 42;
  166.                          DelFlag := not DelFlag;
  167.                       end
  168.                          else if DelFlag then UnDelete else Delete;
  169.                       GS_KeyI_Ret := true;
  170.                       Ch := Kbd_Ret;
  171.                    end else GS_dBase_DB.Check_Func_Keys;
  172.                 end;
  173.      Kbd_F10  : begin
  174.                    GS_KeyI_Ret := true;
  175.                    Ch := Kbd_Ret;
  176.                 end;
  177.      else GS_dBase_DB.Check_Func_Keys;
  178.   end;
  179. end;
  180.  
  181.  
  182. function  GS_dBFld_Objt.DateGet(st : string) : longint;
  183. var
  184.    t     : string;
  185.    v     : longint;
  186. begin
  187.    t := FieldGet(st);
  188.    v := GS_Date_Juln(t);
  189.    if v > 0 then DateGet := v else DateGet := 0;
  190. end;
  191.  
  192. function  GS_dBFld_Objt.DateGetN(n : integer) : longint;
  193. var
  194.    t     : string;
  195.    v     : longint;
  196. begin
  197.    t := FieldGetN(n);
  198.    v := GS_Date_Juln(t);
  199.    if v > 0 then DateGetN := v else DateGetN := 0;
  200. end;
  201.  
  202. Procedure GS_dBFld_Objt.DatePut(st : string; jdte : longint);
  203. var
  204.    f    : integer;
  205.    t    : string[8];
  206. begin
  207.    if not HuntFieldName(st,f) then
  208.    begin
  209.       ShowError(625,st);
  210.       exit;
  211.    end;
  212.    if jdte = 0 then t := '        '
  213.       else t := GS_Date_DBStor(jdte);
  214.    FieldPutN(f,t);
  215. end;
  216.  
  217. Procedure GS_dBFld_Objt.DatePutN(n : integer; jdte : longint);
  218. var
  219.    t    : string[8];
  220. begin
  221.    if n > NumFields then
  222.    begin
  223.       ShowError(627,'Field number out of range');
  224.       exit;
  225.    end;
  226.    if jdte = 0 then t := '        '
  227.       else t := GS_Date_DBStor(jdte);
  228.    FieldPutN(n,t);
  229. end;
  230.  
  231. function  GS_dBFld_Objt.LogicGet(st : string) : boolean;
  232. begin
  233.    LogicGet := ValLogic(FieldGet(st));
  234. end;
  235.  
  236. function  GS_dBFld_Objt.LogicGetN(n : integer) : boolean;
  237. begin
  238.    LogicGetN := ValLogic(FieldGetN(n));
  239. end;
  240.  
  241. Procedure GS_dBFld_Objt.LogicPut(st : string; b : boolean);
  242. begin
  243.    FieldPut(st,StrLogic(b));
  244. end;
  245.  
  246. Procedure GS_dBFld_Objt.LogicPutN(n : integer; b : boolean);
  247. begin
  248.    FieldPutN(n,StrLogic(b));
  249. end;
  250.  
  251. function  GS_dBFld_Objt.NumberGet(st : string) : real;
  252. var
  253.    r : integer;
  254.    v : real;
  255.    s : string;
  256. begin
  257.    s := TrimR(FieldGet(st));
  258.    r := 0;
  259.    if s = '' then v := 0 else val(s,v,r);
  260.    if r <> 0 then
  261.    begin
  262.       ShowError(620,'Not a valid numeric field in NumberGet'+s);
  263.       v := 0;
  264.    end;
  265.    NumberGet := v;
  266. end;
  267.  
  268. function  GS_dBFld_Objt.NumberGetN(n : integer) : real;
  269. var
  270.    r : integer;
  271.    v : real;
  272.    s : string;
  273. begin
  274.    s := TrimR(FieldGetN(n));
  275.    r := 0;
  276.    if s = '' then v := 0 else val(s,v,r);
  277.    if r <> 0 then
  278.    begin
  279.       ShowError(620,'Not a valid numeric field in NumberGetN - '+s);
  280.       v := 0;
  281.    end;
  282.    NumberGetN := v;
  283. end;
  284.  
  285. Procedure GS_dBFld_Objt.NumberPut(st : string; r : real);
  286. var
  287.    f : integer;
  288.    s : string;
  289. begin
  290.    if not HuntFieldName(st,f) then
  291.    begin
  292.       ShowError(625,st);
  293.       exit;
  294.    end;
  295.    Str(r:LastFldLth:LastFldDec,s);
  296.    FieldPutN(f,s);
  297. end;
  298.  
  299. Procedure GS_dBFld_Objt.NumberPutN(n : integer; r : real);
  300. var
  301.    s : string;
  302. begin
  303.    if n > NumFields then
  304.    begin
  305.       ShowError(627,'Field number out of range');
  306.       exit;
  307.    end;
  308.    Str(r:Fields^[n].FieldLen:Fields^[n].FieldDec,s);
  309.    FieldPutN(n,s);
  310. end;
  311.  
  312. function  GS_dBFld_Objt.StringGet(st : string) : string;
  313. begin
  314.    StringGet := TrimR(FieldGet(st));
  315. end;
  316.  
  317. function  GS_dBFld_Objt.StringGetN(n : integer) : string;
  318. begin
  319.    StringGetN := TrimR(FieldGetN(n));
  320. end;
  321.  
  322. Procedure GS_dBFld_Objt.StringPut(st1,st2 : string);
  323. begin
  324.    FieldPut(st1,st2);
  325. end;
  326.  
  327. Procedure GS_dBFld_Objt.StringPutN(n : integer; st1 : string);
  328. begin
  329.    FieldPutN(n,st1);
  330. end;
  331.  
  332. function GS_dBFld_Objt.HuntFieldName(st : string; var fs : integer) : boolean;
  333. var
  334.    FSt : string;
  335.    mtch : boolean;
  336. begin
  337.    FSt := AllCaps(st);             {Capitalize the workstring}
  338.    FSt := TrimR(FSt);              {Remove trailing spaces}
  339.    fs := 1;                        {Initialize field count}
  340.    mtch := false;                  {Set match found to false}
  341.    while (not mtch) and (fs <= NumFields) DO
  342.       if FieldsN^[fs] = FSt then mtch := true else inc(fs);
  343.    if mtch then
  344.    begin
  345.       LastFldTyp := Fields^[fs].FieldType;
  346.       LastFldDec := Fields^[fs].FieldDec;
  347.       LastFldLth := Fields^[fs].FieldLen;
  348.    end;
  349.    HuntFieldName := mtch;
  350. end;
  351.  
  352. Function GS_dBFld_Objt.Create(FName : string) : boolean;
  353. begin
  354.    if GS_dBase_DB.Create(FName) then
  355.    begin
  356.       Init(FName);
  357.       Create := true;
  358.    end else Create := false;
  359. end;
  360.  
  361. Procedure GS_dBFld_Objt.Pack;
  362. const
  363.    EOFMark : Byte = $1A;
  364. var
  365.    df   : file;                       {Local file variable for memo work file}
  366.    mbuf : array[0..GS_dBase_MaxMemoRec] of byte;
  367.    rsl  : word;
  368.    i, j : longint;                    {Local variables   }
  369.    mcnt,
  370.    tcnt : longint;
  371.    don : boolean;
  372.    rl   : real;
  373.    FNam : string[64];
  374.  
  375.    procedure UpdateMemo;
  376.    var
  377.       fp : integer;
  378.    begin
  379.       for fp := 1 to NumFields do
  380.       begin
  381.          if Fields^[fp].FieldType = 'M' then
  382.          begin
  383.             Memo_Loc := Trunc(NumberGetN(fp));
  384.             Memo_Bloks := 0;          {Initialize blocks read}
  385.             if (Memo_Loc <> 0) then
  386.             begin
  387.                tcnt := GS_FileSize(df);
  388.                rl := tcnt;
  389.                NumberPutN(fp,rl);
  390.                 don := false;         {Reset done flag to false}
  391.                while (not don) do    {loop until done (EOF mark)}
  392.                begin
  393.                   GS_FileRead(mFile, Memo_Loc+Memo_Bloks, mbuf, 1, rsl);
  394.                   inc(Memo_Bloks);
  395.                   mCnt := 0;          {Counter into disk read buffer}
  396.                   while (mCnt < GS_dBase_MaxMemoRec) and (don = false) do
  397.                   begin
  398.                      if mbuf[mcnt] = $1A then don := true;
  399.                      inc (mcnt);
  400.                   end;
  401.                   if not don then GS_FileWrite(df,-1,mbuf,1, rsl);
  402.                end;
  403.                FillChar(mbuf[mcnt],GS_dBase_MaxMemoRec - mcnt,#0);
  404.                GS_FileWrite(df,-1,mbuf,1, rsl);
  405.                                       {Write the last block to the .DBT}
  406.             end;
  407.          end;
  408.       end;
  409.    end;
  410.  
  411. begin      {Pack}
  412.    StatusUpdate(StatusStart,StatusPack,NumRecs);
  413.    i := 1;
  414.    while dbfNdxTbl[i] <> nil do
  415.    begin
  416.       Dispose(dbfNdxTbl[i], Done);
  417.       dbfNdxTbl[i] := nil;
  418.       inc(i);
  419.    end;
  420.    dbfNdxActv := nil;
  421.    j := 0;
  422.    if WithMemo then
  423.    begin
  424.       GS_FileAssign(df,'DB3$$$.D$$');
  425.       GS_FileRewrite(df,GS_dBase_MaxMemoRec);
  426.       FillChar(mbuf,GS_dBase_MaxMemoRec,#0);
  427.       mbuf[0] := 1;
  428.       GS_FileWrite(df,0,mbuf,1,rsl);
  429.    end;
  430.    for i := 1 to NumRecs do           {Read .DBF sequentially}
  431.    begin
  432.       GetRec(i);
  433.       if not DelFlag then             {Write to work file if not deleted}
  434.       begin
  435.          inc(j);                      {Increment record count for packed file }
  436.          if WithMemo then UpdateMemo;
  437.          PutRec(j);
  438.       end;
  439.       StatusUpdate(StatusPack,i,0);
  440.    end;
  441.    if i > j then                      {If records were deleted then...}
  442.    begin
  443.       NumRecs := j;                   {Store new record count in objectname}
  444.       GS_FileWrite(dfile, HeadLen+(j*RecLen), EOFMark, 1, rsl);
  445.                                       {Write End of File byte at file end}
  446.       GS_FileTruncate(dfile,HeadLen+(j*RecLen));
  447.                                       {Set new file size for dBase file};
  448.    end;
  449.    if WithMemo then
  450.    begin
  451.       tcnt := GS_FileSize(df);
  452.       FillChar(mbuf,GS_dBase_MaxMemoRec,#0);
  453.       Move(tcnt,mbuf[0],4);
  454.       GS_FileWrite(df,0,mbuf,1, rsl);
  455.                                       {Write the block to the .DBT.  It will}
  456.                                       {point to the next available block};
  457.       FNam := FileName;
  458.       FNam[length(FNam)] := 'T';
  459.       GS_FileClose(mFile);
  460.       GS_FileClose(df);
  461.       GS_FileErase(mFile);            {Erase original file}
  462.       GS_FileRename(df, FNam);        {Rename work file to original file name}
  463.       GS_FileAssign(mFile, FNam); {Set file type to new file}
  464.       GS_FileReset(mFile, GS_dBase_MaxMemoRec);
  465.    end;
  466.    StatusUpdate(StatusStop,0,0);
  467. END;                        { Pack }
  468.  
  469. Procedure GS_dBFld_Objt.Zap;
  470. const
  471.    EOFMark : Byte = $1A;
  472. var
  473.    df   : file;                       {Local file variable for memo work file}
  474.    mbuf : array[0..GS_dBase_MaxMemoRec] of byte;
  475.    rsl  : word;
  476.    i, j : longint;                    {Local variables   }
  477.    mcnt,
  478.    tcnt : longint;
  479.    don : boolean;
  480.    rl   : real;
  481.    FNam : string[64];
  482.  
  483. begin
  484.    i := 1;
  485.    while dbfNdxTbl[i] <> nil do
  486.    begin
  487.       Dispose(dbfNdxTbl[i], Done);
  488.       dbfNdxTbl[i] := nil;
  489.       inc(i);
  490.    end;
  491.    dbfNdxActv := nil;
  492.    if WithMemo then
  493.    begin
  494.       FillChar(mbuf,GS_dBase_MaxMemoRec,#0);
  495.       mbuf[0] := 1;
  496.       GS_FileWrite(mfile,0,mbuf,1,rsl);
  497.       GS_FileTruncate(mfile,1);
  498.    end;
  499.    NumRecs := 0;                   {Store new record count in objectname}
  500.    RecNumber := 0;
  501.    GS_FileWrite(dfile, HeadLen, EOFMark, 1, rsl);
  502.                                       {Write End of File byte at file end}
  503.    GS_FileTruncate(dfile,HeadLen);
  504.                                       {Set new file size for dBase file};
  505.    dStatus := Updated;
  506.    Close;
  507.    Open;
  508. END;                        { Zap }
  509.  
  510. Function GS_dBFld_Objt.FieldAccept(st,Titl : string; x,y : integer) : string;
  511. var
  512.    txtatrb,
  513.    i,
  514.    v         :  integer;              {Counter variables}
  515.    t         :  string[255];          {Work string to hold default (old) value}
  516.    f         : string[2];
  517.  
  518.    Procedure AcceptC;
  519.    var
  520.       r_c : string;
  521.    begin
  522.       GS_Wind_SetIVMode;
  523.       if EditOn then        {If edit permitted, then go edit string}
  524.       begin
  525.          r_c := t;
  526.          t := EditString(t, v, y, LastFldLth);
  527.          if t <> r_c then RecChanged := true;
  528.       end
  529.       else
  530.       begin
  531.          gotoxy(v,y);       {Go to start of field screen position}
  532.          write(t,'':LastFldLth-length(t));
  533.                             {Rewrite the string on screen inverted}
  534.          WaitForKey;
  535.       end;
  536.       GS_Wind_SetNmMode;
  537.       gotoxy(v,y);          {Go to start of field screen position}
  538.       write(t,'':LastFldLth-length(t));
  539.                             {Rewrite the string on screen in the original color}
  540.    end;
  541.  
  542.    Procedure AcceptD;
  543.    var
  544.       okDate : boolean;
  545.       v1,
  546.       v2     : longint;
  547.       h1     : string[10];
  548.    begin
  549.       t := TrimR(t);
  550.       if length(t) <> 8 then
  551.       begin
  552.          t := '  /  /    ';
  553.          if not GS_Date_Century then t[0] := #8;
  554.       end
  555.       else
  556.       begin
  557.          v1 := GS_Date_Juln(t);
  558.          t := GS_Date_View(v1);
  559.       end;
  560.       h1 := t;
  561.       LastFldLth := length(t);
  562.       okDate := false;
  563.       repeat
  564.          AcceptC;
  565.          if EditOn then
  566.          begin
  567.             if GS_KeyI_Esc then v2 := v1
  568.                else v2 := GS_Date_Juln(t);
  569.             if v2 >= 0 then
  570.             begin
  571.                okDate := true;
  572.                t := GS_Date_DBStor(v2);
  573.             end
  574.             else
  575.             begin
  576.                if t = h1 then
  577.                begin
  578.                   t := FieldGet(st);
  579.                   okDate := true;
  580.                end;
  581.             end;
  582.          end else okDate := true;
  583.          if not okDate then SoundBell(BeepTime,BeepFreq);
  584.       until okDate;
  585.    end;
  586.  
  587.    Procedure AcceptL;
  588.    var
  589.       data : string[1];
  590.    begin
  591. {
  592.                     ┌─────────────────────────────────────┐
  593.                     │  Accept keyboard entry.  Loop until │
  594.                     │  value is T,t,Y,y,F,f,N,n.          │
  595.                     └─────────────────────────────────────┘
  596. }
  597.       repeat
  598.          if t = '' then t := 'F';
  599.          AcceptC;
  600.          if not EditOn then exit;
  601.          if t[1] in ['T','t','Y','y','F','f','N','n'] then
  602.          begin end else SoundBell(BeepTime,BeepFreq);
  603.       until t[1] in ['T','t','Y','y','F','f','N','n'];
  604.       if t[1] in ['T','t','Y','y'] then t[1] := 'T' else t[1] := 'F';
  605.    end;
  606.  
  607.    procedure AcceptM;
  608.    var
  609.       ans       :  string[10];        {Work string to hold edit value}
  610.       r_c       :  string[10];        {Work string for memo block number}
  611.    begin
  612.       GS_Wind_SetIvMode;
  613.       ans := 'N';                     {Initialize ans to false}
  614.       if EditOn then write('  Edit ? ') else write('  View ? ');
  615.       repeat
  616.          ans := EditString(ans,v+9,y,1);
  617.                                       {Go edit string t for 1 character}
  618.                                       {at cursor position v,y}
  619.          if ans[1] in ['T','t','Y','y','F','f','N','n'] then
  620.             begin end else SoundBell(BeepTime,BeepFreq);
  621.       until ans[1] in ['T','t','Y','y','F','f','N','n'];
  622.       GS_Wind_SetNmMode;              {Restore original text attribute}
  623.       gotoxy(v,y);                    {Now reset to 'memo' for field name}
  624.       write('---memo---');
  625.       if ans[1] in ['T','t','Y','y'] then
  626.       begin
  627.          r_c := t;
  628.          MemoGet(t);
  629.          If EditOn then Memo_Store.Edit else Memo_Store.View;
  630.          if (EditOn) and (GS_KeyI_Esc) then
  631.          begin
  632.             GS_KeyI_Esc := false;     {Reset Escape flag so its not used}
  633.                                       {elsewhere}
  634.             GS_KeyI_Chr := ' ';
  635.             MemoGet(t);
  636.          end
  637.          else
  638.          begin
  639.             GS_KeyI_Chr := ' ';       {Clear character last entered}
  640.             if EditOn then t := MemoPut;
  641.             if t <> r_c then RecChanged := true;
  642.          end;
  643.       end;
  644.    end;
  645.  
  646.    Procedure AcceptN;
  647.    var
  648.       data : string;
  649.       i   : integer;
  650.       r   : real;
  651.    begin
  652. {
  653.                     ┌─────────────────────────────────────┐
  654.                     │  Accept keyboard entry.  Loop until │
  655.                     │  value is Numeric.                  │
  656.                     └─────────────────────────────────────┘
  657. }
  658.       repeat
  659.          if t = '' then Str(0.0:LastFldLth:LastFldDec,t);
  660.          AcceptC;
  661.          if not EditOn then exit;
  662.          val(t, r, i);
  663.          if i = 0 then
  664.          begin
  665.             Str(r:LastFldLth:LastFldDec,t);
  666.             if length(t) > LastFldLth then i := 999;
  667.          end;
  668.          if i <> 0 then
  669.          begin
  670.             SoundBell(BeepTime,BeepFreq);
  671.             t := '';
  672.          end;
  673.       until i = 0;                    {i will be 0 when data is a valid number}
  674.       gotoxy(v,y);          {Go to start of field screen position}
  675.       write(t,'':LastFldLth-length(t));
  676.                             {Rewrite the string on screen in the original color}
  677.    end;
  678.  
  679. begin
  680.    GotoXY(x,y);                       {Go to position on screen}
  681.    write(Titl);                       {Write the title of field}
  682.    v := WhereX;                       {Save the position after writing title}
  683.    t := TrimR(FieldGet(st));          {Get the field in the work string}
  684.    case LastFldTyp of
  685.       'C'  : begin
  686.                 AcceptC;
  687.                 FieldAccept := t;     {Return the string to calling routine}
  688.              end;
  689.       'D'  : begin
  690.                 AcceptD;
  691.                 FieldAccept := t;
  692.              end;
  693.       'L'  : begin
  694.                 AcceptL;
  695.                 FieldAccept := t;
  696.              end;
  697.       'M'  : begin
  698.                 AcceptM;
  699.                 FieldAccept := t;
  700.              end;
  701.       'N'  : begin
  702.                 AcceptN;
  703.                 FieldAccept := t;
  704.              end;
  705.    end;
  706. end;
  707.  
  708. Procedure GS_dBFld_Objt.FieldDisplay(st,Titl : string; x,y : integer);
  709. var
  710.    i,
  711.    v         :  integer;              {Counter variables}
  712.    t         :  string[255];          {Work string to hold default (old) value}
  713.    data      :  string[10];
  714. begin
  715.    GotoXY(x,y);                       {Go to position on screen}
  716.    write(Titl);                       {Write the title of field}
  717.    v := WhereX;                       {Save the position after writing title}
  718.    t := TrimR(FieldGet(st));          {Get the field in the work string}
  719.  
  720.    case LastFldTyp of
  721.       'C',
  722.       'L'  : begin
  723.                 gotoxy(v,y);          {Go to start of field screen position}
  724.                 write(t,'':LastFldLth-length(t));
  725.                                       {Write the string on screen }
  726.              end;
  727.       'D'  : begin
  728.                 t := GS_Date_View(GS_Date_Juln(t));;
  729.                 write(t);
  730.              end;
  731.       'N'  : begin
  732.                 if t = '' then t := '0';
  733.                 gotoxy(v,y);          {Go to start of field screen position}
  734.                 write(t:LastFldLth);
  735.              end;
  736.       'M'  : begin
  737.                 gotoxy(v,y);          {Go to start of field screen position}
  738.                 write('---memo---');  {Write the '---memo--- on screen }
  739.              end;
  740.    end;
  741. end;
  742.  
  743. Function GS_dBFld_Objt.FieldDisplayScreen : boolean;
  744. var
  745.    f,
  746.    h     : boolean;
  747. begin
  748.    h := EditOn;
  749.    EditOn := false;
  750.    f := FieldUpdateScreen;
  751.    EditOn := h;
  752.    FieldDisplayScreen := f;
  753. end;
  754.  
  755. function GS_dBFld_Objt.FieldGetN(n : integer) : String;
  756. var
  757.    os,
  758.    fs  : longint;
  759.    i,
  760.    k   : integer;
  761.    FSt,
  762.    WSt : string[255];
  763.    NSt : string[10];
  764. begin
  765.    fs := n;                        {Initialize field count}
  766.    if (fs <= NumFields) then
  767.    BEGIN
  768.       os := 1;
  769.       WITH Fields^[fs] DO
  770.       BEGIN
  771.          CnvAscToStr(FieldName,FSt,11);
  772.          FSt := TrimR(FSt);           {Remove trailing spaces}
  773.          move(CurRecord^[FieldAddress], WSt[1], FieldLen);
  774.          WSt[0] := char(FieldLen);    {Set string length to field length}
  775.          FieldGetN := WSt;
  776.          LastFldTyp := FieldType;
  777.          LastFldDec := FieldDec;
  778.          LastFldLth := FieldLen;
  779.          LastFldNum := fs;
  780.          LastFldNam := FSt;
  781.       end;
  782.    end else
  783.    begin
  784.       str(n,NSt);
  785.       ShowError(603,NSt);
  786.       FieldGetN := '';
  787.       LastFldTyp := ' ';
  788.       LastFldDec := 0;
  789.       LastFldLth := 0;
  790.       LastFldNum := 0;
  791.       LastFldNam := '';
  792.    end;
  793. end;
  794.  
  795. function GS_dBFld_Objt.FieldGet(st : string) : String;
  796. var
  797.    fs : integer;
  798. begin
  799.    if HuntFieldName(st,fs) then FieldGet := FieldGetN(fs)
  800.    else
  801.    begin
  802.       ShowError(602,st);
  803.       FieldGet := '';
  804.       LastFldTyp := ' ';
  805.       LastFldDec := 0;
  806.       LastFldLth := 0;
  807.       LastFldNum := 0;
  808.       LastFldNam := '';
  809.    end;
  810. end;
  811.  
  812.  
  813. Procedure GS_dBFld_Objt.FieldPutN(n : integer; st1 : string);
  814. var
  815.    os,
  816.    fs  : longint;
  817.    i,
  818.    k   : integer;
  819.    FSt,
  820.    WSt : string[255];
  821.    NSt : string[10];
  822. begin
  823.    fs := n;                        {Initialize field count}
  824.    if (fs <= NumFields) then
  825.    BEGIN
  826.       WITH Fields^[fs] DO
  827.       BEGIN
  828.          move(FieldName,FSt[1],11);
  829.          FSt[0] := #11;
  830.          FSt[0] := char(pred(pos(#0,FSt)));
  831.          FSt := TrimR(FSt);        {Remove trailing spaces}
  832.          FillChar(CurRecord^[FieldAddress], FieldLen, ' ');
  833.          k := length(st1);         {Get length of input string}
  834.          if k > FieldLen then k := FieldLen;
  835.          Move(st1[1], CurRecord^[FieldAddress], k);
  836.          LastFldTyp := FieldType;
  837.          LastFldDec := FieldDec;
  838.          LastFldLth := FieldLen;
  839.          LastFldNum := fs;
  840.          LastFldNam := FSt;
  841.       end;
  842.    end else
  843.    begin
  844.       str(n,NSt);
  845.       ShowError(605,NSt);
  846.       LastFldTyp := ' ';
  847.       LastFldDec := 0;
  848.       LastFldLth := 0;
  849.       LastFldNum := 0;
  850.       LastFldNam := '';
  851.    end;
  852. end;
  853.  
  854. Procedure GS_dBFld_Objt.FieldPut(st1, st2 : string);
  855. var
  856.    fs : integer;
  857. begin
  858.    if HuntFieldName(st1,fs) then FieldPutN(fs,st2)
  859.    else
  860.    begin
  861.       ShowError(604,st1);
  862.       LastFldTyp := ' ';
  863.       LastFldDec := 0;
  864.       LastFldLth := 0;
  865.       LastFldNum := 0;
  866.       LastFldNam := '';
  867.    end;
  868. end;
  869.  
  870. Function GS_dBFld_Objt.FieldUpdateScreen : boolean;
  871. var
  872.    b,
  873.    i,
  874.    v,
  875.    x,
  876.    y,
  877.    ll    : integer;
  878.    st,
  879.    s     : string[12];
  880.    t     : string;
  881.    activlin,
  882.    activfld : integer;
  883.  
  884.  
  885.    Procedure UpdatePage;
  886.    var
  887.       validcmd : boolean;
  888.    begin
  889.       validcmd := false;
  890.       if activfld < b then activfld := b;
  891.       if activfld >= b+v then activfld := pred(b+v);
  892.       activlin := succ(activfld - b);
  893.       if (activlin < 1) or (activlin > v) then activlin := 1;
  894.       repeat
  895.          t := FieldAccept(FieldsN^[activfld],'',13,activlin);
  896.          if (EditOn) and (not GS_KeyI_Esc) then FieldPutN(activfld,t);
  897.          if (not GS_KeyI_Fuc) and (GS_KeyI_Chr >= #32) then
  898.             GS_KeyI_Chr := Kbd_Ret;
  899.  
  900.             case GS_KeyI_Chr of
  901.                Kbd_F9 :   begin
  902.                              gotoxy(3,ll);
  903.                              GS_Wind_SetIvMode;
  904.                              if DelFlag then write('Deleted')
  905.                                 else write('':8);
  906.                              GS_Wind_SetNmMode;
  907.                           end;
  908.                Kbd_PgUp : begin
  909.                              if activfld = b then
  910.                              begin
  911.                                 b := b-v;
  912.                                 if b < 1 then b := 1;
  913.                                 validcmd := true;
  914.                              end
  915.                              else activfld := b;
  916.                           end;
  917.                Kbd_PgDn : begin
  918.                              if activfld = pred(b+v) then
  919.                              begin
  920.                                 b := b+v;
  921.                                 if b > NumFields-v then b := succ(NumFields-v);
  922.                                 if b < 1 then b := 1;
  923.                                 validcmd := true;
  924.                              end
  925.                              else activfld := pred(b+v);
  926.                           end;
  927.                Kbd_UpAr : begin
  928.                              dec(activfld);
  929.                              if activfld < b then
  930.                              begin
  931.                                 dec(b);
  932.                                 if b < 1 then b := 1;
  933.                                 validcmd := true;
  934.                              end;
  935.                           end;
  936.                Kbd_RtAr,
  937.                Kbd_Tab,
  938.                Kbd_Ret,
  939.                Kbd_DnAr : begin
  940.                              inc(activfld);
  941.                              if activfld > pred(b+v) then
  942.                              begin
  943.                                 if activfld > NumFields then
  944.                                    activfld := NumFields
  945.                                 else
  946.                                 begin
  947.                                    inc(b);
  948.                                    if b > NumFields then
  949.                                       b := succ(NumFields-v);
  950.                                    validcmd := true;
  951.                                 end;
  952.                              end;
  953.                           end;
  954.                Kbd_Esc,
  955.                Kbd_F10  : validcmd := true;
  956.             end;
  957.  
  958.          if activfld < b then activfld := b;
  959.          if activfld >= b+v then activfld := pred(b+v);
  960.          activlin := succ(activfld - b);
  961.          if (activlin < 1) or (activlin > v) then activlin := 1;
  962.       until validcmd;
  963.    end;
  964.  
  965. begin
  966.    ClrScr;
  967.    DeleteOnF9 := true;
  968.    RecChanged := false;
  969.    b := 1;
  970.    activfld := b;
  971.    ll := succ(hi(WindMax)-hi(WindMin));
  972.    v := pred(ll);
  973.    GS_Wind_SetIvMode;
  974.    gotoxy(2,ll);
  975.    write('':pred(lo(WindMax)-lo(WindMin)));
  976.    if EditOn then
  977.    begin
  978.       if RecNumber < 0 then           {If Append, do the following}
  979.       begin
  980.          gotoxy(12,ll);
  981.          write('Append ');
  982.          write('EOF/',NumRecs);
  983.       end
  984.       else
  985.       begin                           {If Update do the following}
  986.          gotoxy(12,ll);
  987.          write('Update ');
  988.          write(RecNumber,'/',NumRecs);
  989.       end;
  990.    end else
  991.    begin                              {If Display then do this}
  992.       gotoxy(12,ll);
  993.       write('Display ');
  994.       write(RecNumber,'/',NumRecs);
  995.    end;
  996.    if DelFlag then
  997.    begin
  998.       gotoxy(3,ll);
  999.       write('Deleted');
  1000.    end;
  1001.    GS_Wind_SetNmMode;
  1002.    if NumFields < v then v := NumFields;
  1003.    x := 1;
  1004.    y := 1;
  1005.    Ch := ' ';
  1006.    repeat
  1007.       for i := b to pred(b+v) do
  1008.       begin
  1009.          s := FieldsN^[i];
  1010.          FillChar(st[1],12,' ');
  1011.          move(s[1],st[11-length(s)],length(s));
  1012.          st[11] := ':';
  1013.          st[0] := #12;
  1014.          FieldDisplay(s,st,x,y);
  1015.          case LastFldTyp of
  1016.            'M' : begin
  1017.                     gotoxy(x+12,y);
  1018.                     write('---memo---');
  1019.                     if RecNumber < 0 then FieldPutN(LastFldNum,' ');
  1020.                                       {If Append, make sure memo field is not}
  1021.                                       {pointing to a memo block              }
  1022.                  end;
  1023.          end;
  1024.          ClrEol;
  1025.          inc(y);
  1026.       end;
  1027.       UpdatePage;
  1028.       y := 1;
  1029.    until (GS_KeyI_Chr in [Kbd_Esc,Kbd_F10]) or
  1030.          ((GS_KeyI_Chr = Kbd_PgUp) and (activfld = 1)) or
  1031.          ((GS_KeyI_Chr = Kbd_PgDn) and (activfld = NumFields));
  1032.    DeleteOnF9 := false;
  1033.    if GS_KeyI_Chr in [Kbd_F10, Kbd_PgUp, Kbd_PgDn] then
  1034.       FieldUpdateScreen := true
  1035.    else FieldUpdateScreen := false;
  1036. end;
  1037.  
  1038. Function GS_dBFld_Objt.FieldAppendScreen(empty : boolean) : boolean;
  1039. begin
  1040.    if empty then Blank;
  1041.    CurRecord^[0] := 32;                   {Ensure delete flag is off}
  1042.    DelFlag := false;
  1043.    RecNumber := -1;
  1044.    FieldAppendScreen := FieldUpdateScreen;
  1045. end;
  1046.  
  1047. Function GS_dBFld_Objt.Formula(st : string; var ftyp : char) : string;
  1048. var
  1049.    FldVal,
  1050.    FldWrk : string;
  1051.    FldPos : integer;
  1052.  
  1053.    function HuntField(fldst : string) : String;
  1054.    var
  1055.       fs   : integer;
  1056.       ss   : string;
  1057.       FSt  : string;
  1058.       mtch : boolean;
  1059.    begin
  1060.       FSt := AllCaps(fldst);          {Capitalize the workstring}
  1061.       FSt := TrimR(FSt);              {Remove trailing spaces}
  1062.       fs := 1;                        {Initialize field count}
  1063.       mtch := false;                  {Set match found to false}
  1064.       while (not mtch) and (fs <= NumFields) DO
  1065.          if FieldsN^[fs] = FSt then mtch := true else inc(fs);
  1066.       if mtch then
  1067.       begin
  1068.          WITH Fields^[fs] DO
  1069.          BEGIN
  1070.             move(CurRecord^[FieldAddress], FSt[1], FieldLen);
  1071.             FSt[0] := char(FieldLen);    {Set string length to field length}
  1072.             ftyp := FieldType;
  1073.             HuntField := FSt;
  1074.          end;
  1075.       end
  1076.       else
  1077.       begin
  1078.          ss := TrimL(fldst);
  1079.          if ss = '' then
  1080.          begin
  1081.             HuntField := '';
  1082.             exit;
  1083.          end;
  1084.          if ss[1] = '"' then
  1085.          begin
  1086.             ss := TrimR(ss);
  1087.             system.delete(ss,1,1);
  1088.             if ss[length(ss)] = '"' then ss[0] := chr(pred(length(ss)));
  1089.             HuntField := ss;
  1090.             exit;
  1091.          end;
  1092.          ShowError(601,st+' ('+fldst+')');
  1093.          HuntField  := '';
  1094.       end;
  1095.    end;
  1096.  
  1097. begin
  1098.    FldVal := '';                      {Initialize the return string value}
  1099.    FldWrk := st;                      {Move the input string to a work field}
  1100.    while FldWrk <> '' do              {Repeat while there is still something}
  1101.                                       {in the work field.}
  1102.    begin
  1103.       FldPos := pos('+', FldWrk);     {Search for a '+' delimiter}
  1104.       if FldPos = 0 then FldPos := length(FldWrk)+1;
  1105.                                       {If no '+' then simulate for this pass}
  1106.                                       {by setting position to one beyond the}
  1107.                                       {end of the target field string.}
  1108.       FldVal := FldVal + HuntField(SubStr(FldWrk,1,FldPos-1));
  1109.                                       {Go find the field using the substring}
  1110.                                       {from the string's beginning to one }
  1111.                                       {position before the '+' character.}
  1112.       system.delete(FldWrk,1,FldPos); {Delete the string up through the '+'};
  1113.       FldWrk := TrimL(FldWrk);        {Remove leading spaces}
  1114.    end;
  1115.    Formula := FldVal;                 {Return value to calling routine}
  1116. end;
  1117.  
  1118. Procedure GS_dBFld_Objt.IndexTo(filname, formla : string);
  1119. var
  1120.    i,
  1121.    j,
  1122.    fl : integer;                      {Local working variable}
  1123.    ft : char;
  1124.    ftyp : char;
  1125.    fval : longint;
  1126.    fkey : string;
  1127.  
  1128. {
  1129.              ┌──────────────────────────────────────────────────┐
  1130.              │  This routine will accumulate the field length   │
  1131.              │  of all fields passes in the calling argument.   │
  1132.              │  This is needed to pass the formula length to    │
  1133.              │  create the index header.                        │
  1134.              └──────────────────────────────────────────────────┘
  1135. }
  1136.  
  1137.  
  1138.    procedure AccumField;
  1139.    var
  1140.       FldWrk : string;
  1141.       FldLoc,
  1142.       FldPos : integer;
  1143.    begin
  1144.       ft := '*';                      {Set field type to new '*'}
  1145.       fl := 0;                        {initialize field length}
  1146.       FldWrk := TrimR(formla);        {Remove trailing spaces from argument}
  1147.       while FldWrk <> '' do           {Repeat while there is still something}
  1148.                                       {in the work field.}
  1149.       begin
  1150.          FldPos := pos('+', FldWrk);  {Search for a '+' delimiter}
  1151.          if FldPos = 0 then FldPos := length(FldWrk)+1;
  1152.                                       {If no '+' then simulate for this pass}
  1153.                                       {by setting position to one beyond the}
  1154.                                       {end of the target field string.}
  1155.  
  1156.                                       {Go find the field using the substring}
  1157.                                       {from the string's beginning to one }
  1158.                                       {position before the '+' character.}
  1159.         if not HuntFieldName(SubStr(FldWrk,1,FldPos-1),FldLoc) then
  1160.          begin
  1161.             fl := 0;
  1162.             exit;
  1163.          end;
  1164.          if ft = '*' then ft := LastFldTyp
  1165.             else ft := 'C';           {Set type to C if more than one field}
  1166.                                       {Else save this field's type         }
  1167.          fl := fl + Fields^[FldLoc].FieldLen;
  1168.                                       {If a valid field, then add the field}
  1169.                                       {length to the total field length value.}
  1170.          system.delete(FldWrk,1,FldPos);
  1171.                                       {Delete the string up through the '+'};
  1172.          FldWrk := TrimL(FldWrk);     {Remove leading spaces}
  1173.       end;
  1174.    end;
  1175.  
  1176. {
  1177.              ┌──────────────────────────────────────────────────┐
  1178.              │  Main routine.  This takes and analyzes the      │
  1179.              │  argument to build an index file.  It does the   │
  1180.              │  following:                                      │
  1181.              │  1.  Reset current index files.                  │
  1182.              │  2.  Get the total new formula field length.     │
  1183.              │  3.  Create an index file.                       │
  1184.              │  4.  Build the index by reading all dbase        │
  1185.              │      records and updating the index file.        │
  1186.              └──────────────────────────────────────────────────┘
  1187. }
  1188.  
  1189. begin
  1190.    StatusUpdate(StatusStart,StatusIndexTo,NumRecs);
  1191.    i := 1;
  1192.    while dbfNdxTbl[i] <> nil do
  1193.    begin
  1194.       Dispose(dbfNdxTbl[i], Done);
  1195.       dbfNdxTbl[i] := nil;
  1196.       inc(i);
  1197.    end;
  1198.    dbfNdxActv := nil;
  1199.    if formla <> '' then
  1200.    begin
  1201.       AccumField;                     {Get field length of the formula}
  1202.       if fl = 0 then
  1203.       begin
  1204.          ShowError(601,formla);       {Display Error if formula is bad}
  1205.          exit;                        {Exit if formula is no good}
  1206.       end;
  1207.       New(dbfNdxTbl[1], Ndx_Make(filname, formla, fl, ft));
  1208.                                       {Go create an index}
  1209.       Dispose(dbfNdxTbl[1], Done);
  1210.       Open;
  1211.       New(dbfNdxTbl[1], Init(filname));
  1212.       GetRec(Top_Record);             {Read all dBase file records}
  1213.       while not File_EOF do
  1214.       begin
  1215.          fkey := Formula(formla,ftyp);
  1216.          if (IsDB3NDX) and (ftyp = 'D') then
  1217.          begin
  1218.             fval := GS_Date_Juln(fkey);
  1219.             str(fval,fkey);
  1220.          end;
  1221.          dbfNdxTbl[1]^.KeyUpdate(fkey,RecNumber,-1);
  1222.                                       {Insert record in the index}
  1223.          StatusUpdate(StatusIndexTo,RecNumber,0);
  1224.          GetRec(Next_Record);
  1225.       end;
  1226.       dbfNdxTbl[1]^.Ndx_Flush;
  1227.       dbfNdxActv := dbfNdxTbl[1];
  1228.       GetRec(Top_Record);             {Reset to top record}
  1229.    end;
  1230.    StatusUpdate(StatusStop,0,0);
  1231. end;
  1232.  
  1233. function GS_dBFld_Objt.MemoGetLine(linenum : integer) : string;
  1234. begin
  1235.    if linenum > Memo_Store.Total_Lines then
  1236.    begin
  1237.       MemoGetLine := '';
  1238.       exit;
  1239.    end;
  1240.    if not Memo_Store.Find_Line(linenum) then
  1241.    begin
  1242.       MemoGetLine := '';
  1243.       exit;
  1244.    end;
  1245.    MemoGetLine := Memo_Store.Work_line^.Valu_Line;
  1246. end;
  1247.  
  1248. Procedure GS_dBFld_Objt.MemoGet(rpt : string);
  1249. const
  1250.    EOFMark : byte = $1A;              {End of disk file code}
  1251.  
  1252. var
  1253.    cnt,                               {Counter for memo storage location}
  1254.    lCnt,                              {Counter for line length in characters}
  1255.    mCnt    : longint;                 {Counter for input buffer char position}
  1256.    Result  : word;                    {BlockRead number of bytes read}
  1257.    don     : boolean;                 {Flag set when end of memo field found}
  1258.    i,j     : integer;                 {Working variable}
  1259.    Mem_Block : array [0..GS_dBase_MaxMemoRec] of byte;
  1260.                                       {Input buffer}
  1261. BEGIN                       { Get Memo Field }
  1262.    Val(rpt, Memo_Loc, i);             {Save starting block number}
  1263.    Memo_Bloks := 0;                   {Initialize blocks read}
  1264.    Memo_Store.Clear_Editor;           {Begin memo line count at zero}
  1265. {
  1266.                     ┌─────────────────────────────────────┐
  1267.                     │  If no .DBT memo field for this     │
  1268.                     │  record, then exit.                 │
  1269.                     └─────────────────────────────────────┘
  1270. }
  1271.    if (Memo_Loc = 0) then exit;
  1272.    Memo_Store.Work_Line := Memo_Store.Get_Line_Mem(Memo_Store.Edit_Lgth);
  1273.                                       {Get the first edit line record}
  1274.    Memo_Store.Active_Line := 1;       {Set active line to first line}
  1275.    don := false;                     {Reset done flag to false}
  1276.    cnt := 0;                          {index into Memo_Store buffer}
  1277.    lCnt := 0;                         {line length counter}
  1278.    BEGIN
  1279.       while (not don) do             {loop until done (EOF mark)}
  1280.       begin
  1281.          GS_FileRead(mFile, Memo_Loc+Memo_Bloks, Mem_Block, 1, Result);
  1282.          inc(Memo_Bloks);
  1283.          mCnt := 0;                   {Counter into disk read buffer}
  1284. {
  1285.                     ┌─────────────────────────────────────┐
  1286.                     │  Start reading and processing the   │
  1287.                     │  sequential memo blocks until EOF   │
  1288.                     │  mark is found.                     │
  1289.                     └─────────────────────────────────────┘
  1290. }
  1291.          while (mCnt < GS_dBase_MaxMemoRec) and
  1292.                (don = false) do
  1293. {
  1294.                  ┌────────────────────────────────────────────┐
  1295.                  │   Repeat the following until you find an   │
  1296.                  │   End-of-Memo condition.  Read the next    │
  1297.                  │   block each time mCnt reaches 512 bytes   │
  1298.                  │   (GS_dBase_MaxMemoRec.  Group the memo    │
  1299.                  │   as a series of lines no greater than     │
  1300.                  │   Memo_Width long.                         │
  1301.                  └────────────────────────────────────────────┘
  1302. }
  1303.          begin
  1304.  
  1305.             case Mem_Block[mCnt] of   {Check for control characters}
  1306.  
  1307.                $1A : begin
  1308.                         don := true; {End of Memo field}
  1309.                         if Memo_Store.Work_line^.Valu_Line = '' then
  1310.                            Memo_Store.Rel_Line_Mem(Memo_Store.Active_Line);
  1311.                      end;
  1312.  
  1313.                $8D : begin            {Soft Return (Wordstar and dBase editor)}
  1314.                         if (Memo_Store.Work_Line^.Valu_Line[lCnt] <> ' ') and
  1315.                            (Memo_Store.Work_Line^.Valu_Line[lCnt] <> '-') and
  1316.                            (lCnt > 0) then
  1317.                         begin
  1318.                            inc(lCnt); {Add to line length count}
  1319.                            Memo_Store.Work_Line^.Valu_Line[lcnt] := ' ';
  1320.                                       {Insert a space in storage}
  1321.                            Memo_Store.Work_Line^.Valu_Line[0] := chr(lcnt);
  1322.                         end;
  1323.                      end;
  1324.  
  1325.                $0A : begin            {Linefeed}
  1326.                      end;             {Ignore these characters}
  1327.  
  1328.                $0D : begin            {Hard Return}
  1329.                         With Memo_Store do
  1330.                         begin
  1331.                            Work_Line^.Return_Cod := $0D;
  1332.                            Work_Line := Get_Line_Mem(Edit_Lgth);
  1333.                            inc(Memo_Store.Active_Line);
  1334.                            lCnt := 0;
  1335.                         end;
  1336.                      end;
  1337.                else                   {Here for other characters}
  1338.                begin
  1339.                   inc(lCnt);          {Add to line length count}
  1340.                   Memo_Store.Work_Line^.Valu_Line[lcnt] :=
  1341.                                       chr(Mem_Block[mCnt]);
  1342.                                       {Insert the character in storage}
  1343.                   Memo_Store.Work_Line^.Valu_Line[0] := chr(lcnt);
  1344.                end;
  1345.             end;
  1346.             inc(mCnt);                {Step to next input buffer location}
  1347.  
  1348.             if lCnt > Memo_Store.Edit_Lgth then
  1349.                                       {If lcnt longer than Memo_Width, you}
  1350.                                       {must word wrap to Memo_Width length}
  1351.                                       {or less}
  1352.             begin
  1353.                while (Memo_Store.Work_Line^.Valu_Line[lCnt] <> ' ') and
  1354.                      (Memo_Store.Work_Line^.Valu_Line[lCnt] <> '-') and
  1355.                      (lCnt > 0) do dec(lCnt);
  1356.                                       {Repeat search for space or hyphen until}
  1357.                                       {found or current line exhausted}
  1358.                if (lCnt = 0) then
  1359.                   lcnt := length(Memo_Store.Work_Line^.Valu_Line) - 1;
  1360.                                       {If no break point, truncate line}
  1361.                with Memo_Store do
  1362.                begin
  1363.                   Temp_Line := Work_Line^.Valu_Line;
  1364.                   system.delete(Temp_Line,1,lCnt);
  1365.                   if lCnt > Memo_Store.Edit_Lgth then
  1366.                      lCnt := Memo_Store.Edit_Lgth;
  1367.                   Work_Line^.Valu_Line[0] := chr(lcnt);
  1368.                                       {Get string up to cursor to split line}
  1369.                   Work_Line := Get_Line_Mem(Edit_Lgth);
  1370.                   inc(Memo_Store.Active_Line);
  1371.                   Work_Line^.Return_Cod := $8D;
  1372.                                       {Insert soft return character}
  1373.                   Work_Line^.Valu_Line  := Temp_Line;
  1374.                   lCnt := length(Work_Line^.Valu_Line);
  1375.                end;
  1376.             end;
  1377.          end;
  1378.       END;
  1379.    end;
  1380. END;                        { Get Memo Field }
  1381.  
  1382. Procedure GS_dBFld_Objt.MemoEdit;
  1383. begin
  1384.    Memo_Store.Edit;
  1385. end;
  1386.  
  1387. Function GS_dBFld_Objt.MemoLines : integer;
  1388. begin
  1389.    MemoLines := Memo_Store.Total_Lines;
  1390. end;
  1391.  
  1392. Procedure GS_dBFld_Objt.MemoWidth(l : integer);
  1393. begin
  1394.    Memo_Store.Edit_Lgth := l;
  1395. end;
  1396.  
  1397. Function GS_dBFld_Objt.MemoPut : string;
  1398. const
  1399.    EOFMark : byte = $1A;              {End of disk file code}
  1400. var
  1401.    bCnt,                              {Will hold bytes in memo field}
  1402.    lCnt,                              {Counter for line length in characters}
  1403.    mCnt,
  1404.    tcnt  :  longint;                  {Counter for input buffer char position}
  1405.    Result  : word;                    {BlockWrite number of bytes written}
  1406.    i     : longint;                   {Working variable}
  1407.    Mem_Block : array [0..GS_dBase_MaxMemoRec*2] of byte;
  1408.                                       {Output buffer}
  1409.    valu  : string[10];                {work string to convert block number}
  1410. BEGIN                       { Put Memo Field }
  1411.    bCnt := Memo_Store.Byte_Count;     {Get count of bytes in memo field}
  1412.    bCnt := bcnt div GS_dBase_MaxMemoRec;
  1413.                                       {Get number of blocks required}
  1414.    inc(bCnt);                         {Adjust from zero}
  1415.    if bCnt > Memo_Bloks then
  1416.    begin
  1417.       GS_FileRead(mFile, 0, Mem_Block, 1, Result);
  1418.                                       {read a block from the .DBT}
  1419.       Move(Mem_Block[0],Memo_Loc,4);
  1420.                                       {Get next block number to append}
  1421.    end;
  1422.    Memo_Bloks := bCnt;                {Set blocks written count}
  1423.    lCnt := 0;                         {line length counter}
  1424.    mCnt := 0;                         {Counter into disk write buffer}
  1425.    tCnt := Memo_Loc;
  1426. {
  1427.                     ┌─────────────────────────────────────┐
  1428.                     │  Start reading and processing the   │
  1429.                     │  sequential memo blocks until EOF   │
  1430.                     │  mark is found.                     │
  1431.                     └─────────────────────────────────────┘
  1432. }
  1433.       with Memo_Store do
  1434.       begin
  1435.          Work_Line := First_Line;
  1436.          while (Work_Line <> nil) do
  1437.          begin
  1438.             move(Work_Line^.Valu_Line[1],Mem_Block[mCnt],
  1439.                  length(Work_Line^.Valu_Line));
  1440.             mCnt := mCnt + length(Work_Line^.Valu_Line);
  1441.             if Work_Line^.Next_Line <> nil then
  1442.             begin
  1443.                Mem_Block[mCnt] := Work_Line^.Return_Cod;
  1444.                Mem_Block[mCnt+1] := $0A;
  1445.                inc(mCnt,2);
  1446.             end;
  1447.             Work_Line := Work_Line^.Next_Line;
  1448.             if (mCnt > GS_dBase_MaxMemoRec) then
  1449.             begin
  1450.                GS_FileWrite(mFile,tcnt,Mem_Block,1, Result);
  1451.                                       {read a block from the .DBT}
  1452.                inc(tcnt);
  1453.                mCnt := mCnt mod GS_dBase_MaxMemoRec;
  1454.                                       {Get excess buffer length used}
  1455.                Move(Mem_Block[GS_dBase_MaxMemoRec],Mem_Block[0],mCnt);
  1456.                                       {Move excess to beginning of buffer}
  1457.             end;
  1458.          end;
  1459.          Mem_Block[mCnt] := EOFMark;
  1460.          FillChar(Mem_Block[succ(mcnt)],GS_dBase_MaxMemoRec - mcnt,#0);
  1461.          GS_FileWrite(mFile,tcnt,Mem_Block,1, Result);
  1462.                                       {Write the last block to the .DBT}
  1463.          i := GS_FileSize(mFile);
  1464.          FillChar(Mem_Block,GS_dBase_MaxMemoRec,#0);
  1465.          Move(i,Mem_Block[0],4);
  1466.          GS_FileWrite(mFile,0,Mem_Block,1, Result);
  1467.                                       {Write the block to the .DBT.  It will}
  1468.                                       {point to the next available block};
  1469.    end;
  1470.    Str(Memo_Loc:10,valu);
  1471.    MemoPut := valu;
  1472. end;
  1473.  
  1474. Procedure GS_dBFld_Objt.StatusUpdate(statword1,statword2,statword3 : longint);
  1475. begin
  1476. end;
  1477.  
  1478.  
  1479. end.
  1480.  
  1481.  
  1482.