Browse Source

* Added jsonconf

git-svn-id: trunk@8573 -
michael 18 years ago
parent
commit
3a0c9a638a

+ 4 - 0
.gitattributes

@@ -4269,10 +4269,14 @@ packages/fcl-json/demo/parsedemo.pp svneol=native#text/plain
 packages/fcl-json/demo/simpledemo.lpi svneol=native#text/plain
 packages/fcl-json/demo/simpledemo.pp svneol=native#text/plain
 packages/fcl-json/src/fpjson.pp svneol=native#text/plain
+packages/fcl-json/src/jsonconf.pp svneol=native#text/plain
 packages/fcl-json/src/jsonparser.pp svneol=native#text/plain
 packages/fcl-json/src/jsonscanner.pp svneol=native#text/plain
+packages/fcl-json/tests/jsonconftest.pp svneol=native#text/plain
 packages/fcl-json/tests/testjson.lpi svneol=native#text/plain
 packages/fcl-json/tests/testjson.pp svneol=native#text/plain
+packages/fcl-json/tests/testjsonconf.lpi svneol=native#text/plain
+packages/fcl-json/tests/testjsonconf.pp svneol=native#text/plain
 packages/fcl-json/tests/testjsondata.pp svneol=native#text/plain
 packages/fcl-json/tests/testjsonparser.pp svneol=native#text/plain
 packages/fcl-net/Makefile svneol=native#text/plain

+ 105 - 104
packages/fcl-json/Makefile

@@ -233,316 +233,316 @@ PACKAGESDIR:=$(wildcard $(FPCDIR) $(FPCDIR)/packages $(FPCDIR)/packages/base $(F
 override PACKAGE_NAME=fcl-json
 override PACKAGE_VERSION=2.2.0
 ifeq ($(FULL_TARGET),i386-linux)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-go32v2)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-win32)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-os2)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-freebsd)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-beos)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-netbsd)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-solaris)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-qnx)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-netware)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-openbsd)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-wdosx)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-darwin)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-emx)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-watcom)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-netwlibc)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-wince)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-embedded)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-symbian)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),m68k-linux)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),m68k-freebsd)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),m68k-netbsd)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),m68k-amiga)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),m68k-atari)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),m68k-openbsd)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),m68k-palmos)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),m68k-embedded)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc-linux)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc-netbsd)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc-amiga)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc-macos)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc-darwin)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc-morphos)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc-embedded)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),sparc-linux)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),sparc-netbsd)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),sparc-solaris)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),sparc-embedded)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),x86_64-linux)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),x86_64-freebsd)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),x86_64-win64)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),x86_64-embedded)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),arm-linux)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),arm-palmos)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),arm-wince)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),arm-gba)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),arm-nds)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),arm-embedded)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),arm-symbian)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc64-linux)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc64-darwin)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc64-embedded)
-override TARGET_UNITS+=fpjson jsonscanner jsonparser
+override TARGET_UNITS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-linux)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-go32v2)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-win32)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-os2)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-freebsd)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-beos)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-netbsd)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-solaris)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-qnx)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-netware)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-openbsd)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-wdosx)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-darwin)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-emx)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-watcom)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-netwlibc)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-wince)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-embedded)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),i386-symbian)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),m68k-linux)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),m68k-freebsd)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),m68k-netbsd)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),m68k-amiga)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),m68k-atari)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),m68k-openbsd)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),m68k-palmos)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),m68k-embedded)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc-linux)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc-netbsd)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc-amiga)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc-macos)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc-darwin)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc-morphos)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc-embedded)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),sparc-linux)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),sparc-netbsd)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),sparc-solaris)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),sparc-embedded)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),x86_64-linux)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),x86_64-freebsd)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),x86_64-win64)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),x86_64-embedded)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),arm-linux)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),arm-palmos)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),arm-wince)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),arm-gba)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),arm-nds)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),arm-embedded)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),arm-symbian)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc64-linux)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc64-darwin)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 ifeq ($(FULL_TARGET),powerpc64-embedded)
-override TARGET_RSTS+=fpjson jsonscanner jsonparser
+override TARGET_RSTS+=fpjson jsonscanner jsonparser jsonconf
 endif
 override INSTALL_FPCPACKAGE=y
 ifeq ($(FULL_TARGET),i386-linux)
@@ -2781,3 +2781,4 @@ include fpcmake.loc
 endif
 .NOTPARALLEL:
 jsonparser$(PPUEXT): jsonparser.pp fpjson$(PPUEXT) jsonscanner$(PPUEXT)
+jsonconf$(PPUEXT): jsonparser$(PPUEXT) fpjson$(PPUEXT)

+ 4 - 2
packages/fcl-json/Makefile.fpc

@@ -7,8 +7,8 @@ name=fcl-json
 version=2.2.0
 
 [target]
