summaryrefslogtreecommitdiff
path: root/extras/contributed/ats/ats_main.pas
diff options
context:
space:
mode:
Diffstat (limited to 'extras/contributed/ats/ats_main.pas')
-rw-r--r--extras/contributed/ats/ats_main.pas643
1 files changed, 643 insertions, 0 deletions
diff --git a/extras/contributed/ats/ats_main.pas b/extras/contributed/ats/ats_main.pas
new file mode 100644
index 00000000..e8efb251
--- /dev/null
+++ b/extras/contributed/ats/ats_main.pas
@@ -0,0 +1,643 @@
+unit ats_main;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils;
+
+type
+ TatsFormat = (atsPureText, atsPascalSource, atsCSV);
+
+ TatsTextItem = record
+ LangId : string;
+ Text : string;
+ end;
+
+ { TatsTextRow }
+
+ TatsTextRow = class
+ protected
+ FTextId : string;
+ FTexts : array of TatsTextItem;
+ public
+ constructor Create(const atextid : string);
+ destructor Destroy; override;
+
+ procedure SetText(const alangid, atext : string);
+ procedure DeleteText(const alangid : string);
+
+ function GetText(const alangid : string; var afound : boolean) : string;
+
+ property TextId : string read FTextId;
+ end;
+
+ { TatsTextTable }
+
+ TatsTextTable = class
+ private
+ FLangIds : TStringList;
+
+ FTable : TStringList;
+
+ FCurrentLangId : string;
+
+ protected
+ function FindRow(const atextid : string) : TatsTextRow;
+
+ function AddRow(const atextid : string) : TatsTextRow;
+
+ public
+ constructor Create;
+ destructor Destroy; override;
+
+ procedure Clear;
+
+ procedure AddLang(const alangid : string);
+
+ procedure SetText(const atextid, alangid, atext : string);
+ function GetText(const atextid, alangid : string; var found : boolean) : string; overload;
+ function GetText(const atextid : string) : string; overload;
+
+ // later this can prepare a fast search table too:
+ procedure SelectLang(const alangid : string);
+
+ //procedure SetFallbackOrder(const alangids : string);
+
+ property CurrentLang : string read FCurrentLangId;
+
+ public
+
+ function LoadFromFile(const afilename : string) : boolean;
+
+ function LoadFromPascalFile(const afilename : string) : boolean;
+
+ function LoadFromArray(const aarr : array of string) : boolean;
+
+ procedure LoadPureText(const fdata : string);
+
+ procedure SaveToFile(const afilename : string; aformat : TatsFormat);
+
+ // utility functions
+ function RowCount : integer;
+ function GetRow(arow : integer) : TatsTextRow;
+
+ property LangList : TStringList read FLangIds;
+ end;
+
+var
+ atsTexts : TatsTextTable;
+
+function atsGetText(const atextid : string) : string;
+function atsText(const atextid : string) : string;
+
+implementation
+
+uses
+ ptrparsefunc;
+
+function atsGetText(const atextid : string) : string;
+begin
+ result := atsTexts.GetText(atextid);
+end;
+
+function atsText(const atextid : string) : string;
+begin
+ result := atsTexts.GetText(atextid);
+end;
+
+{ TatsTextRow }
+
+constructor TatsTextRow.Create(const atextid : string);
+begin
+ FTextId := atextid;
+ SetLength(FTexts,0);
+end;
+
+destructor TatsTextRow.Destroy;
+var
+ n : integer;
+begin
+ // good to be sure about freeing ansi string
+ for n := 0 to length(FTexts)-1 do
+ begin
+ FTexts[n].LangId := '';
+ FTexts[n].Text := '';
+ end;
+ SetLength(FTexts,0);
+end;
+
+procedure TatsTextRow.SetText(const alangid, atext: string);
+var
+ n : integer;
+begin
+ // search for an existing
+ for n := 0 to length(FTexts)-1 do
+ begin
+ if FTexts[n].LangId = alangid then
+ begin
+ FTexts[n].Text := atext;
+ Exit; //==>
+ end;
+ end;
+ // add as new
+ n := length(FTexts);
+ SetLength(FTexts,n+1);
+ FTexts[n].LangId := alangid;
+ FTexts[n].Text := atext;
+end;
+
+procedure TatsTextRow.DeleteText(const alangid: string);
+var
+ n : integer;
+begin
+ // search for an existing
+ n := 0;
+ while (n < length(FTexts)) and (FTexts[n].LangId <> alangid) do
+ begin
+ inc(n);
+ end;
+
+ // for ansi string safety
+ if n < length(FTexts) then
+ begin
+ FTexts[n].LangId := '';
+ FTexts[n].Text := '';
+ inc(n);
+ end;
+
+ while (n < length(FTexts)) do
+ begin
+ FTexts[n-1] := FTexts[n];
+ inc(n);
+ end;
+
+ SetLength(FTexts,length(FTexts)-1);
+end;
+
+function TatsTextRow.GetText(const alangid: string; var afound : boolean) : string;
+var
+ n : integer;
+begin
+ // search for an existing
+ for n := 0 to length(FTexts)-1 do
+ begin
+ if FTexts[n].LangId = alangid then
+ begin
+ result := FTexts[n].Text;
+ afound := true;
+ Exit; //==>
+ end;
+ end;
+ result := '';
+ afound := false;
+end;
+
+{ TatsTextTable }
+
+function TatsTextTable.FindRow(const atextid: string) : TatsTextRow;
+var
+ i : integer;
+begin
+ i := FTable.IndexOf(atextid);
+
+ if i >= 0 then result := TatsTextRow(FTable.Objects[i])
+ else result := nil;
+end;
+
+function TatsTextTable.AddRow(const atextid: string) : TatsTextRow;
+begin
+ result := FindRow(atextid);
+ if result = nil then
+ begin
+ result := TatsTextRow.Create(atextid);
+ FTable.AddObject(atextid, result);
+ end;
+end;
+
+constructor TatsTextTable.Create;
+begin
+ FTable := TStringList.Create;
+ FLangIds := TStringList.Create;
+ FCurrentLangId := '';
+end;
+
+destructor TatsTextTable.Destroy;
+begin
+ Clear;
+ FTable.Free;
+ FLangIds.Free;
+end;
+
+procedure TatsTextTable.Clear;
+var
+ n : integer;
+begin
+ for n := 0 to FTable.Count - 1 do
+ begin
+ TatsTextRow(FTable.Objects[n]).Free;
+ end;
+ FTable.Clear;
+ FLangIds.Clear;
+end;
+
+procedure TatsTextTable.AddLang(const alangid: string);
+var
+ i : integer;
+begin
+ i := FLangIds.IndexOf(alangid);
+ if i < 0 then FLangIds.Add(alangid);
+ if FCurrentLangId = '' then FCurrentLangId := alangid;
+end;
+
+procedure TatsTextTable.SetText(const atextid, alangid, atext: string);
+var
+ tr : TatsTextRow;
+begin
+ AddLang(alangid);
+ tr := AddRow(atextid);
+ tr.SetText(alangid, atext);
+end;
+
+function TatsTextTable.GetText(const atextid, alangid: string; var found: boolean): string;
+var
+ tr : TatsTextRow;
+begin
+ tr := FindRow(atextid);
+ if tr <> nil then result := tr.GetText(alangid, found)
+ else
+ begin
+ result := '';
+ found := false;
+ end;
+end;
+
+function TatsTextTable.GetText(const atextid: string): string;
+var
+ found : boolean;
+begin
+ result := GetText(atextid, FCurrentLangId, found);
+ if not found then
+ begin
+ // some fallback mechanism
+ result := '#'+atextid+'@'+FCurrentLangId;
+ end;
+end;
+
+procedure TatsTextTable.SelectLang(const alangid: string);
+var
+ i : integer;
+begin
+ i := FLangIds.indexof(alangid);
+ if i >= 0 then
+ begin
+ FCurrentLangId := alangid;
+ end;
+end;
+
+function GetFileContent(const afilename : string) : string;
+var
+ f : file;
+ toread, rcnt, brres : integer;
+begin
+ try
+ AssignFile(f,afilename);
+ Reset(f,1);
+
+ toread := FileSize(f);
+ rcnt := 0;
+
+ SetLength(result, toread);
+
+ repeat
+ BlockRead(f, result[1+rcnt], toread, brres);
+
+ if brres > 0 then
+ begin
+ inc(rcnt,brres);
+ dec(toread,brres);
+ end;
+ until toread <= 0;
+
+ finally
+ CloseFile(f);
+ end;
+end;
+
+procedure PutFileContent(const afilename : string; const adata : string);
+var
+ f : file;
+ towrite, wcnt, wrres : integer;
+begin
+ try
+ AssignFile(f,afilename);
+ Rewrite(f,1);
+
+ towrite := length(adata);
+ wcnt := 0;
+
+ repeat
+ BlockWrite(f, adata[1+wcnt], towrite, wrres);
+
+ if wrres > 0 then
+ begin
+ inc(wcnt,wrres);
+ dec(towrite,wrres);
+ end;
+ until towrite <= 0;
+
+ finally
+ CloseFile(f);
+ end;
+end;
+
+
+function TatsTextTable.LoadFromFile(const afilename: string): boolean;
+var
+ fdata : string;
+begin
+ fdata := GetFileContent(afilename);
+ //writeln('File content:');
+ //writeln(fdata);
+ LoadPureText(fdata);
+
+ result := true;
+end;
+
+function TatsTextTable.LoadFromPascalFile(const afilename : string) : boolean;
+var
+ fdata, data : string;
+ rp,sp,ep : PChar; // read ptr, start ptr, end ptr
+ len : integer;
+ tid, lid, txt : string;
+ inquote : boolean;
+begin
+ result := false;
+
+ fdata := GetFileContent(afilename);
+
+ if fdata = '' then Exit;
+
+ sp := @fdata[1];
+ ep := sp + length(fdata);
+
+ rp := sp;
+
+ // skipping UTF8 marker first
+ ppCheckSymbol(rp, ep, #$EF#$BB#$BF);
+
+ ppSkipSpaces(rp, ep);
+
+ if not ppCheckSymbolCI(rp, ep, 'array') then EXIT;
+
+ ppSkipSpaces(rp, ep);
+ if not ppCheckSymbol(rp, ep, '[') then EXIT;
+
+ if not ppSearchPattern(rp, ep, ']', len) then EXIT;
+
+ ppSkipSpaces(rp, ep);
+ if not ppCheckSymbolCI(rp, ep, 'of') then EXIT;
+ ppSkipSpaces(rp, ep);
+ if not ppCheckSymbolCI(rp, ep, 'string') then EXIT;
+ ppSkipSpaces(rp, ep);
+ if not ppCheckSymbol(rp, ep, '=') then EXIT;
+ ppSkipSpaces(rp, ep);
+ if not ppCheckSymbol(rp, ep, '(') then EXIT;
+
+ ppSkipSpaces(rp, ep);
+
+ data := '';
+
+ inquote := false;
+
+ while rp < ep do
+ begin
+ if not inquote then
+ begin
+ ppSkipSpaces(rp, ep);
+ if ppCheckSymbol(rp, ep, '''') then
+ begin
+ inquote := true;
+ sp := rp;
+ end
+ else if ppCheckSymbol(rp, ep, ',') then
+ begin
+ // just skip ip
+ ppSkipSpaces(rp, ep);
+ end
+ else if ppCheckSymbol(rp, ep, ')') then
+ begin
+ // closing char
+ break;
+ end
+ else
+ begin
+ // invalid char
+ break;
+ end;
+ end;
+
+ if inquote then
+ begin
+ if ppReadTo(rp, ep, '''', len) then
+ begin
+ // closing quote or double quote
+ if len > 0 then data := data + ppMakeString(sp, len);
+ inc(rp);
+ if (rp < ep) and (rp^ = '''') then
+ begin
+ data := data + '''';
+ inc(rp);
+ sp := rp;
+ end
+ else
+ begin
+ data := data + #10;
+ inquote := false;
+ end;
+ end;
+ end;
+ end; // while
+
+ //writeln('Pure content:');
+ //writeln(data);
+
+ LoadPureText(data);
+
+ result := true;
+end;
+
+function TatsTextTable.LoadFromArray(const aarr: array of string): boolean;
+var
+ fdata : string;
+ n : integer;
+begin
+ fdata := '';
+ for n := low(aarr) to high(aarr) do
+ begin
+ fdata := fdata + aarr[n] + #10;
+ end;
+ LoadPureText(fdata);
+end;
+
+procedure TatsTextTable.LoadPureText(const fdata: string);
+var
+ rp,sp,ep : PChar; // read ptr, start ptr, end ptr
+ len : integer;
+ tid, lid, txt : string;
+begin
+ if fdata = '' then Exit;
+
+ sp := @fdata[1];
+ ep := sp + length(fdata);
+
+ rp := sp;
+
+ // skipping UTF8 marker first
+ ppCheckSymbol(rp, ep, #$EF#$BB#$BF);
+
+ ppSkipSpaces(rp, ep);
+
+ tid := '???';
+
+ while rp < ep do
+ begin
+ sp := rp;
+ // reading identifier (txt or lang)
+ if ppReadTo(rp, ep, '=:', len) then
+ begin
+ if rp^ = ':' then
+ begin
+ // text id is this
+ tid := trim(ppMakeString(sp, len));
+ inc(rp); // skip ':'
+ end
+ else if rp^ = '=' then
+ begin
+ // lang id is this
+ lid := trim(ppMakeString(sp,len));
+ inc(rp); // skip '='
+
+ ppSkipSpaces(rp, ep);
+
+ if not ppCheckSymbol(rp,ep,'"') then
+ begin
+ // starting quote is missing
+ end;
+
+ txt := '';
+ sp := rp;
+ if ppReadTo(rp, ep, '"', len) then
+ begin
+ txt := ppMakeString(sp,len);
+ inc(rp);
+ end
+ else
+ begin
+ // end quote is missing
+ end;
+
+ if txt <> '' then
+ begin
+ atsTexts.SetText(tid, lid, txt);
+ end;
+ end;
+
+ ppSkipSpaces(rp, ep);
+ end; // reading identifier
+ end;
+end;
+
+procedure TatsTextTable.SaveToFile(const afilename: string; aformat: TatsFormat);
+var
+ sl : TStringList;
+ tr : TatsTextRow;
+ n,i : integer;
+ s : string;
+ b : boolean;
+ fdata : string;
+begin
+ sl := TStringList.Create;
+
+ for n:=0 to FTable.Count-1 do
+ begin
+ tr := TatsTextRow(FTable.Objects[n]);
+ if aformat = atsCSV then
+ begin
+ s := '"'+tr.TextId+'"';
+ for i := 0 to FLangIds.Count-1 do
+ begin
+ s := s + ',"' + tr.GetText(FLangIds[i],b) + '"';
+ end;
+ sl.Add(s);
+ end
+ else
+ begin
+ sl.Add(tr.TextID+':');
+ for i := 0 to FLangIds.Count-1 do
+ begin
+ s := tr.GetText(FLangIds[i],b);
+ if b then sl.Add(' '+FLangIds[i]+'="'+s+'"');
+ end;
+ end;
+ end;
+
+ // assembly the final buffer
+
+ if aformat = atsCSV then
+ begin
+ fdata := '"ATSF1"';
+ for i := 0 to FLangIds.Count-1 do
+ begin
+ fdata := fdata + ',"' + FLangIds[i] + '"';
+ end;
+ for n := 0 to sl.Count-1 do
+ begin
+ fdata := fdata + #13#10 + sl[n];
+ end;
+ end
+ else if aformat = atsPascalSource then
+ begin
+ fdata := 'array[1..'+IntToStr(sl.Count)+'] of string = ('+#13#10;
+ s := ' ';
+ for n := 0 to sl.Count-1 do
+ begin
+ fdata := fdata + ' ' + s + QuotedStr(sl[n]) + #13#10;
+ s := ',';
+ end;
+ fdata := fdata + #13#10 + ');' + #13#10;
+ end
+ else
+ begin
+ // pure text...
+ fdata := ''; // no header
+ for n := 0 to sl.Count-1 do
+ begin
+ fdata := fdata + sl[n] + #13#10;
+ end;
+ end;
+
+ sl.Free;
+
+ PutFileContent(afilename, fdata);
+end;
+
+function TatsTextTable.RowCount: integer;
+begin
+ result := FTable.Count;
+end;
+
+function TatsTextTable.GetRow(arow: integer): TatsTextRow;
+begin
+ result := TatsTextRow(FTable.Objects[arow]);
+end;
+
+
+initialization
+begin
+ atsTexts := TatsTextTable.Create;
+end;
+
+end.
+