123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602 |
- unit dbf_parser;
- interface
- {$I dbf_common.inc}
- uses
- SysUtils,
- Classes,
- {$ifdef KYLIX}
- Libc,
- {$endif}
- {$ifndef WINDOWS}
- dbf_wtil,
- {$endif}
- db,
- dbf_prscore,
- dbf_common,
- dbf_fields,
- dbf_prsdef,
- dbf_prssupp;
- type
- TStringFieldMode = (smRaw, smAnsi, smAnsiTrim);
- TDbfParser = class(TCustomExpressionParser)
- private
- FDbfFile: Pointer;
- FFieldVarList: TStringList;
- FIsExpression: Boolean; // expression or simple field?
- FFieldType: TExpressionType;
- FCaseInsensitive: Boolean;
- FStringFieldMode: TStringFieldMode;
- FPartialMatch: boolean;
- protected
- FCurrentExpression: string;
- procedure FillExpressList; override;
- procedure HandleUnknownVariable(VarName: string); override;
- function GetVariableInfo(VarName: string): TDbfFieldDef;
- function CurrentExpression: string; override;
- procedure ValidateExpression(AExpression: string); virtual;
- function GetResultType: TExpressionType; override;
- function GetResultLen: Integer;
- procedure SetCaseInsensitive(NewInsensitive: Boolean);
- procedure SetStringFieldMode(NewMode: TStringFieldMode);
- procedure SetPartialMatch(NewPartialMatch: boolean);
- public
- constructor Create(ADbfFile: Pointer);
- destructor Destroy; override;
- procedure ClearExpressions; override;
- procedure ParseExpression(AExpression: string); virtual;
- function ExtractFromBuffer(Buffer: TRecordBuffer): PChar; virtual;
- property DbfFile: Pointer read FDbfFile write FDbfFile;
- property Expression: string read FCurrentExpression;
- property ResultLen: Integer read GetResultLen;
- property CaseInsensitive: Boolean read FCaseInsensitive write SetCaseInsensitive;
- property StringFieldMode: TStringFieldMode read FStringFieldMode write SetStringFieldMode;
- property PartialMatch: boolean read FPartialMatch write SetPartialMatch;
- end;
- implementation
- uses
- dbf,
- dbf_dbffile,
- dbf_str
- {$ifdef WINDOWS}
- ,Windows
- {$endif}
- ;
- type
- // TFieldVar aids in retrieving field values from records
- // in their proper type
- TFieldVar = class(TObject)
- private
- FFieldDef: TDbfFieldDef;
- FDbfFile: TDbfFile;
- FFieldName: string;
- FExprWord: TExprWord;
- protected
- function GetFieldVal: Pointer; virtual; abstract;
- function GetFieldType: TExpressionType; virtual; abstract;
- procedure SetExprWord(NewExprWord: TExprWord); virtual;
- property ExprWord: TExprWord read FExprWord write SetExprWord;
- public
- constructor Create(UseFieldDef: TDbfFieldDef; ADbfFile: TDbfFile);
- procedure Refresh(Buffer: TRecordBuffer); virtual; abstract;
- property FieldVal: Pointer read GetFieldVal;
- property FieldDef: TDbfFieldDef read FFieldDef;
- property FieldType: TExpressionType read GetFieldType;
- property DbfFile: TDbfFile read FDbfFile;
- property FieldName: string read FFieldName;
- end;
- TStringFieldVar = class(TFieldVar)
- protected
- FFieldVal: PChar;
- FMode: TStringFieldMode;
- function GetFieldVal: Pointer; override;
- function GetFieldType: TExpressionType; override;
- procedure SetExprWord(NewExprWord: TExprWord); override;
- procedure SetMode(NewMode: TStringFieldMode);
- procedure UpdateExprWord;
- public
- destructor Destroy; override;
- procedure Refresh(Buffer: TRecordBuffer); override;
- property Mode: TStringFieldMode read FMode write SetMode;
- end;
- TFloatFieldVar = class(TFieldVar)
- private
- FFieldVal: Double;
- protected
- function GetFieldVal: Pointer; override;
- function GetFieldType: TExpressionType; override;
- public
- procedure Refresh(Buffer: TRecordBuffer); override;
- end;
- TIntegerFieldVar = class(TFieldVar)
- private
- FFieldVal: Integer;
- protected
- function GetFieldVal: Pointer; override;
- function GetFieldType: TExpressionType; override;
- public
- procedure Refresh(Buffer: TRecordBuffer); override;
- end;
- {$ifdef SUPPORT_INT64}
- TLargeIntFieldVar = class(TFieldVar)
- private
- FFieldVal: Int64;
- protected
- function GetFieldVal: Pointer; override;
- function GetFieldType: TExpressionType; override;
- public
- procedure Refresh(Buffer: TRecordBuffer); override;
- end;
- {$endif}
- TDateTimeFieldVar = class(TFieldVar)
- private
- FFieldVal: TDateTimeRec;
- function GetFieldType: TExpressionType; override;
- protected
- function GetFieldVal: Pointer; override;
- public
- procedure Refresh(Buffer: TRecordBuffer); override;
- end;
- TBooleanFieldVar = class(TFieldVar)
- private
- FFieldVal: boolean;
- function GetFieldType: TExpressionType; override;
- protected
- function GetFieldVal: Pointer; override;
- public
- procedure Refresh(Buffer: TRecordBuffer); override;
- end;
- { TFieldVar }
- constructor TFieldVar.Create(UseFieldDef: TDbfFieldDef; ADbfFile: TDbfFile);
- begin
- inherited Create;
- // store field
- FFieldDef := UseFieldDef;
- FDbfFile := ADbfFile;
- FFieldName := UseFieldDef.FieldName;
- end;
- procedure TFieldVar.SetExprWord(NewExprWord: TExprWord);
- begin
- FExprWord := NewExprWord;
- end;
- { TStringFieldVar }
- destructor TStringFieldVar.Destroy;
- begin
- if FMode <> smRaw then
- FreeMem(FFieldVal);
- inherited;
- end;
- function TStringFieldVar.GetFieldVal: Pointer;
- begin
- Result := @FFieldVal;
- end;
- function TStringFieldVar.GetFieldType: TExpressionType;
- begin
- Result := etString;
- end;
- procedure TStringFieldVar.Refresh(Buffer: TRecordBuffer);
- var
- Len: Integer;
- Src: TRecordBuffer;
- begin
- Src := Buffer+FieldDef.Offset;
- if FMode <> smRaw then
- begin
- // copy field data
- Len := FieldDef.Size;
- if FMode = smAnsiTrim then
- while (Len >= 1) and (Src[Len-1] = TRecordbufferbasetype(' ')) do Dec(Len);
- // translate to ANSI
- Len := TranslateString(DbfFile.UseCodePage, GetACP, pansichar(Src), FFieldVal, Len);
- FFieldVal[Len] := #0;
- end else
- FFieldVal := pansichar(Src);
- end;
- procedure TStringFieldVar.SetExprWord(NewExprWord: TExprWord);
- begin
- inherited;
- UpdateExprWord;
- end;
- procedure TStringFieldVar.UpdateExprWord;
- begin
- if FMode <> smAnsiTrim then
- FExprWord.FixedLen := FieldDef.Size
- else
- FExprWord.FixedLen := -1;
- end;
- procedure TStringFieldVar.SetMode(NewMode: TStringFieldMode);
- begin
- if NewMode = FMode then exit;
- FMode := NewMode;
- if NewMode = smRaw then
- begin
- FreeMem(FFieldVal);
- FFieldVal := nil;
- end else
- GetMem(FFieldVal, FieldDef.Size*3+1);
- UpdateExprWord;
- end;
- //--TFloatFieldVar-----------------------------------------------------------
- function TFloatFieldVar.GetFieldVal: Pointer;
- begin
- Result := @FFieldVal;
- end;
- function TFloatFieldVar.GetFieldType: TExpressionType;
- begin
- Result := etFloat;
- end;
- procedure TFloatFieldVar.Refresh(Buffer: TRecordBuffer);
- begin
- // database width is default 64-bit double
- if not FDbfFile.GetFieldDataFromDef(FieldDef, FieldDef.FieldType, Buffer, @FFieldVal, false) then
- FFieldVal := 0.0;
- end;
- //--TIntegerFieldVar----------------------------------------------------------
- function TIntegerFieldVar.GetFieldVal: Pointer;
- begin
- Result := @FFieldVal;
- end;
- function TIntegerFieldVar.GetFieldType: TExpressionType;
- begin
- Result := etInteger;
- end;
- procedure TIntegerFieldVar.Refresh(Buffer: TRecordBuffer);
- begin
- FFieldVal := 0;
- FDbfFile.GetFieldDataFromDef(FieldDef, FieldDef.FieldType, Buffer, @FFieldVal, false);
- end;
- {$ifdef SUPPORT_INT64}
- //--TLargeIntFieldVar----------------------------------------------------------
- function TLargeIntFieldVar.GetFieldVal: Pointer;
- begin
- Result := @FFieldVal;
- end;
- function TLargeIntFieldVar.GetFieldType: TExpressionType;
- begin
- Result := etLargeInt;
- end;
- procedure TLargeIntFieldVar.Refresh(Buffer: TRecordBuffer);
- begin
- if not FDbfFile.GetFieldDataFromDef(FieldDef, FieldDef.FieldType, Buffer, @FFieldVal, false) then
- FFieldVal := 0;
- end;
- {$endif}
- //--TDateTimeFieldVar---------------------------------------------------------
- function TDateTimeFieldVar.GetFieldVal: Pointer;
- begin
- Result := @FFieldVal;
- end;
- function TDateTimeFieldVar.GetFieldType: TExpressionType;
- begin
- Result := etDateTime;
- end;
- procedure TDateTimeFieldVar.Refresh(Buffer: TRecordBuffer);
- begin
- if not FDbfFile.GetFieldDataFromDef(FieldDef, ftDateTime, Buffer, @FFieldVal, false) then
- FFieldVal.DateTime := 0.0;
- end;
- //--TBooleanFieldVar---------------------------------------------------------
- function TBooleanFieldVar.GetFieldVal: Pointer;
- begin
- Result := @FFieldVal;
- end;
- function TBooleanFieldVar.GetFieldType: TExpressionType;
- begin
- Result := etBoolean;
- end;
- procedure TBooleanFieldVar.Refresh(Buffer: TRecordBuffer);
- var
- lFieldVal: word;
- begin
- if FDbfFile.GetFieldDataFromDef(FieldDef, ftBoolean, Buffer, @lFieldVal, false) then
- FFieldVal := lFieldVal <> 0
- else
- FFieldVal := false;
- end;
- //--TDbfParser---------------------------------------------------------------
- constructor TDbfParser.Create(ADbfFile: Pointer);
- begin
- FDbfFile := ADbfFile;
- FFieldVarList := TStringList.Create;
- FCaseInsensitive := true;
- inherited Create;
- end;
- destructor TDbfParser.Destroy;
- begin
- ClearExpressions;
- inherited;
- FreeAndNil(FFieldVarList);
- end;
- function TDbfParser.GetResultType: TExpressionType;
- begin
- // if not a real expression, return type ourself
- if FIsExpression then
- Result := inherited GetResultType
- else
- Result := FFieldType;
- end;
- function TDbfParser.GetResultLen: Integer;
- begin
- // set result len for fixed length expressions / fields
- case ResultType of
- etBoolean: Result := 1;
- etInteger: Result := 4;
- etFloat: Result := 8;
- etDateTime: Result := 8;
- etString:
- begin
- if not FIsExpression and (TStringFieldVar(FFieldVarList.Objects[0]).Mode <> smAnsiTrim) then
- Result := TStringFieldVar(FFieldVarList.Objects[0]).FieldDef.Size
- else
- Result := -1;
- end;
- else
- Result := -1;
- end;
- end;
- procedure TDbfParser.SetCaseInsensitive(NewInsensitive: Boolean);
- begin
- if FCaseInsensitive <> NewInsensitive then
- begin
- // clear and regenerate functions
- FCaseInsensitive := NewInsensitive;
- FillExpressList;
- end;
- end;
- procedure TDbfParser.SetPartialMatch(NewPartialMatch: boolean);
- begin
- if FPartialMatch <> NewPartialMatch then
- begin
- // refill function list
- FPartialMatch := NewPartialMatch;
- FillExpressList;
- end;
- end;
- procedure TDbfParser.SetStringFieldMode(NewMode: TStringFieldMode);
- var
- I: integer;
- begin
- if FStringFieldMode <> NewMode then
- begin
- // clear and regenerate functions, custom fields will be deleted too
- FStringFieldMode := NewMode;
- for I := 0 to FFieldVarList.Count - 1 do
- if FFieldVarList.Objects[I] is TStringFieldVar then
- TStringFieldVar(FFieldVarList.Objects[I]).Mode := NewMode;
- end;
- end;
- procedure TDbfParser.FillExpressList;
- var
- lExpression: string;
- begin
- lExpression := FCurrentExpression;
- ClearExpressions;
- FWordsList.FreeAll;
- FWordsList.AddList(DbfWordsGeneralList, 0, DbfWordsGeneralList.Count - 1);
- if FCaseInsensitive then
- begin
- FWordsList.AddList(DbfWordsInsensGeneralList, 0, DbfWordsInsensGeneralList.Count - 1);
- if FPartialMatch then
- begin
- FWordsList.AddList(DbfWordsInsensPartialList, 0, DbfWordsInsensPartialList.Count - 1);
- end else begin
- FWordsList.AddList(DbfWordsInsensNoPartialList, 0, DbfWordsInsensNoPartialList.Count - 1);
- end;
- end else begin
- FWordsList.AddList(DbfWordsSensGeneralList, 0, DbfWordsSensGeneralList.Count - 1);
- if FPartialMatch then
- begin
- FWordsList.AddList(DbfWordsSensPartialList, 0, DbfWordsSensPartialList.Count - 1);
- end else begin
- FWordsList.AddList(DbfWordsSensNoPartialList, 0, DbfWordsSensNoPartialList.Count - 1);
- end;
- end;
- if Length(lExpression) > 0 then
- ParseExpression(lExpression);
- end;
- function TDbfParser.GetVariableInfo(VarName: string): TDbfFieldDef;
- begin
- Result := TDbfFile(FDbfFile).GetFieldInfo(VarName);
- end;
- procedure TDbfParser.HandleUnknownVariable(VarName: string);
- var
- FieldInfo: TDbfFieldDef;
- TempFieldVar: TFieldVar;
- begin
- // is this variable a fieldname?
- FieldInfo := GetVariableInfo(VarName);
- if FieldInfo = nil then
- raise EDbfError.CreateFmt(STRING_INDEX_BASED_ON_UNKNOWN_FIELD, [VarName]);
- // define field in parser
- case FieldInfo.FieldType of
- ftString:
- begin
- TempFieldVar := TStringFieldVar.Create(FieldInfo, TDbfFile(FDbfFile));
- TempFieldVar.ExprWord := DefineStringVariable(VarName, TempFieldVar.FieldVal);
- TStringFieldVar(TempFieldVar).Mode := FStringFieldMode;
- end;
- ftBoolean:
- begin
- TempFieldVar := TBooleanFieldVar.Create(FieldInfo, TDbfFile(FDbfFile));
- TempFieldVar.ExprWord := DefineBooleanVariable(VarName, TempFieldVar.FieldVal);
- end;
- ftFloat:
- begin
- TempFieldVar := TFloatFieldVar.Create(FieldInfo, TDbfFile(FDbfFile));
- TempFieldVar.ExprWord := DefineFloatVariable(VarName, TempFieldVar.FieldVal);
- end;
- ftAutoInc, ftInteger, ftSmallInt:
- begin
- TempFieldVar := TIntegerFieldVar.Create(FieldInfo, TDbfFile(FDbfFile));
- TempFieldVar.ExprWord := DefineIntegerVariable(VarName, TempFieldVar.FieldVal);
- end;
- {$ifdef SUPPORT_INT64}
- ftLargeInt:
- begin
- TempFieldVar := TLargeIntFieldVar.Create(FieldInfo, TDbfFile(FDbfFile));
- TempFieldVar.ExprWord := DefineLargeIntVariable(VarName, TempFieldVar.FieldVal);
- end;
- {$endif}
- ftDate, ftDateTime:
- begin
- TempFieldVar := TDateTimeFieldVar.Create(FieldInfo, TDbfFile(FDbfFile));
- TempFieldVar.ExprWord := DefineDateTimeVariable(VarName, TempFieldVar.FieldVal);
- end;
- else
- raise EDbfError.CreateFmt(STRING_INDEX_BASED_ON_INVALID_FIELD, [VarName]);
- end;
- // add to our own list
- FFieldVarList.AddObject(VarName, TempFieldVar);
- end;
- function TDbfParser.CurrentExpression: string;
- begin
- Result := FCurrentExpression;
- end;
- procedure TDbfParser.ClearExpressions;
- var
- I: Integer;
- begin
- inherited;
- // test if already freed
- if FFieldVarList <> nil then
- begin
- // free field list
- for I := 0 to FFieldVarList.Count - 1 do
- begin
- // replacing with nil = undefining variable
- FWordsList.DoFree(TFieldVar(FFieldVarList.Objects[I]).FExprWord);
- TFieldVar(FFieldVarList.Objects[I]).Free;
- end;
- FFieldVarList.Clear;
- end;
- // clear expression
- FCurrentExpression := EmptyStr;
- end;
- procedure TDbfParser.ValidateExpression(AExpression: string);
- begin
- end;
- procedure TDbfParser.ParseExpression(AExpression: string);
- begin
- // clear any current expression
- ClearExpressions;
- // is this a simple field or complex expression?
- FIsExpression := GetVariableInfo(AExpression) = nil;
- if FIsExpression then
- begin
- // parse requested
- CompileExpression(AExpression);
- end else begin
- // simple field, create field variable for it
- HandleUnknownVariable(AExpression);
- FFieldType := TFieldVar(FFieldVarList.Objects[0]).FieldType;
- end;
- ValidateExpression(AExpression);
- // if no errors, assign current expression
- FCurrentExpression := AExpression;
- end;
- function TDbfParser.ExtractFromBuffer(Buffer: TRecordBuffer): PChar;
- var
- I: Integer;
- begin
- // prepare all field variables
- for I := 0 to FFieldVarList.Count - 1 do
- TFieldVar(FFieldVarList.Objects[I]).Refresh(Buffer);
- // complex expression?
- if FIsExpression then
- begin
- // execute expression
- EvaluateCurrent;
- Result := ExpResult;
- end else begin
- // simple field, get field result
- Result := TFieldVar(FFieldVarList.Objects[0]).FieldVal;
- // if string then dereference
- if FFieldType = etString then
- Result := PPChar(Result)^;
- end;
- end;
- end.
|