-units=fpjson jsonscanner jsonparser
-rsts=fpjson jsonscanner jsonparser
+units=fpjson jsonscanner jsonparser jsonconf
+rsts=fpjson jsonscanner jsonparser jsonconf
 
 [require]
 packages=fcl-base
@@ -27,3 +27,5 @@ fpcdir=../..
 .NOTPARALLEL:
 
 jsonparser$(PPUEXT): jsonparser.pp fpjson$(PPUEXT) jsonscanner$(PPUEXT)
+
+jsonconf$(PPUEXT): jsonparser$(PPUEXT) fpjson$(PPUEXT)

+ 51 - 1
packages/fcl-json/src/fpjson.pp

@@ -50,7 +50,9 @@ type
     procedure SetItem(Index : Integer; const AValue: TJSONData); virtual;
     function GetCount: Integer; virtual;
   public
+    Constructor Create; virtual;
     Class function JSONType: TJSONType; virtual;
+    Procedure Clear;  virtual; Abstract;
     property Count: Integer read GetCount;
     property Items[Index: Integer]: TJSONData read GetItem write SetItem;
     property Value: variant read GetValue write SetValue;
@@ -62,6 +64,7 @@ type
     Property AsJSON : String Read GetAsJSON;
   end;
 
+  TJSONDataClass = Class of TJSONData;
   TJSONNumberType = (ntFloat,ntInteger);
 
   TJSONNumber = class(TJSONData)
@@ -91,6 +94,7 @@ type
   public
     Constructor Create(AValue : TJSONFloat);
     class function NumberType : TJSONNumberType; override;
+    Procedure Clear;  override;
   end;
   
   { TJSONIntegerNumber }
@@ -113,6 +117,7 @@ type
   public
     Constructor Create(AValue : Integer);
     class function NumberType : TJSONNumberType; override;
+    Procedure Clear;  override;
   end;
 
   { TJSONString }
@@ -135,6 +140,7 @@ type
   public
     Constructor Create(AValue : TJSONStringType);
     class function JSONType: TJSONType; override;
+    Procedure Clear;  override;
   end;
 
   { TJSONboolean }
@@ -157,6 +163,7 @@ type
   public
     Constructor Create(AValue : Boolean);
     class function JSONType: TJSONType; override;
+    Procedure Clear;  override;
   end;
 
   { TJSONnull }
@@ -178,6 +185,7 @@ type
     procedure SetValue(const AValue: variant); override;
   public
     class function JSONType: TJSONType; override;
+    Procedure Clear;  override;
   end;
 
   TJSONArrayIterator = procedure(Item: TJSONData; Data: TObject; var Continue: Boolean) of object;
@@ -227,6 +235,7 @@ type
     procedure Iterate(Iterator : TJSONArrayIterator; Data: TObject);
     function IndexOf(obj: TJSONData): Integer;
     // Manipulate
+    Procedure Clear;  override;
     function Add(Item : TJSONData): Integer;
     function Add(I : Integer): Integer;
     function Add(S : String): Integer;
@@ -300,6 +309,7 @@ type
     function IndexOf(Item: TJSONData): Integer;
     Function IndexOfName(const AName: TJSONStringType): Integer;
     // Manipulate
+    Procedure Clear;  override;
     function Add(const AName: TJSONStringType; AValue: TJSONData): Integer; overload;
     function Add(const AName: TJSONStringType; AValue: Boolean): Integer; overload;
     function Add(const AName: TJSONStringType; AValue: TJSONFloat): Integer; overload;
@@ -448,6 +458,11 @@ begin
   Result:=0;
 end;
 
+constructor TJSONData.Create;
+begin
+  Clear;
+end;
+
 function TJSONData.GetIsNull: Boolean;
 begin
   Result:=False;
@@ -479,6 +494,11 @@ begin
   Result:=jtString;
 end;
 
+procedure TJSONString.Clear;
+begin
+  FValue:='';
+end;
+
 function TJSONstring.GetValue: Variant;
 begin
   Result:=FValue;
@@ -560,6 +580,11 @@ begin
   Result:=jtBoolean;
 end;
 
+procedure TJSONBoolean.Clear;
+begin
+  FValue:=False;
+end;
+
 
 procedure TJSONboolean.SetValue(const AValue: Variant);
 begin
@@ -695,6 +720,11 @@ begin
   Result:=jtNull;
 end;
 
+procedure TJSONNull.Clear;
+begin
+  // Do nothing
+end;
+
 
 
 { TJSONFloatNumber }
@@ -770,6 +800,11 @@ begin
   Result:=ntFloat;
 end;
 
+procedure TJSONFloatNumber.Clear;
+begin
+  FValue:=0;
+end;
+
 { TJSONIntegerNumber }
 
 function TJSONIntegerNumber.GetAsBoolean: Boolean;
@@ -837,6 +872,11 @@ begin
   Result:=ntInteger;
 end;
 
+procedure TJSONIntegerNumber.Clear;
+begin
+  FValue:=0;
+end;
+
 
 { TJSONArray }
 
@@ -1084,6 +1124,11 @@ begin
   Result:=FList.IndexOf(Obj);
 end;
 
+procedure TJSONArray.Clear;
+begin
+  FList.Clear;
+end;
+
 function TJSONArray.Add(Item: TJSONData): Integer;
 begin
   Result:=FList.Add(Item);
@@ -1402,12 +1447,17 @@ end;
 
 function TJSONObject.IndexOf(Item: TJSONData): Integer;
 begin
-
+  Result:=FHash.IndexOf(Item);
 end;
 
 function TJSONObject.IndexOfName(const AName: TJSONStringType): Integer;
 begin
+  Result:=FHash.FindIndexOf(AName);
+end;
 
+procedure TJSONObject.Clear;
+begin
+  FHash.Clear;
 end;
 
 function TJSONObject.Add(const AName: TJSONStringType; AValue: TJSONData

+ 625 - 0
packages/fcl-json/src/jsonconf.pp

@@ -0,0 +1,625 @@
+{
+    This file is part of the Free Component Library
+
+    Implementation of TJSONConfig class
+    Copyright (c) 2007 Michael Van Canneyt [email protected]
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+{
+  TJSONConfig enables applications to use JSON files for storing their
+  configuration data
+}
+
+{$IFDEF FPC}
+{$MODE objfpc}
+{$H+}
+{$ENDIF}
+
+unit jsonConf;
+
+interface
+
+uses
+  SysUtils, Classes, fpjson, jsonparser;
+
+resourcestring
+  SWrongRootName = 'XML file has wrong root element name';
+
+type
+  EJSONConfigError = class(Exception);
+  TPathFlags = set of (pfHasValue, pfWriteAccess);
+
+(* ********************************************************************
+   "APath" is the path and name of a value: A JSON configuration file 
+   is hierachical. "/" is the path delimiter, the part after the last 
+   "/" is the name of the value. The path components will be mapped 
+   to nested JSON objects, with the name equal to the part. In practice 
+   this means that "/my/path/value" will be written as:
+   { 
+     "my" : {
+       "path" : {
+         "value" : Value
+       }
+     }
+   }
+   ******************************************************************** *)
+
+  { TJSONConfig }
+
+  TJSONConfig = class(TComponent)
+  private
+    FFilename: String;
+    FKey: TJSONObject;
+    procedure DoSetFilename(const AFilename: String; ForceReload: Boolean);
+    procedure SetFilename(const AFilename: String);
+    Function StripSlash(P : WideString) : WideString;
+  protected
+    FJSON: TJSONObject;
+    FModified: Boolean;
+    procedure Loaded; override;
+    function FindPath(Const APath: WideString; AllowCreate : Boolean) : TJSONObject;
+    function FindObject(Const APath: WideString; AllowCreate : Boolean) : TJSONObject;
+    function FindObject(Const APath: WideString; AllowCreate : Boolean;Var ElName : WideString) : TJSONObject;
+    function FindElement(Const APath: WideString; CreateParent : Boolean) : TJSONData;
+    function FindElement(Const APath: WideString; CreateParent : Boolean; Var AParent : TJSONObject; Var ElName : WideString) : TJSONData;
+  public
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+    procedure Clear;
+    procedure Flush;    // Writes the JSON file
+    procedure OpenKey(const aPath: WideString; AllowCreate : Boolean);
+    procedure CloseKey;
+    procedure ResetKey;
+    Procedure EnumSubKeys(Const APath : String; List : TStrings);
+    Procedure EnumValues(Const APath : String; List : TStrings);
+
+    function  GetValue(const APath: WideString; const ADefault: WideString): WideString; overload;
+    function  GetValue(const APath: WideString; ADefault: Integer): Integer; overload;
+    function  GetValue(const APath: WideString; ADefault: Boolean): Boolean; overload;
+    function  GetValue(const APath: WideString; ADefault: Double): Double; overload;
+    procedure SetValue(const APath: WideString; const AValue: WideString); overload;
+    procedure SetValue(const APath: WideString; AValue: Integer); overload;
+    procedure SetValue(const APath: WideString; AValue: Boolean); overload;
+    procedure SetValue(const APath: WideString; AValue: Double); overload;
+
+    procedure SetDeleteValue(const APath: WideString; const AValue, DefValue: WideString); overload;
+    procedure SetDeleteValue(const APath: WideString; AValue, DefValue: Integer); overload;
+    procedure SetDeleteValue(const APath: WideString; AValue, DefValue: Boolean); overload;
+
+    procedure DeletePath(const APath: WideString);
+    procedure DeleteValue(const APath: WideString);
+    property Modified: Boolean read FModified;
+  published
+    property Filename: String read FFilename write SetFilename;
+  end;
+
+
+// ===================================================================
+
+implementation
+
+Const
+  SErrInvalidJSONFile = '"%s" is not a valid JSON configuration file.';
+  SErrCouldNotOpenKey = 'Could not open key "%s".';
+
+constructor TJSONConfig.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+  FJSON:=TJSONObject.Create;
+  FKey:=FJSON;
+end;
+
+destructor TJSONConfig.Destroy;
+begin
+  if Assigned(FJSON) then
+    begin
+    Flush;
+    FreeANdNil(FJSON);
+    end;
+  inherited Destroy;
+end;
+
+procedure TJSONConfig.Clear;
+begin
+  FJSON.Clear;
+  FKey:=FJSON;
+end;
+
+procedure TJSONConfig.Flush;
+
+Var
+  F : Text;
+
+begin
+  if Modified then
+    begin
+    AssignFile(F,FileName);
+    Rewrite(F);
+    Try
+      Writeln(F,FJSON.AsJSON);
+    Finally
+      CloseFile(F);
+    end;
+    FModified := False;
+    end;
+end;
+
+
+function TJSONConfig.FindObject(Const APath: WideString; AllowCreate : Boolean) : TJSONObject;
+
+Var
+  Dummy : WideString;
+
+begin
+  Result:=FindObject(APath,AllowCreate,Dummy);
+end;
+
+function TJSONConfig.FindObject(Const APath: WideString; AllowCreate : Boolean;Var ElName : WideString) : TJSONObject;
+
+Var
+  S,El : WideString;
+  P,I : Integer;
+  T : TJSonObject;
+  
+begin
+//  Writeln('Looking for : ', APath);
+  S:=APath;
+  If Pos('/',S)=1 then
+    Result:=FJSON
+  else
+    Result:=FKey;
+  Repeat
+    P:=Pos('/',S);
+    If (P<>0) then
+      begin
+      // Only real paths, ignore double slash
+      If (P<>1) then
+        begin
+        El:=Copy(S,1,P-1);
+        If (Result.Count=0) then
+          I:=-1
+        else
+          I:=Result.IndexOfName(El);
+        If (I=-1) then
+          // No element with this name.
+          begin
+          If AllowCreate then
+            begin
+            // Create new node.
+            T:=Result;
+            Result:=TJSonObject.Create;
+            T.Add(El,Result);
+            end
+          else
+            Result:=Nil
+          end
+        else
+          // Node found, check if it is an object
+          begin
+          if (Result.Items[i].JSONtype=jtObject) then
+            Result:=Result.Objects[el]
+          else
+            begin
+//            Writeln(el,' type wrong');
+            If AllowCreate then
+              begin
+//              Writeln('Creating ',el);
+              Result.Delete(I);
+              T:=Result;
+              Result:=TJSonObject.Create;
+              T.Add(El,Result);
+              end
+            else
+              Result:=Nil
+            end;
+          end;
+        end;
+      Delete(S,1,P);
+      end;
+  Until (P=0) or (Result=Nil);
+  ElName:=S;
+end;
+
+function TJSONConfig.FindElement(Const APath: WideString; CreateParent : Boolean) : TJSONData;
+
+Var
+  O : TJSONObject;
+  ElName : WideString;
+  
+begin
+  Result:=FindElement(APath,CreateParent,O,ElName);
+end;
+
+function TJSONConfig.FindElement(Const APath: WideString; CreateParent : Boolean; Var AParent : TJSONObject; Var ElName : WideString) : TJSONData;
+
+Var
+  I : Integer;
+
+begin
+  Result:=Nil;
+  Aparent:=FindObject(APath,CreateParent,ElName);
+  If Assigned(Aparent) then
+    begin
+//    Writeln('Found parent, looking for element:',elName);
+    I:=AParent.IndexOfName(ElName);
+//    Writeln('Element index is',I);
+    If (I<>-1) And (AParent.items[I].JSONType<>jtObject) then
+      Result:=AParent.Items[i];
+    end;
+end;
+
+
+function TJSONConfig.GetValue(const APath: WideString; const ADefault: WideString): WideString;
+
+var
+  El : TJSONData;
+  
+begin
+  El:=FindElement(StripSlash(APath),False);
+  If Assigned(El) then
+    Result:=El.AsString
+  else
+    Result:=ADefault;
+end;
+
+function TJSONConfig.GetValue(const APath: WideString; ADefault: Integer): Integer;
+var
+  El : TJSONData;
+  
+begin
+  El:=FindElement(StripSlash(APath),False);
+  If Not Assigned(el) then
+    Result:=ADefault
+  else if (el is TJSONNumber) then
+    Result:=El.AsInteger
+  else
+    Result:=StrToIntDef(El.AsString,ADefault);
+end;
+
+function TJSONConfig.GetValue(const APath: WideString; ADefault: Boolean): Boolean;
+
+var
+  El : TJSONData;
+  
+begin
+  El:=FindElement(StripSlash(APath),False);
+  If Not Assigned(el) then
+    Result:=ADefault
+  else if (el is TJSONBoolean) then
+    Result:=El.AsBoolean
+  else
+    Result:=StrToBoolDef(El.AsString,ADefault);
+end;
+
+function TJSONConfig.GetValue(const APath: WideString; ADefault: Double): Double;
+
+var
+  El : TJSONData;
+
+begin
+  El:=FindElement(StripSlash(APath),False);
+  If Not Assigned(el) then
+    Result:=ADefault
+  else if (el is TJSONNumber) then
+    Result:=El.AsFloat
+  else
+    Result:=StrToFloatDef(El.AsString,ADefault);
+end;
+
+
+procedure TJSONConfig.SetValue(const APath: WideString; const AValue: WideString);
+
+var
+  El : TJSONData;
+  ElName : WideString;
+  O : TJSONObject;
+  I : integer;
+  
+begin
+  El:=FindElement(StripSlash(APath),True,O,ElName);
+  if Assigned(El) and (El.JSONType<>jtString) then
+    begin
+    I:=O.IndexOfName(elName);
+    O.Delete(i);
+    El:=Nil;
+    end;
+  If Not Assigned(el) then
+    begin
+    El:=TJSONString.Create(AValue);
+    O.Add(ElName,El);
+    end
+  else
+    El.AsString:=AVAlue;
+  FModified:=True;
+end;
+
+procedure TJSONConfig.SetDeleteValue(const APath: WideString; const AValue, DefValue: WideString);
+begin
+  if AValue = DefValue then
+    DeleteValue(APath)
+  else
+    SetValue(APath, AValue);
+end;
+
+procedure TJSONConfig.SetValue(const APath: WideString; AValue: Integer);
+
+var
+  El : TJSONData;
+  ElName : WideString;
+  O : TJSONObject;
+  I : integer;
+
+begin
+  El:=FindElement(StripSlash(APath),True,O,ElName);
+  if Assigned(El) and (Not (El is TJSONIntegerNumber)) then
+    begin
+    I:=O.IndexOfName(elName);
+    If (I<>-1) then // Normally not needed...
+      O.Delete(i);
+    El:=Nil;
+    end;
+  If Not Assigned(el) then
+    begin
+    El:=TJSONIntegerNumber.Create(AValue);
+    O.Add(ElName,El);
+    end
+  else
+    El.AsInteger:=AValue;
+  FModified:=True;
+end;
+
+procedure TJSONConfig.SetDeleteValue(const APath: WideString; AValue,
+  DefValue: Integer);
+begin
+  if AValue = DefValue then
+    DeleteValue(APath)
+  else
+    SetValue(APath, AValue);
+end;
+
+procedure TJSONConfig.SetValue(const APath: WideString; AValue: Boolean);
+
+var
+  El : TJSONData;
+  ElName : WideString;
+  O : TJSONObject;
+  I : integer;
+
+begin
+  El:=FindElement(StripSlash(APath),True,O,ElName);
+  if Assigned(El) and (el.JSONType<>jtBoolean) then
+    begin
+    I:=O.IndexOfName(elName);
+    O.Delete(i);
+    El:=Nil;
+    end;
+  If Not Assigned(el) then
+    begin
+    El:=TJSONBoolean.Create(AValue);
+    O.Add(ElName,El);
+    end
+  else
+    El.AsBoolean:=AValue;
+  FModified:=True;
+end;
+
+procedure TJSONConfig.SetValue(const APath: WideString; AValue: Double);
+
+var
+  El : TJSONData;
+  ElName : WideString;
+  O : TJSONObject;
+  I : integer;
+
+begin
+  El:=FindElement(StripSlash(APath),True,O,ElName);
+  if Assigned(El) and (Not (El is TJSONFloatNumber)) then
+    begin
+    I:=O.IndexOfName(elName);
+    O.Delete(i);
+    El:=Nil;
+    end;
+  If Not Assigned(el) then
+    begin
+    El:=TJSONFloatNumber.Create(AValue);
+    O.Add(ElName,El);
+    end
+  else
+    El.AsFloat:=AValue;
+  FModified:=True;
+end;
+
+procedure TJSONConfig.SetDeleteValue(const APath: WideString; AValue,
+  DefValue: Boolean);
+begin
+  if AValue = DefValue then
+    DeleteValue(APath)
+  else
+    SetValue(APath,AValue);
+end;
+
+procedure TJSONConfig.DeletePath(const APath: WideString);
+
+Var
+  P : String;
+  L : integer;
+  Node : TJSONObject;
+  ElName : WideString;
+  
+begin
+  P:=StripSlash(APath);
+  L:=Length(P);
+  If (L>0) then
+    begin
+    Node := FindObject(P,False,ElName);
+    If Assigned(Node) then
+      begin
+      L:=Node.IndexOfName(ElName);
+      If (L<>-1) then
+        Node.Delete(L);
+      end;
+    end;
+end;
+
+procedure TJSONConfig.DeleteValue(const APath: WideString);
+
+begin
+  DeletePath(APath);
+end;
+
+procedure TJSONConfig.Loaded;
+begin
+  inherited Loaded;
+  if Length(Filename) > 0 then
+    DoSetFilename(Filename,True);
+end;
+
+function TJSONConfig.FindPath(const APath: WideString; AllowCreate: Boolean
+  ): TJSONObject;
+  
+Var
+  P : WideString;
+  L : Integer;
+  
+begin
+  P:=APath;
+  L:=Length(P);
+  If (L=0) or (P[L]<>'/') then
+    P:=P+'/';
+  Result:=FindObject(P,AllowCreate);
+end;
+
+procedure TJSONConfig.DoSetFilename(const AFilename: String; ForceReload: Boolean);
+
+Var
+  P : TJSONParser;
+  J : TJSONData;
+  F : TFileStream;
+  
+begin
+  if (not ForceReload) and (FFilename = AFilename) then
+    exit;
+  FFilename := AFilename;
+
+  if csLoading in ComponentState then
+    exit;
+
+  Flush;
+  If Not FileExists(AFileName) then
+    Clear
+  else
+    begin
+    F:=TFileStream.Create(AFileName,fmopenRead);
+    try
+      P:=TJSONParser.Create(F);
+      try
+        J:=P.Parse;
+        If (J is TJSONObject) then
+          begin
+          FreeAndNil(FJSON);
+          FJSON:=J as TJSONObject;
+          FKey:=FJSON;
+          end
+        else
+          Raise EJSONConfigError.CreateFmt(SErrInvalidJSONFile,[AFileName]);
+      finally
+        P.Free;
+      end;
+    finally
+      F.Free;
+    end;
+    end;
+end;
+
+procedure TJSONConfig.SetFilename(const AFilename: String);
+begin
+  DoSetFilename(AFilename, False);
+end;
+
+function TJSONConfig.StripSlash(P: WideString): WideString;
+
+Var
+  L : Integer;
+
+begin
+  L:=Length(P);
+  If (L>0) and (P[l]='/') then
+    Result:=Copy(P,1,L-1)
+  else
+    Result:=P;
+end;
+
+
+procedure TJSONConfig.CloseKey;
+begin
+  ResetKey;
+end;
+
+procedure TJSONConfig.OpenKey(const aPath: WideString; AllowCreate: Boolean);
+
+Var
+  ElName : WideString;
+  P : String;
+  L : Integer;
+begin
+  P:=APath;
+  L:=Length(P);
+  If (L=0) then
+    FKey:=FJSON
+  else
+    begin
+    if (P[L]<>'/') then
+      P:=P+'/';
+    FKey:=FindObject(P,AllowCreate);
+    If (FKey=Nil) Then
+      Raise EJSONConfigError.CreateFmt(SErrCouldNotOpenKey,[APath]);
+    end;
+end;
+
+procedure TJSONConfig.ResetKey;
+begin
+  FKey:=FJSON;
+end;
+
+procedure TJSONConfig.EnumSubKeys(const APath: String; List: TStrings);
+
+Var
+  AKey : TJSONObject;
+  I : Integer;
+  
+begin
+  AKey:=FindPath(APath,False);
+  If Assigned(AKey) then
+    begin
+    For I:=0 to AKey.Count-1 do
+      If AKey.Items[i] is TJSONObject then
+        List.Add(AKey.Names[i]);
+    end;
+end;
+
+procedure TJSONConfig.EnumValues(const APath: String; List: TStrings);
+
+Var
+  AKey : TJSONObject;
+  I : Integer;
+
+begin
+  AKey:=FindPath(APath,False);
+  If Assigned(AKey) then
+    begin
+    For I:=0 to AKey.Count-1 do
+      If Not (AKey.Items[i] is TJSONObject) then
+        List.Add(AKey.Names[i]);
+    end;
+end;
+
+
+end.

+ 258 - 0
packages/fcl-json/tests/jsonconftest.pp

@@ -0,0 +1,258 @@
+unit jsonconftest;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, fpcunit, testutils, testregistry, jsonconf;
+
+type
+
+  { TTestJSONConfig }
+
+  TTestJSONConfig= class(TTestCase)
+  Private
+    Function CreateConf(AFileName : String) : TJSONCOnfig;
+    Procedure DeleteConf(C : TJSONConfig; DeleteConfFile : Boolean = true);
+  published
+    procedure TestDataTypes;
+    procedure TestSubNodes;
+    procedure TestEnumSubkeys;
+    procedure TestEnumValues;
+    procedure TestClear;
+    procedure TestKey;
+  end;
+
+implementation
+
+function TTestJSONConfig.CreateConf(AFileName: String): TJSONCOnfig;
+begin
+  Result:=TJSONConfig.Create(Nil);
+  Result.FileName:=AFileName;
+end;
+
+procedure TTestJSONConfig.DeleteConf(C: TJSONConfig; DeleteConfFile: Boolean);
+
+Var
+  FN : String;
+
+begin
+  If DeleteConfFile then
+    FN:=C.FileName;
+  FreeAndNil(C);
+  If DeleteConfFile then
+    DeleteFile(FN);
+end;
+
+procedure TTestJSONConfig.TestDataTypes;
+
+Const
+  A = 1;
+  B = 'A string';
+  C = 1.23;
+  D = True;
+
+Var
+  Co : TJSONCOnfig;
+
+begin
+  Co:=CreateConf('test.json');
+  try
+    Co.SetValue('a',a);
+    AssertEquals('Integer read/Write',a,Co.GetValue('a',0));
+    Co.SetValue('b',b);
+    AssertEquals('String read/Write',b,Co.GetValue('b',''));
+    Co.SetValue('c',C);
+    AssertEquals('Float read/Write',c,Co.GetValue('c',0.0),0.01);
+    Co.SetValue('d',d);
+    AssertEquals('Boolean read/Write',d,Co.GetValue('d',False));
+    Co.Flush;
+  finally
+    DeleteConf(Co,True);
+  end;
+end;
+
+procedure TTestJSONConfig.TestSubNodes;
+
+Var
+  C : TJSONCOnfig;
+
+begin
+  C:=CreateConf('test.json');
+  try
+    C.SetValue('a',1);
+    AssertEquals('Read at root',1,C.GetValue('a',0));
+    C.SetValue('b/a',2);
+    AssertEquals('Read at root',2,C.GetValue('b/a',2));
+    C.SetValue('b/c/a',3);
+    AssertEquals('Read at root',3,C.GetValue('b/c/a',3));
+  finally
+    DeleteConf(C,True);
+  end;
+end;
+
+procedure TTestJSONConfig.TestEnumSubkeys;
+Var
+  C : TJSONCOnfig;
+  L : TStringList;
+  
+begin
+  C:=CreateConf('test.json');
+  try
+    C.SetValue('/a',1);
+    C.SetValue('/b/a',2);
+    C.SetValue('/b/b',2);
+    C.SetValue('/c/a',3);
+    C.SetValue('/c/b/a',4);
+    C.SetValue('/c/c/a',4);
+    C.SetValue('/c/d/d',4);
+    L:=TStringList.Create;
+    try
+      C.EnumSubKeys('/',L);
+      If (L.Count<>2) then
+        Fail('EnumSubkeys count');
+      If (L[0]<>'b') then
+        Fail('EnumSubkeys first element');
+      If (L[1]<>'c') then
+        Fail('EnumSubkeys second element');
+    finally
+      L.Free;
+    end;
+  finally
+    DeleteConf(C,True);
+  end;
+end;
+
+procedure TTestJSONConfig.TestEnumValues;
+Var
+  C : TJSONCOnfig;
+  L : TStringList;
+
+begin
+  C:=CreateConf('test.json');
+  try
+    C.SetValue('/a',1);
+    C.SetValue('/b/a',2);
+    C.SetValue('/b/b',2);
+    C.SetValue('/c/a',3);
+    C.SetValue('/c/b/a',4);
+    C.SetValue('/c/c/a',4);
+    C.SetValue('/c/d/d',4);
+    L:=TStringList.Create;
+    try
+      C.EnumValues('/',L);
+      If (L.Count<>1) then
+        Fail('EnumValues count');
+      If (L[0]<>'a') then
+        Fail('EnumValues first element');
+      L.Clear;
+      C.EnumValues('/b',L);
+      If (L.Count<>2) then
+        Fail('EnumValues subkey count');
+      If (L[0]<>'a') then
+        Fail('EnumValues subkey first element');
+      If (L[1]<>'b') then
+        Fail('EnumValues subkey second element');
+    finally
+      L.Free;
+    end;
+  finally
+    DeleteConf(C,True);
+  end;
+end;
+
+procedure TTestJSONConfig.TestClear;
+
+Var
+  C : TJSONCOnfig;
+
+begin
+  C:=CreateConf('test.json');
+  try
+    C.SetValue('a',1);
+    C.DeleteValue('a');
+    AssertEquals('Delete value',0,C.GetValue('a',0));
+    C.SetValue('b/a',1);
+    C.SetValue('b/c',2);
+    C.DeleteValue('b/a');
+    AssertEquals('Delete value in subkey',0,C.GetValue('a',0));
+    AssertEquals('Delete value only clears deleted value',2,C.GetValue('b/c',0));
+    C.SetValue('b/a',1);
+    C.DeletePath('b');
+    AssertEquals('Delete path',0,C.GetValue('b/a',0));
+    AssertEquals('Delete path deletes all values',0,C.GetValue('b/c',0));
+    C.Clear;
+    AssertEquals('Clear',0,C.GetValue('/a',0));
+  finally
+    DeleteConf(C,True);
+  end;
+end;
+
+procedure TTestJSONConfig.TestKey;
+
+Var
+  C : TJSONCOnfig;
+  L : TStrings;
+  
+begin
+  C:=CreateConf('test.json');
+  try
+    C.SetValue('a',1);
+    C.SetValue('b/a',2);
+    C.SetValue('b/b',2);
+    C.SetValue('b/c/a',3);
+    C.SetValue('b/c/b',3);
+    C.OpenKey('/b',False);
+    AssertEquals('Read relative to key a',2,C.GetValue('a',0));
+    AssertEquals('Read relative to key b',2,C.GetValue('b',0));
+    AssertEquals('Read in subkey relative to key a',3,C.GetValue('c/a',0));
+    AssertEquals('Read in subkey relative to key b',3,C.GetValue('c/b',0));
+    AssertEquals('Read absolute, disregarding key',1,C.GetValue('/a',0));
+    AssertEquals('Read absolute in subkey, disregarding key',2,C.GetValue('/b/a',0));
+    AssertEquals('Read absolute in subkeys, disregarding key',3,C.GetValue('/b/c/a',0));
+    C.CloseKey;
+    AssertEquals('Closekey',1,C.GetValue('a',0));
+    C.OpenKey('b',False);
+    C.OpenKey('c',False);
+    AssertEquals('Open relative key',3,C.GetValue('a',0));
+    C.ResetKey;
+    AssertEquals('ResetKey',1,C.GetValue('a',0));
+    C.Clear;
+    L:=TStringList.Create;
+    try
+      C.EnumSubKeys('/',L);
+      If (L.Count<>0) then
+        Fail('clear failed');
+      C.OpenKey('/a/b/c/d',true);
+      C.EnumSubKeys('/a',L);
+      If (L.Count<>1) then
+        Fail('Open key with allowcreate, level 1');
+      If (L[0]<>'b') then
+        Fail('Open key with allowcreate, level 1');
+      L.Clear;
+      C.EnumSubKeys('/a/b',L);
+      If (L.Count<>1) then
+        Fail('Open key with allowcreate, level 2');
+      If (L[0]<>'c') then
+        Fail('Open key with allowcreate, level 2');
+      L.Clear;
+      C.EnumSubKeys('/a/b/c',L);
+      If (L.Count<>1) then
+        Fail('Open key with allowcreate, level 3');
+      If (L[0]<>'d') then
+        Fail('Open key with allowcreate, level 3');
+    finally
+      L.Free;
+    end;
+  finally
+    DeleteConf(C,True);
+  end;
+end;
+
+
+initialization
+
+  RegisterTest(TTestJSONConfig); 
+end.
+

+ 64 - 0
packages/fcl-json/tests/testjsonconf.lpi

@@ -0,0 +1,64 @@
+<?xml version="1.0"?>
+<CONFIG>
+  <ProjectOptions>
+    <PathDelim Value="/"/>
+    <Version Value="5"/>
+    <General>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <TargetFileExt Value=""/>
+    </General>
+    <VersionInfo>
+      <ProjectVersion Value=""/>
+    </VersionInfo>
+    <PublishOptions>
+      <Version Value="2"/>
+      <IgnoreBinaries Value="False"/>
+      <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
+      <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
+    </PublishOptions>
+    <RunParams>
+      <local>
+        <FormatVersion Value="1"/>
+        <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
+      </local>
+    </RunParams>
+    <RequiredPackages Count="2">
+      <Item1>
+        <PackageName Value="FPCUnitConsoleRunner"/>
+      </Item1>
+      <Item2>
+        <PackageName Value="FCL"/>
+      </Item2>
+    </RequiredPackages>
+    <Units Count="3">
+      <Unit0>
+        <Filename Value="testjsonconf.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="testjsonconf"/>
+      </Unit0>
+      <Unit1>
+        <Filename Value="jsonconftest.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="jsonconftest"/>
+      </Unit1>
+      <Unit2>
+        <Filename Value="../src/jsonconf.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="jsonConf"/>
+      </Unit2>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="5"/>
+    <SearchPaths>
+      <OtherUnitFiles Value="../src/"/>
+    </SearchPaths>
+    <CodeGeneration>
+      <Generate Value="Faster"/>
+    </CodeGeneration>
+    <Other>
+      <CompilerPath Value="$(CompPath)"/>
+    </Other>
+  </CompilerOptions>
+</CONFIG>

+ 25 - 0
packages/fcl-json/tests/testjsonconf.pp

@@ -0,0 +1,25 @@
+program testjsonconf;
+
+{$mode objfpc}{$H+}
+
+uses
+  Classes, consoletestrunner, jsonconftest, jsonconf;
+
+type
+
+  { TLazTestRunner }
+
+  TMyTestRunner = class(TTestRunner)
+  protected
+  // override the protected methods of TTestRunner to customize its behavior
+  end;
+
+var
+  Application: TMyTestRunner;
+
+begin
+  Application := TMyTestRunner.Create(nil);
+  Application.Initialize;
+  Application.Run;
+  Application.Free;
+end.